2 Translate the DataHub records via EFI_DATA_HUB_PROTOCOL to Smbios recorders
3 via EFI_SMBIOS_PROTOCOL.
5 Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 EFI_SMBIOS_PROTOCOL
*mSmbiosProtocol
= NULL
;
21 Release the structure Node.
23 @param StructureNode Point to SMBIOS_STRUCTURE_NODE which will be removed.
26 ReleaseStructureNode (
27 SMBIOS_STRUCTURE_NODE
*StructureNode
30 EFI_SMBIOS_PROTOCOL
*Smbios
;
32 RemoveEntryList (&(StructureNode
->Link
));
33 Smbios
= GetSmbiosProtocol();
34 ASSERT (Smbios
!= NULL
);
35 Smbios
->Remove (Smbios
, StructureNode
->SmbiosHandle
);
36 gBS
->FreePool (StructureNode
);
40 Process a datahub's record and find corresponding translation way to translate
43 @param Record Point to datahub record.
46 SmbiosProcessDataRecord (
47 IN EFI_DATA_RECORD_HEADER
*Record
50 EFI_DATA_RECORD_HEADER
*RecordHeader
;
51 EFI_SUBCLASS_TYPE1_HEADER
*DataHeader
;
53 SMBIOS_CONVERSION_TABLE_ENTRY
*Conversion
;
57 SMBIOS_STRUCTURE_NODE
*StructureNode
;
58 BOOLEAN StructureCreated
;
63 StructureCreated
= FALSE
;
64 RecordHeader
= Record
;
65 DataHeader
= (EFI_SUBCLASS_TYPE1_HEADER
*) (Record
+ 1);
66 SrcData
= (UINT8
*) (DataHeader
+ 1);
67 SrcDataSize
= RecordHeader
->RecordSize
- RecordHeader
->HeaderSize
- sizeof (EFI_SUBCLASS_TYPE1_HEADER
);
69 if (DataHeader
->HeaderSize
!= sizeof (EFI_SUBCLASS_TYPE1_HEADER
) ||
70 DataHeader
->Instance
== EFI_SUBCLASS_INSTANCE_RESERVED
||
71 DataHeader
->SubInstance
== EFI_SUBCLASS_INSTANCE_RESERVED
74 // Invalid Data Record
82 // Find a matching entry in the conversion table for this
83 // (SubClass, RecordNumber) pair
85 for (; !CompareGuid (&(mConversionTable
[Index
].SubClass
), &gZeroGuid
); Index
++) {
87 &(mConversionTable
[Index
].SubClass
),
88 &(RecordHeader
->DataRecordGuid
)
90 if (mConversionTable
[Index
].RecordType
== DataHeader
->RecordType
) {
96 if (CompareGuid (&(mConversionTable
[Index
].SubClass
), &gZeroGuid
)) {
98 // We cannot find a matching entry in conversion table,
99 // this means this data record cannot be used for SMBIOS.
105 Conversion
= &mConversionTable
[Index
++];
108 // Find corresponding structure in the Structure List
110 for (Link
= mStructureList
.ForwardLink
; Link
!= &mStructureList
; Link
= Link
->ForwardLink
) {
114 SMBIOS_STRUCTURE_NODE
,
116 SMBIOS_STRUCTURE_NODE_SIGNATURE
119 if (Conversion
->StructureLocatingMethod
== BySubclassInstanceSubinstanceProducer
) {
121 // Look at SubClass, Instance, SubInstance and ProducerName for a matching
124 if (CompareGuid (&(StructureNode
->SubClass
), &(RecordHeader
->DataRecordGuid
)) &&
125 StructureNode
->Instance
== DataHeader
->Instance
&&
126 StructureNode
->SubInstance
== DataHeader
->SubInstance
&&
127 CompareGuid (&(StructureNode
->ProducerName
), &(RecordHeader
->ProducerName
))
129 if (Conversion
->SmbiosType
>= 0x80) {
130 if (StructureNode
->SmbiosType
== ((SMBIOS_STRUCTURE_HDR
*) SrcData
)->Type
) {
133 } else if (StructureNode
->SmbiosType
== Conversion
->SmbiosType
) {
138 } else if (Conversion
->StructureLocatingMethod
== BySubClassInstanceProducer
) {
140 // Look at SubClass, Instance and ProducerName for a matching node
142 if (CompareGuid (&(StructureNode
->SubClass
), &(RecordHeader
->DataRecordGuid
)) &&
143 StructureNode
->Instance
== DataHeader
->Instance
&&
144 CompareGuid (&(StructureNode
->ProducerName
), &(RecordHeader
->ProducerName
))
146 if (Conversion
->SmbiosType
>= 0x80) {
147 if (StructureNode
->SmbiosType
== ((SMBIOS_STRUCTURE_HDR
*) SrcData
)->Type
) {
150 } else if (StructureNode
->SmbiosType
== Conversion
->SmbiosType
) {
157 // Invalid conversion table entry
163 if (Link
== &mStructureList
|| StructureNode
== NULL
) {
166 // Not found, create a new structure
168 StructureNode
= AllocateZeroPool (sizeof (SMBIOS_STRUCTURE_NODE
));
170 if (StructureNode
== NULL
) {
174 if (Conversion
->StructureLocatingMethod
== BySubclassInstanceSubinstanceProducer
) {
176 // Fill in SubClass, Instance, SubInstance and ProducerName
178 CopyMem (&(StructureNode
->SubClass
), &(RecordHeader
->DataRecordGuid
), sizeof (EFI_GUID
));
179 StructureNode
->Instance
= DataHeader
->Instance
;
180 StructureNode
->SubInstance
= DataHeader
->SubInstance
;
181 CopyMem (&(StructureNode
->ProducerName
), &(RecordHeader
->ProducerName
), sizeof (EFI_GUID
));
183 } else if (Conversion
->StructureLocatingMethod
== BySubClassInstanceProducer
) {
185 // Fill in at SubClass, Instance and ProducerName, mark SubInstance as Non
188 CopyMem (&(StructureNode
->SubClass
), &(RecordHeader
->DataRecordGuid
), sizeof (EFI_GUID
));
189 StructureNode
->Instance
= DataHeader
->Instance
;
190 StructureNode
->SubInstance
= EFI_SUBCLASS_INSTANCE_NON_APPLICABLE
;
191 CopyMem (&(StructureNode
->ProducerName
), &(RecordHeader
->ProducerName
), sizeof (EFI_GUID
));
195 // Allocate the structure instance
197 StructureNode
->StructureSize
= SmbiosGetTypeMinimalLength (Conversion
->SmbiosType
);
200 // StructureSize include the TWO trailing zero byte.
202 if (StructureNode
->StructureSize
< (sizeof(SMBIOS_STRUCTURE
) + 2)) {
206 gBS
->FreePool (StructureNode
);
211 // Assign correct SmbiosType when OEM type and Non-OEM type
213 if (Conversion
->SmbiosType
>= 0x80) {
214 StructureNode
->SmbiosType
= ((SMBIOS_STRUCTURE_HDR
*) SrcData
)->Type
;
216 StructureNode
->SmbiosType
= Conversion
->SmbiosType
;
219 StructureNode
->SmbiosHandle
= SMBIOS_HANDLE_PI_RESERVED
;
220 Status
= SmbiosProtocolCreateRecord (
224 if (EFI_ERROR (Status
)) {
228 // Temporary cache the structrue pointer to Smbios database.
230 StructureNode
->Structure
= GetSmbiosBufferFromHandle (StructureNode
->SmbiosHandle
, StructureNode
->SmbiosType
, NULL
);
232 InitializeListHead (&StructureNode
->LinkDataFixup
);
235 // Insert the Structure Node into the Strucutre List
237 StructureNode
->Signature
= SMBIOS_STRUCTURE_NODE_SIGNATURE
;
238 InsertTailList (&mStructureList
, &(StructureNode
->Link
));
240 StructureCreated
= TRUE
;
246 // Re-calculate the structure pointer to Smbios database.
248 StructureNode
->Structure
= GetSmbiosBufferFromHandle (StructureNode
->SmbiosHandle
, StructureNode
->SmbiosType
, NULL
);
251 // Fill the Structure's field corresponding to this data record
253 if (Conversion
->FieldFillingMethod
== RecordDataUnchangedOffsetSpecified
) {
255 // Field data is just the record data without transforming and
256 // offset is specified directly in the conversion table entry
258 if (Conversion
->FieldOffset
+ SrcDataSize
> StructureNode
->Structure
->Length
) {
260 // Invalid Conversion Table Entry
262 if (StructureCreated
) {
263 ReleaseStructureNode (StructureNode
);
269 CopyMem ((UINT8
*) (StructureNode
->Structure
) + Conversion
->FieldOffset
, SrcData
, SrcDataSize
);
271 } else if (Conversion
->FieldFillingMethod
== ByFunctionWithOffsetSpecified
) {
273 // Field offfset is specified in the conversion table entry, but
274 // record data needs to be transformed to be filled into the field,
275 // so let the FieldFillingFunction do it.
277 if (Conversion
->FieldFillingFunction
== NULL
) {
279 // Invalid Conversion Table Entry
281 if (StructureCreated
) {
282 ReleaseStructureNode (StructureNode
);
288 Status
= Conversion
->FieldFillingFunction (
290 Conversion
->FieldOffset
,
294 if (EFI_ERROR (Status
)) {
295 if (StructureCreated
) {
296 ReleaseStructureNode (StructureNode
);
301 } else if (Conversion
->FieldFillingMethod
== ByFunction
) {
303 // Both field offset and field content are determined by
304 // FieldFillingFunction
306 if (Conversion
->FieldFillingFunction
== NULL
) {
308 // Invalid Conversion Table Entry
310 if (StructureCreated
) {
311 ReleaseStructureNode (StructureNode
);
317 Status
= Conversion
->FieldFillingFunction (
323 if (EFI_ERROR (Status
)) {
324 if (StructureCreated
) {
325 ReleaseStructureNode (StructureNode
);
330 } else if (Conversion
->FieldFillingMethod
== ByFunctionWithWholeDataRecord
) {
332 // Both field offset and field content are determined by
333 // FieldFillingFunction and the function accepts the whole data record
334 // including the data header
336 if (Conversion
->FieldFillingFunction
== NULL
) {
338 // Invalid Conversion Table Entry
340 if (StructureCreated
) {
341 ReleaseStructureNode (StructureNode
);
347 Status
= Conversion
->FieldFillingFunction (
351 RecordHeader
->RecordSize
- RecordHeader
->HeaderSize
353 if (EFI_ERROR (Status
)) {
354 if (StructureCreated
) {
355 ReleaseStructureNode (StructureNode
);
362 // Invalid Conversion Table Entry
364 if (StructureCreated
) {
365 ReleaseStructureNode (StructureNode
);
372 // SmbiosEnlargeStructureBuffer is called to remove and add again
373 // this SMBIOS entry to reflash SMBIOS table in configuration table.
375 SmbiosEnlargeStructureBuffer (
377 StructureNode
->Structure
->Length
,
378 StructureNode
->StructureSize
,
379 StructureNode
->StructureSize
387 Calculate the minimal length for a SMBIOS type. This length maybe not equal
388 to sizeof (SMBIOS_RECORD_STRUCTURE), but defined in conformance chapter in SMBIOS specification.
390 @param Type SMBIOS's type.
392 @return the minimal length of a smbios record.
395 SmbiosGetTypeMinimalLength (
401 for (Index
= 0; mTypeInfoTable
[Index
].MinLength
!= 0; Index
++) {
402 if (mTypeInfoTable
[Index
].Type
== Type
) {
403 return mTypeInfoTable
[Index
].MinLength
;
411 Get pointer of EFI_SMBIOS_PROTOCOL.
413 @return pointer of EFI_SMBIOS_PROTOCOL.
422 if (mSmbiosProtocol
== NULL
) {
423 Status
= gBS
->LocateProtocol (&gEfiSmbiosProtocolGuid
, NULL
, (VOID
*) &mSmbiosProtocol
);
424 ASSERT_EFI_ERROR (Status
);
427 ASSERT (mSmbiosProtocol
!= NULL
);
428 return mSmbiosProtocol
;
432 Create a blank smbios record. The datahub record is only a field of smbios record.
433 So before fill any field from datahub's record. A blank smbios record need to be
436 @param ProducerHandle The produce handle for a datahub record
437 @param StructureNode Point to SMBIOS_STRUCTURE_NODE
439 @retval EFI_OUT_OF_RESOURCES Fail to allocate memory for new blank SMBIOS record.
440 @retval EFI_SUCCESS Success to create blank smbios record.
443 SmbiosProtocolCreateRecord (
444 IN EFI_HANDLE ProducerHandle
, OPTIONAL
445 IN SMBIOS_STRUCTURE_NODE
*StructureNode
448 EFI_SMBIOS_PROTOCOL
*Smbios
;
449 EFI_SMBIOS_TABLE_HEADER
*BlankRecord
;
451 SMBIOS_STRUCTURE_NODE
*RefStructureNode
;
455 SMBIOS_LINK_DATA_FIXUP_NODE
*LinkDataFixupNode
;
456 UINT8
*BufferPointer
;
458 Smbios
= GetSmbiosProtocol();
459 ASSERT (Smbios
!= NULL
);
462 // Prepare a blank smbios record.
464 BlankRecord
= (EFI_SMBIOS_TABLE_HEADER
*) AllocateZeroPool (StructureNode
->StructureSize
);
465 if (BlankRecord
== NULL
) {
466 return EFI_OUT_OF_RESOURCES
;
468 BlankRecord
->Type
= StructureNode
->SmbiosType
;
469 BlankRecord
->Length
= (UINT8
) (StructureNode
->StructureSize
- 2);
472 // Add blank record into SMBIOS database.
474 Status
= Smbios
->Add (Smbios
, NULL
, &StructureNode
->SmbiosHandle
, BlankRecord
);
475 FreePool (BlankRecord
);
478 // Fix up the InterLink node for new added smbios record if some other
479 // existing smbios record want to link this new record's handle.
481 for (Link
= mStructureList
.ForwardLink
; Link
!= &mStructureList
; Link
= Link
->ForwardLink
) {
482 RefStructureNode
= CR (Link
, SMBIOS_STRUCTURE_NODE
, Link
, SMBIOS_STRUCTURE_NODE_SIGNATURE
);
483 for (Link1
= RefStructureNode
->LinkDataFixup
.ForwardLink
; Link1
!= &RefStructureNode
->LinkDataFixup
;) {
484 LinkDataFixupNode
= CR (Link1
, SMBIOS_LINK_DATA_FIXUP_NODE
, Link
, SMBIOS_LINK_DATA_FIXUP_NODE_SIGNATURE
);
486 Link1
= Link1
->ForwardLink
;
488 if ((StructureNode
->SmbiosType
!= LinkDataFixupNode
->TargetType
) ||
489 !(CompareGuid (&StructureNode
->SubClass
, &LinkDataFixupNode
->SubClass
)) ||
490 (StructureNode
->Instance
!= LinkDataFixupNode
->LinkData
.Instance
) ||
491 (StructureNode
->SubInstance
!= LinkDataFixupNode
->LinkData
.SubInstance
)) {
496 // Fill the field with the handle found
498 BufferPointer
= (UINT8
*) (RefStructureNode
->Structure
) + LinkDataFixupNode
->Offset
;
499 *BufferPointer
= (UINT8
) (StructureNode
->SmbiosHandle
& 0xFF);
500 *(BufferPointer
+ 1) = (UINT8
) ((StructureNode
->SmbiosHandle
>> 8) & 0xFF);
501 BufferPointer
= NULL
;
503 RemoveEntryList (Link2
);
504 FreePool (LinkDataFixupNode
);
512 Get pointer of a SMBIOS record's buffer according to its handle.
514 @param Handle The handle of SMBIOS record want to be searched.
515 @param Type The type of SMBIOS record want to be searched.
516 @param ProducerHandle The producer handle of SMBIOS record.
518 @return EFI_SMBIOS_TABLE_HEADER Point to a SMBIOS record's buffer.
520 EFI_SMBIOS_TABLE_HEADER
*
521 GetSmbiosBufferFromHandle (
522 IN EFI_SMBIOS_HANDLE Handle
,
523 IN EFI_SMBIOS_TYPE Type
,
524 IN EFI_HANDLE ProducerHandle OPTIONAL
527 EFI_SMBIOS_PROTOCOL
* Smbios
;
528 EFI_SMBIOS_HANDLE SearchingHandle
;
529 EFI_SMBIOS_TABLE_HEADER
*RecordInSmbiosDatabase
;
532 SearchingHandle
= SMBIOS_HANDLE_PI_RESERVED
;
533 Smbios
= GetSmbiosProtocol();
534 ASSERT (Smbios
!= NULL
);
537 Status
= Smbios
->GetNext (Smbios
, &SearchingHandle
, &Type
, &RecordInSmbiosDatabase
, NULL
);
538 } while ((SearchingHandle
!= Handle
) && (Status
!= EFI_NOT_FOUND
));
540 return RecordInSmbiosDatabase
;
545 Get the full size of smbios structure including optional strings that follow the formatted structure.
547 @param Head Pointer to the beginning of smbios structure.
548 @param Size The returned size.
549 @param NumberOfStrings The returned number of optional strings that follow the formatted structure.
551 @retval EFI_SUCCESS Size retured in Size.
552 @retval EFI_INVALID_PARAMETER Input smbios structure mal-formed or Size is NULL.
557 GetSmbiosStructureSize (
558 IN EFI_SMBIOS_TABLE_HEADER
*Head
,
560 OUT UINT8
*NumberOfStrings
567 if (Size
== NULL
|| NumberOfStrings
== NULL
) {
568 return EFI_INVALID_PARAMETER
;
571 FullSize
= Head
->Length
;
572 CharInStr
= (INT8
*)Head
+ Head
->Length
;
574 *NumberOfStrings
= 0;
577 // look for the two consecutive zeros, check the string limit by the way.
579 while (*CharInStr
!= 0 || *(CharInStr
+1) != 0) {
580 if (*CharInStr
== 0) {
585 for (StrLen
= 0 ; StrLen
< SMBIOS_STRING_MAX_LENGTH
; StrLen
++) {
586 if (*(CharInStr
+StrLen
) == 0) {
591 if (StrLen
== SMBIOS_STRING_MAX_LENGTH
) {
592 return EFI_INVALID_PARAMETER
;
595 // forward the pointer
599 *NumberOfStrings
+= 1;
604 // count ending two zeros.