alder_lake_bios/Insyde/InsydeModulePkg/Universal/BdsDxe/MemoryTest.c

925 lines
28 KiB
C

/** @file
Perform the platform memory test
;******************************************************************************
;* Copyright (c) 2012 - 2021, Insyde Software Corp. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corporation.
;*
;******************************************************************************
Copyright (c) 2004 - 2012, 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 "Bds.h"
#include "String.h"
#include "OemDataHubSubClassMemory.h"
STATIC BOOLEAN mAbortMemoryTest = FALSE;
//
// BDS Platform Functions
//
EFI_STATUS
VerifyMemorySize (
VOID
);
EFI_STATUS
GetEfiSysMemSize (
OUT UINT64 *MemSize
);
EFI_STATUS
GetSpdMemSize (
OUT UINT64 *MemSize
);
VOID
FakeMemoryTestFn (
IN EXTENDMEM_COVERAGE_LEVEL Level,
IN UINTN BaseLine,
IN UINT64 MemSize,
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground,
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background,
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color
);
EFI_STATUS
MemoryTestFn (
IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *GenMemoryTest,
IN BOOLEAN RequireSoftECCInit,
IN BOOLEAN DisplayProgress,
IN UINTN BaseLine,
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground,
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background,
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color
);
/**
Clear Memory test information.
@param[in] Background Background color for String.
@retval EFI_SUCCESS Clear memory test information successfully.
@retval EFI_NOT_FOUND Cannot find corresponding gEfiGraphicsOutputProtocolGuid or
gEfiUgaDrawProtocolGuid protocol.
@retval EFI_UNSUPPORTED Cannot get horizontal and vertical resolution.
@retval EFI_OUT_OF_RESOURCES Allocate memory failed.
**/
STATIC
EFI_STATUS
BdsClearMemoryProgress (
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background
)
{
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
EFI_UGA_DRAW_PROTOCOL *UgaDraw;
UINT32 ColorDepth;
UINT32 RefreshRate;
EFI_STATUS Status;
UINT32 SizeOfX;
UINT32 SizeOfY;
UINTN PosY;
CHAR16 *SpaceString;
UINTN Index;
UINTN StrLength;
UgaDraw = NULL;
Status = gBS->HandleProtocol (
gST->ConsoleOutHandle,
&gEfiGraphicsOutputProtocolGuid,
(VOID **) &GraphicsOutput
);
if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
GraphicsOutput = NULL;
Status = gBS->HandleProtocol (
gST->ConsoleOutHandle,
&gEfiUgaDrawProtocolGuid,
(VOID **) &UgaDraw
);
}
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
SizeOfX = 0;
SizeOfY = 0;
if (GraphicsOutput != NULL) {
SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
} else if (UgaDraw != NULL) {
Status = UgaDraw->GetMode (
UgaDraw,
&SizeOfX,
&SizeOfY,
&ColorDepth,
&RefreshRate
);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
} else {
return EFI_UNSUPPORTED;
}
StrLength = SizeOfX / EFI_GLYPH_WIDTH;
SpaceString = AllocateZeroPool ((StrLength + 1) * sizeof (CHAR16));
if (SpaceString == NULL) {
return EFI_OUT_OF_RESOURCES;
}
for (Index = 0; Index < StrLength; Index++) {
SpaceString[Index] = 0x20;
}
PosY = SizeOfY * 48 / 50;
PrintXY (
0,
PosY - EFI_GLYPH_HEIGHT - 1,
&Background,
&Background,
SpaceString
);
PrintXY (
0,
PosY - 1,
&Background,
&Background,
SpaceString
);
FreePool (SpaceString);
return EFI_SUCCESS;
}
/**
Perform the memory test base on the memory test intensive level,
and update the memory resource.
@param[in] Level The memory test intensive level.
@param[in] BaseLine Row value of base line
@retval EFI_STATUS Success test all the system memory and update the memory resource
**/
EFI_STATUS
EFIAPI
BdsMemoryTest (
IN EXTENDMEM_COVERAGE_LEVEL Level,
IN UINTN BaseLine
)
{
EFI_STATUS Status;
BOOLEAN RequireSoftECCInit;
EFI_GENERIC_MEMORY_TEST_PROTOCOL *GenMemoryTest;
UINT64 TotalMemorySize;
UINT64 PreviousValue;
CHAR16 *StrTotalMemory;
CHAR16 *Pos;
CHAR16 *TmpStr;
BOOLEAN IsFirstBoot;
BOOLEAN DisplayProgress;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color;
BOOLEAN QuietBootEnabled;
UINT8 BootDisplayMode;
BdsLibGetQuietBootState (&QuietBootEnabled);
DisplayProgress = TRUE;
if (Level == IGNORE) {
DisplayProgress = FALSE;
}
TotalMemorySize = 0;
PreviousValue = 0;
SetMem (&Foreground, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);
SetMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);
SetMem (&Color , sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);
RequireSoftECCInit = FALSE;
gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE);
gST->ConOut->EnableCursor (gST->ConOut, FALSE);
Status = gBS->LocateProtocol (
&gEfiGenericMemTestProtocolGuid,
NULL,
(VOID **) &GenMemoryTest
);
if (EFI_ERROR (Status)) {
return EFI_SUCCESS;
}
Status = GenMemoryTest->MemoryTestInit (
GenMemoryTest,
Level,
&RequireSoftECCInit
);
if (Status == EFI_NO_MEDIA) {
//
// The PEI codes also have the relevant memory test code to check the memory,
// it can select to test some range of the memory or all of them. If PEI code
// checks all the memory, this BDS memory test will has no not-test memory to
// do the test, and then the status of EFI_NO_MEDIA will be returned by
// "MemoryTestInit". So it does not need to test memory again, just return.
//
if (DisplayProgress) {
Status = GetEfiSysMemSize (&TotalMemorySize);
if (!EFI_ERROR (Status)) {
FakeMemoryTestFn (Level, BaseLine, TotalMemorySize, Foreground, Background, Color);
}
}
} else {
Status = MemoryTestFn (
GenMemoryTest,
RequireSoftECCInit,
DisplayProgress,
BaseLine,
Foreground,
Background,
Color
);
if (EFI_ERROR (Status)) {
return Status;
}
}
//
// Check the memory size between memory map(E820) and SPD
//
Status = VerifyMemorySize ();
ASSERT_EFI_ERROR (Status);
if (DisplayProgress) {
Pos = AllocatePool (128);
if (Pos == NULL) {
return EFI_SUCCESS;
}
StrTotalMemory = Pos;
GetSpdMemSize (&TotalMemorySize);
UnicodeValueToStringS (StrTotalMemory, 128, COMMA_TYPE, TotalMemorySize, 0);
if (StrTotalMemory[0] == L',') {
StrTotalMemory++;
}
TmpStr = GetStringById (STRING_TOKEN (STR_MEM_TEST_COMPLETED));
if (TmpStr != NULL) {
StrCatS (StrTotalMemory, 128 / sizeof(CHAR16), TmpStr);
FreePool (TmpStr);
}
gBdsServices->GetBootDisplayMode (gBdsServices, &BootDisplayMode);
if (BootDisplayMode == H2O_BDS_BOOT_DISPLAY_MODE_NORMAL) {
gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE);
gST->ConOut->SetCursorPosition (gST->ConOut, 0, (BaseLine + 2));
gST->ConOut->EnableCursor (gST->ConOut, FALSE);
gST->ConOut->OutputString (gST->ConOut, StrTotalMemory);
gST->ConOut->SetCursorPosition (gST->ConOut, 0, (BaseLine + 3));
} else {
BdsLibShowProgress (
Foreground,
Background,
StrTotalMemory,
Color,
100,
(UINTN) PreviousValue
);
BdsClearMemoryProgress (Background);
}
FreePool (Pos);
}
//
// Use a DynamicHii type pcd to save the boot status, which is used to
// control configuration mode, such as FULL/MINIMAL/NO_CHANGES configuration.
//
IsFirstBoot = PcdGetBool(PcdBootState);
if (IsFirstBoot) {
Status = PcdSetBoolS(PcdBootState, FALSE);
ASSERT_EFI_ERROR (Status);
}
return EFI_SUCCESS;
}
/**
Check the memory size between memory map(E820) and SPD
@retval EFI_SUCCESS Check memory finish.
@retval Other Error return value from get memory function
**/
EFI_STATUS
VerifyMemorySize (
VOID
)
{
EFI_STATUS Status;
UINT64 MemoryMapSize;
UINT64 SPDMemorySize;
EFI_HANDLE Handle;
Handle = NULL;
SPDMemorySize = 0;
MemoryMapSize = 0;
Status = GetEfiSysMemSize (&MemoryMapSize);
if (EFI_ERROR (Status)) {
return Status;
}
Status = GetSpdMemSize (&SPDMemorySize);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Compare memory size between memory map size and SPD size
//
if (SPDMemorySize != MemoryMapSize) {
//
// Install gMemoryErrorEventGuid protocol when memory information is not consistent with Memory SPD
//
Status = gBS->InstallProtocolInterface (
&Handle,
&gMemoryErrorEventGuid,
EFI_NATIVE_INTERFACE,
NULL
);
}
return EFI_SUCCESS;
}
/**
Get SPD memory size from SMBIOS
@param[out] MemSize SPD memory size.
@retval EFI_SUCCESS Get system memory size success.
@retval EFI_INVALID_PARAMETER Output parameter is NULL.
@retval Other Locate SMBIOS protocol fail.
**/
EFI_STATUS
GetSpdMemSize (
OUT UINT64 *MemSize
)
{
EFI_STATUS Status;
EFI_SMBIOS_PROTOCOL *Smbios;
EFI_SMBIOS_HANDLE SmbiosHandle;
EFI_SMBIOS_TABLE_HEADER *Record;
SMBIOS_TABLE_TYPE17 *Type17Record;
UINT64 Size;
UINT64 SPDMemorySize;
if (MemSize == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = gBS->LocateProtocol (
&gEfiSmbiosProtocolGuid,
NULL,
(VOID **) &Smbios
);
if (EFI_ERROR (Status)) {
return Status;
}
Size = 0;
SPDMemorySize = 0;
SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
do {
Status = Smbios->GetNext (Smbios, &SmbiosHandle, NULL, &Record, NULL);
if (EFI_ERROR(Status)) {
break;
}
if (Record->Type == EFI_SMBIOS_TYPE_MEMORY_DEVICE) {
Type17Record = (SMBIOS_TABLE_TYPE17 *) Record;
if (Type17Record->Size == 0 || Type17Record->Size == 0xFFFF) {
continue;
}
if (Type17Record->Size < 0x8000) {
Size = MultU64x32 (Type17Record->Size, MEGABYTE);
} else {
Size = MultU64x32 (Type17Record->Size - 0x8000, KILOBYTE);
}
SPDMemorySize += Size;
}
} while (Status == EFI_SUCCESS);
*MemSize = SPDMemorySize;
return EFI_SUCCESS;
}
/**
Get EFI system memory size.
@param[out] MemSize EFI system memory size.
@retval EFI_SUCCESS Get system memory size success.
@retval EFI_INVALID_PARAMETER Output parameter is NULL.
@retval Other Get system memory map fail.
**/
EFI_STATUS
GetEfiSysMemSize (
OUT UINT64 *MemSize
)
{
EFI_STATUS Status;
EFI_MEMORY_DESCRIPTOR *EfiMemoryMap;
EFI_MEMORY_DESCRIPTOR *EfiMemoryMapEnd;
EFI_MEMORY_DESCRIPTOR *EfiEntry;
UINTN EfiMemoryMapSize;
UINTN EfiMapKey;
UINTN EfiDescriptorSize;
UINT32 EfiDescriptorVersion;
EFI_PEI_HOB_POINTERS Hob;
EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
UINT64 MemoryBlockLength;
UINT64 MemoryMapSize;
if (MemSize == NULL) {
return EFI_INVALID_PARAMETER;
}
EfiMemoryMapSize = 0;
EfiMemoryMap = NULL;
Status = gBS->GetMemoryMap (
&EfiMemoryMapSize,
EfiMemoryMap,
&EfiMapKey,
&EfiDescriptorSize,
&EfiDescriptorVersion
);
while (Status == EFI_BUFFER_TOO_SMALL) {
EfiMemoryMap = AllocatePool (EfiMemoryMapSize);
ASSERT (EfiMemoryMap != NULL);
if (EfiMemoryMap == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Status = gBS->GetMemoryMap (
&EfiMemoryMapSize,
EfiMemoryMap,
&EfiMapKey,
&EfiDescriptorSize,
&EfiDescriptorVersion
);
if (EFI_ERROR (Status)) {
FreePool (EfiMemoryMap);
EfiMemoryMap = NULL;
}
}
if (EfiMemoryMap == NULL) {
return EFI_ABORTED;
}
//
// Calculate the system memory size from EFI memory map and resourceHob
//
EfiEntry = EfiMemoryMap;
EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);
//
// Default memory is 1MB, due to some platform doesn't save A0000~100000h in memory map or Hob.
//
MemoryMapSize = 0x100000;
while (EfiEntry < EfiMemoryMapEnd) {
MemoryBlockLength = (UINT64) (LShiftU64 (EfiEntry->NumberOfPages, 12));
if ((EfiEntry->PhysicalStart + MemoryBlockLength) > 0x100000) {
if ((EfiEntry->Type != EfiMemoryMappedIO) &&
(EfiEntry->Type != EfiMemoryMappedIOPortSpace)) {
MemoryMapSize += MemoryBlockLength;
}
}
EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
}
//
// Search the reserved memory map
//
Hob.Raw = GetHobList ();
if (Hob.Raw != NULL) {
for (; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
ResourceHob = Hob.ResourceDescriptor;
if (ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_RESERVED) {
if ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > 0x100000) {
MemoryMapSize += ResourceHob->ResourceLength;
}
}
}
}
}
*MemSize = MemoryMapSize;
FreePool (EfiMemoryMap);
return EFI_SUCCESS;
}
/**
Fake memory test function which only show memory test progress information.
@param[in] Level The memory test intensive level.
@param[in] BaseLine Row value of base line
@param[in] MemSize Memory size.
@param[in] Foreground Foreground color for Title.
@param[in] Background Background color for Title.
@param[in] Color Progress bar color.
**/
VOID
FakeMemoryTestFn (
IN EXTENDMEM_COVERAGE_LEVEL Level,
IN UINTN BaseLine,
IN UINT64 MemSize,
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground,
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background,
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color
)
{
CHAR16 StrPercent[80];
CHAR16 *TmpStr;
UINTN TestPercent;
UINT64 PreviousValue;
UINTN TestBlockSize;
UINT64 TestBlockNum;
UINTN Index;
UINT8 BootDisplayMode;
CHAR8 *PcdASCIIStr;
CHAR16 *PerfMemTestStr;
CHAR16 *UnicodeHotKey;
CHAR16 *SkipHotKeyStr;
UINTN CombineStrSize;
PreviousValue = 0;
UnicodeHotKey = NULL;
SkipHotKeyStr = NULL;
PerfMemTestStr = GetStringById (STRING_TOKEN (STR_PERFORM_MEM_TEST));
PcdASCIIStr = (CHAR8 *) PcdGetPtr(PcdH2OBdsCancelMemoryTestHotKey);
if (PerfMemTestStr != NULL && PcdASCIIStr != NULL && *PcdASCIIStr != '\0') {
UnicodeHotKey = AllocateZeroPool (AsciiStrSize (PcdASCIIStr) * sizeof (CHAR16));
if (UnicodeHotKey == NULL) {
goto Exit;
}
AsciiStrToUnicodeStrS (PcdASCIIStr, UnicodeHotKey, AsciiStrSize (PcdASCIIStr));
TmpStr = GetStringById (STRING_TOKEN (STR_PROMPT_SKIP));
if (TmpStr == NULL) {
goto Exit;
}
CombineStrSize = StrSize (TmpStr) + StrSize (UnicodeHotKey);
SkipHotKeyStr = AllocateZeroPool (CombineStrSize);
if (SkipHotKeyStr == NULL) {
FreePool (TmpStr);
goto Exit;
}
UnicodeSPrint (SkipHotKeyStr, CombineStrSize, TmpStr, UnicodeHotKey);
FreePool (TmpStr);
CombineStrSize = StrSize (PerfMemTestStr) + StrSize (SkipHotKeyStr);
TmpStr = AllocateZeroPool (CombineStrSize);
if (TmpStr == NULL) {
goto Exit;
}
UnicodeSPrint (TmpStr, CombineStrSize, L"%s%s", PerfMemTestStr, SkipHotKeyStr);
FreePool (PerfMemTestStr);
PerfMemTestStr = TmpStr;
}
if (Level == EXTENSIVE) {
TestBlockSize = 0x40;
} else {
TestBlockSize = 0x200000;
}
TestBlockNum = DivU64x32 (MemSize, (UINT32) TestBlockSize);
gBdsServices->GetBootDisplayMode (gBdsServices, &BootDisplayMode);
for (Index = 0; Index <= TestBlockNum; Index++) {
TestPercent = (UINTN) DivU64x64Remainder (MultU64x32 (Index, 100), TestBlockNum, NULL);
if (TestPercent == PreviousValue) {
continue;
}
if (BootDisplayMode == H2O_BDS_BOOT_DISPLAY_MODE_NORMAL) {
UnicodeValueToStringS (StrPercent, sizeof(StrPercent), 0, TestPercent, 0);
gST->ConOut->SetCursorPosition (gST->ConOut, 0, BaseLine);
TmpStr = GetStringById (STRING_TOKEN (STR_MEMORY_TEST_PERCENT));
if (TmpStr != NULL) {
//
// TmpStr size is 64, StrPercent is reserved to 16.
//
BdsLibOutputStrings (gST->ConOut, StrPercent, TmpStr, NULL);
FreePool (TmpStr);
}
} else {
if (PerfMemTestStr != NULL) {
BdsLibShowProgress (
Foreground,
Background,
PerfMemTestStr,
Color,
TestPercent,
(UINTN) PreviousValue
);
}
}
PreviousValue = TestPercent;
}
Exit:
if (PerfMemTestStr != NULL) {
FreePool (PerfMemTestStr);
}
if (UnicodeHotKey != NULL) {
FreePool (UnicodeHotKey);
}
if (SkipHotKeyStr != NULL) {
FreePool (SkipHotKeyStr);
}
}
/**
Key notification function to check if the hot key of aborting memory test is pressed.
@param[in] KeyData The key that was pressed.
@retval EFI_SUCCESS The operation was successful.
**/
EFI_STATUS
EFIAPI
MemoryTestKeyNotifyFn (
IN EFI_KEY_DATA *KeyData
)
{
mAbortMemoryTest = TRUE;
return EFI_SUCCESS;
}
/**
Perform memory test.
@param[in] GenMemoryTest Memory test function instance.
@param[in] RequireSoftECCInit Indicate if the memory need software ECC init.
@param[in] DisplayProgress Flag to decide to show progress or not.
@param[in] BaseLine Row value of base line
@param[in] Foreground Foreground color for Title.
@param[in] Background Background color for Title.
@param[in] Color Progress bar color.
@retval EFI_SUCCESS Success to perform memory test.
@retval EFI_INVALID_PARAMETER Memory test funtion pointer is NULL.
@retval Other Memory test function return error status.
**/
EFI_STATUS
MemoryTestFn (
IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *GenMemoryTest,
IN BOOLEAN RequireSoftECCInit,
IN BOOLEAN DisplayProgress,
IN UINTN BaseLine,
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground,
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background,
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color
)
{
EFI_STATUS Status;
CHAR16 *TmpStr;
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleTextInEx;
UINT64 TestedMemorySize;
UINT64 TotalMemorySize;
UINTN TestPercent;
UINT64 PreviousValue;
BOOLEAN ErrorOut;
BOOLEAN TestAbort;
CHAR16 StrPercent[80];
EFI_KEY_DATA KeyData;
UINT8 BootDisplayMode;
EFI_HANDLE KeyNotifyHandle;
H2O_KEY_DESC_PROTOCOL *KeyDesc;
CHAR8 *PcdASCIIStr;
CHAR16 *PerfMemTestStr;
CHAR16 *UnicodeHotKey;
CHAR16 *CombineStr;
CHAR16 *SkipHotKeyStr;
UINTN CombineStrSize;
if (GenMemoryTest == NULL) {
return EFI_INVALID_PARAMETER;
}
TestedMemorySize = 0;
TotalMemorySize = 0;
PreviousValue = 0;
ErrorOut = FALSE;
TestAbort = FALSE;
SimpleTextInEx = NULL;
KeyNotifyHandle = NULL;
mAbortMemoryTest = FALSE;
UnicodeHotKey = NULL;
SkipHotKeyStr = NULL;
gBdsServices->GetBootDisplayMode (gBdsServices, &BootDisplayMode);
Status = gBS->LocateProtocol (&gH2OKeyDescProtocolGuid, NULL, (VOID **) &KeyDesc);
if (EFI_ERROR (Status)) {
return Status;
}
PerfMemTestStr = GetStringById (STRING_TOKEN (STR_PERFORM_MEM_TEST));
PcdASCIIStr = (CHAR8 *) PcdGetPtr(PcdH2OBdsCancelMemoryTestHotKey);
if (PerfMemTestStr != NULL && PcdASCIIStr != NULL && *PcdASCIIStr != '\0') {
UnicodeHotKey = AllocateZeroPool (AsciiStrSize (PcdASCIIStr) * sizeof (CHAR16));
if (UnicodeHotKey == NULL) {
return EFI_OUT_OF_RESOURCES;
}
AsciiStrToUnicodeStrS (PcdASCIIStr, UnicodeHotKey, AsciiStrSize (PcdASCIIStr));
TmpStr = GetStringById (STRING_TOKEN (STR_PROMPT_SKIP));
if (TmpStr == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto Exit;
}
CombineStrSize = StrSize (TmpStr) + StrSize (UnicodeHotKey);
SkipHotKeyStr = AllocateZeroPool (CombineStrSize);
if (SkipHotKeyStr == NULL) {
Status = EFI_OUT_OF_RESOURCES;
FreePool (TmpStr);
goto Exit;
}
UnicodeSPrint (SkipHotKeyStr, CombineStrSize, TmpStr, UnicodeHotKey);
FreePool (TmpStr);
CombineStrSize = StrSize (PerfMemTestStr) + StrSize (SkipHotKeyStr);
TmpStr = AllocateZeroPool (CombineStrSize);
if (TmpStr == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto Exit;
}
UnicodeSPrint (TmpStr, CombineStrSize, L"%s%s", PerfMemTestStr, SkipHotKeyStr);
FreePool (PerfMemTestStr);
PerfMemTestStr = TmpStr;
}
if (DisplayProgress && (UnicodeHotKey != NULL)) {
if (BootDisplayMode == H2O_BDS_BOOT_DISPLAY_MODE_NORMAL) {
gST->ConOut->SetCursorPosition (gST->ConOut, 0, (BaseLine + 2));
TmpStr = GetStringById (STRING_TOKEN (STR_TO_SKIP_MEM_TEST));
if (TmpStr == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto Exit;
}
CombineStrSize = StrSize (TmpStr) + StrSize (UnicodeHotKey);
CombineStr = AllocateZeroPool (CombineStrSize);
if (CombineStr != NULL) {
UnicodeSPrint (CombineStr, CombineStrSize, TmpStr, UnicodeHotKey);
gST->ConOut->OutputString (gST->ConOut, CombineStr);
FreePool (TmpStr);
FreePool (CombineStr);
}
}
gBS->HandleProtocol (
gST->ConsoleInHandle,
&gEfiSimpleTextInputExProtocolGuid,
(VOID **) &SimpleTextInEx
);
if (SimpleTextInEx != NULL) {
ZeroMem (&KeyData, sizeof (KeyData));
Status = KeyDesc->KeyFromString (KeyDesc, UnicodeHotKey, &KeyData);
if (!EFI_ERROR (Status)) {
KeyData.KeyState.KeyToggleState = 0;
SimpleTextInEx->RegisterKeyNotify (SimpleTextInEx, &KeyData, MemoryTestKeyNotifyFn, &KeyNotifyHandle);
}
}
}
do {
Status = GenMemoryTest->PerformMemoryTest (
GenMemoryTest,
&TestedMemorySize,
&TotalMemorySize,
&ErrorOut,
TestAbort
);
if (ErrorOut && (Status == EFI_DEVICE_ERROR)) {
if (BootDisplayMode == H2O_BDS_BOOT_DISPLAY_MODE_NORMAL) {
TmpStr = GetStringById (STRING_TOKEN (STR_SYSTEM_MEM_ERROR));
if (TmpStr != NULL) {
PrintXY (10, 10, NULL, NULL, TmpStr);
gST->ConOut->SetCursorPosition (gST->ConOut, 0, (BaseLine + 4));
gST->ConOut->OutputString (gST->ConOut, TmpStr);
FreePool (TmpStr);
}
}
ASSERT (0);
}
if (!DisplayProgress) {
continue;
}
TestPercent = (UINTN) DivU64x64Remainder (
MultU64x32 (TestedMemorySize, 100),
TotalMemorySize,
NULL
);
if (TestPercent != PreviousValue) {
if (BootDisplayMode == H2O_BDS_BOOT_DISPLAY_MODE_NORMAL) {
UnicodeValueToStringS (StrPercent, sizeof(StrPercent), 0, TestPercent, 0);
gST->ConOut->SetCursorPosition (gST->ConOut, 0, BaseLine);
TmpStr = GetStringById (STRING_TOKEN (STR_MEMORY_TEST_PERCENT));
if (TmpStr != NULL) {
//
// TmpStr size is 64, StrPercent is reserved to 16.
//
BdsLibOutputStrings (gST->ConOut, StrPercent, TmpStr, NULL);
FreePool (TmpStr);
}
} else {
if (PerfMemTestStr != NULL) {
BdsLibShowProgress (
Foreground,
Background,
PerfMemTestStr,
Color,
TestPercent,
(UINTN) PreviousValue
);
}
}
}
PreviousValue = TestPercent;
if (mAbortMemoryTest) {
SimpleTextInEx->Reset (SimpleTextInEx, FALSE);
if (!RequireSoftECCInit) {
if (BootDisplayMode == H2O_BDS_BOOT_DISPLAY_MODE_NORMAL) {
gST->ConOut->SetCursorPosition (gST->ConOut, 0, BaseLine);
gST->ConOut->OutputString (gST->ConOut, L"100");
TmpStr = GetStringById (STRING_TOKEN (STR_MEMORY_TEST_PERCENT));
gST->ConOut->OutputString (gST->ConOut, TmpStr);
FreePool (TmpStr);
} else {
if (PerfMemTestStr != NULL) {
BdsLibShowProgress (
Foreground,
Background,
PerfMemTestStr,
Color,
100,
(UINTN) PreviousValue
);
}
}
break;
}
TestAbort = TRUE;
}
} while (Status != EFI_NOT_FOUND);
if (SimpleTextInEx != NULL && KeyNotifyHandle != NULL) {
SimpleTextInEx->UnregisterKeyNotify (SimpleTextInEx, KeyNotifyHandle);
}
Status = GenMemoryTest->Finished (GenMemoryTest);
Exit:
if (PerfMemTestStr != NULL) {
FreePool (PerfMemTestStr);
}
if (UnicodeHotKey != NULL) {
FreePool (UnicodeHotKey);
}
if (SkipHotKeyStr != NULL) {
FreePool (SkipHotKeyStr);
}
return Status;
}