Home | History | Annotate | Download | only in BdsDxe
      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