/** @file * * Copyright (c) 2015, Hisilicon Limited. All rights reserved. * Copyright (c) 2015, Linaro Limited. All rights reserved. * * This program and the accompanying materials * are licensed and made available under the terms and conditions of the BSD License * which accompanies this distribution. The full text of the license may be found at * http://opensource.org/licenses/bsd-license.php * * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. * **/ #include "MemorySubClass.h" EFI_SMBIOS_PROTOCOL *mSmbios = NULL; EFI_HII_HANDLE mHiiHandle; UINT8 mMaxSkt; UINT8 mMaxCh; VOID SmbiosGetManufacturer ( IN UINT8 MfgIdLSB, IN UINT8 MfgIdMSB, OUT CHAR16 *Manufacturer ) { UINT32 Index = 0; (VOID)StrCpyS(Manufacturer, SMBIOS_STRING_MAX_LENGTH - 1, L"Unknown"); while (JEP106[Index].MfgIdLSB != 0xFF && JEP106[Index].MfgIdMSB != 0xFF ) { if (JEP106[Index].MfgIdLSB == MfgIdLSB && JEP106[Index].MfgIdMSB == MfgIdMSB) { (VOID)StrCpyS (Manufacturer, SMBIOS_STRING_MAX_LENGTH - 1, JEP106[Index].Name); break; } Index++; } } VOID SmbiosGetPartNumber ( IN pGBL_DATA pGblData, IN UINT8 Skt, IN UINT8 Ch, IN UINT8 Dimm, OUT CHAR16 *PartNumber ) { CHAR16 StringBuffer2[SMBIOS_STRING_MAX_LENGTH]; UINT32 Index2; (VOID)StrCpyS(PartNumber, SMBIOS_STRING_MAX_LENGTH - 1, L""); if (pGblData->Channel[Skt][Ch].Dimm[Dimm].DramType == SPD_TYPE_DDR3) { for (Index2 = 0; Index2 < SPD_MODULE_PART; Index2++) { UnicodeSPrint (StringBuffer2, SMBIOS_STRING_MAX_LENGTH - 1, L"%c", pGblData->Channel[Skt][Ch].Dimm[Dimm].SpdModPart[Index2]); (VOID)StrCatS(PartNumber, SMBIOS_STRING_MAX_LENGTH - 1, StringBuffer2); } } else { for (Index2 = 0; Index2 < SPD_MODULE_PART_DDR4; Index2++) { UnicodeSPrint (StringBuffer2, SMBIOS_STRING_MAX_LENGTH - 1, L"%c", pGblData->Channel[Skt][Ch].Dimm[Dimm].SpdModPartDDR4[Index2]); (VOID)StrCatS(PartNumber, SMBIOS_STRING_MAX_LENGTH - 1, StringBuffer2); } } return; } VOID SmbiosGetSerialNumber ( IN pGBL_DATA pGblData, IN UINT8 Skt, IN UINT8 Ch, IN UINT8 Dimm, OUT CHAR16 *SerialNumber ) { UINT32 Temp; Temp = SwapBytes32 (pGblData->Channel[Skt][Ch].Dimm[Dimm].SpdSerialNum); UnicodeSPrint(SerialNumber, SMBIOS_STRING_MAX_LENGTH, L"0x%08x", Temp); return; } BOOLEAN IsDimmPresent ( IN pGBL_DATA pGblData, IN UINT8 Skt, IN UINT8 Ch, IN UINT8 Dimm ) { if (pGblData->Channel[Skt][Ch].Status == FALSE || pGblData->Channel[Skt][Ch].Dimm[Dimm].Status == FALSE) { return FALSE; } else { return TRUE; } } UINT8 SmbiosGetMemoryType ( IN pGBL_DATA pGblData, IN UINT8 Skt, IN UINT8 Ch, IN UINT8 Dimm ) { UINT8 MemoryType; if(!IsDimmPresent(pGblData, Skt, Ch, Dimm)) { return MemoryTypeUnknown; } if (pGblData->Channel[Skt][Ch].Dimm[Dimm].DramType == SPD_TYPE_DDR3) { MemoryType = MemoryTypeDdr3; } else if (pGblData->Channel[Skt][Ch].Dimm[Dimm].DramType == SPD_TYPE_DDR4) { MemoryType = MemoryTypeDdr4; } else { MemoryType = MemoryTypeUnknown; } return MemoryType; } VOID SmbiosGetTypeDetail ( IN pGBL_DATA pGblData, IN UINT8 Skt, IN UINT8 Ch, IN UINT8 Dimm, IN OUT MEMORY_DEVICE_TYPE_DETAIL *TypeDetail ) { if (NULL == TypeDetail) { return; } if(!IsDimmPresent(pGblData, Skt, Ch, Dimm)) { TypeDetail->Unknown = 1; return; } switch (pGblData->Channel[Skt][Ch].Dimm[Dimm].ModuleType) { case SPD_UDIMM: TypeDetail->Unbuffered = 1; break; case SPD_LRDIMM: TypeDetail->LrDimm = 1; break; case SPD_RDIMM: TypeDetail->Registered = 1; break; default: TypeDetail->Unknown = 1; break; } } VOID SmbiosGetDimmVoltageInfo ( IN pGBL_DATA pGblData, IN UINT8 Skt, IN UINT8 Ch, IN UINT8 Dimm, IN OUT SMBIOS_TABLE_TYPE17 *Type17Record ) { if(!IsDimmPresent(pGblData, Skt, Ch, Dimm)) { return; } if (pGblData->Channel[Skt][Ch].Dimm[Dimm].DramType == SPD_TYPE_DDR3) { Type17Record->MinimumVoltage = 1250; Type17Record->MaximumVoltage = 1500; switch (pGblData->Channel[Skt][Ch].Dimm[Dimm].SpdVdd) { case SPD_VDD_150: Type17Record->ConfiguredVoltage = 1500; break; case SPD_VDD_135: Type17Record->ConfiguredVoltage = 1350; break; case SPD_VDD_125: Type17Record->ConfiguredVoltage = 1250; break; default: break; } } else if (pGblData->Channel[Skt][Ch].Dimm[Dimm].DramType == SPD_TYPE_DDR4) { Type17Record->MinimumVoltage = 1200; Type17Record->MaximumVoltage = 2000; switch (pGblData->Channel[Skt][Ch].Dimm[Dimm].SpdVdd) { case SPD_VDD_120: Type17Record->ConfiguredVoltage = 1200; break; default: break; } } } VOID SmbiosGetMemoryDevicesNumber ( IN OUT UINT16 *NumberOfDevices ) { UINT8 Skt, Ch, Dimm; for(Skt = 0; Skt < mMaxSkt; Skt++) { for(Ch = 0; Ch < mMaxCh; Ch++) { for(Dimm = 0; Dimm < OemGetDimmSlot(Skt, Ch); Dimm++) { (*NumberOfDevices)++; } } } } UINT8 SmbiosGetPartitionWidth ( ) { UINT8 Skt, Ch, Dimm; UINT8 PartitionWidth = 0; for(Skt = 0; Skt < mMaxSkt; Skt++) { for(Ch = 0; Ch < mMaxCh; Ch++) { for(Dimm = 0; Dimm < OemGetDimmSlot(Skt, Ch); Dimm++) { PartitionWidth++; } } } return PartitionWidth; } EFI_STATUS SmbiosAddType16Table ( IN pGBL_DATA pGblData, OUT EFI_SMBIOS_HANDLE *MemArraySmbiosHandle ) { EFI_STATUS Status; UINT64 MemoryCapacity; SMBIOS_TABLE_TYPE16 *Type16Record; UINT16 NumberOfMemoryDevices = 0; SmbiosGetMemoryDevicesNumber (&NumberOfMemoryDevices); MemoryCapacity = (UINT64) LShiftU64 (NumberOfMemoryDevices * MAX_DIMM_SIZE, 20); // GB to KB. // // Type 16 SMBIOS Record // Type16Record = AllocateZeroPool(sizeof(SMBIOS_TABLE_TYPE16) + 1 + 1); if (NULL == Type16Record) { return EFI_OUT_OF_RESOURCES; } Type16Record->Hdr.Type = EFI_SMBIOS_TYPE_PHYSICAL_MEMORY_ARRAY; Type16Record->Hdr.Length = sizeof (SMBIOS_TABLE_TYPE16); Type16Record->Hdr.Handle = 0x0; Type16Record->Location = MemoryArrayLocationSystemBoard; Type16Record->Use = MemoryArrayUseSystemMemory; Type16Record->MemoryErrorInformationHandle = 0xFFFE; Type16Record->NumberOfMemoryDevices = NumberOfMemoryDevices; if(pGblData->EccEn) { Type16Record->MemoryErrorCorrection = MemoryErrorCorrectionSingleBitEcc; } else { Type16Record->MemoryErrorCorrection = MemoryErrorCorrectionNone; } if (MemoryCapacity >= 0x80000000) { Type16Record->MaximumCapacity = 0x80000000; // in KB; Type16Record->ExtendedMaximumCapacity = MemoryCapacity << 10; // Extended Max capacity should be stored in bytes. } else { Type16Record->MaximumCapacity = (UINT32)MemoryCapacity; // Max capacity should be stored in kilo bytes. Type16Record->ExtendedMaximumCapacity = 0; } *MemArraySmbiosHandle = SMBIOS_HANDLE_PI_RESERVED; Status = mSmbios->Add (mSmbios, NULL, MemArraySmbiosHandle, (EFI_SMBIOS_TABLE_HEADER *)Type16Record); if(EFI_ERROR(Status)) { DEBUG((EFI_D_ERROR, "[%a]:[%dL] Smbios Type16 Table Log Failed! %r \n", __FUNCTION__, __LINE__, Status)); } FreePool(Type16Record); return Status; } EFI_STATUS SmbiosAddType19Table ( IN pGBL_DATA pGblData, IN EFI_SMBIOS_HANDLE MemArraySmbiosHandle ) { EFI_STATUS Status; UINT32 MemInfoTotalMem; UINT64 TotalMemorySize; EFI_SMBIOS_HANDLE MemArrayMappedAddrSmbiosHandle; SMBIOS_TABLE_TYPE19 *Type19Record; MemInfoTotalMem = pGblData->MemSize; // In MB if (MemInfoTotalMem == 0) { return EFI_NOT_FOUND; } TotalMemorySize = (UINT64) LShiftU64 (MemInfoTotalMem, 10); // MB to KB. // // Type 19 SMBIOS Record // Type19Record = AllocateZeroPool(sizeof(SMBIOS_TABLE_TYPE19) + 1 + 1); if (NULL == Type19Record) { return EFI_OUT_OF_RESOURCES; } Type19Record->Hdr.Type = EFI_SMBIOS_TYPE_MEMORY_ARRAY_MAPPED_ADDRESS; Type19Record->Hdr.Length = sizeof(SMBIOS_TABLE_TYPE19); Type19Record->Hdr.Handle = 0x0; Type19Record->StartingAddress = 0x0; Type19Record->EndingAddress = (UINT32) (TotalMemorySize - 1); // in KB; Type19Record->MemoryArrayHandle = MemArraySmbiosHandle; Type19Record->PartitionWidth = SmbiosGetPartitionWidth (); Type19Record->ExtendedStartingAddress = 0x0; Type19Record->ExtendedEndingAddress = 0x0; MemArrayMappedAddrSmbiosHandle = SMBIOS_HANDLE_PI_RESERVED; Status = mSmbios->Add (mSmbios, NULL, &MemArrayMappedAddrSmbiosHandle, (EFI_SMBIOS_TABLE_HEADER *)Type19Record); if(EFI_ERROR(Status)) { DEBUG((EFI_D_ERROR, "[%a]:[%dL] Smbios Type19 Table Log Failed! %r \n", __FUNCTION__, __LINE__, Status)); } FreePool(Type19Record); return Status; } EFI_STATUS SmbiosAddType17Table ( IN pGBL_DATA pGblData, IN UINT8 Skt, IN UINT8 Ch, IN UINT8 Dimm, IN EFI_SMBIOS_HANDLE MemArraySmbiosHandle ) { EFI_STATUS Status; SMBIOS_TABLE_TYPE17 *Type17Record; EFI_SMBIOS_HANDLE MemDevSmbiosHandle; UINTN TableSize; UINTN StringBufferSize; EFI_STRING StringBuffer; UINT16 MemInfoMemFreq; UINT16 MemoryTotalWidth; UINT16 MemoryDataWidth; UINT16 MemoryDeviceSize; UINT16 MemorySpeed; UINT8 Attributes; UINT32 MemoryDeviceExtendSize; UINT16 CfgMemorySpeed; CHAR8 *OptionalStrStart; UINTN DeviceLocatorStrLen; UINTN BankLocatorStrLen; UINTN ManufactureStrLen; UINTN SerialNumberStrLen; UINTN AssertTagStrLen; UINTN PartNumberStrLen; EFI_STRING DeviceLocatorStr; EFI_STRING BankLocatorStr; EFI_STRING ManufactureStr; EFI_STRING SerialNumberStr; EFI_STRING AssertTagStr; EFI_STRING PartNumberStr; EFI_STRING_ID DeviceLocator; Type17Record = NULL; DeviceLocatorStr = NULL; BankLocatorStr = NULL; ManufactureStr = NULL; SerialNumberStr = NULL; AssertTagStr = NULL; PartNumberStr = NULL; MemoryTotalWidth = 0; MemoryDataWidth = 0; MemoryDeviceSize = 0; MemoryDeviceExtendSize = 0; MemorySpeed = 0; Attributes = 0; CfgMemorySpeed = 0; // // Allocate Buffers // StringBufferSize = (sizeof (CHAR16)) * SMBIOS_STRING_MAX_LENGTH; StringBuffer = AllocateZeroPool (StringBufferSize); if(NULL == StringBuffer) { return EFI_OUT_OF_RESOURCES; } // // Manufacture // ManufactureStr = AllocateZeroPool (StringBufferSize); if(NULL == ManufactureStr) { Status = EFI_OUT_OF_RESOURCES; goto FREE_STR_BUF; } UnicodeSPrint(ManufactureStr, SMBIOS_STRING_MAX_LENGTH - 1, L"NO DIMM"); // // SerialNumber // SerialNumberStr = AllocateZeroPool (StringBufferSize); if(NULL == SerialNumberStr) { Status = EFI_OUT_OF_RESOURCES; goto FREE_STR_MAN; } UnicodeSPrint(SerialNumberStr, SMBIOS_STRING_MAX_LENGTH - 1, L"NO DIMM"); // // AssetTag // AssertTagStr = AllocateZeroPool (StringBufferSize); if(NULL == AssertTagStr) { Status = EFI_OUT_OF_RESOURCES; goto FREE_STR_SN; } UnicodeSPrint(AssertTagStr, SMBIOS_STRING_MAX_LENGTH - 1, L"NO DIMM"); // // PartNumber // PartNumberStr = AllocateZeroPool (StringBufferSize); if(NULL == PartNumberStr) { Status = EFI_OUT_OF_RESOURCES; goto FREE_STR_AST; } UnicodeSPrint(PartNumberStr, SMBIOS_STRING_MAX_LENGTH - 1, L"NO DIMM"); if(IsDimmPresent(pGblData, Skt, Ch, Dimm)) { MemoryDataWidth = pGblData->Channel[Skt][Ch].Dimm[Dimm].PrimaryBusWidth; MemoryTotalWidth = MemoryDataWidth + pGblData->Channel[Skt][Ch].Dimm[Dimm].ExtensionBusWidth; MemoryDeviceSize = pGblData->Channel[Skt][Ch].Dimm[Dimm].DimmSize; //in MB MemoryDeviceExtendSize = 0; if (MemoryDeviceSize >= 0x7fff) { MemoryDeviceExtendSize = MemoryDeviceSize; // in MB MemoryDeviceSize = 0x7fff; // max value } MemInfoMemFreq = pGblData->Freq; MemorySpeed = pGblData->Channel[Skt][Ch].Dimm[Dimm].DimmSpeed; Attributes = pGblData->Channel[Skt][Ch].Dimm[Dimm].RankNum; CfgMemorySpeed = MemInfoMemFreq; // // Manufacturer // SmbiosGetManufacturer (pGblData->Channel[Skt][Ch].Dimm[Dimm].SpdMMfgId & 0xFF, pGblData->Channel[Skt][Ch].Dimm[Dimm].SpdMMfgId >> 8, ManufactureStr ); // // SerialNumber // SmbiosGetSerialNumber(pGblData, Skt, Ch, Dimm, SerialNumberStr); // // AssetTag // UnicodeSPrint(AssertTagStr, SMBIOS_STRING_MAX_LENGTH - 1, L"Unknown"); // // PartNumber // SmbiosGetPartNumber(pGblData, Skt, Ch, Dimm, PartNumberStr); } // // DeviceLocator // DeviceLocatorStr = AllocateZeroPool ((sizeof (CHAR16)) * SMBIOS_STRING_MAX_LENGTH); if(NULL == DeviceLocatorStr) { Status = EFI_OUT_OF_RESOURCES; goto FREE_STR_PN; } DeviceLocator = gDimmToDevLocator[Skt][Ch][Dimm]; if (DeviceLocator != 0xFFFF) { UnicodeSPrint(DeviceLocatorStr, SMBIOS_STRING_MAX_LENGTH, L"DIMM%x%x%x ", Skt, Ch, Dimm); StringBuffer = HiiGetPackageString (&gEfiCallerIdGuid, DeviceLocator, NULL); (VOID)StrCatS(DeviceLocatorStr, SMBIOS_STRING_MAX_LENGTH, StringBuffer); } else { UnicodeSPrint(DeviceLocatorStr, SMBIOS_STRING_MAX_LENGTH, L"DIMM%x%x%x", Skt, Ch, Dimm); } DeviceLocatorStrLen = StrLen (DeviceLocatorStr); // // BankLocator // BankLocatorStr = AllocateZeroPool ((sizeof (CHAR16)) * SMBIOS_STRING_MAX_LENGTH); if(NULL == BankLocatorStr) { Status = EFI_OUT_OF_RESOURCES; goto FREE_STR_DEV; } UnicodeSPrint(BankLocatorStr, SMBIOS_STRING_MAX_LENGTH, L"SOCKET %x CHANNEL %x DIMM %x", Skt, Ch, Dimm); BankLocatorStrLen = StrLen (BankLocatorStr); ManufactureStrLen = StrLen (ManufactureStr); SerialNumberStrLen = StrLen (SerialNumberStr); AssertTagStrLen = StrLen (AssertTagStr); PartNumberStrLen = StrLen (PartNumberStr); // // Report Type 17 SMBIOS Record // TableSize = sizeof(SMBIOS_TABLE_TYPE17) + DeviceLocatorStrLen + 1 + BankLocatorStrLen + 1 + ManufactureStrLen + 1 + SerialNumberStrLen + 1 + AssertTagStrLen + 1 + PartNumberStrLen + 1 + 1; Type17Record = AllocateZeroPool (TableSize); if(NULL == Type17Record) { Status = EFI_OUT_OF_RESOURCES; goto FREE_BL; } Type17Record->Hdr.Type = EFI_SMBIOS_TYPE_MEMORY_DEVICE; Type17Record->Hdr.Length = sizeof (SMBIOS_TABLE_TYPE17); Type17Record->Hdr.Handle = 0; Type17Record->MemoryArrayHandle = MemArraySmbiosHandle; Type17Record->MemoryErrorInformationHandle = 0xFFFE; Type17Record->TotalWidth = MemoryTotalWidth; Type17Record->DataWidth = MemoryDataWidth; Type17Record->Size = MemoryDeviceSize; // in MB Type17Record->FormFactor = MemoryFormFactorDimm; Type17Record->DeviceLocator = 1; Type17Record->BankLocator = 2; Type17Record->MemoryType = SmbiosGetMemoryType (pGblData, Skt, Ch, Dimm); Type17Record->TypeDetail.Synchronous = 1; SmbiosGetTypeDetail (pGblData, Skt, Ch, Dimm, &(Type17Record->TypeDetail)); Type17Record->Speed = MemorySpeed; // in MHZ Type17Record->Manufacturer = 3; Type17Record->SerialNumber = 4; Type17Record->AssetTag = 5; Type17Record->PartNumber = 6; Type17Record->Attributes = Attributes; Type17Record->ExtendedSize = MemoryDeviceExtendSize; Type17Record->ConfiguredMemoryClockSpeed = CfgMemorySpeed; // // Add for smbios 2.8.0 // SmbiosGetDimmVoltageInfo (pGblData, Skt, Ch, Dimm, Type17Record); OptionalStrStart = (CHAR8 *) (Type17Record + 1); UnicodeStrToAsciiStr (DeviceLocatorStr, OptionalStrStart); UnicodeStrToAsciiStr (BankLocatorStr, OptionalStrStart + DeviceLocatorStrLen + 1); UnicodeStrToAsciiStr (ManufactureStr, OptionalStrStart + DeviceLocatorStrLen + 1 + BankLocatorStrLen + 1); UnicodeStrToAsciiStr (SerialNumberStr, OptionalStrStart + DeviceLocatorStrLen + 1 + BankLocatorStrLen + 1 + ManufactureStrLen + 1); UnicodeStrToAsciiStr (AssertTagStr, OptionalStrStart + DeviceLocatorStrLen + 1 + BankLocatorStrLen + 1 + ManufactureStrLen + 1 + SerialNumberStrLen + 1); UnicodeStrToAsciiStr (PartNumberStr, OptionalStrStart + DeviceLocatorStrLen + 1 + BankLocatorStrLen + 1 + ManufactureStrLen + 1 + SerialNumberStrLen + 1 + AssertTagStrLen + 1); MemDevSmbiosHandle = SMBIOS_HANDLE_PI_RESERVED; Status = mSmbios->Add (mSmbios, NULL, &MemDevSmbiosHandle, (EFI_SMBIOS_TABLE_HEADER*) Type17Record); if(EFI_ERROR(Status)) { DEBUG((EFI_D_ERROR, "[%a]:[%dL] Smbios Type17 Table Log Failed! %r \n", __FUNCTION__, __LINE__, Status)); } FreePool (Type17Record); FREE_BL: FreePool (BankLocatorStr); FREE_STR_DEV: FreePool (DeviceLocatorStr); FREE_STR_PN: FreePool (PartNumberStr); FREE_STR_AST: FreePool (AssertTagStr); FREE_STR_SN: FreePool (SerialNumberStr); FREE_STR_MAN: FreePool (ManufactureStr); FREE_STR_BUF: FreePool (StringBuffer); return Status; } /** Standard EFI driver point. This driver locates the MemoryConfigurationData Variable, if it exists, add the related SMBIOS tables by PI SMBIOS protocol. @param ImageHandle Handle for the image of this driver @param SystemTable Pointer to the EFI System Table @retval EFI_SUCCESS The data was successfully stored. **/ EFI_STATUS EFIAPI MemorySubClassEntryPoint( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; EFI_SMBIOS_PROTOCOL *Smbios; EFI_HOB_GUID_TYPE *GuidHob; pGBL_DATA pGblData; EFI_SMBIOS_HANDLE MemArraySmbiosHandle; UINT8 Skt, Ch, Dimm; GuidHob = GetFirstGuidHob(&gHisiEfiMemoryMapGuid); if(NULL == GuidHob) { DEBUG((EFI_D_ERROR, "Could not get MemoryMap Guid hob. %r\n")); return EFI_NOT_FOUND; } pGblData = (pGBL_DATA) GET_GUID_HOB_DATA(GuidHob); // // Locate dependent protocols // Status = gBS->LocateProtocol(&gEfiSmbiosProtocolGuid, NULL, (VOID**)&Smbios); if (EFI_ERROR(Status)) { DEBUG((EFI_D_ERROR, "Could not locate SMBIOS protocol. %r\n", Status)); return Status; } mSmbios = Smbios; // // Add our default strings to the HII database. They will be modified later. // mHiiHandle = OemGetPackages(); if(NULL == mHiiHandle) { return EFI_OUT_OF_RESOURCES; } mMaxSkt = OemGetSocketNumber(); mMaxCh = OemGetDdrChannel(); // Get DIMM slot number on Socket 0 Channel 0 // TODO: Assume all channels have same slot number Status = SmbiosAddType16Table (pGblData, &MemArraySmbiosHandle); if(EFI_ERROR(Status)) { DEBUG((EFI_D_ERROR, "Smbios Add Type16 Table Failed. %r\n", Status)); return Status; } Status = SmbiosAddType19Table (pGblData, MemArraySmbiosHandle); if(EFI_ERROR(Status)) { DEBUG((EFI_D_ERROR, "Smbios Add Type19 Table Failed. %r\n", Status)); return Status; } for(Skt = 0; Skt < mMaxSkt; Skt++) { for(Ch = 0; Ch < mMaxCh; Ch++) { for(Dimm = 0; Dimm < OemGetDimmSlot(Skt, Ch); Dimm++) { Status = SmbiosAddType17Table (pGblData, Skt, Ch, Dimm, MemArraySmbiosHandle); if(EFI_ERROR(Status)) { DEBUG((EFI_D_ERROR, "Smbios Add Type17 Table Failed. %r\n", Status)); } } } } return Status; }