1 /** @file 2 Perform the platform memory test 3 4 Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR> 5 This program and the accompanying materials 6 are licensed and made available under the terms and conditions of the BSD License 7 which accompanies this distribution. The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT 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 **/ 36 EFI_STATUS 37 PlatformBdsShowProgress ( 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 **/ 205 EFI_STATUS 206 EFIAPI 207 BdsMemoryTest ( 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 387 Done: 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