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