2 This is the driver that locates the MemoryConfigurationData Variable, if it
3 exists, and reports the data to the DataHub.
5 Copyright (c) 2013-2015 Intel Corporation.
7 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include "MemorySubClass.h"
13 extern UINT8 MemorySubClassStrings
[];
15 EFI_GUID gEfiMemorySubClassDriverGuid
= EFI_MEMORY_SUBCLASS_DRIVER_GUID
;
18 MemorySubClassEntryPoint (
19 IN EFI_HANDLE ImageHandle
,
20 IN EFI_SYSTEM_TABLE
*SystemTable
25 This is the standard EFI driver point that detects whether there is a
26 MemoryConfigurationData Variable and, if so, reports memory configuration info
30 ImageHandle - Handle for the image of this driver
31 SystemTable - Pointer to the EFI System Table
34 EFI_SUCCESS if the data is successfully reported
35 EFI_NOT_FOUND if the HOB list could not be located.
42 UINTN StringBufferSize
;
47 UINTN SerialNumStrLen
;
48 UINTN AssertTagStrLen
;
50 UINTN MemoryDeviceSize
;
51 CHAR8
* OptionalStrStart
;
53 UINT64 DimmMemorySize
;
54 UINT64 TotalMemorySize
;
56 UINT32 MemoryCapacity
;
57 BOOLEAN MemoryDeviceSizeUnitMega
;
59 EFI_STRING StringBuffer
;
61 EFI_STRING BankLocStr
;
63 EFI_STRING SerialNumStr
;
64 EFI_STRING AssertTagStr
;
65 EFI_STRING PartNumStr
;
66 EFI_HII_HANDLE HiiHandle
;
67 EFI_SMBIOS_HANDLE MemArraySmbiosHandle
;
68 EFI_SMBIOS_HANDLE MemArrayMappedAddrSmbiosHandle
;
69 EFI_SMBIOS_HANDLE MemDevSmbiosHandle
;
70 EFI_SMBIOS_HANDLE MemDevMappedAddrSmbiosHandle
;
71 EFI_SMBIOS_HANDLE MemModuleInfoSmbiosHandle
;
72 SMBIOS_TABLE_TYPE6
*Type6Record
;
73 SMBIOS_TABLE_TYPE16
*Type16Record
;
74 SMBIOS_TABLE_TYPE17
*Type17Record
;
75 SMBIOS_TABLE_TYPE19
*Type19Record
;
76 SMBIOS_TABLE_TYPE20
*Type20Record
;
77 EFI_SMBIOS_PROTOCOL
*Smbios
;
78 EFI_MEMORY_ARRAY_LINK_DATA ArrayLink
;
79 EFI_MEMORY_ARRAY_LOCATION_DATA ArrayLocationData
;
80 EFI_MEMORY_DEVICE_START_ADDRESS_DATA DeviceStartAddress
;
90 StringBufferSize
= (sizeof (CHAR16
)) * 100;
91 StringBuffer
= AllocateZeroPool (StringBufferSize
);
92 ASSERT (StringBuffer
!= NULL
);
95 // Locate dependent protocols
97 Status
= gBS
->LocateProtocol (&gEfiSmbiosProtocolGuid
, NULL
, (VOID
**)&Smbios
);
98 ASSERT_EFI_ERROR (Status
);
102 // Add our default strings to the HII database. They will be modified later.
104 HiiHandle
= HiiAddPackages (
105 &gEfiMemorySubClassDriverGuid
,
107 MemorySubClassStrings
,
110 ASSERT (HiiHandle
!= NULL
);
113 // Create physical array and associated data for all mainboard memory
114 // This will translate into a Type 16 SMBIOS Record
118 McD0PciCfg32 (QNC_ACCESS_PORT_MCR
) = MESSAGE_READ_DW (0x3, 0x8);
119 TotalMemorySize
= McD0PciCfg32 (QNC_ACCESS_PORT_MDR
);
121 ArrayLocationData
.MemoryArrayLocation
= EfiMemoryArrayLocationSystemBoard
;
122 ArrayLocationData
.MemoryArrayUse
= EfiMemoryArrayUseSystemMemory
;
124 ArrayLocationData
.MemoryErrorCorrection
= EfiMemoryErrorCorrectionNone
;
126 Data
= 0x40000000;//(UINT32) RShiftU64(MemConfigData->RowInfo.MaxMemory, 10);
128 ArrayLocationData
.MaximumMemoryCapacity
.Exponent
= (UINT16
) LowBitSet32 (Data
);
129 ArrayLocationData
.MaximumMemoryCapacity
.Value
= (UINT16
) (Data
>> ArrayLocationData
.MaximumMemoryCapacity
.Exponent
);
131 NumSlots
= 2;// (UINT8)(MemConfigData->RowInfo.MaxRows >> 1);
132 ArrayLocationData
.NumberMemoryDevices
= (UINT16
)(NumSlots
);
135 // Report top level physical array to Type 16 SMBIOS Record
137 Type16Record
= AllocatePool(sizeof(SMBIOS_TABLE_TYPE16
) + 1 + 1);
138 ZeroMem(Type16Record
, sizeof(SMBIOS_TABLE_TYPE16
) + 1 + 1);
140 Type16Record
->Hdr
.Type
= EFI_SMBIOS_TYPE_PHYSICAL_MEMORY_ARRAY
;
141 Type16Record
->Hdr
.Length
= sizeof(SMBIOS_TABLE_TYPE16
);
142 Type16Record
->Hdr
.Handle
= 0;
144 Type16Record
->Location
= (UINT8
)ArrayLocationData
.MemoryArrayLocation
;
146 Type16Record
->Use
= (UINT8
)ArrayLocationData
.MemoryArrayUse
;
148 Type16Record
->MemoryErrorCorrection
= (UINT8
)ArrayLocationData
.MemoryErrorCorrection
;
150 MemoryCapacity
= (UINT32
) ArrayLocationData
.MaximumMemoryCapacity
.Value
* (1 << ((UINT32
) ArrayLocationData
.MaximumMemoryCapacity
.Exponent
- 10));
151 Type16Record
->MaximumCapacity
= MemoryCapacity
;
153 Type16Record
->MemoryErrorInformationHandle
= 0xfffe;
155 Type16Record
->NumberOfMemoryDevices
= ArrayLocationData
.NumberMemoryDevices
;
157 // Don't change it. This handle will be referenced by type 17 records
159 MemArraySmbiosHandle
= SMBIOS_HANDLE_PI_RESERVED
;
160 Status
= Smbios
->Add (Smbios
, NULL
, &MemArraySmbiosHandle
, (EFI_SMBIOS_TABLE_HEADER
*) Type16Record
);
161 FreePool(Type16Record
);
162 ASSERT_EFI_ERROR (Status
);
164 // Do associated data for each DIMM
165 //RowConfArray = &MemConfigData->RowConfArray;
168 // Get total memory size for the construction of smbios record type 19
170 //TotalMemorySize = 0;// MSG_BUS_READ(0x0208);
173 // Generate Memory Array Mapped Address info
175 Type19Record
= AllocatePool(sizeof (SMBIOS_TABLE_TYPE19
));
176 ZeroMem(Type19Record
, sizeof(SMBIOS_TABLE_TYPE19
));
177 Type19Record
->Hdr
.Type
= EFI_SMBIOS_TYPE_MEMORY_ARRAY_MAPPED_ADDRESS
;
178 Type19Record
->Hdr
.Length
= sizeof(SMBIOS_TABLE_TYPE19
);
179 Type19Record
->Hdr
.Handle
= 0;
180 Type19Record
->StartingAddress
= 0;
181 Type19Record
->EndingAddress
= (UINT32
)RShiftU64(TotalMemorySize
, 10) - 1;
182 Type19Record
->MemoryArrayHandle
= MemArraySmbiosHandle
;
183 Type19Record
->PartitionWidth
= (UINT8
)(NumSlots
);
186 // Generate Memory Array Mapped Address info (TYPE 19)
188 MemArrayMappedAddrSmbiosHandle
= SMBIOS_HANDLE_PI_RESERVED
;
189 Status
= Smbios
->Add (Smbios
, NULL
, &MemArrayMappedAddrSmbiosHandle
, (EFI_SMBIOS_TABLE_HEADER
*) Type19Record
);
190 FreePool(Type19Record
);
191 ASSERT_EFI_ERROR (Status
);
194 // Use SPD data to generate Device Type info
195 ZeroMem (&ArrayLink
, sizeof (EFI_MEMORY_ARRAY_LINK_DATA
));
196 ArrayLink
.MemoryDeviceLocator
= STRING_TOKEN(STR_MEMORY_SUBCLASS_DEVICE_LOCATOR_0
);
197 ArrayLink
.MemoryBankLocator
= STRING_TOKEN(STR_MEMORY_SUBCLASS_DEVICE_LOCATOR_0
);
198 ArrayLink
.MemoryAssetTag
= STRING_TOKEN(STR_MEMORY_SUBCLASS_UNKNOWN
);
199 ArrayLink
.MemoryArrayLink
.ProducerName
= gEfiMemorySubClassDriverGuid
;
200 ArrayLink
.MemoryArrayLink
.Instance
= ArrayInstance
;
201 ArrayLink
.MemoryArrayLink
.SubInstance
= EFI_SUBCLASS_INSTANCE_NON_APPLICABLE
;
202 ArrayLink
.MemorySubArrayLink
.ProducerName
= gEfiMemorySubClassDriverGuid
;
203 ArrayLink
.MemorySubArrayLink
.SubInstance
= EFI_SUBCLASS_INSTANCE_NON_APPLICABLE
;
204 ArrayLink
.MemoryFormFactor
= EfiMemoryFormFactorChip
;
205 ArrayLink
.MemoryType
= EfiMemoryTypeDdr2
;
208 StrCpy (StringBuffer
, L
"NO DIMM,MEMROY DOWN");
209 ArrayLink
.MemoryManufacturer
= HiiSetString (
215 ArrayLink
.MemorySerialNumber
= HiiSetString (
222 ArrayLink
.MemoryPartNumber
= HiiSetString (
230 // Hardcode value. Need to revise for different configuration.
232 ArrayLink
.MemoryTotalWidth
= 64;
233 ArrayLink
.MemoryDataWidth
= 64;
235 DimmMemorySize
= TotalMemorySize
;// MSG_BUS_READ(0x0208);
237 ArrayLink
.MemoryDeviceSize
.Exponent
= (UINT16
) LowBitSet64 (DimmMemorySize
);
238 ArrayLink
.MemoryDeviceSize
.Value
= (UINT16
) RShiftU64(DimmMemorySize
, ArrayLink
.MemoryDeviceSize
.Exponent
);
239 ArrayLink
.MemoryTypeDetail
.Synchronous
= 1;
241 ArrayLink
.MemorySpeed
= *((EFI_EXP_BASE10_DATA
*) &Data
);
245 DevLocStr
= HiiGetPackageString(&gEfiMemorySubClassDriverGuid
, ArrayLink
.MemoryDeviceLocator
, NULL
);
246 DevLocStrLen
= StrLen(DevLocStr
);
247 ASSERT(DevLocStrLen
<= SMBIOS_STRING_MAX_LENGTH
);
249 BankLocStr
= HiiGetPackageString(&gEfiMemorySubClassDriverGuid
, ArrayLink
.MemoryBankLocator
, NULL
);
250 BankLocStrLen
= StrLen(BankLocStr
);
251 ASSERT(BankLocStrLen
<= SMBIOS_STRING_MAX_LENGTH
);
253 ManuStr
= HiiGetPackageString(&gEfiMemorySubClassDriverGuid
, ArrayLink
.MemoryManufacturer
, NULL
);
254 ManuStrLen
= StrLen(ManuStr
);
255 ASSERT(ManuStrLen
<= SMBIOS_STRING_MAX_LENGTH
);
257 SerialNumStr
= HiiGetPackageString(&gEfiMemorySubClassDriverGuid
, ArrayLink
.MemorySerialNumber
, NULL
);
258 SerialNumStrLen
= StrLen(SerialNumStr
);
259 ASSERT(SerialNumStrLen
<= SMBIOS_STRING_MAX_LENGTH
);
261 AssertTagStr
= HiiGetPackageString(&gEfiMemorySubClassDriverGuid
, ArrayLink
.MemoryAssetTag
, NULL
);
262 AssertTagStrLen
= StrLen(AssertTagStr
);
263 ASSERT(AssertTagStrLen
<= SMBIOS_STRING_MAX_LENGTH
);
265 PartNumStr
= HiiGetPackageString(&gEfiMemorySubClassDriverGuid
, ArrayLink
.MemoryPartNumber
, NULL
);
266 PartNumStrLen
= StrLen(PartNumStr
);
267 ASSERT(PartNumStrLen
<= SMBIOS_STRING_MAX_LENGTH
);
270 // Report DIMM level memory module information to smbios (Type 6)
272 DataSize
= sizeof(SMBIOS_TABLE_TYPE6
) + DevLocStrLen
+ 1 + 1;
273 Type6Record
= AllocatePool(DataSize
);
274 ZeroMem(Type6Record
, DataSize
);
275 Type6Record
->Hdr
.Type
= EFI_SMBIOS_TYPE_MEMORY_MODULE_INFORMATON
;
276 Type6Record
->Hdr
.Length
= sizeof (SMBIOS_TABLE_TYPE6
);
277 Type6Record
->Hdr
.Handle
= 0;
278 Type6Record
->SocketDesignation
= 1;
279 if (ArrayLink
.MemorySpeed
.Value
== 0) {
280 Type6Record
->CurrentSpeed
= 0;
283 // Memory speed is in ns unit
285 Type6Record
->CurrentSpeed
= (UINT8
)(1000 / (ArrayLink
.MemorySpeed
.Value
));
290 MemoryDeviceSize
= (UINTN
)(ArrayLink
.MemoryDeviceSize
.Value
) * (UINTN
)(1 << ArrayLink
.MemoryDeviceSize
.Exponent
);
291 if (MemoryDeviceSize
== 0) {
292 *(UINT8
*)&(Type6Record
->InstalledSize
) = 0x7F;
293 *(UINT8
*)&(Type6Record
->EnabledSize
) = 0x7F;
295 MemoryDeviceSize
= (UINTN
) RShiftU64 ((UINT64
) MemoryDeviceSize
, 21);
296 while (MemoryDeviceSize
!= 0) {
297 (*(UINT8
*)&(Type6Record
->InstalledSize
))++;
298 (*(UINT8
*)&(Type6Record
->EnabledSize
))++;
299 MemoryDeviceSize
= (UINTN
) RShiftU64 ((UINT64
) MemoryDeviceSize
,1);
303 if (ArrayLink
.MemoryFormFactor
== EfiMemoryFormFactorDimm
||
304 ArrayLink
.MemoryFormFactor
== EfiMemoryFormFactorFbDimm
) {
305 *(UINT16
*)&Type6Record
->CurrentMemoryType
|= 1<<8;
307 if (ArrayLink
.MemoryFormFactor
== EfiMemoryFormFactorSimm
) {
308 *(UINT16
*)&Type6Record
->CurrentMemoryType
|= 1<<7;
310 if (ArrayLink
.MemoryType
== EfiMemoryTypeSdram
) {
311 *(UINT16
*)&Type6Record
->CurrentMemoryType
|= 1<<10;
313 if (ArrayLink
.MemoryTypeDetail
.Edo
== 1) {
314 *(UINT16
*)&Type6Record
->CurrentMemoryType
|= 1<<4;
316 if (ArrayLink
.MemoryTypeDetail
.FastPaged
== 1) {
317 *(UINT16
*)&Type6Record
->CurrentMemoryType
|= 1<<3;
319 OptionalStrStart
= (CHAR8
*)(Type6Record
+ 1);
320 UnicodeStrToAsciiStr(DevLocStr
, OptionalStrStart
);
321 MemModuleInfoSmbiosHandle
= SMBIOS_HANDLE_PI_RESERVED
;
322 Status
= Smbios
->Add (Smbios
, NULL
, &MemModuleInfoSmbiosHandle
, (EFI_SMBIOS_TABLE_HEADER
*) Type6Record
);
323 FreePool(Type6Record
);
324 ASSERT_EFI_ERROR (Status
);
326 // Report DIMM level Device Type to smbios (Type 17)
328 DataSize
= sizeof (SMBIOS_TABLE_TYPE17
) + DevLocStrLen
+ 1 + BankLocStrLen
+ 1 + ManuStrLen
+ 1 + SerialNumStrLen
+ 1 + AssertTagStrLen
+ 1 + PartNumStrLen
+ 1 + 1;
329 Type17Record
= AllocatePool(DataSize
);
330 ZeroMem(Type17Record
, DataSize
);
331 Type17Record
->Hdr
.Type
= EFI_SMBIOS_TYPE_MEMORY_DEVICE
;
332 Type17Record
->Hdr
.Length
= sizeof (SMBIOS_TABLE_TYPE17
);
333 Type17Record
->Hdr
.Handle
= 0;
335 Type17Record
->MemoryArrayHandle
= MemArraySmbiosHandle
;
336 Type17Record
->MemoryErrorInformationHandle
= 0xfffe;
337 Type17Record
->TotalWidth
= ArrayLink
.MemoryTotalWidth
;
338 Type17Record
->DataWidth
= ArrayLink
.MemoryDataWidth
;
342 MemoryDeviceSize
= ((UINTN
) ArrayLink
.MemoryDeviceSize
.Value
) << (ArrayLink
.MemoryDeviceSize
.Exponent
- 10);
343 MemoryDeviceSizeUnitMega
= FALSE
;
347 if (MemoryDeviceSize
> 0xffff) {
348 MemoryDeviceSize
= MemoryDeviceSize
>> 10;
352 MemoryDeviceSizeUnitMega
= TRUE
;
355 MemoryDeviceSize
= MemoryDeviceSize
& 0x7fff;
356 if (MemoryDeviceSize
!= 0 && MemoryDeviceSizeUnitMega
== FALSE
) {
357 MemoryDeviceSize
|= 0x8000;
359 Type17Record
->Size
= (UINT16
)MemoryDeviceSize
;
361 Type17Record
->FormFactor
= (UINT8
)ArrayLink
.MemoryFormFactor
;
362 Type17Record
->DeviceLocator
= 1;
363 Type17Record
->BankLocator
= 2;
364 Type17Record
->MemoryType
= (UINT8
)ArrayLink
.MemoryType
;
366 (UINT8
*) &Type17Record
->TypeDetail
,
367 &ArrayLink
.MemoryTypeDetail
,
371 Type17Record
->Speed
= ArrayLink
.MemorySpeed
.Value
;
372 Type17Record
->Manufacturer
= 3;
373 Type17Record
->SerialNumber
= 4;
374 Type17Record
->AssetTag
= 5;
375 Type17Record
->PartNumber
= 6;
377 // temporary solution for save device label information.
379 Type17Record
->Attributes
= (UINT8
)(Dimm
+ 1);
381 OptionalStrStart
= (CHAR8
*)(Type17Record
+ 1);
382 UnicodeStrToAsciiStr(DevLocStr
, OptionalStrStart
);
383 UnicodeStrToAsciiStr(BankLocStr
, OptionalStrStart
+ DevLocStrLen
+ 1);
384 UnicodeStrToAsciiStr(ManuStr
, OptionalStrStart
+ DevLocStrLen
+ 1 + BankLocStrLen
+ 1);
385 UnicodeStrToAsciiStr(SerialNumStr
, OptionalStrStart
+ DevLocStrLen
+ 1 + BankLocStrLen
+ 1 + ManuStrLen
+ 1);
386 UnicodeStrToAsciiStr(AssertTagStr
, OptionalStrStart
+ DevLocStrLen
+ 1 + BankLocStrLen
+ 1 + ManuStrLen
+ 1 + SerialNumStrLen
+ 1);
387 UnicodeStrToAsciiStr(PartNumStr
, OptionalStrStart
+ DevLocStrLen
+ 1 + BankLocStrLen
+ 1 + ManuStrLen
+ 1 + SerialNumStrLen
+ 1 + AssertTagStrLen
+ 1);
388 MemDevSmbiosHandle
= SMBIOS_HANDLE_PI_RESERVED
;
389 Status
= Smbios
->Add (Smbios
, NULL
, &MemDevSmbiosHandle
, (EFI_SMBIOS_TABLE_HEADER
*) Type17Record
);
390 FreePool(Type17Record
);
391 ASSERT_EFI_ERROR (Status
);
394 // Generate Memory Device Mapped Address info
396 ZeroMem(&DeviceStartAddress
, sizeof(EFI_MEMORY_DEVICE_START_ADDRESS_DATA
));
397 DeviceStartAddress
.MemoryDeviceStartAddress
= 0;
398 DeviceStartAddress
.MemoryDeviceEndAddress
= DeviceStartAddress
.MemoryDeviceStartAddress
+ DimmMemorySize
-1;
399 DeviceStartAddress
.PhysicalMemoryDeviceLink
.ProducerName
= gEfiMemorySubClassDriverGuid
;
400 DeviceStartAddress
.PhysicalMemoryDeviceLink
.Instance
= ArrayInstance
;
401 DeviceStartAddress
.PhysicalMemoryDeviceLink
.SubInstance
= (UINT16
)(Dimm
+ 1);
402 DeviceStartAddress
.PhysicalMemoryArrayLink
.ProducerName
= gEfiMemorySubClassDriverGuid
;
403 DeviceStartAddress
.PhysicalMemoryArrayLink
.Instance
= ArrayInstance
;
404 DeviceStartAddress
.PhysicalMemoryArrayLink
.SubInstance
= EFI_SUBCLASS_INSTANCE_NON_APPLICABLE
;
407 // Single channel mode
409 DeviceStartAddress
.MemoryDevicePartitionRowPosition
= 0x01;
410 DeviceStartAddress
.MemoryDeviceInterleavePosition
= 0x00;
411 DeviceStartAddress
.MemoryDeviceInterleaveDataDepth
= 0x00;
414 // Generate Memory Device Mapped Address info (TYPE 20)
416 Type20Record
= AllocatePool(sizeof (SMBIOS_TABLE_TYPE20
));
417 ZeroMem(Type20Record
, sizeof (SMBIOS_TABLE_TYPE20
));
418 Type20Record
->Hdr
.Type
= EFI_SMBIOS_TYPE_MEMORY_DEVICE_MAPPED_ADDRESS
;
419 Type20Record
->Hdr
.Length
= sizeof(SMBIOS_TABLE_TYPE20
);
420 Type20Record
->Hdr
.Handle
= 0;
422 Type20Record
->StartingAddress
= (UINT32
)RShiftU64 (DeviceStartAddress
.MemoryDeviceStartAddress
, 10);
423 Type20Record
->EndingAddress
= (UINT32
)RShiftU64 (DeviceStartAddress
.MemoryDeviceEndAddress
, 10);
424 Type20Record
->MemoryDeviceHandle
= MemDevSmbiosHandle
;
425 Type20Record
->MemoryArrayMappedAddressHandle
= MemArrayMappedAddrSmbiosHandle
;
426 Type20Record
->PartitionRowPosition
= DeviceStartAddress
.MemoryDevicePartitionRowPosition
;
427 Type20Record
->InterleavePosition
= DeviceStartAddress
.MemoryDeviceInterleavePosition
;
428 Type20Record
->InterleavedDataDepth
= DeviceStartAddress
.MemoryDeviceInterleaveDataDepth
;
429 MemDevMappedAddrSmbiosHandle
= SMBIOS_HANDLE_PI_RESERVED
;
430 Status
= Smbios
->Add (Smbios
, NULL
, &MemDevMappedAddrSmbiosHandle
, (EFI_SMBIOS_TABLE_HEADER
*) Type20Record
);
431 FreePool(Type20Record
);
432 ASSERT_EFI_ERROR (Status
);