Home | History | Annotate | Download | only in MemorySubClass
      1 /** @file
      2 This is the driver that locates the MemoryConfigurationData Variable, if it
      3 exists, and reports the data to the DataHub.
      4 
      5 Copyright (c) 2013-2015 Intel Corporation.
      6 
      7 This program and the accompanying materials
      8 are licensed and made available under the terms and conditions of the BSD License
      9 which accompanies this distribution.  The full text of the license may be found at
     10 http://opensource.org/licenses/bsd-license.php
     11 
     12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include "MemorySubClass.h"
     18 
     19 extern UINT8 MemorySubClassStrings[];
     20 
     21 EFI_GUID  gEfiMemorySubClassDriverGuid = EFI_MEMORY_SUBCLASS_DRIVER_GUID;
     22 
     23 EFI_STATUS
     24 MemorySubClassEntryPoint (
     25   IN EFI_HANDLE       ImageHandle,
     26   IN EFI_SYSTEM_TABLE *SystemTable
     27   )
     28 /*++
     29 
     30   Routine Description:
     31     This is the standard EFI driver point that detects whether there is a
     32     MemoryConfigurationData Variable and, if so, reports memory configuration info
     33     to the DataHub.
     34 
     35   Arguments:
     36     ImageHandle   - Handle for the image of this driver
     37     SystemTable   - Pointer to the EFI System Table
     38 
     39   Returns:
     40     EFI_SUCCESS if the data is successfully reported
     41     EFI_NOT_FOUND if the HOB list could not be located.
     42 
     43 --*/
     44 {
     45 //  UINT8                           Index;
     46   UINTN                           DataSize;
     47   UINT8                           Dimm;
     48   UINTN                           StringBufferSize;
     49   UINT8                           NumSlots;
     50   UINTN                           DevLocStrLen;
     51   UINTN                           BankLocStrLen;
     52   UINTN                           ManuStrLen;
     53   UINTN                           SerialNumStrLen;
     54   UINTN                           AssertTagStrLen;
     55   UINTN                           PartNumStrLen;
     56   UINTN                           MemoryDeviceSize;
     57   CHAR8*                          OptionalStrStart;
     58   UINT16                          ArrayInstance;
     59   UINT64                          DimmMemorySize;
     60   UINT64                          TotalMemorySize;
     61   UINT32                          Data;
     62   UINT32                          MemoryCapacity;
     63   BOOLEAN                         MemoryDeviceSizeUnitMega;
     64   EFI_STATUS                      Status;
     65   EFI_STRING                      StringBuffer;
     66   EFI_STRING                      DevLocStr;
     67   EFI_STRING                      BankLocStr;
     68   EFI_STRING                      ManuStr;
     69   EFI_STRING                      SerialNumStr;
     70   EFI_STRING                      AssertTagStr;
     71   EFI_STRING                      PartNumStr;
     72   EFI_HII_HANDLE                  HiiHandle;
     73   EFI_SMBIOS_HANDLE               MemArraySmbiosHandle;
     74   EFI_SMBIOS_HANDLE               MemArrayMappedAddrSmbiosHandle;
     75   EFI_SMBIOS_HANDLE               MemDevSmbiosHandle;
     76   EFI_SMBIOS_HANDLE               MemDevMappedAddrSmbiosHandle;
     77   EFI_SMBIOS_HANDLE               MemModuleInfoSmbiosHandle;
     78   SMBIOS_TABLE_TYPE6              *Type6Record;
     79   SMBIOS_TABLE_TYPE16             *Type16Record;
     80   SMBIOS_TABLE_TYPE17             *Type17Record;
     81   SMBIOS_TABLE_TYPE19              *Type19Record;
     82   SMBIOS_TABLE_TYPE20             *Type20Record;
     83   EFI_SMBIOS_PROTOCOL             *Smbios;
     84   EFI_MEMORY_ARRAY_LINK_DATA      ArrayLink;
     85   EFI_MEMORY_ARRAY_LOCATION_DATA  ArrayLocationData;
     86   EFI_MEMORY_DEVICE_START_ADDRESS_DATA  DeviceStartAddress;
     87 
     88 
     89   DataSize = 0;
     90   Dimm = 0;
     91 
     92 
     93   //
     94   // Allocate Buffers
     95   //
     96   StringBufferSize = (sizeof (CHAR16)) * 100;
     97   StringBuffer = AllocateZeroPool (StringBufferSize);
     98   ASSERT (StringBuffer != NULL);
     99 
    100   //
    101   // Locate dependent protocols
    102   //
    103   Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID**)&Smbios);
    104   ASSERT_EFI_ERROR (Status);
    105 
    106 
    107   //
    108   // Add our default strings to the HII database. They will be modified later.
    109   //
    110   HiiHandle = HiiAddPackages (
    111                 &gEfiMemorySubClassDriverGuid,
    112                 NULL,
    113                 MemorySubClassStrings,
    114                 NULL
    115                 );
    116   ASSERT (HiiHandle != NULL);
    117 
    118   //
    119   // Create physical array and associated data for all mainboard memory
    120   // This will translate into a Type 16 SMBIOS Record
    121   //
    122   ArrayInstance = 1;
    123 
    124   McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = MESSAGE_READ_DW (0x3, 0x8);
    125   TotalMemorySize =     McD0PciCfg32 (QNC_ACCESS_PORT_MDR);
    126 
    127   ArrayLocationData.MemoryArrayLocation = EfiMemoryArrayLocationSystemBoard;
    128   ArrayLocationData.MemoryArrayUse = EfiMemoryArrayUseSystemMemory;
    129 
    130   ArrayLocationData.MemoryErrorCorrection = EfiMemoryErrorCorrectionNone;
    131 
    132   Data = 0x40000000;//(UINT32) RShiftU64(MemConfigData->RowInfo.MaxMemory, 10);
    133 
    134   ArrayLocationData.MaximumMemoryCapacity.Exponent = (UINT16) LowBitSet32 (Data);
    135   ArrayLocationData.MaximumMemoryCapacity.Value    = (UINT16) (Data >> ArrayLocationData.MaximumMemoryCapacity.Exponent);
    136 
    137   NumSlots = 2;// (UINT8)(MemConfigData->RowInfo.MaxRows >> 1);
    138   ArrayLocationData.NumberMemoryDevices = (UINT16)(NumSlots);
    139 
    140   //
    141   // Report top level physical array to Type 16 SMBIOS Record
    142   //
    143   Type16Record = AllocatePool(sizeof(SMBIOS_TABLE_TYPE16) + 1 + 1);
    144   ZeroMem(Type16Record, sizeof(SMBIOS_TABLE_TYPE16) + 1 + 1);
    145 
    146   Type16Record->Hdr.Type = EFI_SMBIOS_TYPE_PHYSICAL_MEMORY_ARRAY;
    147   Type16Record->Hdr.Length = sizeof(SMBIOS_TABLE_TYPE16);
    148   Type16Record->Hdr.Handle = 0;
    149 
    150   Type16Record->Location = (UINT8)ArrayLocationData.MemoryArrayLocation;
    151 
    152   Type16Record->Use = (UINT8)ArrayLocationData.MemoryArrayUse;
    153 
    154   Type16Record->MemoryErrorCorrection = (UINT8)ArrayLocationData.MemoryErrorCorrection;
    155 
    156   MemoryCapacity = (UINT32) ArrayLocationData.MaximumMemoryCapacity.Value * (1 << ((UINT32) ArrayLocationData.MaximumMemoryCapacity.Exponent - 10));
    157   Type16Record->MaximumCapacity = MemoryCapacity;
    158 
    159   Type16Record->MemoryErrorInformationHandle = 0xfffe;
    160 
    161   Type16Record->NumberOfMemoryDevices = ArrayLocationData.NumberMemoryDevices;
    162   //
    163   // Don't change it. This handle will be referenced by type 17 records
    164   //
    165   MemArraySmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
    166   Status = Smbios->Add (Smbios, NULL, &MemArraySmbiosHandle, (EFI_SMBIOS_TABLE_HEADER*) Type16Record);
    167   FreePool(Type16Record);
    168   ASSERT_EFI_ERROR (Status);
    169 
    170   // Do  associated data for each DIMM
    171   //RowConfArray = &MemConfigData->RowConfArray;
    172 
    173   //
    174   // Get total memory size for the construction of smbios record type 19
    175   //
    176   //TotalMemorySize = 0;// MSG_BUS_READ(0x0208);
    177 
    178   //
    179   // Generate Memory Array Mapped Address info
    180   //
    181   Type19Record = AllocatePool(sizeof (SMBIOS_TABLE_TYPE19));
    182   ZeroMem(Type19Record, sizeof(SMBIOS_TABLE_TYPE19));
    183   Type19Record->Hdr.Type = EFI_SMBIOS_TYPE_MEMORY_ARRAY_MAPPED_ADDRESS;
    184   Type19Record->Hdr.Length = sizeof(SMBIOS_TABLE_TYPE19);
    185   Type19Record->Hdr.Handle = 0;
    186   Type19Record->StartingAddress = 0;
    187   Type19Record->EndingAddress = (UINT32)RShiftU64(TotalMemorySize, 10) - 1;
    188   Type19Record->MemoryArrayHandle = MemArraySmbiosHandle;
    189   Type19Record->PartitionWidth = (UINT8)(NumSlots);
    190 
    191   //
    192   // Generate Memory Array Mapped Address info (TYPE 19)
    193   //
    194   MemArrayMappedAddrSmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
    195   Status = Smbios->Add (Smbios, NULL, &MemArrayMappedAddrSmbiosHandle, (EFI_SMBIOS_TABLE_HEADER*) Type19Record);
    196   FreePool(Type19Record);
    197   ASSERT_EFI_ERROR (Status);
    198 
    199 
    200   // Use SPD data to generate Device Type info
    201   ZeroMem (&ArrayLink, sizeof (EFI_MEMORY_ARRAY_LINK_DATA));
    202   ArrayLink.MemoryDeviceLocator = STRING_TOKEN(STR_MEMORY_SUBCLASS_DEVICE_LOCATOR_0);
    203   ArrayLink.MemoryBankLocator = STRING_TOKEN(STR_MEMORY_SUBCLASS_DEVICE_LOCATOR_0);
    204   ArrayLink.MemoryAssetTag = STRING_TOKEN(STR_MEMORY_SUBCLASS_UNKNOWN);
    205   ArrayLink.MemoryArrayLink.ProducerName = gEfiMemorySubClassDriverGuid;
    206   ArrayLink.MemoryArrayLink.Instance = ArrayInstance;
    207   ArrayLink.MemoryArrayLink.SubInstance = EFI_SUBCLASS_INSTANCE_NON_APPLICABLE;
    208   ArrayLink.MemorySubArrayLink.ProducerName = gEfiMemorySubClassDriverGuid;
    209   ArrayLink.MemorySubArrayLink.SubInstance = EFI_SUBCLASS_INSTANCE_NON_APPLICABLE;
    210   ArrayLink.MemoryFormFactor = EfiMemoryFormFactorChip;
    211   ArrayLink.MemoryType = EfiMemoryTypeDdr2;
    212 
    213 
    214   StrCpy (StringBuffer, L"NO DIMM,MEMROY DOWN");
    215   ArrayLink.MemoryManufacturer = HiiSetString (
    216                                    HiiHandle,
    217                                    0,
    218                                    StringBuffer,
    219                                    NULL
    220                                    );
    221   ArrayLink.MemorySerialNumber = HiiSetString (
    222                                    HiiHandle,
    223                                    0,
    224                                    StringBuffer,
    225                                    NULL
    226                                    );
    227 
    228   ArrayLink.MemoryPartNumber = HiiSetString (
    229                                  HiiHandle,
    230                                  0,
    231                                  StringBuffer,
    232                                  NULL
    233                                  );
    234 
    235   //
    236   // Hardcode value. Need to revise for different configuration.
    237   //
    238   ArrayLink.MemoryTotalWidth = 64;
    239   ArrayLink.MemoryDataWidth = 64;
    240 
    241   DimmMemorySize = TotalMemorySize;// MSG_BUS_READ(0x0208);
    242 
    243   ArrayLink.MemoryDeviceSize.Exponent = (UINT16) LowBitSet64 (DimmMemorySize);
    244   ArrayLink.MemoryDeviceSize.Value    = (UINT16) RShiftU64(DimmMemorySize, ArrayLink.MemoryDeviceSize.Exponent);
    245   ArrayLink.MemoryTypeDetail.Synchronous  = 1;
    246   Data = 800;
    247   ArrayLink.MemorySpeed = *((EFI_EXP_BASE10_DATA *) &Data);
    248 
    249 
    250 
    251   DevLocStr = HiiGetPackageString(&gEfiMemorySubClassDriverGuid, ArrayLink.MemoryDeviceLocator, NULL);
    252   DevLocStrLen = StrLen(DevLocStr);
    253   ASSERT(DevLocStrLen <= SMBIOS_STRING_MAX_LENGTH);
    254 
    255   BankLocStr = HiiGetPackageString(&gEfiMemorySubClassDriverGuid, ArrayLink.MemoryBankLocator, NULL);
    256   BankLocStrLen = StrLen(BankLocStr);
    257   ASSERT(BankLocStrLen <= SMBIOS_STRING_MAX_LENGTH);
    258 
    259   ManuStr = HiiGetPackageString(&gEfiMemorySubClassDriverGuid, ArrayLink.MemoryManufacturer, NULL);
    260   ManuStrLen = StrLen(ManuStr);
    261   ASSERT(ManuStrLen <= SMBIOS_STRING_MAX_LENGTH);
    262 
    263   SerialNumStr = HiiGetPackageString(&gEfiMemorySubClassDriverGuid, ArrayLink.MemorySerialNumber, NULL);
    264   SerialNumStrLen = StrLen(SerialNumStr);
    265   ASSERT(SerialNumStrLen <= SMBIOS_STRING_MAX_LENGTH);
    266 
    267   AssertTagStr = HiiGetPackageString(&gEfiMemorySubClassDriverGuid, ArrayLink.MemoryAssetTag, NULL);
    268   AssertTagStrLen = StrLen(AssertTagStr);
    269   ASSERT(AssertTagStrLen <= SMBIOS_STRING_MAX_LENGTH);
    270 
    271   PartNumStr = HiiGetPackageString(&gEfiMemorySubClassDriverGuid, ArrayLink.MemoryPartNumber, NULL);
    272   PartNumStrLen = StrLen(PartNumStr);
    273   ASSERT(PartNumStrLen <= SMBIOS_STRING_MAX_LENGTH);
    274 
    275   //
    276   // Report DIMM level memory module information to smbios (Type 6)
    277   //
    278   DataSize = sizeof(SMBIOS_TABLE_TYPE6) + DevLocStrLen + 1 + 1;
    279   Type6Record = AllocatePool(DataSize);
    280   ZeroMem(Type6Record, DataSize);
    281   Type6Record->Hdr.Type = EFI_SMBIOS_TYPE_MEMORY_MODULE_INFORMATON;
    282   Type6Record->Hdr.Length = sizeof (SMBIOS_TABLE_TYPE6);
    283   Type6Record->Hdr.Handle = 0;
    284   Type6Record->SocketDesignation = 1;
    285   if (ArrayLink.MemorySpeed.Value == 0) {
    286     Type6Record->CurrentSpeed = 0;
    287   } else {
    288     //
    289     // Memory speed is in ns unit
    290     //
    291     Type6Record->CurrentSpeed = (UINT8)(1000 / (ArrayLink.MemorySpeed.Value));
    292   }
    293   //
    294   // Device Size
    295   //
    296   MemoryDeviceSize = (UINTN)(ArrayLink.MemoryDeviceSize.Value) * (UINTN)(1 << ArrayLink.MemoryDeviceSize.Exponent);
    297   if (MemoryDeviceSize == 0) {
    298     *(UINT8*)&(Type6Record->InstalledSize) = 0x7F;
    299     *(UINT8*)&(Type6Record->EnabledSize)   = 0x7F;
    300   } else {
    301     MemoryDeviceSize = (UINTN) RShiftU64 ((UINT64) MemoryDeviceSize, 21);
    302     while (MemoryDeviceSize != 0) {
    303       (*(UINT8*)&(Type6Record->InstalledSize))++;
    304       (*(UINT8*)&(Type6Record->EnabledSize))++;
    305       MemoryDeviceSize = (UINTN) RShiftU64 ((UINT64) MemoryDeviceSize,1);
    306     }
    307   }
    308 
    309   if (ArrayLink.MemoryFormFactor == EfiMemoryFormFactorDimm ||
    310     ArrayLink.MemoryFormFactor == EfiMemoryFormFactorFbDimm) {
    311     *(UINT16*)&Type6Record->CurrentMemoryType |= 1<<8;
    312   }
    313   if (ArrayLink.MemoryFormFactor == EfiMemoryFormFactorSimm) {
    314     *(UINT16*)&Type6Record->CurrentMemoryType |= 1<<7;
    315   }
    316   if (ArrayLink.MemoryType == EfiMemoryTypeSdram) {
    317     *(UINT16*)&Type6Record->CurrentMemoryType |= 1<<10;
    318   }
    319   if (ArrayLink.MemoryTypeDetail.Edo == 1) {
    320     *(UINT16*)&Type6Record->CurrentMemoryType |= 1<<4;
    321   }
    322   if (ArrayLink.MemoryTypeDetail.FastPaged == 1) {
    323     *(UINT16*)&Type6Record->CurrentMemoryType |= 1<<3;
    324   }
    325   OptionalStrStart = (CHAR8 *)(Type6Record + 1);
    326   UnicodeStrToAsciiStr(DevLocStr, OptionalStrStart);
    327   MemModuleInfoSmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
    328   Status = Smbios->Add (Smbios, NULL, &MemModuleInfoSmbiosHandle, (EFI_SMBIOS_TABLE_HEADER*) Type6Record);
    329   FreePool(Type6Record);
    330   ASSERT_EFI_ERROR (Status);
    331   //
    332   // Report DIMM level Device Type to smbios (Type 17)
    333   //
    334   DataSize = sizeof (SMBIOS_TABLE_TYPE17) + DevLocStrLen + 1 + BankLocStrLen + 1 + ManuStrLen + 1 + SerialNumStrLen + 1 + AssertTagStrLen + 1 + PartNumStrLen + 1 + 1;
    335   Type17Record = AllocatePool(DataSize);
    336   ZeroMem(Type17Record, DataSize);
    337   Type17Record->Hdr.Type = EFI_SMBIOS_TYPE_MEMORY_DEVICE;
    338   Type17Record->Hdr.Length = sizeof (SMBIOS_TABLE_TYPE17);
    339   Type17Record->Hdr.Handle = 0;
    340 
    341   Type17Record->MemoryArrayHandle = MemArraySmbiosHandle;
    342   Type17Record->MemoryErrorInformationHandle = 0xfffe;
    343   Type17Record->TotalWidth = ArrayLink.MemoryTotalWidth;
    344   Type17Record->DataWidth = ArrayLink.MemoryDataWidth;
    345   //
    346   // Device Size
    347   //
    348   MemoryDeviceSize          = ((UINTN) ArrayLink.MemoryDeviceSize.Value) << (ArrayLink.MemoryDeviceSize.Exponent - 10);
    349   MemoryDeviceSizeUnitMega  = FALSE;
    350   //
    351   // kilo as unit
    352   //
    353   if (MemoryDeviceSize > 0xffff) {
    354     MemoryDeviceSize = MemoryDeviceSize >> 10;
    355     //
    356     // Mega as unit
    357     //
    358     MemoryDeviceSizeUnitMega = TRUE;
    359   }
    360 
    361   MemoryDeviceSize = MemoryDeviceSize & 0x7fff;
    362   if (MemoryDeviceSize != 0 && MemoryDeviceSizeUnitMega == FALSE) {
    363     MemoryDeviceSize |= 0x8000;
    364   }
    365   Type17Record->Size = (UINT16)MemoryDeviceSize;
    366 
    367   Type17Record->FormFactor = (UINT8)ArrayLink.MemoryFormFactor;
    368   Type17Record->DeviceLocator = 1;
    369   Type17Record->BankLocator = 2;
    370   Type17Record->MemoryType = (UINT8)ArrayLink.MemoryType;
    371   CopyMem (
    372     (UINT8 *) &Type17Record->TypeDetail,
    373     &ArrayLink.MemoryTypeDetail,
    374     2
    375   );
    376 
    377   Type17Record->Speed = ArrayLink.MemorySpeed.Value;
    378   Type17Record->Manufacturer = 3;
    379   Type17Record->SerialNumber = 4;
    380   Type17Record->AssetTag = 5;
    381   Type17Record->PartNumber = 6;
    382   //
    383   // temporary solution for save device label information.
    384   //
    385   Type17Record->Attributes = (UINT8)(Dimm + 1);
    386 
    387   OptionalStrStart = (CHAR8 *)(Type17Record + 1);
    388   UnicodeStrToAsciiStr(DevLocStr, OptionalStrStart);
    389   UnicodeStrToAsciiStr(BankLocStr, OptionalStrStart + DevLocStrLen + 1);
    390   UnicodeStrToAsciiStr(ManuStr, OptionalStrStart + DevLocStrLen + 1 + BankLocStrLen + 1);
    391   UnicodeStrToAsciiStr(SerialNumStr, OptionalStrStart + DevLocStrLen + 1 + BankLocStrLen + 1 + ManuStrLen + 1);
    392   UnicodeStrToAsciiStr(AssertTagStr, OptionalStrStart + DevLocStrLen + 1 + BankLocStrLen + 1 + ManuStrLen + 1 + SerialNumStrLen + 1);
    393   UnicodeStrToAsciiStr(PartNumStr, OptionalStrStart + DevLocStrLen + 1 + BankLocStrLen + 1 + ManuStrLen + 1 + SerialNumStrLen + 1 + AssertTagStrLen + 1);
    394   MemDevSmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
    395   Status = Smbios->Add (Smbios, NULL, &MemDevSmbiosHandle, (EFI_SMBIOS_TABLE_HEADER*) Type17Record);
    396   FreePool(Type17Record);
    397   ASSERT_EFI_ERROR (Status);
    398 
    399   //
    400   // Generate Memory Device Mapped Address info
    401   //
    402   ZeroMem(&DeviceStartAddress, sizeof(EFI_MEMORY_DEVICE_START_ADDRESS_DATA));
    403   DeviceStartAddress.MemoryDeviceStartAddress = 0;
    404   DeviceStartAddress.MemoryDeviceEndAddress = DeviceStartAddress.MemoryDeviceStartAddress + DimmMemorySize-1;
    405   DeviceStartAddress.PhysicalMemoryDeviceLink.ProducerName = gEfiMemorySubClassDriverGuid;
    406   DeviceStartAddress.PhysicalMemoryDeviceLink.Instance = ArrayInstance;
    407   DeviceStartAddress.PhysicalMemoryDeviceLink.SubInstance = (UINT16)(Dimm + 1);
    408   DeviceStartAddress.PhysicalMemoryArrayLink.ProducerName = gEfiMemorySubClassDriverGuid;
    409   DeviceStartAddress.PhysicalMemoryArrayLink.Instance = ArrayInstance;
    410   DeviceStartAddress.PhysicalMemoryArrayLink.SubInstance = EFI_SUBCLASS_INSTANCE_NON_APPLICABLE;
    411 
    412   //
    413   // Single channel mode
    414   //
    415   DeviceStartAddress.MemoryDevicePartitionRowPosition = 0x01;
    416   DeviceStartAddress.MemoryDeviceInterleavePosition = 0x00;
    417   DeviceStartAddress.MemoryDeviceInterleaveDataDepth = 0x00;
    418 
    419   //
    420   // Generate Memory Device Mapped Address info (TYPE 20)
    421   //
    422   Type20Record = AllocatePool(sizeof (SMBIOS_TABLE_TYPE20));
    423   ZeroMem(Type20Record, sizeof (SMBIOS_TABLE_TYPE20));
    424   Type20Record->Hdr.Type = EFI_SMBIOS_TYPE_MEMORY_DEVICE_MAPPED_ADDRESS;
    425   Type20Record->Hdr.Length = sizeof(SMBIOS_TABLE_TYPE20);
    426   Type20Record->Hdr.Handle = 0;
    427 
    428   Type20Record->StartingAddress = (UINT32)RShiftU64 (DeviceStartAddress.MemoryDeviceStartAddress, 10);
    429   Type20Record->EndingAddress = (UINT32)RShiftU64 (DeviceStartAddress.MemoryDeviceEndAddress, 10);
    430   Type20Record->MemoryDeviceHandle = MemDevSmbiosHandle;
    431   Type20Record->MemoryArrayMappedAddressHandle = MemArrayMappedAddrSmbiosHandle;
    432   Type20Record->PartitionRowPosition = DeviceStartAddress.MemoryDevicePartitionRowPosition;
    433   Type20Record->InterleavePosition = DeviceStartAddress.MemoryDeviceInterleavePosition;
    434   Type20Record->InterleavedDataDepth = DeviceStartAddress.MemoryDeviceInterleaveDataDepth;
    435   MemDevMappedAddrSmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
    436   Status = Smbios->Add (Smbios, NULL, &MemDevMappedAddrSmbiosHandle, (EFI_SMBIOS_TABLE_HEADER*) Type20Record);
    437   FreePool(Type20Record);
    438   ASSERT_EFI_ERROR (Status);
    439 
    440   return Status;
    441 }
    442