/** @file This is the driver that locates the MemoryConfigurationData Variable, if it exists, and reports the data to the DataHub. Copyright (c) 2013-2015 Intel Corporation. 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" extern UINT8 MemorySubClassStrings[]; EFI_GUID gEfiMemorySubClassDriverGuid = EFI_MEMORY_SUBCLASS_DRIVER_GUID; EFI_STATUS MemorySubClassEntryPoint ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) /*++ Routine Description: This is the standard EFI driver point that detects whether there is a MemoryConfigurationData Variable and, if so, reports memory configuration info to the DataHub. Arguments: ImageHandle - Handle for the image of this driver SystemTable - Pointer to the EFI System Table Returns: EFI_SUCCESS if the data is successfully reported EFI_NOT_FOUND if the HOB list could not be located. --*/ { // UINT8 Index; UINTN DataSize; UINT8 Dimm; UINTN StringBufferSize; UINT8 NumSlots; UINTN DevLocStrLen; UINTN BankLocStrLen; UINTN ManuStrLen; UINTN SerialNumStrLen; UINTN AssertTagStrLen; UINTN PartNumStrLen; UINTN MemoryDeviceSize; CHAR8* OptionalStrStart; UINT16 ArrayInstance; UINT64 DimmMemorySize; UINT64 TotalMemorySize; UINT32 Data; UINT32 MemoryCapacity; BOOLEAN MemoryDeviceSizeUnitMega; EFI_STATUS Status; EFI_STRING StringBuffer; EFI_STRING DevLocStr; EFI_STRING BankLocStr; EFI_STRING ManuStr; EFI_STRING SerialNumStr; EFI_STRING AssertTagStr; EFI_STRING PartNumStr; EFI_HII_HANDLE HiiHandle; EFI_SMBIOS_HANDLE MemArraySmbiosHandle; EFI_SMBIOS_HANDLE MemArrayMappedAddrSmbiosHandle; EFI_SMBIOS_HANDLE MemDevSmbiosHandle; EFI_SMBIOS_HANDLE MemDevMappedAddrSmbiosHandle; EFI_SMBIOS_HANDLE MemModuleInfoSmbiosHandle; SMBIOS_TABLE_TYPE6 *Type6Record; SMBIOS_TABLE_TYPE16 *Type16Record; SMBIOS_TABLE_TYPE17 *Type17Record; SMBIOS_TABLE_TYPE19 *Type19Record; SMBIOS_TABLE_TYPE20 *Type20Record; EFI_SMBIOS_PROTOCOL *Smbios; EFI_MEMORY_ARRAY_LINK_DATA ArrayLink; EFI_MEMORY_ARRAY_LOCATION_DATA ArrayLocationData; EFI_MEMORY_DEVICE_START_ADDRESS_DATA DeviceStartAddress; DataSize = 0; Dimm = 0; // // Allocate Buffers // StringBufferSize = (sizeof (CHAR16)) * 100; StringBuffer = AllocateZeroPool (StringBufferSize); ASSERT (StringBuffer != NULL); // // Locate dependent protocols // Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID**)&Smbios); ASSERT_EFI_ERROR (Status); // // Add our default strings to the HII database. They will be modified later. // HiiHandle = HiiAddPackages ( &gEfiMemorySubClassDriverGuid, NULL, MemorySubClassStrings, NULL ); ASSERT (HiiHandle != NULL); // // Create physical array and associated data for all mainboard memory // This will translate into a Type 16 SMBIOS Record // ArrayInstance = 1; McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = MESSAGE_READ_DW (0x3, 0x8); TotalMemorySize = McD0PciCfg32 (QNC_ACCESS_PORT_MDR); ArrayLocationData.MemoryArrayLocation = EfiMemoryArrayLocationSystemBoard; ArrayLocationData.MemoryArrayUse = EfiMemoryArrayUseSystemMemory; ArrayLocationData.MemoryErrorCorrection = EfiMemoryErrorCorrectionNone; Data = 0x40000000;//(UINT32) RShiftU64(MemConfigData->RowInfo.MaxMemory, 10); ArrayLocationData.MaximumMemoryCapacity.Exponent = (UINT16) LowBitSet32 (Data); ArrayLocationData.MaximumMemoryCapacity.Value = (UINT16) (Data >> ArrayLocationData.MaximumMemoryCapacity.Exponent); NumSlots = 2;// (UINT8)(MemConfigData->RowInfo.MaxRows >> 1); ArrayLocationData.NumberMemoryDevices = (UINT16)(NumSlots); // // Report top level physical array to Type 16 SMBIOS Record // Type16Record = AllocatePool(sizeof(SMBIOS_TABLE_TYPE16) + 1 + 1); ZeroMem(Type16Record, sizeof(SMBIOS_TABLE_TYPE16) + 1 + 1); Type16Record->Hdr.Type = EFI_SMBIOS_TYPE_PHYSICAL_MEMORY_ARRAY; Type16Record->Hdr.Length = sizeof(SMBIOS_TABLE_TYPE16); Type16Record->Hdr.Handle = 0; Type16Record->Location = (UINT8)ArrayLocationData.MemoryArrayLocation; Type16Record->Use = (UINT8)ArrayLocationData.MemoryArrayUse; Type16Record->MemoryErrorCorrection = (UINT8)ArrayLocationData.MemoryErrorCorrection; MemoryCapacity = (UINT32) ArrayLocationData.MaximumMemoryCapacity.Value * (1 << ((UINT32) ArrayLocationData.MaximumMemoryCapacity.Exponent - 10)); Type16Record->MaximumCapacity = MemoryCapacity; Type16Record->MemoryErrorInformationHandle = 0xfffe; Type16Record->NumberOfMemoryDevices = ArrayLocationData.NumberMemoryDevices; // // Don't change it. This handle will be referenced by type 17 records // MemArraySmbiosHandle = SMBIOS_HANDLE_PI_RESERVED; Status = Smbios->Add (Smbios, NULL, &MemArraySmbiosHandle, (EFI_SMBIOS_TABLE_HEADER*) Type16Record); FreePool(Type16Record); ASSERT_EFI_ERROR (Status); // Do associated data for each DIMM //RowConfArray = &MemConfigData->RowConfArray; // // Get total memory size for the construction of smbios record type 19 // //TotalMemorySize = 0;// MSG_BUS_READ(0x0208); // // Generate Memory Array Mapped Address info // Type19Record = AllocatePool(sizeof (SMBIOS_TABLE_TYPE19)); ZeroMem(Type19Record, sizeof(SMBIOS_TABLE_TYPE19)); Type19Record->Hdr.Type = EFI_SMBIOS_TYPE_MEMORY_ARRAY_MAPPED_ADDRESS; Type19Record->Hdr.Length = sizeof(SMBIOS_TABLE_TYPE19); Type19Record->Hdr.Handle = 0; Type19Record->StartingAddress = 0; Type19Record->EndingAddress = (UINT32)RShiftU64(TotalMemorySize, 10) - 1; Type19Record->MemoryArrayHandle = MemArraySmbiosHandle; Type19Record->PartitionWidth = (UINT8)(NumSlots); // // Generate Memory Array Mapped Address info (TYPE 19) // MemArrayMappedAddrSmbiosHandle = SMBIOS_HANDLE_PI_RESERVED; Status = Smbios->Add (Smbios, NULL, &MemArrayMappedAddrSmbiosHandle, (EFI_SMBIOS_TABLE_HEADER*) Type19Record); FreePool(Type19Record); ASSERT_EFI_ERROR (Status); // Use SPD data to generate Device Type info ZeroMem (&ArrayLink, sizeof (EFI_MEMORY_ARRAY_LINK_DATA)); ArrayLink.MemoryDeviceLocator = STRING_TOKEN(STR_MEMORY_SUBCLASS_DEVICE_LOCATOR_0); ArrayLink.MemoryBankLocator = STRING_TOKEN(STR_MEMORY_SUBCLASS_DEVICE_LOCATOR_0); ArrayLink.MemoryAssetTag = STRING_TOKEN(STR_MEMORY_SUBCLASS_UNKNOWN); ArrayLink.MemoryArrayLink.ProducerName = gEfiMemorySubClassDriverGuid; ArrayLink.MemoryArrayLink.Instance = ArrayInstance; ArrayLink.MemoryArrayLink.SubInstance = EFI_SUBCLASS_INSTANCE_NON_APPLICABLE; ArrayLink.MemorySubArrayLink.ProducerName = gEfiMemorySubClassDriverGuid; ArrayLink.MemorySubArrayLink.SubInstance = EFI_SUBCLASS_INSTANCE_NON_APPLICABLE; ArrayLink.MemoryFormFactor = EfiMemoryFormFactorChip; ArrayLink.MemoryType = EfiMemoryTypeDdr2; StrCpy (StringBuffer, L"NO DIMM,MEMROY DOWN"); ArrayLink.MemoryManufacturer = HiiSetString ( HiiHandle, 0, StringBuffer, NULL ); ArrayLink.MemorySerialNumber = HiiSetString ( HiiHandle, 0, StringBuffer, NULL ); ArrayLink.MemoryPartNumber = HiiSetString ( HiiHandle, 0, StringBuffer, NULL ); // // Hardcode value. Need to revise for different configuration. // ArrayLink.MemoryTotalWidth = 64; ArrayLink.MemoryDataWidth = 64; DimmMemorySize = TotalMemorySize;// MSG_BUS_READ(0x0208); ArrayLink.MemoryDeviceSize.Exponent = (UINT16) LowBitSet64 (DimmMemorySize); ArrayLink.MemoryDeviceSize.Value = (UINT16) RShiftU64(DimmMemorySize, ArrayLink.MemoryDeviceSize.Exponent); ArrayLink.MemoryTypeDetail.Synchronous = 1; Data = 800; ArrayLink.MemorySpeed = *((EFI_EXP_BASE10_DATA *) &Data); DevLocStr = HiiGetPackageString(&gEfiMemorySubClassDriverGuid, ArrayLink.MemoryDeviceLocator, NULL); DevLocStrLen = StrLen(DevLocStr); ASSERT(DevLocStrLen <= SMBIOS_STRING_MAX_LENGTH); BankLocStr = HiiGetPackageString(&gEfiMemorySubClassDriverGuid, ArrayLink.MemoryBankLocator, NULL); BankLocStrLen = StrLen(BankLocStr); ASSERT(BankLocStrLen <= SMBIOS_STRING_MAX_LENGTH); ManuStr = HiiGetPackageString(&gEfiMemorySubClassDriverGuid, ArrayLink.MemoryManufacturer, NULL); ManuStrLen = StrLen(ManuStr); ASSERT(ManuStrLen <= SMBIOS_STRING_MAX_LENGTH); SerialNumStr = HiiGetPackageString(&gEfiMemorySubClassDriverGuid, ArrayLink.MemorySerialNumber, NULL); SerialNumStrLen = StrLen(SerialNumStr); ASSERT(SerialNumStrLen <= SMBIOS_STRING_MAX_LENGTH); AssertTagStr = HiiGetPackageString(&gEfiMemorySubClassDriverGuid, ArrayLink.MemoryAssetTag, NULL); AssertTagStrLen = StrLen(AssertTagStr); ASSERT(AssertTagStrLen <= SMBIOS_STRING_MAX_LENGTH); PartNumStr = HiiGetPackageString(&gEfiMemorySubClassDriverGuid, ArrayLink.MemoryPartNumber, NULL); PartNumStrLen = StrLen(PartNumStr); ASSERT(PartNumStrLen <= SMBIOS_STRING_MAX_LENGTH); // // Report DIMM level memory module information to smbios (Type 6) // DataSize = sizeof(SMBIOS_TABLE_TYPE6) + DevLocStrLen + 1 + 1; Type6Record = AllocatePool(DataSize); ZeroMem(Type6Record, DataSize); Type6Record->Hdr.Type = EFI_SMBIOS_TYPE_MEMORY_MODULE_INFORMATON; Type6Record->Hdr.Length = sizeof (SMBIOS_TABLE_TYPE6); Type6Record->Hdr.Handle = 0; Type6Record->SocketDesignation = 1; if (ArrayLink.MemorySpeed.Value == 0) { Type6Record->CurrentSpeed = 0; } else { // // Memory speed is in ns unit // Type6Record->CurrentSpeed = (UINT8)(1000 / (ArrayLink.MemorySpeed.Value)); } // // Device Size // MemoryDeviceSize = (UINTN)(ArrayLink.MemoryDeviceSize.Value) * (UINTN)(1 << ArrayLink.MemoryDeviceSize.Exponent); if (MemoryDeviceSize == 0) { *(UINT8*)&(Type6Record->InstalledSize) = 0x7F; *(UINT8*)&(Type6Record->EnabledSize) = 0x7F; } else { MemoryDeviceSize = (UINTN) RShiftU64 ((UINT64) MemoryDeviceSize, 21); while (MemoryDeviceSize != 0) { (*(UINT8*)&(Type6Record->InstalledSize))++; (*(UINT8*)&(Type6Record->EnabledSize))++; MemoryDeviceSize = (UINTN) RShiftU64 ((UINT64) MemoryDeviceSize,1); } } if (ArrayLink.MemoryFormFactor == EfiMemoryFormFactorDimm || ArrayLink.MemoryFormFactor == EfiMemoryFormFactorFbDimm) { *(UINT16*)&Type6Record->CurrentMemoryType |= 1<<8; } if (ArrayLink.MemoryFormFactor == EfiMemoryFormFactorSimm) { *(UINT16*)&Type6Record->CurrentMemoryType |= 1<<7; } if (ArrayLink.MemoryType == EfiMemoryTypeSdram) { *(UINT16*)&Type6Record->CurrentMemoryType |= 1<<10; } if (ArrayLink.MemoryTypeDetail.Edo == 1) { *(UINT16*)&Type6Record->CurrentMemoryType |= 1<<4; } if (ArrayLink.MemoryTypeDetail.FastPaged == 1) { *(UINT16*)&Type6Record->CurrentMemoryType |= 1<<3; } OptionalStrStart = (CHAR8 *)(Type6Record + 1); UnicodeStrToAsciiStr(DevLocStr, OptionalStrStart); MemModuleInfoSmbiosHandle = SMBIOS_HANDLE_PI_RESERVED; Status = Smbios->Add (Smbios, NULL, &MemModuleInfoSmbiosHandle, (EFI_SMBIOS_TABLE_HEADER*) Type6Record); FreePool(Type6Record); ASSERT_EFI_ERROR (Status); // // Report DIMM level Device Type to smbios (Type 17) // DataSize = sizeof (SMBIOS_TABLE_TYPE17) + DevLocStrLen + 1 + BankLocStrLen + 1 + ManuStrLen + 1 + SerialNumStrLen + 1 + AssertTagStrLen + 1 + PartNumStrLen + 1 + 1; Type17Record = AllocatePool(DataSize); ZeroMem(Type17Record, DataSize); 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 = ArrayLink.MemoryTotalWidth; Type17Record->DataWidth = ArrayLink.MemoryDataWidth; // // Device Size // MemoryDeviceSize = ((UINTN) ArrayLink.MemoryDeviceSize.Value) << (ArrayLink.MemoryDeviceSize.Exponent - 10); MemoryDeviceSizeUnitMega = FALSE; // // kilo as unit // if (MemoryDeviceSize > 0xffff) { MemoryDeviceSize = MemoryDeviceSize >> 10; // // Mega as unit // MemoryDeviceSizeUnitMega = TRUE; } MemoryDeviceSize = MemoryDeviceSize & 0x7fff; if (MemoryDeviceSize != 0 && MemoryDeviceSizeUnitMega == FALSE) { MemoryDeviceSize |= 0x8000; } Type17Record->Size = (UINT16)MemoryDeviceSize; Type17Record->FormFactor = (UINT8)ArrayLink.MemoryFormFactor; Type17Record->DeviceLocator = 1; Type17Record->BankLocator = 2; Type17Record->MemoryType = (UINT8)ArrayLink.MemoryType; CopyMem ( (UINT8 *) &Type17Record->TypeDetail, &ArrayLink.MemoryTypeDetail, 2 ); Type17Record->Speed = ArrayLink.MemorySpeed.Value; Type17Record->Manufacturer = 3; Type17Record->SerialNumber = 4; Type17Record->AssetTag = 5; Type17Record->PartNumber = 6; // // temporary solution for save device label information. // Type17Record->Attributes = (UINT8)(Dimm + 1); OptionalStrStart = (CHAR8 *)(Type17Record + 1); UnicodeStrToAsciiStr(DevLocStr, OptionalStrStart); UnicodeStrToAsciiStr(BankLocStr, OptionalStrStart + DevLocStrLen + 1); UnicodeStrToAsciiStr(ManuStr, OptionalStrStart + DevLocStrLen + 1 + BankLocStrLen + 1); UnicodeStrToAsciiStr(SerialNumStr, OptionalStrStart + DevLocStrLen + 1 + BankLocStrLen + 1 + ManuStrLen + 1); UnicodeStrToAsciiStr(AssertTagStr, OptionalStrStart + DevLocStrLen + 1 + BankLocStrLen + 1 + ManuStrLen + 1 + SerialNumStrLen + 1); UnicodeStrToAsciiStr(PartNumStr, OptionalStrStart + DevLocStrLen + 1 + BankLocStrLen + 1 + ManuStrLen + 1 + SerialNumStrLen + 1 + AssertTagStrLen + 1); MemDevSmbiosHandle = SMBIOS_HANDLE_PI_RESERVED; Status = Smbios->Add (Smbios, NULL, &MemDevSmbiosHandle, (EFI_SMBIOS_TABLE_HEADER*) Type17Record); FreePool(Type17Record); ASSERT_EFI_ERROR (Status); // // Generate Memory Device Mapped Address info // ZeroMem(&DeviceStartAddress, sizeof(EFI_MEMORY_DEVICE_START_ADDRESS_DATA)); DeviceStartAddress.MemoryDeviceStartAddress = 0; DeviceStartAddress.MemoryDeviceEndAddress = DeviceStartAddress.MemoryDeviceStartAddress + DimmMemorySize-1; DeviceStartAddress.PhysicalMemoryDeviceLink.ProducerName = gEfiMemorySubClassDriverGuid; DeviceStartAddress.PhysicalMemoryDeviceLink.Instance = ArrayInstance; DeviceStartAddress.PhysicalMemoryDeviceLink.SubInstance = (UINT16)(Dimm + 1); DeviceStartAddress.PhysicalMemoryArrayLink.ProducerName = gEfiMemorySubClassDriverGuid; DeviceStartAddress.PhysicalMemoryArrayLink.Instance = ArrayInstance; DeviceStartAddress.PhysicalMemoryArrayLink.SubInstance = EFI_SUBCLASS_INSTANCE_NON_APPLICABLE; // // Single channel mode // DeviceStartAddress.MemoryDevicePartitionRowPosition = 0x01; DeviceStartAddress.MemoryDeviceInterleavePosition = 0x00; DeviceStartAddress.MemoryDeviceInterleaveDataDepth = 0x00; // // Generate Memory Device Mapped Address info (TYPE 20) // Type20Record = AllocatePool(sizeof (SMBIOS_TABLE_TYPE20)); ZeroMem(Type20Record, sizeof (SMBIOS_TABLE_TYPE20)); Type20Record->Hdr.Type = EFI_SMBIOS_TYPE_MEMORY_DEVICE_MAPPED_ADDRESS; Type20Record->Hdr.Length = sizeof(SMBIOS_TABLE_TYPE20); Type20Record->Hdr.Handle = 0; Type20Record->StartingAddress = (UINT32)RShiftU64 (DeviceStartAddress.MemoryDeviceStartAddress, 10); Type20Record->EndingAddress = (UINT32)RShiftU64 (DeviceStartAddress.MemoryDeviceEndAddress, 10); Type20Record->MemoryDeviceHandle = MemDevSmbiosHandle; Type20Record->MemoryArrayMappedAddressHandle = MemArrayMappedAddrSmbiosHandle; Type20Record->PartitionRowPosition = DeviceStartAddress.MemoryDevicePartitionRowPosition; Type20Record->InterleavePosition = DeviceStartAddress.MemoryDeviceInterleavePosition; Type20Record->InterleavedDataDepth = DeviceStartAddress.MemoryDeviceInterleaveDataDepth; MemDevMappedAddrSmbiosHandle = SMBIOS_HANDLE_PI_RESERVED; Status = Smbios->Add (Smbios, NULL, &MemDevMappedAddrSmbiosHandle, (EFI_SMBIOS_TABLE_HEADER*) Type20Record); FreePool(Type20Record); ASSERT_EFI_ERROR (Status); return Status; }