Home | History | Annotate | Download | only in MemorySubClassDxe
      1 /** @file
      2 *
      3 *  Copyright (c) 2015, Hisilicon Limited. All rights reserved.
      4 *  Copyright (c) 2015, Linaro Limited. All rights reserved.
      5 *
      6 *  This program and the accompanying materials
      7 *  are licensed and made available under the terms and conditions of the BSD License
      8 *  which accompanies this distribution.  The 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 
     17 #include "MemorySubClass.h"
     18 
     19 EFI_SMBIOS_PROTOCOL             *mSmbios = NULL;
     20 EFI_HII_HANDLE                  mHiiHandle;
     21 
     22 UINT8                           mMaxSkt;
     23 UINT8                           mMaxCh;
     24 
     25 VOID
     26 SmbiosGetManufacturer (
     27   IN  UINT8           MfgIdLSB,
     28   IN  UINT8           MfgIdMSB,
     29   OUT CHAR16          *Manufacturer
     30 )
     31 {
     32     UINT32                  Index = 0;
     33 
     34     (VOID)StrCpyS(Manufacturer, SMBIOS_STRING_MAX_LENGTH - 1, L"Unknown");
     35     while (JEP106[Index].MfgIdLSB != 0xFF && JEP106[Index].MfgIdMSB != 0xFF )
     36     {
     37         if (JEP106[Index].MfgIdLSB == MfgIdLSB && JEP106[Index].MfgIdMSB == MfgIdMSB)
     38         {
     39             (VOID)StrCpyS (Manufacturer, SMBIOS_STRING_MAX_LENGTH - 1, JEP106[Index].Name);
     40             break;
     41         }
     42         Index++;
     43     }
     44 }
     45 
     46 VOID
     47 SmbiosGetPartNumber (
     48   IN pGBL_DATA          pGblData,
     49   IN UINT8              Skt,
     50   IN UINT8              Ch,
     51   IN UINT8              Dimm,
     52   OUT CHAR16             *PartNumber
     53   )
     54 {
     55     CHAR16                        StringBuffer2[SMBIOS_STRING_MAX_LENGTH];
     56     UINT32                        Index2;
     57 
     58     (VOID)StrCpyS(PartNumber, SMBIOS_STRING_MAX_LENGTH - 1, L"");
     59     if (pGblData->Channel[Skt][Ch].Dimm[Dimm].DramType == SPD_TYPE_DDR3)
     60     {
     61         for (Index2 = 0; Index2 < SPD_MODULE_PART; Index2++)
     62         {
     63             UnicodeSPrint (StringBuffer2, SMBIOS_STRING_MAX_LENGTH - 1, L"%c", pGblData->Channel[Skt][Ch].Dimm[Dimm].SpdModPart[Index2]);
     64             (VOID)StrCatS(PartNumber, SMBIOS_STRING_MAX_LENGTH - 1, StringBuffer2);
     65         }
     66     }
     67     else
     68     {
     69         for (Index2 = 0; Index2 < SPD_MODULE_PART_DDR4; Index2++)
     70         {
     71             UnicodeSPrint (StringBuffer2, SMBIOS_STRING_MAX_LENGTH - 1, L"%c", pGblData->Channel[Skt][Ch].Dimm[Dimm].SpdModPartDDR4[Index2]);
     72             (VOID)StrCatS(PartNumber, SMBIOS_STRING_MAX_LENGTH - 1, StringBuffer2);
     73         }
     74     }
     75 
     76     return;
     77 }
     78 
     79 VOID
     80 SmbiosGetSerialNumber (
     81   IN pGBL_DATA          pGblData,
     82   IN UINT8              Skt,
     83   IN UINT8              Ch,
     84   IN UINT8              Dimm,
     85   OUT CHAR16            *SerialNumber
     86   )
     87 {
     88     UINT32              Temp;
     89 
     90     Temp = SwapBytes32 (pGblData->Channel[Skt][Ch].Dimm[Dimm].SpdSerialNum);
     91 
     92     UnicodeSPrint(SerialNumber, SMBIOS_STRING_MAX_LENGTH, L"0x%08x", Temp);
     93 
     94     return;
     95 }
     96 
     97 BOOLEAN
     98 IsDimmPresent (
     99   IN  pGBL_DATA          pGblData,
    100   IN  UINT8              Skt,
    101   IN  UINT8              Ch,
    102   IN  UINT8              Dimm
    103 )
    104 {
    105     if (pGblData->Channel[Skt][Ch].Status == FALSE ||
    106           pGblData->Channel[Skt][Ch].Dimm[Dimm].Status == FALSE)
    107     {
    108         return FALSE;
    109     }
    110     else
    111     {
    112         return TRUE;
    113     }
    114 }
    115 
    116 UINT8
    117 SmbiosGetMemoryType (
    118   IN  pGBL_DATA          pGblData,
    119   IN  UINT8              Skt,
    120   IN  UINT8              Ch,
    121   IN  UINT8              Dimm
    122 )
    123 {
    124     UINT8 MemoryType;
    125 
    126     if(!IsDimmPresent(pGblData, Skt, Ch, Dimm))
    127     {
    128         return MemoryTypeUnknown;
    129     }
    130 
    131     if (pGblData->Channel[Skt][Ch].Dimm[Dimm].DramType == SPD_TYPE_DDR3)
    132     {
    133         MemoryType = MemoryTypeDdr3;
    134     }
    135     else if (pGblData->Channel[Skt][Ch].Dimm[Dimm].DramType == SPD_TYPE_DDR4)
    136     {
    137         MemoryType = MemoryTypeDdr4;
    138     }
    139     else
    140     {
    141         MemoryType = MemoryTypeUnknown;
    142     }
    143 
    144     return MemoryType;
    145 }
    146 
    147 VOID
    148 SmbiosGetTypeDetail (
    149   IN  pGBL_DATA             pGblData,
    150   IN  UINT8                 Skt,
    151   IN  UINT8                 Ch,
    152   IN  UINT8                 Dimm,
    153   IN  OUT MEMORY_DEVICE_TYPE_DETAIL *TypeDetail
    154 )
    155 {
    156     if (NULL == TypeDetail)
    157     {
    158         return;
    159     }
    160 
    161     if(!IsDimmPresent(pGblData, Skt, Ch, Dimm))
    162     {
    163         TypeDetail->Unknown = 1;
    164         return;
    165     }
    166 
    167     switch (pGblData->Channel[Skt][Ch].Dimm[Dimm].ModuleType)
    168     {
    169         case SPD_UDIMM:
    170           TypeDetail->Unbuffered = 1;
    171           break;
    172 
    173         case SPD_LRDIMM:
    174           TypeDetail->LrDimm = 1;
    175           break;
    176 
    177         case SPD_RDIMM:
    178           TypeDetail->Registered = 1;
    179           break;
    180 
    181         default:
    182           TypeDetail->Unknown = 1;
    183           break;
    184     }
    185 }
    186 
    187 VOID
    188 SmbiosGetDimmVoltageInfo (
    189   IN     pGBL_DATA             pGblData,
    190   IN     UINT8                 Skt,
    191   IN     UINT8                 Ch,
    192   IN     UINT8                 Dimm,
    193   IN OUT SMBIOS_TABLE_TYPE17   *Type17Record
    194 
    195 )
    196 {
    197     if(!IsDimmPresent(pGblData, Skt, Ch, Dimm))
    198     {
    199         return;
    200     }
    201 
    202     if (pGblData->Channel[Skt][Ch].Dimm[Dimm].DramType == SPD_TYPE_DDR3)
    203     {
    204         Type17Record->MinimumVoltage                = 1250;
    205         Type17Record->MaximumVoltage                = 1500;
    206 
    207         switch (pGblData->Channel[Skt][Ch].Dimm[Dimm].SpdVdd)
    208         {
    209             case SPD_VDD_150:
    210               Type17Record->ConfiguredVoltage = 1500;
    211               break;
    212 
    213             case SPD_VDD_135:
    214               Type17Record->ConfiguredVoltage = 1350;
    215               break;
    216 
    217             case SPD_VDD_125:
    218               Type17Record->ConfiguredVoltage = 1250;
    219               break;
    220 
    221             default:
    222               break;
    223         }
    224     }
    225     else if (pGblData->Channel[Skt][Ch].Dimm[Dimm].DramType == SPD_TYPE_DDR4)
    226     {
    227         Type17Record->MinimumVoltage                = 1200;
    228         Type17Record->MaximumVoltage                = 2000;
    229         switch (pGblData->Channel[Skt][Ch].Dimm[Dimm].SpdVdd)
    230         {
    231             case SPD_VDD_120:
    232               Type17Record->ConfiguredVoltage = 1200;
    233               break;
    234 
    235             default:
    236               break;
    237         }
    238     }
    239 }
    240 
    241 VOID
    242 SmbiosGetMemoryDevicesNumber (
    243   IN OUT UINT16 *NumberOfDevices
    244 )
    245 {
    246     UINT8       Skt, Ch, Dimm;
    247 
    248     for(Skt = 0; Skt < mMaxSkt; Skt++)
    249     {
    250         for(Ch = 0; Ch < mMaxCh; Ch++)
    251         {
    252             for(Dimm = 0; Dimm < OemGetDimmSlot(Skt, Ch); Dimm++)
    253             {
    254                 (*NumberOfDevices)++;
    255             }
    256         }
    257     }
    258 }
    259 
    260 UINT8
    261 SmbiosGetPartitionWidth (
    262 )
    263 {
    264 
    265     UINT8       Skt, Ch, Dimm;
    266     UINT8       PartitionWidth = 0;
    267 
    268     for(Skt = 0; Skt < mMaxSkt; Skt++)
    269     {
    270         for(Ch = 0; Ch < mMaxCh; Ch++)
    271         {
    272             for(Dimm = 0; Dimm < OemGetDimmSlot(Skt, Ch); Dimm++)
    273             {
    274                 PartitionWidth++;
    275             }
    276         }
    277     }
    278 
    279     return PartitionWidth;
    280 }
    281 
    282 EFI_STATUS
    283 SmbiosAddType16Table (
    284   IN  pGBL_DATA          pGblData,
    285   OUT EFI_SMBIOS_HANDLE  *MemArraySmbiosHandle
    286   )
    287 {
    288     EFI_STATUS                      Status;
    289     UINT64                          MemoryCapacity;
    290     SMBIOS_TABLE_TYPE16             *Type16Record;
    291 
    292     UINT16                          NumberOfMemoryDevices = 0;
    293 
    294     SmbiosGetMemoryDevicesNumber (&NumberOfMemoryDevices);
    295 
    296     MemoryCapacity = (UINT64) LShiftU64 (NumberOfMemoryDevices * MAX_DIMM_SIZE, 20); // GB to KB.
    297 
    298     //
    299     // Type 16 SMBIOS Record
    300     //
    301     Type16Record = AllocateZeroPool(sizeof(SMBIOS_TABLE_TYPE16) + 1 + 1);
    302     if (NULL == Type16Record)
    303     {
    304         return EFI_OUT_OF_RESOURCES;
    305     }
    306 
    307     Type16Record->Hdr.Type                          = EFI_SMBIOS_TYPE_PHYSICAL_MEMORY_ARRAY;
    308     Type16Record->Hdr.Length                        = sizeof (SMBIOS_TABLE_TYPE16);
    309     Type16Record->Hdr.Handle                        = 0x0;
    310     Type16Record->Location                          = MemoryArrayLocationSystemBoard;
    311     Type16Record->Use                               = MemoryArrayUseSystemMemory;
    312     Type16Record->MemoryErrorInformationHandle      = 0xFFFE;
    313     Type16Record->NumberOfMemoryDevices             = NumberOfMemoryDevices;
    314 
    315     if(pGblData->EccEn)
    316     {
    317         Type16Record->MemoryErrorCorrection         = MemoryErrorCorrectionSingleBitEcc;
    318     }
    319     else
    320     {
    321         Type16Record->MemoryErrorCorrection         = MemoryErrorCorrectionNone;
    322     }
    323 
    324     if (MemoryCapacity >= 0x80000000)
    325     {
    326         Type16Record->MaximumCapacity = 0x80000000;   // in KB;
    327         Type16Record->ExtendedMaximumCapacity = MemoryCapacity << 10;  // Extended Max capacity should be stored in bytes.
    328     }
    329     else
    330     {
    331         Type16Record->MaximumCapacity = (UINT32)MemoryCapacity;  // Max capacity should be stored in kilo bytes.
    332         Type16Record->ExtendedMaximumCapacity = 0;
    333     }
    334 
    335     *MemArraySmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
    336     Status = mSmbios->Add (mSmbios, NULL, MemArraySmbiosHandle, (EFI_SMBIOS_TABLE_HEADER *)Type16Record);
    337     if(EFI_ERROR(Status))
    338     {
    339         DEBUG((EFI_D_ERROR, "[%a]:[%dL] Smbios Type16 Table Log Failed! %r \n", __FUNCTION__, __LINE__, Status));
    340     }
    341 
    342     FreePool(Type16Record);
    343     return Status;
    344 }
    345 
    346 EFI_STATUS
    347 SmbiosAddType19Table (
    348   IN pGBL_DATA          pGblData,
    349   IN EFI_SMBIOS_HANDLE  MemArraySmbiosHandle
    350   )
    351 {
    352     EFI_STATUS                      Status;
    353     UINT32                          MemInfoTotalMem;
    354     UINT64                          TotalMemorySize;
    355     EFI_SMBIOS_HANDLE               MemArrayMappedAddrSmbiosHandle;
    356     SMBIOS_TABLE_TYPE19             *Type19Record;
    357 
    358     MemInfoTotalMem = pGblData->MemSize;  // In MB
    359 
    360     if (MemInfoTotalMem == 0)
    361     {
    362         return EFI_NOT_FOUND;
    363     }
    364 
    365     TotalMemorySize = (UINT64) LShiftU64 (MemInfoTotalMem, 10);  // MB to KB.
    366 
    367     //
    368     // Type 19 SMBIOS Record
    369     //
    370     Type19Record = AllocateZeroPool(sizeof(SMBIOS_TABLE_TYPE19) + 1 + 1);
    371     if (NULL == Type19Record)
    372     {
    373         return EFI_OUT_OF_RESOURCES;
    374     }
    375 
    376     Type19Record->Hdr.Type                          = EFI_SMBIOS_TYPE_MEMORY_ARRAY_MAPPED_ADDRESS;
    377     Type19Record->Hdr.Length                        = sizeof(SMBIOS_TABLE_TYPE19);
    378     Type19Record->Hdr.Handle                        = 0x0;
    379     Type19Record->StartingAddress                   = 0x0;
    380     Type19Record->EndingAddress                     = (UINT32) (TotalMemorySize - 1); // in KB;
    381     Type19Record->MemoryArrayHandle                 = MemArraySmbiosHandle;
    382     Type19Record->PartitionWidth                    = SmbiosGetPartitionWidth ();
    383     Type19Record->ExtendedStartingAddress           = 0x0;
    384     Type19Record->ExtendedEndingAddress             = 0x0;
    385 
    386     MemArrayMappedAddrSmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
    387     Status = mSmbios->Add (mSmbios, NULL, &MemArrayMappedAddrSmbiosHandle, (EFI_SMBIOS_TABLE_HEADER *)Type19Record);
    388     if(EFI_ERROR(Status))
    389     {
    390         DEBUG((EFI_D_ERROR, "[%a]:[%dL] Smbios Type19 Table Log Failed! %r \n", __FUNCTION__, __LINE__, Status));
    391     }
    392 
    393     FreePool(Type19Record);
    394     return Status;
    395 }
    396 
    397 
    398 EFI_STATUS
    399 SmbiosAddType17Table (
    400   IN pGBL_DATA          pGblData,
    401   IN UINT8              Skt,
    402   IN UINT8              Ch,
    403   IN UINT8              Dimm,
    404   IN EFI_SMBIOS_HANDLE  MemArraySmbiosHandle
    405   )
    406 {
    407     EFI_STATUS                      Status;
    408     SMBIOS_TABLE_TYPE17             *Type17Record;
    409     EFI_SMBIOS_HANDLE               MemDevSmbiosHandle;
    410     UINTN                           TableSize;
    411 
    412     UINTN                           StringBufferSize;
    413     EFI_STRING                      StringBuffer;
    414     UINT16                          MemInfoMemFreq;
    415     UINT16                          MemoryTotalWidth;
    416     UINT16                          MemoryDataWidth;
    417     UINT16                          MemoryDeviceSize;
    418     UINT16                          MemorySpeed;
    419     UINT8                           Attributes;
    420     UINT32                          MemoryDeviceExtendSize;
    421     UINT16                          CfgMemorySpeed;
    422 
    423     CHAR8                           *OptionalStrStart;
    424     UINTN                           DeviceLocatorStrLen;
    425     UINTN                           BankLocatorStrLen;
    426     UINTN                           ManufactureStrLen;
    427     UINTN                           SerialNumberStrLen;
    428     UINTN                           AssertTagStrLen;
    429     UINTN                           PartNumberStrLen;
    430     EFI_STRING                      DeviceLocatorStr;
    431     EFI_STRING                      BankLocatorStr;
    432     EFI_STRING                      ManufactureStr;
    433     EFI_STRING                      SerialNumberStr;
    434     EFI_STRING                      AssertTagStr;
    435     EFI_STRING                      PartNumberStr;
    436     EFI_STRING_ID                   DeviceLocator;
    437 
    438     Type17Record        = NULL;
    439     DeviceLocatorStr    = NULL;
    440     BankLocatorStr      = NULL;
    441     ManufactureStr      = NULL;
    442     SerialNumberStr     = NULL;
    443     AssertTagStr        = NULL;
    444     PartNumberStr       = NULL;
    445 
    446     MemoryTotalWidth    = 0;
    447     MemoryDataWidth     = 0;
    448     MemoryDeviceSize    = 0;
    449     MemoryDeviceExtendSize = 0;
    450     MemorySpeed         = 0;
    451     Attributes          = 0;
    452     CfgMemorySpeed      = 0;
    453 
    454     //
    455     // Allocate Buffers
    456     //
    457     StringBufferSize = (sizeof (CHAR16)) * SMBIOS_STRING_MAX_LENGTH;
    458     StringBuffer = AllocateZeroPool (StringBufferSize);
    459     if(NULL == StringBuffer)
    460     {
    461         return EFI_OUT_OF_RESOURCES;
    462     }
    463 
    464 
    465     //
    466     // Manufacture
    467     //
    468     ManufactureStr = AllocateZeroPool (StringBufferSize);
    469     if(NULL == ManufactureStr)
    470     {
    471         Status = EFI_OUT_OF_RESOURCES;
    472         goto FREE_STR_BUF;
    473     }
    474     UnicodeSPrint(ManufactureStr, SMBIOS_STRING_MAX_LENGTH - 1, L"NO DIMM");
    475 
    476     //
    477     // SerialNumber
    478     //
    479     SerialNumberStr = AllocateZeroPool (StringBufferSize);
    480     if(NULL == SerialNumberStr)
    481     {
    482         Status = EFI_OUT_OF_RESOURCES;
    483         goto FREE_STR_MAN;
    484     }
    485     UnicodeSPrint(SerialNumberStr, SMBIOS_STRING_MAX_LENGTH - 1, L"NO DIMM");
    486 
    487     //
    488     // AssetTag
    489     //
    490     AssertTagStr = AllocateZeroPool (StringBufferSize);
    491     if(NULL == AssertTagStr)
    492     {
    493         Status = EFI_OUT_OF_RESOURCES;
    494         goto FREE_STR_SN;
    495     }
    496     UnicodeSPrint(AssertTagStr, SMBIOS_STRING_MAX_LENGTH - 1, L"NO DIMM");
    497 
    498     //
    499     // PartNumber
    500     //
    501     PartNumberStr = AllocateZeroPool (StringBufferSize);
    502     if(NULL == PartNumberStr)
    503     {
    504         Status = EFI_OUT_OF_RESOURCES;
    505         goto FREE_STR_AST;
    506     }
    507     UnicodeSPrint(PartNumberStr, SMBIOS_STRING_MAX_LENGTH - 1, L"NO DIMM");
    508 
    509 
    510     if(IsDimmPresent(pGblData, Skt, Ch, Dimm))
    511     {
    512         MemoryDataWidth = pGblData->Channel[Skt][Ch].Dimm[Dimm].PrimaryBusWidth;
    513         MemoryTotalWidth = MemoryDataWidth + pGblData->Channel[Skt][Ch].Dimm[Dimm].ExtensionBusWidth;
    514 
    515         MemoryDeviceSize = pGblData->Channel[Skt][Ch].Dimm[Dimm].DimmSize;  //in MB
    516         MemoryDeviceExtendSize = 0;
    517 
    518         if (MemoryDeviceSize >= 0x7fff)
    519         {
    520             MemoryDeviceExtendSize = MemoryDeviceSize;  // in MB
    521             MemoryDeviceSize = 0x7fff;                    // max value
    522         }
    523 
    524         MemInfoMemFreq = pGblData->Freq;
    525         MemorySpeed = pGblData->Channel[Skt][Ch].Dimm[Dimm].DimmSpeed;
    526         Attributes = pGblData->Channel[Skt][Ch].Dimm[Dimm].RankNum;
    527         CfgMemorySpeed = MemInfoMemFreq;
    528 
    529         //
    530         // Manufacturer
    531         //
    532         SmbiosGetManufacturer (pGblData->Channel[Skt][Ch].Dimm[Dimm].SpdMMfgId & 0xFF,
    533                                         pGblData->Channel[Skt][Ch].Dimm[Dimm].SpdMMfgId >> 8,
    534                                         ManufactureStr
    535                                         );
    536 
    537         //
    538         // SerialNumber
    539         //
    540         SmbiosGetSerialNumber(pGblData, Skt, Ch, Dimm, SerialNumberStr);
    541 
    542         //
    543         // AssetTag
    544         //
    545         UnicodeSPrint(AssertTagStr, SMBIOS_STRING_MAX_LENGTH - 1, L"Unknown");
    546 
    547         //
    548         // PartNumber
    549         //
    550         SmbiosGetPartNumber(pGblData, Skt, Ch, Dimm, PartNumberStr);
    551     }
    552 
    553     //
    554     // DeviceLocator
    555     //
    556     DeviceLocatorStr = AllocateZeroPool ((sizeof (CHAR16)) * SMBIOS_STRING_MAX_LENGTH);
    557     if(NULL == DeviceLocatorStr)
    558     {
    559         Status = EFI_OUT_OF_RESOURCES;
    560         goto FREE_STR_PN;
    561     }
    562     DeviceLocator = gDimmToDevLocator[Skt][Ch][Dimm];
    563     if (DeviceLocator != 0xFFFF)
    564     {
    565         UnicodeSPrint(DeviceLocatorStr, SMBIOS_STRING_MAX_LENGTH, L"DIMM%x%x%x ", Skt, Ch, Dimm);
    566         StringBuffer = HiiGetPackageString (&gEfiCallerIdGuid, DeviceLocator, NULL);
    567         (VOID)StrCatS(DeviceLocatorStr, SMBIOS_STRING_MAX_LENGTH, StringBuffer);
    568     }
    569     else
    570     {
    571     UnicodeSPrint(DeviceLocatorStr, SMBIOS_STRING_MAX_LENGTH, L"DIMM%x%x%x", Skt, Ch, Dimm);
    572     }
    573     DeviceLocatorStrLen = StrLen (DeviceLocatorStr);
    574 
    575     //
    576     // BankLocator
    577     //
    578     BankLocatorStr = AllocateZeroPool ((sizeof (CHAR16)) * SMBIOS_STRING_MAX_LENGTH);
    579     if(NULL == BankLocatorStr)
    580     {
    581         Status = EFI_OUT_OF_RESOURCES;
    582         goto FREE_STR_DEV;
    583     }
    584     UnicodeSPrint(BankLocatorStr, SMBIOS_STRING_MAX_LENGTH, L"SOCKET %x CHANNEL %x DIMM %x", Skt, Ch, Dimm);
    585     BankLocatorStrLen = StrLen (BankLocatorStr);
    586 
    587     ManufactureStrLen = StrLen (ManufactureStr);
    588     SerialNumberStrLen = StrLen (SerialNumberStr);
    589     AssertTagStrLen = StrLen (AssertTagStr);
    590     PartNumberStrLen = StrLen (PartNumberStr);
    591 
    592     //
    593     // Report Type 17 SMBIOS Record
    594     //
    595     TableSize = sizeof(SMBIOS_TABLE_TYPE17) + DeviceLocatorStrLen + 1 + BankLocatorStrLen + 1 + ManufactureStrLen + 1 + SerialNumberStrLen + 1 + AssertTagStrLen + 1 + PartNumberStrLen + 1 + 1;
    596     Type17Record = AllocateZeroPool (TableSize);
    597     if(NULL == Type17Record)
    598     {
    599         Status = EFI_OUT_OF_RESOURCES;
    600         goto FREE_BL;
    601     }
    602 
    603     Type17Record->Hdr.Type                      = EFI_SMBIOS_TYPE_MEMORY_DEVICE;
    604     Type17Record->Hdr.Length                    = sizeof (SMBIOS_TABLE_TYPE17);
    605     Type17Record->Hdr.Handle                    = 0;
    606     Type17Record->MemoryArrayHandle             = MemArraySmbiosHandle;
    607     Type17Record->MemoryErrorInformationHandle  = 0xFFFE;
    608     Type17Record->TotalWidth                    = MemoryTotalWidth;
    609     Type17Record->DataWidth                     = MemoryDataWidth;
    610     Type17Record->Size                          = MemoryDeviceSize;           // in MB
    611     Type17Record->FormFactor                    = MemoryFormFactorDimm;
    612     Type17Record->DeviceLocator                 = 1;
    613     Type17Record->BankLocator                   = 2;
    614     Type17Record->MemoryType                    = SmbiosGetMemoryType (pGblData, Skt, Ch, Dimm);
    615 
    616     Type17Record->TypeDetail.Synchronous    = 1;
    617 
    618     SmbiosGetTypeDetail (pGblData, Skt, Ch, Dimm, &(Type17Record->TypeDetail));
    619 
    620     Type17Record->Speed                         = MemorySpeed; // in MHZ
    621     Type17Record->Manufacturer                  = 3;
    622     Type17Record->SerialNumber                  = 4;
    623     Type17Record->AssetTag                      = 5;
    624     Type17Record->PartNumber                    = 6;
    625     Type17Record->Attributes                    = Attributes;
    626     Type17Record->ExtendedSize                  = MemoryDeviceExtendSize;
    627     Type17Record->ConfiguredMemoryClockSpeed    = CfgMemorySpeed;
    628     //
    629     // Add for smbios 2.8.0
    630     //
    631     SmbiosGetDimmVoltageInfo (pGblData, Skt, Ch, Dimm, Type17Record);
    632 
    633     OptionalStrStart = (CHAR8 *) (Type17Record + 1);
    634     UnicodeStrToAsciiStr (DeviceLocatorStr, OptionalStrStart);
    635     UnicodeStrToAsciiStr (BankLocatorStr, OptionalStrStart + DeviceLocatorStrLen + 1);
    636     UnicodeStrToAsciiStr (ManufactureStr, OptionalStrStart + DeviceLocatorStrLen + 1 + BankLocatorStrLen + 1);
    637     UnicodeStrToAsciiStr (SerialNumberStr, OptionalStrStart + DeviceLocatorStrLen + 1 + BankLocatorStrLen + 1 + ManufactureStrLen + 1);
    638     UnicodeStrToAsciiStr (AssertTagStr, OptionalStrStart + DeviceLocatorStrLen + 1 + BankLocatorStrLen + 1 + ManufactureStrLen + 1 + SerialNumberStrLen + 1);
    639     UnicodeStrToAsciiStr (PartNumberStr, OptionalStrStart + DeviceLocatorStrLen + 1 + BankLocatorStrLen + 1 + ManufactureStrLen + 1 + SerialNumberStrLen + 1 + AssertTagStrLen + 1);
    640 
    641     MemDevSmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
    642     Status = mSmbios->Add (mSmbios, NULL, &MemDevSmbiosHandle, (EFI_SMBIOS_TABLE_HEADER*) Type17Record);
    643     if(EFI_ERROR(Status))
    644     {
    645         DEBUG((EFI_D_ERROR, "[%a]:[%dL] Smbios Type17 Table Log Failed! %r \n", __FUNCTION__, __LINE__, Status));
    646     }
    647 
    648     FreePool (Type17Record);
    649 
    650 FREE_BL:
    651     FreePool (BankLocatorStr);
    652 
    653 FREE_STR_DEV:
    654     FreePool (DeviceLocatorStr);
    655 
    656 FREE_STR_PN:
    657     FreePool (PartNumberStr);
    658 
    659 FREE_STR_AST:
    660     FreePool (AssertTagStr);
    661 
    662 FREE_STR_SN:
    663     FreePool (SerialNumberStr);
    664 
    665 FREE_STR_MAN:
    666     FreePool (ManufactureStr);
    667 
    668 FREE_STR_BUF:
    669     FreePool (StringBuffer);
    670 
    671     return Status;
    672 }
    673 
    674 
    675 /**
    676   Standard EFI driver point.  This driver locates the MemoryConfigurationData Variable,
    677   if it exists, add the related SMBIOS tables by PI SMBIOS protocol.
    678 
    679   @param  ImageHandle     Handle for the image of this driver
    680   @param  SystemTable     Pointer to the EFI System Table
    681 
    682   @retval  EFI_SUCCESS    The data was successfully stored.
    683 
    684 **/
    685 EFI_STATUS
    686 EFIAPI
    687 MemorySubClassEntryPoint(
    688   IN EFI_HANDLE         ImageHandle,
    689   IN EFI_SYSTEM_TABLE   *SystemTable
    690   )
    691 {
    692     EFI_STATUS                      Status;
    693     EFI_SMBIOS_PROTOCOL             *Smbios;
    694     EFI_HOB_GUID_TYPE               *GuidHob;
    695     pGBL_DATA                       pGblData;
    696     EFI_SMBIOS_HANDLE               MemArraySmbiosHandle;
    697     UINT8                           Skt, Ch, Dimm;
    698 
    699     GuidHob = GetFirstGuidHob(&gHisiEfiMemoryMapGuid);
    700     if(NULL == GuidHob)
    701     {
    702         DEBUG((EFI_D_ERROR, "Could not get MemoryMap Guid hob.  %r\n"));
    703         return EFI_NOT_FOUND;
    704     }
    705     pGblData = (pGBL_DATA) GET_GUID_HOB_DATA(GuidHob);
    706 
    707     //
    708     // Locate dependent protocols
    709     //
    710     Status = gBS->LocateProtocol(&gEfiSmbiosProtocolGuid, NULL, (VOID**)&Smbios);
    711     if (EFI_ERROR(Status))
    712     {
    713         DEBUG((EFI_D_ERROR, "Could not locate SMBIOS protocol.  %r\n", Status));
    714         return Status;
    715     }
    716     mSmbios = Smbios;
    717 
    718     //
    719     // Add our default strings to the HII database. They will be modified later.
    720     //
    721     mHiiHandle = OemGetPackages();
    722     if(NULL == mHiiHandle)
    723     {
    724         return EFI_OUT_OF_RESOURCES;
    725     }
    726 
    727     mMaxSkt  = OemGetSocketNumber();
    728     mMaxCh   = OemGetDdrChannel();
    729     // Get DIMM slot number on Socket 0 Channel 0
    730     // TODO: Assume all channels have same slot number
    731 
    732     Status = SmbiosAddType16Table (pGblData, &MemArraySmbiosHandle);
    733     if(EFI_ERROR(Status))
    734     {
    735         DEBUG((EFI_D_ERROR, "Smbios Add Type16 Table Failed.  %r\n", Status));
    736         return Status;
    737     }
    738 
    739     Status = SmbiosAddType19Table (pGblData, MemArraySmbiosHandle);
    740     if(EFI_ERROR(Status))
    741     {
    742         DEBUG((EFI_D_ERROR, "Smbios Add Type19 Table Failed.  %r\n", Status));
    743         return Status;
    744     }
    745 
    746     for(Skt = 0; Skt < mMaxSkt; Skt++)
    747     {
    748         for(Ch = 0; Ch < mMaxCh; Ch++)
    749         {
    750             for(Dimm = 0; Dimm < OemGetDimmSlot(Skt, Ch); Dimm++)
    751             {
    752                 Status = SmbiosAddType17Table (pGblData, Skt, Ch, Dimm, MemArraySmbiosHandle);
    753                 if(EFI_ERROR(Status))
    754                 {
    755                     DEBUG((EFI_D_ERROR, "Smbios Add Type17 Table Failed.  %r\n", Status));
    756                 }
    757             }
    758         }
    759     }
    760 
    761     return Status;
    762 }
    763