1/** @file 2 Perform the platform memory test 3 4Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR> 5This program and the accompanying materials 6are licensed and made available under the terms and conditions of the BSD License 7which accompanies this distribution. The full text of the license may be found at 8http://opensource.org/licenses/bsd-license.php 9 10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13**/ 14 15#include "Bds.h" 16#include "String.h" 17 18// 19// BDS Platform Functions 20// 21/** 22 23 Show progress bar with title above it. It only works in Graphics mode. 24 25 26 @param TitleForeground Foreground color for Title. 27 @param TitleBackground Background color for Title. 28 @param Title Title above progress bar. 29 @param ProgressColor Progress bar color. 30 @param Progress Progress (0-100) 31 @param PreviousValue The previous value of the progress. 32 33 @retval EFI_STATUS Success update the progress bar 34 35**/ 36EFI_STATUS 37PlatformBdsShowProgress ( 38 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleForeground, 39 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleBackground, 40 IN CHAR16 *Title, 41 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL ProgressColor, 42 IN UINTN Progress, 43 IN UINTN PreviousValue 44 ) 45{ 46 EFI_STATUS Status; 47 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; 48 EFI_UGA_DRAW_PROTOCOL *UgaDraw; 49 UINT32 SizeOfX; 50 UINT32 SizeOfY; 51 UINT32 ColorDepth; 52 UINT32 RefreshRate; 53 EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color; 54 UINTN BlockHeight; 55 UINTN BlockWidth; 56 UINTN BlockNum; 57 UINTN PosX; 58 UINTN PosY; 59 UINTN Index; 60 61 if (Progress > 100) { 62 return EFI_INVALID_PARAMETER; 63 } 64 65 UgaDraw = NULL; 66 Status = gBS->HandleProtocol ( 67 gST->ConsoleOutHandle, 68 &gEfiGraphicsOutputProtocolGuid, 69 (VOID **) &GraphicsOutput 70 ); 71 if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) { 72 GraphicsOutput = NULL; 73 74 Status = gBS->HandleProtocol ( 75 gST->ConsoleOutHandle, 76 &gEfiUgaDrawProtocolGuid, 77 (VOID **) &UgaDraw 78 ); 79 } 80 if (EFI_ERROR (Status)) { 81 return EFI_UNSUPPORTED; 82 } 83 84 SizeOfX = 0; 85 SizeOfY = 0; 86 if (GraphicsOutput != NULL) { 87 SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution; 88 SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution; 89 } else if (UgaDraw != NULL) { 90 Status = UgaDraw->GetMode ( 91 UgaDraw, 92 &SizeOfX, 93 &SizeOfY, 94 &ColorDepth, 95 &RefreshRate 96 ); 97 if (EFI_ERROR (Status)) { 98 return EFI_UNSUPPORTED; 99 } 100 } else { 101 return EFI_UNSUPPORTED; 102 } 103 104 BlockWidth = SizeOfX / 100; 105 BlockHeight = SizeOfY / 50; 106 107 BlockNum = Progress; 108 109 PosX = 0; 110 PosY = SizeOfY * 48 / 50; 111 112 if (BlockNum == 0) { 113 // 114 // Clear progress area 115 // 116 SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0); 117 118 if (GraphicsOutput != NULL) { 119 Status = GraphicsOutput->Blt ( 120 GraphicsOutput, 121 &Color, 122 EfiBltVideoFill, 123 0, 124 0, 125 0, 126 PosY - EFI_GLYPH_HEIGHT - 1, 127 SizeOfX, 128 SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1), 129 SizeOfX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) 130 ); 131 } else if (FeaturePcdGet (PcdUgaConsumeSupport)) { 132 Status = UgaDraw->Blt ( 133 UgaDraw, 134 (EFI_UGA_PIXEL *) &Color, 135 EfiUgaVideoFill, 136 0, 137 0, 138 0, 139 PosY - EFI_GLYPH_HEIGHT - 1, 140 SizeOfX, 141 SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1), 142 SizeOfX * sizeof (EFI_UGA_PIXEL) 143 ); 144 } else { 145 return EFI_UNSUPPORTED; 146 } 147 } 148 // 149 // Show progress by drawing blocks 150 // 151 for (Index = PreviousValue; Index < BlockNum; Index++) { 152 PosX = Index * BlockWidth; 153 if (GraphicsOutput != NULL) { 154 Status = GraphicsOutput->Blt ( 155 GraphicsOutput, 156 &ProgressColor, 157 EfiBltVideoFill, 158 0, 159 0, 160 PosX, 161 PosY, 162 BlockWidth - 1, 163 BlockHeight, 164 (BlockWidth) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) 165 ); 166 } else if (FeaturePcdGet (PcdUgaConsumeSupport)) { 167 Status = UgaDraw->Blt ( 168 UgaDraw, 169 (EFI_UGA_PIXEL *) &ProgressColor, 170 EfiUgaVideoFill, 171 0, 172 0, 173 PosX, 174 PosY, 175 BlockWidth - 1, 176 BlockHeight, 177 (BlockWidth) * sizeof (EFI_UGA_PIXEL) 178 ); 179 } else { 180 return EFI_UNSUPPORTED; 181 } 182 } 183 184 PrintXY ( 185 (SizeOfX - StrLen (Title) * EFI_GLYPH_WIDTH) / 2, 186 PosY - EFI_GLYPH_HEIGHT - 1, 187 &TitleForeground, 188 &TitleBackground, 189 Title 190 ); 191 192 return EFI_SUCCESS; 193} 194 195/** 196 Perform the memory test base on the memory test intensive level, 197 and update the memory resource. 198 199 @param Level The memory test intensive level. 200 201 @retval EFI_STATUS Success test all the system memory and update 202 the memory resource 203 204**/ 205EFI_STATUS 206EFIAPI 207BdsMemoryTest ( 208 IN EXTENDMEM_COVERAGE_LEVEL Level 209 ) 210{ 211 EFI_STATUS Status; 212 EFI_STATUS KeyStatus; 213 EFI_STATUS InitStatus; 214 EFI_STATUS ReturnStatus; 215 BOOLEAN RequireSoftECCInit; 216 EFI_GENERIC_MEMORY_TEST_PROTOCOL *GenMemoryTest; 217 UINT64 TestedMemorySize; 218 UINT64 TotalMemorySize; 219 UINTN TestPercent; 220 UINT64 PreviousValue; 221 BOOLEAN ErrorOut; 222 BOOLEAN TestAbort; 223 EFI_INPUT_KEY Key; 224 CHAR16 StrPercent[80]; 225 CHAR16 *StrTotalMemory; 226 CHAR16 *Pos; 227 CHAR16 *TmpStr; 228 EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground; 229 EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background; 230 EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color; 231 BOOLEAN IsFirstBoot; 232 UINT32 TempData; 233 UINTN StrTotalMemorySize; 234 235 ReturnStatus = EFI_SUCCESS; 236 ZeroMem (&Key, sizeof (EFI_INPUT_KEY)); 237 238 StrTotalMemorySize = 128; 239 Pos = AllocateZeroPool (StrTotalMemorySize); 240 241 if (Pos == NULL) { 242 return ReturnStatus; 243 } 244 245 StrTotalMemory = Pos; 246 247 TestedMemorySize = 0; 248 TotalMemorySize = 0; 249 PreviousValue = 0; 250 ErrorOut = FALSE; 251 TestAbort = FALSE; 252 253 SetMem (&Foreground, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff); 254 SetMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0); 255 SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff); 256 257 RequireSoftECCInit = FALSE; 258 259 Status = gBS->LocateProtocol ( 260 &gEfiGenericMemTestProtocolGuid, 261 NULL, 262 (VOID **) &GenMemoryTest 263 ); 264 if (EFI_ERROR (Status)) { 265 FreePool (Pos); 266 return EFI_SUCCESS; 267 } 268 269 InitStatus = GenMemoryTest->MemoryTestInit ( 270 GenMemoryTest, 271 Level, 272 &RequireSoftECCInit 273 ); 274 if (InitStatus == EFI_NO_MEDIA) { 275 // 276 // The PEI codes also have the relevant memory test code to check the memory, 277 // it can select to test some range of the memory or all of them. If PEI code 278 // checks all the memory, this BDS memory test will has no not-test memory to 279 // do the test, and then the status of EFI_NO_MEDIA will be returned by 280 // "MemoryTestInit". So it does not need to test memory again, just return. 281 // 282 FreePool (Pos); 283 return EFI_SUCCESS; 284 } 285 286 if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) { 287 TmpStr = GetStringById (STRING_TOKEN (STR_ESC_TO_SKIP_MEM_TEST)); 288 289 if (TmpStr != NULL) { 290 PrintXY (10, 10, NULL, NULL, TmpStr); 291 FreePool (TmpStr); 292 } 293 } else { 294 DEBUG ((EFI_D_INFO, "Enter memory test.\n")); 295 } 296 do { 297 Status = GenMemoryTest->PerformMemoryTest ( 298 GenMemoryTest, 299 &TestedMemorySize, 300 &TotalMemorySize, 301 &ErrorOut, 302 TestAbort 303 ); 304 if (ErrorOut && (Status == EFI_DEVICE_ERROR)) { 305 TmpStr = GetStringById (STRING_TOKEN (STR_SYSTEM_MEM_ERROR)); 306 if (TmpStr != NULL) { 307 PrintXY (10, 10, NULL, NULL, TmpStr); 308 FreePool (TmpStr); 309 } 310 311 ASSERT (0); 312 } 313 314 if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) { 315 TempData = (UINT32) DivU64x32 (TotalMemorySize, 16); 316 TestPercent = (UINTN) DivU64x32 ( 317 DivU64x32 (MultU64x32 (TestedMemorySize, 100), 16), 318 TempData 319 ); 320 if (TestPercent != PreviousValue) { 321 UnicodeValueToString (StrPercent, 0, TestPercent, 0); 322 TmpStr = GetStringById (STRING_TOKEN (STR_MEMORY_TEST_PERCENT)); 323 if (TmpStr != NULL) { 324 // 325 // TmpStr size is 64, StrPercent is reserved to 16. 326 // 327 StrnCatS ( 328 StrPercent, 329 sizeof (StrPercent) / sizeof (CHAR16), 330 TmpStr, 331 sizeof (StrPercent) / sizeof (CHAR16) - StrLen (StrPercent) - 1 332 ); 333 PrintXY (10, 10, NULL, NULL, StrPercent); 334 FreePool (TmpStr); 335 } 336 337 TmpStr = GetStringById (STRING_TOKEN (STR_PERFORM_MEM_TEST)); 338 if (TmpStr != NULL) { 339 PlatformBdsShowProgress ( 340 Foreground, 341 Background, 342 TmpStr, 343 Color, 344 TestPercent, 345 (UINTN) PreviousValue 346 ); 347 FreePool (TmpStr); 348 } 349 } 350 351 PreviousValue = TestPercent; 352 } else { 353 DEBUG ((EFI_D_INFO, "Perform memory test (ESC to skip).\n")); 354 } 355 356 if (!PcdGetBool (PcdConInConnectOnDemand)) { 357 KeyStatus = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); 358 if (!EFI_ERROR (KeyStatus) && (Key.ScanCode == SCAN_ESC)) { 359 if (!RequireSoftECCInit) { 360 if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) { 361 TmpStr = GetStringById (STRING_TOKEN (STR_PERFORM_MEM_TEST)); 362 if (TmpStr != NULL) { 363 PlatformBdsShowProgress ( 364 Foreground, 365 Background, 366 TmpStr, 367 Color, 368 100, 369 (UINTN) PreviousValue 370 ); 371 FreePool (TmpStr); 372 } 373 374 PrintXY (10, 10, NULL, NULL, L"100"); 375 } 376 Status = GenMemoryTest->Finished (GenMemoryTest); 377 goto Done; 378 } 379 380 TestAbort = TRUE; 381 } 382 } 383 } while (Status != EFI_NOT_FOUND); 384 385 Status = GenMemoryTest->Finished (GenMemoryTest); 386 387Done: 388 if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) { 389 UnicodeValueToString (StrTotalMemory, COMMA_TYPE, TotalMemorySize, 0); 390 if (StrTotalMemory[0] == L',') { 391 StrTotalMemory++; 392 StrTotalMemorySize -= sizeof (CHAR16); 393 } 394 395 TmpStr = GetStringById (STRING_TOKEN (STR_MEM_TEST_COMPLETED)); 396 if (TmpStr != NULL) { 397 StrnCatS ( 398 StrTotalMemory, 399 StrTotalMemorySize / sizeof (CHAR16), 400 TmpStr, 401 StrTotalMemorySize / sizeof (CHAR16) - StrLen (StrTotalMemory) - 1 402 ); 403 FreePool (TmpStr); 404 } 405 406 PrintXY (10, 10, NULL, NULL, StrTotalMemory); 407 PlatformBdsShowProgress ( 408 Foreground, 409 Background, 410 StrTotalMemory, 411 Color, 412 100, 413 (UINTN) PreviousValue 414 ); 415 416 } else { 417 DEBUG ((EFI_D_INFO, "%d bytes of system memory tested OK\r\n", TotalMemorySize)); 418 } 419 420 FreePool (Pos); 421 422 423 // 424 // Use a DynamicHii type pcd to save the boot status, which is used to 425 // control configuration mode, such as FULL/MINIMAL/NO_CHANGES configuration. 426 // 427 IsFirstBoot = PcdGetBool(PcdBootState); 428 if (IsFirstBoot) { 429 Status = PcdSetBoolS(PcdBootState, FALSE); 430 if (EFI_ERROR (Status)) { 431 DEBUG ((EFI_D_ERROR, "Set PcdBootState to FALSE failed.\n")); 432 } 433 } 434 435 return ReturnStatus; 436} 437