Home | History | Annotate | Download | only in GenericMemoryTestDxe
      1 /** @file
      2 
      3   Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
      4 
      5   This program and the accompanying materials
      6   are licensed and made available under the terms and conditions
      7   of the BSD License which accompanies this distribution.  The
      8   full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "LightMemoryTest.h"
     17 
     18 //
     19 // Global:
     20 // Since this driver will only ever produce one instance of the memory test
     21 // protocol, so we do not need to dynamically allocate the PrivateData.
     22 //
     23 EFI_PHYSICAL_ADDRESS    mCurrentAddress;
     24 LIST_ENTRY          *mCurrentLink;
     25 NONTESTED_MEMORY_RANGE  *mCurrentRange;
     26 UINT64                  mTestedSystemMemory;
     27 UINT64                  mNonTestedSystemMemory;
     28 
     29 UINT32                  GenericMemoryTestMonoPattern[GENERIC_CACHELINE_SIZE / 4] = {
     30   0x5a5a5a5a,
     31   0xa5a5a5a5,
     32   0x5a5a5a5a,
     33   0xa5a5a5a5,
     34   0x5a5a5a5a,
     35   0xa5a5a5a5,
     36   0x5a5a5a5a,
     37   0xa5a5a5a5,
     38   0x5a5a5a5a,
     39   0xa5a5a5a5,
     40   0x5a5a5a5a,
     41   0xa5a5a5a5,
     42   0x5a5a5a5a,
     43   0xa5a5a5a5,
     44   0x5a5a5a5a,
     45   0xa5a5a5a5
     46 };
     47 
     48 /**
     49   Compares the contents of two buffers.
     50 
     51   This function compares Length bytes of SourceBuffer to Length bytes of DestinationBuffer.
     52   If all Length bytes of the two buffers are identical, then 0 is returned.  Otherwise, the
     53   value returned is the first mismatched byte in SourceBuffer subtracted from the first
     54   mismatched byte in DestinationBuffer.
     55 
     56   If Length = 0, then ASSERT().
     57 
     58   @param[in] DestinationBuffer The pointer to the destination buffer to compare.
     59   @param[in] SourceBuffer      The pointer to the source buffer to compare.
     60   @param[in] Length            The number of bytes to compare.
     61 
     62   @return 0                 All Length bytes of the two buffers are identical.
     63   @retval Non-zero          The first mismatched byte in SourceBuffer subtracted from the first
     64                             mismatched byte in DestinationBuffer.
     65 
     66 **/
     67 INTN
     68 EFIAPI
     69 CompareMemWithoutCheckArgument (
     70   IN      CONST VOID                *DestinationBuffer,
     71   IN      CONST VOID                *SourceBuffer,
     72   IN      UINTN                     Length
     73   )
     74 {
     75   ASSERT (Length > 0);
     76   while ((--Length != 0) &&
     77          (*(INT8*)DestinationBuffer == *(INT8*)SourceBuffer)) {
     78     DestinationBuffer = (INT8*)DestinationBuffer + 1;
     79     SourceBuffer = (INT8*)SourceBuffer + 1;
     80   }
     81   return (INTN)*(UINT8*)DestinationBuffer - (INTN)*(UINT8*)SourceBuffer;
     82 }
     83 
     84 /**
     85   Construct the system base memory range through GCD service.
     86 
     87   @param[in] Private  Point to generic memory test driver's private data.
     88 
     89   @retval EFI_SUCCESS          Successful construct the base memory range through GCD service.
     90   @retval EFI_OUT_OF_RESOURCE  Could not allocate needed resource from base memory.
     91   @retval Others               Failed to construct base memory range through GCD service.
     92 
     93 **/
     94 EFI_STATUS
     95 ConstructBaseMemoryRange (
     96   IN  GENERIC_MEMORY_TEST_PRIVATE  *Private
     97   )
     98 {
     99   UINTN                           NumberOfDescriptors;
    100   EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
    101   UINTN                           Index;
    102 
    103   //
    104   // Base memory will always below 4G
    105   //
    106   gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
    107 
    108   for (Index = 0; Index < NumberOfDescriptors; Index++) {
    109     if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) {
    110       Private->BaseMemorySize += MemorySpaceMap[Index].Length;
    111     }
    112   }
    113 
    114   return EFI_SUCCESS;
    115 }
    116 
    117 /**
    118   Destroy the link list base on the correspond link list type.
    119 
    120   @param[in] Private  Point to generic memory test driver's private data.
    121 
    122 **/
    123 VOID
    124 DestroyLinkList (
    125   IN  GENERIC_MEMORY_TEST_PRIVATE  *Private
    126   )
    127 {
    128   LIST_ENTRY          *Link;
    129   NONTESTED_MEMORY_RANGE  *NontestedRange;
    130 
    131   Link = Private->NonTestedMemRanList.BackLink;
    132 
    133   while (Link != &Private->NonTestedMemRanList) {
    134     RemoveEntryList (Link);
    135     NontestedRange = NONTESTED_MEMORY_RANGE_FROM_LINK (Link);
    136     gBS->FreePool (NontestedRange);
    137     Link = Private->NonTestedMemRanList.BackLink;;
    138   }
    139 }
    140 
    141 /**
    142   Add the extened memory to whole system memory map.
    143 
    144   @param[in] Private  Point to generic memory test driver's private data.
    145 
    146   @retval EFI_SUCCESS Successful add all the extended memory to system memory map.
    147   @retval Others      Failed to add the tested extended memory.
    148 
    149 **/
    150 EFI_STATUS
    151 UpdateMemoryMap (
    152   IN  GENERIC_MEMORY_TEST_PRIVATE  *Private
    153   )
    154 {
    155   LIST_ENTRY          *Link;
    156   NONTESTED_MEMORY_RANGE  *Range;
    157 
    158   Link = Private->NonTestedMemRanList.ForwardLink;
    159 
    160   while (Link != &Private->NonTestedMemRanList) {
    161     Range = NONTESTED_MEMORY_RANGE_FROM_LINK (Link);
    162 
    163     gDS->RemoveMemorySpace (
    164           Range->StartAddress,
    165           Range->Length
    166           );
    167 
    168     gDS->AddMemorySpace (
    169           EfiGcdMemoryTypeSystemMemory,
    170           Range->StartAddress,
    171           Range->Length,
    172           Range->Capabilities &~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
    173           );
    174 
    175     Link = Link->ForwardLink;
    176   }
    177 
    178   return EFI_SUCCESS;
    179 }
    180 
    181 /**
    182   Test a range of the memory directly .
    183 
    184   @param[in] Private       Point to generic memory test driver's private data.
    185   @param[in] StartAddress  Starting address of the memory range to be tested.
    186   @param[in] Length        Length in bytes of the memory range to be tested.
    187   @param[in] Capabilities  The bit mask of attributes that the memory range supports.
    188 
    189   @retval EFI_SUCCESS      Successful test the range of memory.
    190   @retval Others           Failed to test the range of memory.
    191 
    192 **/
    193 EFI_STATUS
    194 DirectRangeTest (
    195   IN  GENERIC_MEMORY_TEST_PRIVATE  *Private,
    196   IN  EFI_PHYSICAL_ADDRESS         StartAddress,
    197   IN  UINT64                       Length,
    198   IN  UINT64                       Capabilities
    199   )
    200 {
    201   EFI_STATUS  Status;
    202 
    203   //
    204   // Perform a dummy memory test, so directly write the pattern to all range
    205   //
    206   WriteMemory (Private, StartAddress, Length);
    207 
    208   //
    209   // Verify the memory range
    210   //
    211   Status = VerifyMemory (Private, StartAddress, Length);
    212   if (EFI_ERROR (Status)) {
    213     return Status;
    214   }
    215   //
    216   // Add the tested compatible memory to system memory using GCD service
    217   //
    218   gDS->RemoveMemorySpace (
    219         StartAddress,
    220         Length
    221         );
    222 
    223   gDS->AddMemorySpace (
    224         EfiGcdMemoryTypeSystemMemory,
    225         StartAddress,
    226         Length,
    227         Capabilities &~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
    228         );
    229 
    230   return EFI_SUCCESS;
    231 }
    232 
    233 /**
    234   Construct the system non-tested memory range through GCD service.
    235 
    236   @param[in] Private  Point to generic memory test driver's private data.
    237 
    238   @retval EFI_SUCCESS          Successful construct the non-tested memory range through GCD service.
    239   @retval EFI_OUT_OF_RESOURCE  Could not allocate needed resource from base memory.
    240   @retval Others               Failed to construct non-tested memory range through GCD service.
    241 
    242 **/
    243 EFI_STATUS
    244 ConstructNonTestedMemoryRange (
    245   IN  GENERIC_MEMORY_TEST_PRIVATE  *Private
    246   )
    247 {
    248   NONTESTED_MEMORY_RANGE          *Range;
    249   BOOLEAN                         NoFound;
    250   UINTN                           NumberOfDescriptors;
    251   EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
    252   UINTN                           Index;
    253 
    254   //
    255   // Non tested memory range may be span 4G here
    256   //
    257   NoFound = TRUE;
    258 
    259   gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
    260 
    261   for (Index = 0; Index < NumberOfDescriptors; Index++) {
    262     if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeReserved &&
    263         (MemorySpaceMap[Index].Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
    264           (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)
    265           ) {
    266       NoFound = FALSE;
    267       //
    268       // Light version do not need to process >4G memory range
    269       //
    270       gBS->AllocatePool (
    271             EfiBootServicesData,
    272             sizeof (NONTESTED_MEMORY_RANGE),
    273             (VOID **) &Range
    274             );
    275 
    276       Range->Signature    = EFI_NONTESTED_MEMORY_RANGE_SIGNATURE;
    277       Range->StartAddress = MemorySpaceMap[Index].BaseAddress;
    278       Range->Length       = MemorySpaceMap[Index].Length;
    279       Range->Capabilities = MemorySpaceMap[Index].Capabilities;
    280 
    281       mNonTestedSystemMemory += MemorySpaceMap[Index].Length;
    282       InsertTailList (&Private->NonTestedMemRanList, &Range->Link);
    283     }
    284   }
    285 
    286   if (NoFound) {
    287     return EFI_NOT_FOUND;
    288   }
    289 
    290   return EFI_SUCCESS;
    291 }
    292 
    293 /**
    294   Write the memory test pattern into a range of physical memory.
    295 
    296   @param[in] Private  Point to generic memory test driver's private data.
    297   @param[in] Start    The memory range's start address.
    298   @param[in] Size     The memory range's size.
    299 
    300   @retval EFI_SUCCESS Successful write the test pattern into the non-tested memory.
    301   @retval Others      The test pattern may not really write into the physical memory.
    302 
    303 **/
    304 EFI_STATUS
    305 WriteMemory (
    306   IN  GENERIC_MEMORY_TEST_PRIVATE  *Private,
    307   IN  EFI_PHYSICAL_ADDRESS         Start,
    308   IN  UINT64                       Size
    309   )
    310 {
    311   EFI_PHYSICAL_ADDRESS  Address;
    312 
    313   Address = Start;
    314 
    315   //
    316   // Add 4G memory address check for IA32 platform
    317   // NOTE: Without page table, there is no way to use memory above 4G.
    318   //
    319   if (Start + Size > MAX_ADDRESS) {
    320     return EFI_SUCCESS;
    321   }
    322 
    323   while (Address < (Start + Size)) {
    324     CopyMem ((VOID *) (UINTN) Address, Private->MonoPattern, Private->MonoTestSize);
    325     Address += Private->CoverageSpan;
    326   }
    327   //
    328   // bug bug: we may need GCD service to make the code cache and data uncache,
    329   // if GCD do not support it or return fail, then just flush the whole cache.
    330   //
    331   if (Private->Cpu != NULL) {
    332     Private->Cpu->FlushDataCache (Private->Cpu, Start, Size, EfiCpuFlushTypeWriteBackInvalidate);
    333   }
    334 
    335   return EFI_SUCCESS;
    336 }
    337 
    338 /**
    339   Verify the range of physical memory which covered by memory test pattern.
    340 
    341   This function will also do not return any informatin just cause system reset,
    342   because the handle error encount fatal error and disable the bad DIMMs.
    343 
    344   @param[in] Private  Point to generic memory test driver's private data.
    345   @param[in] Start    The memory range's start address.
    346   @param[in] Size     The memory range's size.
    347 
    348   @retval EFI_SUCCESS Successful verify the range of memory, no errors' location found.
    349   @retval Others      The range of memory have errors contained.
    350 
    351 **/
    352 EFI_STATUS
    353 VerifyMemory (
    354   IN  GENERIC_MEMORY_TEST_PRIVATE  *Private,
    355   IN  EFI_PHYSICAL_ADDRESS         Start,
    356   IN  UINT64                       Size
    357   )
    358 {
    359   EFI_PHYSICAL_ADDRESS            Address;
    360   INTN                            ErrorFound;
    361   EFI_MEMORY_EXTENDED_ERROR_DATA  *ExtendedErrorData;
    362 
    363   Address           = Start;
    364   ExtendedErrorData = NULL;
    365 
    366   //
    367   // Add 4G memory address check for IA32 platform
    368   // NOTE: Without page table, there is no way to use memory above 4G.
    369   //
    370   if (Start + Size > MAX_ADDRESS) {
    371     return EFI_SUCCESS;
    372   }
    373 
    374   //
    375   // Use the software memory test to check whether have detected miscompare
    376   // error here. If there is miscompare error here then check if generic
    377   // memory test driver can disable the bad DIMM.
    378   //
    379   while (Address < (Start + Size)) {
    380     ErrorFound = CompareMemWithoutCheckArgument (
    381                   (VOID *) (UINTN) (Address),
    382                   Private->MonoPattern,
    383                   Private->MonoTestSize
    384                   );
    385     if (ErrorFound != 0) {
    386       //
    387       // Report uncorrectable errors
    388       //
    389       ExtendedErrorData = AllocateZeroPool (sizeof (EFI_MEMORY_EXTENDED_ERROR_DATA));
    390       if (ExtendedErrorData == NULL) {
    391         return EFI_OUT_OF_RESOURCES;
    392       }
    393 
    394       ExtendedErrorData->DataHeader.HeaderSize  = (UINT16) sizeof (EFI_STATUS_CODE_DATA);
    395       ExtendedErrorData->DataHeader.Size        = (UINT16) (sizeof (EFI_MEMORY_EXTENDED_ERROR_DATA) - sizeof (EFI_STATUS_CODE_DATA));
    396       ExtendedErrorData->Granularity            = EFI_MEMORY_ERROR_DEVICE;
    397       ExtendedErrorData->Operation              = EFI_MEMORY_OPERATION_READ;
    398       ExtendedErrorData->Syndrome               = 0x0;
    399       ExtendedErrorData->Address                = Address;
    400       ExtendedErrorData->Resolution             = 0x40;
    401 
    402       REPORT_STATUS_CODE_EX (
    403           EFI_ERROR_CODE,
    404           EFI_COMPUTING_UNIT_MEMORY | EFI_CU_MEMORY_EC_UNCORRECTABLE,
    405           0,
    406           &gEfiGenericMemTestProtocolGuid,
    407           NULL,
    408           (UINT8 *) ExtendedErrorData + sizeof (EFI_STATUS_CODE_DATA),
    409           ExtendedErrorData->DataHeader.Size
    410           );
    411 
    412       return EFI_DEVICE_ERROR;
    413     }
    414 
    415     Address += Private->CoverageSpan;
    416   }
    417 
    418   return EFI_SUCCESS;
    419 }
    420 
    421 /**
    422   Initialize the generic memory test.
    423 
    424   @param[in]  This                The protocol instance pointer.
    425   @param[in]  Level               The coverage level of the memory test.
    426   @param[out] RequireSoftECCInit  Indicate if the memory need software ECC init.
    427 
    428   @retval EFI_SUCCESS         The generic memory test is initialized correctly.
    429   @retval EFI_NO_MEDIA        The system had no memory to be tested.
    430 
    431 **/
    432 EFI_STATUS
    433 EFIAPI
    434 InitializeMemoryTest (
    435   IN EFI_GENERIC_MEMORY_TEST_PROTOCOL          *This,
    436   IN  EXTENDMEM_COVERAGE_LEVEL                 Level,
    437   OUT BOOLEAN                                  *RequireSoftECCInit
    438   )
    439 {
    440   EFI_STATUS                  Status;
    441   GENERIC_MEMORY_TEST_PRIVATE *Private;
    442   EFI_CPU_ARCH_PROTOCOL       *Cpu;
    443 
    444   Private             = GENERIC_MEMORY_TEST_PRIVATE_FROM_THIS (This);
    445   *RequireSoftECCInit = FALSE;
    446 
    447   //
    448   // This is initialize for default value, but some value may be reset base on
    449   // platform memory test driver.
    450   //
    451   Private->CoverLevel   = Level;
    452   Private->BdsBlockSize = TEST_BLOCK_SIZE;
    453   Private->MonoPattern  = GenericMemoryTestMonoPattern;
    454   Private->MonoTestSize = GENERIC_CACHELINE_SIZE;
    455 
    456   //
    457   // Initialize several internal link list
    458   //
    459   InitializeListHead (&Private->NonTestedMemRanList);
    460 
    461   //
    462   // Construct base memory range
    463   //
    464   ConstructBaseMemoryRange (Private);
    465 
    466   //
    467   // get the cpu arch protocol to support flash cache
    468   //
    469   Status = gBS->LocateProtocol (
    470                   &gEfiCpuArchProtocolGuid,
    471                   NULL,
    472                   (VOID **) &Cpu
    473                   );
    474   if (!EFI_ERROR (Status)) {
    475     Private->Cpu = Cpu;
    476   }
    477   //
    478   // Create the CoverageSpan of the memory test base on the coverage level
    479   //
    480   switch (Private->CoverLevel) {
    481   case EXTENSIVE:
    482     Private->CoverageSpan = GENERIC_CACHELINE_SIZE;
    483     break;
    484 
    485   case SPARSE:
    486     Private->CoverageSpan = SPARSE_SPAN_SIZE;
    487     break;
    488 
    489   //
    490   // Even the BDS do not need to test any memory, but in some case it
    491   // still need to init ECC memory.
    492   //
    493   default:
    494     Private->CoverageSpan = QUICK_SPAN_SIZE;
    495     break;
    496   }
    497   //
    498   // This is the first time we construct the non-tested memory range, if no
    499   // extended memory found, we know the system have not any extended memory
    500   // need to be test
    501   //
    502   Status = ConstructNonTestedMemoryRange (Private);
    503   if (Status == EFI_NOT_FOUND) {
    504     return EFI_NO_MEDIA;
    505   }
    506   //
    507   // ready to perform the R/W/V memory test
    508   //
    509   mTestedSystemMemory = Private->BaseMemorySize;
    510   mCurrentLink        = Private->NonTestedMemRanList.ForwardLink;
    511   mCurrentRange       = NONTESTED_MEMORY_RANGE_FROM_LINK (mCurrentLink);
    512   mCurrentAddress     = mCurrentRange->StartAddress;
    513 
    514   return EFI_SUCCESS;
    515 }
    516 
    517 /**
    518   Perform the memory test.
    519 
    520   @param[in]  This              The protocol instance pointer.
    521   @param[out] TestedMemorySize  Return the tested extended memory size.
    522   @param[out] TotalMemorySize   Return the whole system physical memory size.
    523                                 The total memory size does not include memory in a slot with a disabled DIMM.
    524   @param[out] ErrorOut          TRUE if the memory error occured.
    525   @param[in]  IfTestAbort       Indicates that the user pressed "ESC" to skip the memory test.
    526 
    527   @retval EFI_SUCCESS         One block of memory passed the test.
    528   @retval EFI_NOT_FOUND       All memory blocks have already been tested.
    529   @retval EFI_DEVICE_ERROR    Memory device error occured, and no agent can handle it.
    530 
    531 **/
    532 EFI_STATUS
    533 EFIAPI
    534 GenPerformMemoryTest (
    535   IN EFI_GENERIC_MEMORY_TEST_PROTOCOL          *This,
    536   OUT UINT64                                   *TestedMemorySize,
    537   OUT UINT64                                   *TotalMemorySize,
    538   OUT BOOLEAN                                  *ErrorOut,
    539   IN BOOLEAN                                   TestAbort
    540   )
    541 {
    542   EFI_STATUS                      Status;
    543   GENERIC_MEMORY_TEST_PRIVATE     *Private;
    544   EFI_MEMORY_RANGE_EXTENDED_DATA  *RangeData;
    545   UINT64                          BlockBoundary;
    546 
    547   Private       = GENERIC_MEMORY_TEST_PRIVATE_FROM_THIS (This);
    548   *ErrorOut     = FALSE;
    549   RangeData     = NULL;
    550   BlockBoundary = 0;
    551 
    552   //
    553   // In extensive mode the boundary of "mCurrentRange->Length" may will lost
    554   // some range that is not Private->BdsBlockSize size boundary, so need
    555   // the software mechanism to confirm all memory location be covered.
    556   //
    557   if (mCurrentAddress < (mCurrentRange->StartAddress + mCurrentRange->Length)) {
    558     if ((mCurrentAddress + Private->BdsBlockSize) <= (mCurrentRange->StartAddress + mCurrentRange->Length)) {
    559       BlockBoundary = Private->BdsBlockSize;
    560     } else {
    561       BlockBoundary = mCurrentRange->StartAddress + mCurrentRange->Length - mCurrentAddress;
    562     }
    563     //
    564     // If TestAbort is true, means user cancel the memory test
    565     //
    566     if (!TestAbort && Private->CoverLevel != IGNORE) {
    567       //
    568       // Report status code of every memory range
    569       //
    570       RangeData                         = AllocateZeroPool (sizeof (EFI_MEMORY_RANGE_EXTENDED_DATA));
    571       if (RangeData == NULL) {
    572         return EFI_OUT_OF_RESOURCES;
    573       }
    574       RangeData->DataHeader.HeaderSize  = (UINT16) sizeof (EFI_STATUS_CODE_DATA);
    575       RangeData->DataHeader.Size        = (UINT16) (sizeof (EFI_MEMORY_RANGE_EXTENDED_DATA) - sizeof (EFI_STATUS_CODE_DATA));
    576       RangeData->Start                  = mCurrentAddress;
    577       RangeData->Length                 = BlockBoundary;
    578 
    579       REPORT_STATUS_CODE_EX (
    580           EFI_PROGRESS_CODE,
    581           EFI_COMPUTING_UNIT_MEMORY | EFI_CU_MEMORY_PC_TEST,
    582           0,
    583           &gEfiGenericMemTestProtocolGuid,
    584           NULL,
    585           (UINT8 *) RangeData + sizeof (EFI_STATUS_CODE_DATA),
    586           RangeData->DataHeader.Size
    587           );
    588 
    589       //
    590       // The software memory test (R/W/V) perform here. It will detect the
    591       // memory mis-compare error.
    592       //
    593       WriteMemory (Private, mCurrentAddress, BlockBoundary);
    594 
    595       Status = VerifyMemory (Private, mCurrentAddress, BlockBoundary);
    596       if (EFI_ERROR (Status)) {
    597         //
    598         // If perform here, means there is mis-compare error, and no agent can
    599         // handle it, so we return to BDS EFI_DEVICE_ERROR.
    600         //
    601         *ErrorOut = TRUE;
    602         return EFI_DEVICE_ERROR;
    603       }
    604     }
    605 
    606     mTestedSystemMemory += BlockBoundary;
    607     *TestedMemorySize = mTestedSystemMemory;
    608 
    609     //
    610     // If the memory test restart after the platform driver disable dimms,
    611     // the NonTestSystemMemory may be changed, but the base memory size will
    612     // not changed, so we can get the current total memory size.
    613     //
    614     *TotalMemorySize = Private->BaseMemorySize + mNonTestedSystemMemory;
    615 
    616     //
    617     // Update the current test address pointing to next BDS BLOCK
    618     //
    619     mCurrentAddress += Private->BdsBlockSize;
    620 
    621     return EFI_SUCCESS;
    622   }
    623   //
    624   // Change to next non tested memory range
    625   //
    626   mCurrentLink = mCurrentLink->ForwardLink;
    627   if (mCurrentLink != &Private->NonTestedMemRanList) {
    628     mCurrentRange   = NONTESTED_MEMORY_RANGE_FROM_LINK (mCurrentLink);
    629     mCurrentAddress = mCurrentRange->StartAddress;
    630     return EFI_SUCCESS;
    631   } else {
    632     //
    633     // Here means all the memory test have finished
    634     //
    635     *TestedMemorySize = mTestedSystemMemory;
    636     *TotalMemorySize  = Private->BaseMemorySize + mNonTestedSystemMemory;
    637     return EFI_NOT_FOUND;
    638   }
    639 
    640 }
    641 
    642 /**
    643   Finish the memory test.
    644 
    645   @param[in] This             The protocol instance pointer.
    646 
    647   @retval EFI_SUCCESS         Success. All resources used in the memory test are freed.
    648 
    649 **/
    650 EFI_STATUS
    651 EFIAPI
    652 GenMemoryTestFinished (
    653   IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This
    654   )
    655 {
    656   EFI_STATUS                  Status;
    657   GENERIC_MEMORY_TEST_PRIVATE *Private;
    658 
    659   Private = GENERIC_MEMORY_TEST_PRIVATE_FROM_THIS (This);
    660 
    661   //
    662   // Perform Data and Address line test
    663   //
    664   Status = PerformAddressDataLineTest (Private);
    665   ASSERT_EFI_ERROR (Status);
    666 
    667   //
    668   // Add the non tested memory range to system memory map through GCD service
    669   //
    670   UpdateMemoryMap (Private);
    671 
    672   //
    673   // we need to free all the memory allocate
    674   //
    675   DestroyLinkList (Private);
    676 
    677   return EFI_SUCCESS;
    678 }
    679 
    680 /**
    681   Provides the capability to test the compatible range used by some special drivers.
    682 
    683   @param[in]  This              The protocol instance pointer.
    684   @param[in]  StartAddress      The start address of the compatible memory range that
    685                                 must be below 16M.
    686   @param[in]  Length            The compatible memory range's length.
    687 
    688   @retval EFI_SUCCESS           The compatible memory range pass the memory test.
    689   @retval EFI_INVALID_PARAMETER The compatible memory range are not below Low 16M.
    690 
    691 **/
    692 EFI_STATUS
    693 EFIAPI
    694 GenCompatibleRangeTest (
    695   IN EFI_GENERIC_MEMORY_TEST_PROTOCOL         *This,
    696   IN EFI_PHYSICAL_ADDRESS                     StartAddress,
    697   IN UINT64                                   Length
    698   )
    699 {
    700   EFI_STATUS                      Status;
    701   GENERIC_MEMORY_TEST_PRIVATE     *Private;
    702   EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
    703   EFI_PHYSICAL_ADDRESS            CurrentBase;
    704   UINT64                          CurrentLength;
    705 
    706   Private = GENERIC_MEMORY_TEST_PRIVATE_FROM_THIS (This);
    707 
    708   //
    709   // Check if the parameter is below 16MB
    710   //
    711   if (StartAddress + Length > 0x1000000) {
    712     return EFI_INVALID_PARAMETER;
    713   }
    714   CurrentBase = StartAddress;
    715   do {
    716     //
    717     // Check the required memory range status; if the required memory range span
    718     // the different GCD memory descriptor, it may be cause different action.
    719     //
    720     Status = gDS->GetMemorySpaceDescriptor (
    721                     CurrentBase,
    722                     &Descriptor
    723                     );
    724     if (EFI_ERROR (Status)) {
    725       return Status;
    726     }
    727 
    728     if (Descriptor.GcdMemoryType == EfiGcdMemoryTypeReserved &&
    729         (Descriptor.Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
    730           (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)
    731           ) {
    732       CurrentLength = Descriptor.BaseAddress + Descriptor.Length - CurrentBase;
    733       if (CurrentBase + CurrentLength > StartAddress + Length) {
    734         CurrentLength = StartAddress + Length - CurrentBase;
    735       }
    736       Status = DirectRangeTest (
    737                  Private,
    738                  CurrentBase,
    739                  CurrentLength,
    740                  Descriptor.Capabilities
    741                  );
    742       if (EFI_ERROR (Status)) {
    743         return Status;
    744       }
    745     }
    746     CurrentBase = Descriptor.BaseAddress + Descriptor.Length;
    747   } while (CurrentBase < StartAddress + Length);
    748   //
    749   // Here means the required range already be tested, so just return success.
    750   //
    751   return EFI_SUCCESS;
    752 }
    753 
    754 /**
    755   Perform the address line walking ones test.
    756 
    757   @param[in] Private  Point to generic memory test driver's private data.
    758 
    759   @retval EFI_SUCCESS          Successful finished walking ones test.
    760   @retval EFI_OUT_OF_RESOURCE  Could not get resource in base memory.
    761   @retval EFI_ACCESS_DENIED    Code may can not run here because if walking one test
    762                                failed, system may be already halt.
    763 
    764 **/
    765 EFI_STATUS
    766 PerformAddressDataLineTest (
    767   IN  GENERIC_MEMORY_TEST_PRIVATE      *Private
    768   )
    769 {
    770   LIST_ENTRY              *ExtendedLink;
    771   NONTESTED_MEMORY_RANGE  *ExtendedRange;
    772   BOOLEAN                 InExtendedRange;
    773   EFI_PHYSICAL_ADDRESS    TestAddress;
    774 
    775   //
    776   // Light version no data line test, only perform the address line test
    777   //
    778   TestAddress = (EFI_PHYSICAL_ADDRESS) 0x1;
    779   while (TestAddress < MAX_ADDRESS && TestAddress > 0) {
    780     //
    781     // only test if the address falls in the enabled range
    782     //
    783     InExtendedRange = FALSE;
    784     ExtendedLink    = Private->NonTestedMemRanList.BackLink;
    785     while (ExtendedLink != &Private->NonTestedMemRanList) {
    786       ExtendedRange = NONTESTED_MEMORY_RANGE_FROM_LINK (ExtendedLink);
    787       if ((TestAddress >= ExtendedRange->StartAddress) &&
    788           (TestAddress < (ExtendedRange->StartAddress + ExtendedRange->Length))
    789           ) {
    790         InExtendedRange = TRUE;
    791       }
    792 
    793       ExtendedLink = ExtendedLink->BackLink;
    794     }
    795 
    796     if (InExtendedRange) {
    797       *(EFI_PHYSICAL_ADDRESS *) (UINTN) TestAddress = TestAddress;
    798       Private->Cpu->FlushDataCache (Private->Cpu, TestAddress, 1, EfiCpuFlushTypeWriteBackInvalidate);
    799       if (*(EFI_PHYSICAL_ADDRESS *) (UINTN) TestAddress != TestAddress) {
    800         return EFI_ACCESS_DENIED;
    801       }
    802     }
    803 
    804     TestAddress = LShiftU64 (TestAddress, 1);
    805   }
    806 
    807   return EFI_SUCCESS;
    808 }
    809 //
    810 // Driver entry here
    811 //
    812 GENERIC_MEMORY_TEST_PRIVATE mGenericMemoryTestPrivate = {
    813   EFI_GENERIC_MEMORY_TEST_PRIVATE_SIGNATURE,
    814   NULL,
    815   NULL,
    816   {
    817     InitializeMemoryTest,
    818     GenPerformMemoryTest,
    819     GenMemoryTestFinished,
    820     GenCompatibleRangeTest
    821   },
    822   (EXTENDMEM_COVERAGE_LEVEL) 0,
    823   0,
    824   0,
    825   NULL,
    826   0,
    827   0,
    828   {
    829     NULL,
    830     NULL
    831   }
    832 };
    833 
    834 /**
    835   The generic memory test driver's entry point.
    836 
    837   It initializes private data to default value.
    838 
    839   @param[in] ImageHandle  The firmware allocated handle for the EFI image.
    840   @param[in] SystemTable  A pointer to the EFI System Table.
    841 
    842   @retval EFI_SUCCESS     The entry point is executed successfully.
    843   @retval EFI_NOT_FOUND   Can't find HandOff Hob in HobList.
    844   @retval other           Some error occurs when executing this entry point.
    845 
    846 **/
    847 EFI_STATUS
    848 EFIAPI
    849 GenericMemoryTestEntryPoint (
    850   IN  EFI_HANDLE           ImageHandle,
    851   IN  EFI_SYSTEM_TABLE     *SystemTable
    852   )
    853 {
    854   EFI_STATUS            Status;
    855   VOID                  *HobList;
    856   EFI_BOOT_MODE         BootMode;
    857   EFI_PEI_HOB_POINTERS  Hob;
    858 
    859   //
    860   // Use the generic pattern to test compatible memory range
    861   //
    862   mGenericMemoryTestPrivate.MonoPattern   = GenericMemoryTestMonoPattern;
    863   mGenericMemoryTestPrivate.MonoTestSize  = GENERIC_CACHELINE_SIZE;
    864 
    865   //
    866   // Get the platform boot mode
    867   //
    868   HobList = GetHobList ();
    869 
    870   Hob.Raw = HobList;
    871   if (Hob.Header->HobType != EFI_HOB_TYPE_HANDOFF) {
    872     return EFI_NOT_FOUND;
    873   }
    874 
    875   BootMode = Hob.HandoffInformationTable->BootMode;
    876 
    877   //
    878   // Get the platform boot mode and create the default memory test coverage
    879   // level and span size for compatible memory test using
    880   //
    881   switch (BootMode) {
    882   case BOOT_WITH_FULL_CONFIGURATION:
    883   case BOOT_WITH_DEFAULT_SETTINGS:
    884     mGenericMemoryTestPrivate.CoverageSpan = SPARSE_SPAN_SIZE;
    885     break;
    886 
    887   case BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS:
    888     mGenericMemoryTestPrivate.CoverageSpan = GENERIC_CACHELINE_SIZE;
    889     break;
    890 
    891   default:
    892     mGenericMemoryTestPrivate.CoverageSpan = QUICK_SPAN_SIZE;
    893     break;
    894   }
    895   //
    896   // Install the protocol
    897   //
    898   Status = gBS->InstallProtocolInterface (
    899                   &mGenericMemoryTestPrivate.Handle,
    900                   &gEfiGenericMemTestProtocolGuid,
    901                   EFI_NATIVE_INTERFACE,
    902                   &mGenericMemoryTestPrivate.GenericMemoryTest
    903                   );
    904 
    905   return Status;
    906 }
    907