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 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
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.
17 #include "MemorySubClass.h"
19 extern UINT8 MemorySubClassStrings
[];
21 EFI_GUID gEfiMemorySubClassDriverGuid
= EFI_MEMORY_SUBCLASS_DRIVER_GUID
;
24 MemorySubClassEntryPoint (
25 IN EFI_HANDLE ImageHandle
,
26 IN EFI_SYSTEM_TABLE
*SystemTable
31 This is the standard EFI driver point that detects whether there is a
32 MemoryConfigurationData Variable and, if so, reports memory configuration info
36 ImageHandle - Handle for the image of this driver
37 SystemTable - Pointer to the EFI System Table
40 EFI_SUCCESS if the data is successfully reported
41 EFI_NOT_FOUND if the HOB list could not be located.
48 UINTN StringBufferSize
;
53 UINTN SerialNumStrLen
;
54 UINTN AssertTagStrLen
;
56 UINTN MemoryDeviceSize
;
57 CHAR8
* OptionalStrStart
;
59 UINT64 DimmMemorySize
;
60 UINT64 TotalMemorySize
;
62 UINT32 MemoryCapacity
;
63 BOOLEAN MemoryDeviceSizeUnitMega
;
65 EFI_STRING StringBuffer
;
67 EFI_STRING BankLocStr
;
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
;
96 StringBufferSize
= (sizeof (CHAR16
)) * 100;
97 StringBuffer
= AllocateZeroPool (StringBufferSize
);
98 ASSERT (StringBuffer
!= NULL
);
101 // Locate dependent protocols
103 Status
= gBS
->LocateProtocol (&gEfiSmbiosProtocolGuid
, NULL
, (VOID
**)&Smbios
);
104 ASSERT_EFI_ERROR (Status
);
108 // Add our default strings to the HII database. They will be modified later.
110 HiiHandle
= HiiAddPackages (
111 &gEfiMemorySubClassDriverGuid
,
113 MemorySubClassStrings
,
116 ASSERT (HiiHandle
!= NULL
);
119 // Create physical array and associated data for all mainboard memory
120 // This will translate into a Type 16 SMBIOS Record
124 McD0PciCfg32 (QNC_ACCESS_PORT_MCR
) = MESSAGE_READ_DW (0x3, 0x8);
125 TotalMemorySize
= McD0PciCfg32 (QNC_ACCESS_PORT_MDR
);
127 ArrayLocationData
.MemoryArrayLocation
= EfiMemoryArrayLocationSystemBoard
;
128 ArrayLocationData
.MemoryArrayUse
= EfiMemoryArrayUseSystemMemory
;
130 ArrayLocationData
.MemoryErrorCorrection
= EfiMemoryErrorCorrectionNone
;
132 Data
= 0x40000000;//(UINT32) RShiftU64(MemConfigData->RowInfo.MaxMemory, 10);
134 ArrayLocationData
.MaximumMemoryCapacity
.Exponent
= (UINT16
) LowBitSet32 (Data
);
135 ArrayLocationData
.MaximumMemoryCapacity
.Value
= (UINT16
) (Data
>> ArrayLocationData
.MaximumMemoryCapacity
.Exponent
);
137 NumSlots
= 2;// (UINT8)(MemConfigData->RowInfo.MaxRows >> 1);
138 ArrayLocationData
.NumberMemoryDevices
= (UINT16
)(NumSlots
);
141 // Report top level physical array to Type 16 SMBIOS Record
143 Type16Record
= AllocatePool(sizeof(SMBIOS_TABLE_TYPE16
) + 1 + 1);
144 ZeroMem(Type16Record
, sizeof(SMBIOS_TABLE_TYPE16
) + 1 + 1);
146 Type16Record
->Hdr
.Type
= EFI_SMBIOS_TYPE_PHYSICAL_MEMORY_ARRAY
;
147 Type16Record
->Hdr
.Length
= sizeof(SMBIOS_TABLE_TYPE16
);
148 Type16Record
->Hdr
.Handle
= 0;
150 Type16Record
->Location
= (UINT8
)ArrayLocationData
.MemoryArrayLocation
;
152 Type16Record
->Use
= (UINT8
)ArrayLocationData
.MemoryArrayUse
;
154 Type16Record
->MemoryErrorCorrection
= (UINT8
)ArrayLocationData
.MemoryErrorCorrection
;
156 MemoryCapacity
= (UINT32
) ArrayLocationData
.MaximumMemoryCapacity
.Value
* (1 << ((UINT32
) ArrayLocationData
.MaximumMemoryCapacity
.Exponent
- 10));
157 Type16Record
->MaximumCapacity
= MemoryCapacity
;
159 Type16Record
->MemoryErrorInformationHandle
= 0xfffe;
161 Type16Record
->NumberOfMemoryDevices
= ArrayLocationData
.NumberMemoryDevices
;
163 // Don't change it. This handle will be referenced by type 17 records
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
);
170 // Do associated data for each DIMM
171 //RowConfArray = &MemConfigData->RowConfArray;
174 // Get total memory size for the construction of smbios record type 19
176 //TotalMemorySize = 0;// MSG_BUS_READ(0x0208);
179 // Generate Memory Array Mapped Address info
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
);
192 // Generate Memory Array Mapped Address info (TYPE 19)
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
);
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
;
214 StrCpy (StringBuffer
, L
"NO DIMM,MEMROY DOWN");
215 ArrayLink
.MemoryManufacturer
= HiiSetString (
221 ArrayLink
.MemorySerialNumber
= HiiSetString (
228 ArrayLink
.MemoryPartNumber
= HiiSetString (
236 // Hardcode value. Need to revise for different configuration.
238 ArrayLink
.MemoryTotalWidth
= 64;
239 ArrayLink
.MemoryDataWidth
= 64;
241 DimmMemorySize
= TotalMemorySize
;// MSG_BUS_READ(0x0208);
243 ArrayLink
.MemoryDeviceSize
.Exponent
= (UINT16
) LowBitSet64 (DimmMemorySize
);
244 ArrayLink
.MemoryDeviceSize
.Value
= (UINT16
) RShiftU64(DimmMemorySize
, ArrayLink
.MemoryDeviceSize
.Exponent
);
245 ArrayLink
.MemoryTypeDetail
.Synchronous
= 1;
247 ArrayLink
.MemorySpeed
= *((EFI_EXP_BASE10_DATA
*) &Data
);
251 DevLocStr
= HiiGetPackageString(&gEfiMemorySubClassDriverGuid
, ArrayLink
.MemoryDeviceLocator
, NULL
);
252 DevLocStrLen
= StrLen(DevLocStr
);
253 ASSERT(DevLocStrLen
<= SMBIOS_STRING_MAX_LENGTH
);
255 BankLocStr
= HiiGetPackageString(&gEfiMemorySubClassDriverGuid
, ArrayLink
.MemoryBankLocator
, NULL
);
256 BankLocStrLen
= StrLen(BankLocStr
);
257 ASSERT(BankLocStrLen
<= SMBIOS_STRING_MAX_LENGTH
);
259 ManuStr
= HiiGetPackageString(&gEfiMemorySubClassDriverGuid
, ArrayLink
.MemoryManufacturer
, NULL
);
260 ManuStrLen
= StrLen(ManuStr
);
261 ASSERT(ManuStrLen
<= SMBIOS_STRING_MAX_LENGTH
);
263 SerialNumStr
= HiiGetPackageString(&gEfiMemorySubClassDriverGuid
, ArrayLink
.MemorySerialNumber
, NULL
);
264 SerialNumStrLen
= StrLen(SerialNumStr
);
265 ASSERT(SerialNumStrLen
<= SMBIOS_STRING_MAX_LENGTH
);
267 AssertTagStr
= HiiGetPackageString(&gEfiMemorySubClassDriverGuid
, ArrayLink
.MemoryAssetTag
, NULL
);
268 AssertTagStrLen
= StrLen(AssertTagStr
);
269 ASSERT(AssertTagStrLen
<= SMBIOS_STRING_MAX_LENGTH
);
271 PartNumStr
= HiiGetPackageString(&gEfiMemorySubClassDriverGuid
, ArrayLink
.MemoryPartNumber
, NULL
);
272 PartNumStrLen
= StrLen(PartNumStr
);
273 ASSERT(PartNumStrLen
<= SMBIOS_STRING_MAX_LENGTH
);
276 // Report DIMM level memory module information to smbios (Type 6)
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;
289 // Memory speed is in ns unit
291 Type6Record
->CurrentSpeed
= (UINT8
)(1000 / (ArrayLink
.MemorySpeed
.Value
));
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;
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);
309 if (ArrayLink
.MemoryFormFactor
== EfiMemoryFormFactorDimm
||
310 ArrayLink
.MemoryFormFactor
== EfiMemoryFormFactorFbDimm
) {
311 *(UINT16
*)&Type6Record
->CurrentMemoryType
|= 1<<8;
313 if (ArrayLink
.MemoryFormFactor
== EfiMemoryFormFactorSimm
) {
314 *(UINT16
*)&Type6Record
->CurrentMemoryType
|= 1<<7;
316 if (ArrayLink
.MemoryType
== EfiMemoryTypeSdram
) {
317 *(UINT16
*)&Type6Record
->CurrentMemoryType
|= 1<<10;
319 if (ArrayLink
.MemoryTypeDetail
.Edo
== 1) {
320 *(UINT16
*)&Type6Record
->CurrentMemoryType
|= 1<<4;
322 if (ArrayLink
.MemoryTypeDetail
.FastPaged
== 1) {
323 *(UINT16
*)&Type6Record
->CurrentMemoryType
|= 1<<3;
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
);
332 // Report DIMM level Device Type to smbios (Type 17)
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;
341 Type17Record
->MemoryArrayHandle
= MemArraySmbiosHandle
;
342 Type17Record
->MemoryErrorInformationHandle
= 0xfffe;
343 Type17Record
->TotalWidth
= ArrayLink
.MemoryTotalWidth
;
344 Type17Record
->DataWidth
= ArrayLink
.MemoryDataWidth
;
348 MemoryDeviceSize
= ((UINTN
) ArrayLink
.MemoryDeviceSize
.Value
) << (ArrayLink
.MemoryDeviceSize
.Exponent
- 10);
349 MemoryDeviceSizeUnitMega
= FALSE
;
353 if (MemoryDeviceSize
> 0xffff) {
354 MemoryDeviceSize
= MemoryDeviceSize
>> 10;
358 MemoryDeviceSizeUnitMega
= TRUE
;
361 MemoryDeviceSize
= MemoryDeviceSize
& 0x7fff;
362 if (MemoryDeviceSize
!= 0 && MemoryDeviceSizeUnitMega
== FALSE
) {
363 MemoryDeviceSize
|= 0x8000;
365 Type17Record
->Size
= (UINT16
)MemoryDeviceSize
;
367 Type17Record
->FormFactor
= (UINT8
)ArrayLink
.MemoryFormFactor
;
368 Type17Record
->DeviceLocator
= 1;
369 Type17Record
->BankLocator
= 2;
370 Type17Record
->MemoryType
= (UINT8
)ArrayLink
.MemoryType
;
372 (UINT8
*) &Type17Record
->TypeDetail
,
373 &ArrayLink
.MemoryTypeDetail
,
377 Type17Record
->Speed
= ArrayLink
.MemorySpeed
.Value
;
378 Type17Record
->Manufacturer
= 3;
379 Type17Record
->SerialNumber
= 4;
380 Type17Record
->AssetTag
= 5;
381 Type17Record
->PartNumber
= 6;
383 // temporary solution for save device label information.
385 Type17Record
->Attributes
= (UINT8
)(Dimm
+ 1);
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
);
400 // Generate Memory Device Mapped Address info
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
;
413 // Single channel mode
415 DeviceStartAddress
.MemoryDevicePartitionRowPosition
= 0x01;
416 DeviceStartAddress
.MemoryDeviceInterleavePosition
= 0x00;
417 DeviceStartAddress
.MemoryDeviceInterleaveDataDepth
= 0x00;
420 // Generate Memory Device Mapped Address info (TYPE 20)
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;
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
);