2 Translate the DataHub records via EFI_DATA_HUB_PROTOCOL to Smbios recorders
3 via EFI_SMBIOS_PROTOCOL.
5 Copyright (c) 2009 - 2011, 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_GUID ZeroGuid
= { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } };
19 EFI_SMBIOS_PROTOCOL
*mSmbiosProtocol
= NULL
;
22 Release the structure Node.
24 @param StructureNode Point to SMBIOS_STRUCTURE_NODE which will be removed.
27 ReleaseStructureNode (
28 SMBIOS_STRUCTURE_NODE
*StructureNode
31 EFI_SMBIOS_PROTOCOL
*Smbios
;
33 RemoveEntryList (&(StructureNode
->Link
));
34 Smbios
= GetSmbiosProtocol();
35 ASSERT (Smbios
!= NULL
);
36 Smbios
->Remove (Smbios
, StructureNode
->SmbiosHandle
);
37 gBS
->FreePool (StructureNode
);
41 Process a datahub's record and find corresponding translation way to translate
44 @param Record Point to datahub record.
47 SmbiosProcessDataRecord (
48 IN EFI_DATA_RECORD_HEADER
*Record
51 EFI_DATA_RECORD_HEADER
*RecordHeader
;
52 EFI_SUBCLASS_TYPE1_HEADER
*DataHeader
;
54 SMBIOS_CONVERSION_TABLE_ENTRY
*Conversion
;
58 SMBIOS_STRUCTURE_NODE
*StructureNode
;
59 BOOLEAN StructureCreated
;
64 StructureCreated
= FALSE
;
65 RecordHeader
= Record
;
66 DataHeader
= (EFI_SUBCLASS_TYPE1_HEADER
*) (Record
+ 1);
67 SrcData
= (UINT8
*) (DataHeader
+ 1);
68 SrcDataSize
= RecordHeader
->RecordSize
- RecordHeader
->HeaderSize
- sizeof (EFI_SUBCLASS_TYPE1_HEADER
);
70 if (DataHeader
->HeaderSize
!= sizeof (EFI_SUBCLASS_TYPE1_HEADER
) ||
71 DataHeader
->Instance
== EFI_SUBCLASS_INSTANCE_RESERVED
||
72 DataHeader
->SubInstance
== EFI_SUBCLASS_INSTANCE_RESERVED
75 // Invalid Data Record
83 // Find a matching entry in the conversion table for this
84 // (SubClass, RecordNumber) pair
86 for (; !CompareGuid (&(mConversionTable
[Index
].SubClass
), &ZeroGuid
); Index
++) {
88 &(mConversionTable
[Index
].SubClass
),
89 &(RecordHeader
->DataRecordGuid
)
91 if (mConversionTable
[Index
].RecordType
== DataHeader
->RecordType
) {
97 if (CompareGuid (&(mConversionTable
[Index
].SubClass
), &ZeroGuid
)) {
99 // We cannot find a matching entry in conversion table,
100 // this means this data record cannot be used for SMBIOS.
106 Conversion
= &mConversionTable
[Index
++];
109 // Find corresponding structure in the Structure List
111 for (Link
= mStructureList
.ForwardLink
; Link
!= &mStructureList
; Link
= Link
->ForwardLink
) {
115 SMBIOS_STRUCTURE_NODE
,
117 SMBIOS_STRUCTURE_NODE_SIGNATURE
120 if (Conversion
->StructureLocatingMethod
== BySubclassInstanceSubinstanceProducer
) {
122 // Look at SubClass, Instance, SubInstance and ProducerName for a matching
125 if (CompareGuid (&(StructureNode
->SubClass
), &(RecordHeader
->DataRecordGuid
)) &&
126 StructureNode
->Instance
== DataHeader
->Instance
&&
127 StructureNode
->SubInstance
== DataHeader
->SubInstance
&&
128 CompareGuid (&(StructureNode
->ProducerName
), &(RecordHeader
->ProducerName
))
130 if (Conversion
->SmbiosType
>= 0x80) {
131 if (StructureNode
->SmbiosType
== ((SMBIOS_STRUCTURE_HDR
*) SrcData
)->Type
) {
134 } else if (StructureNode
->SmbiosType
== Conversion
->SmbiosType
) {
139 } else if (Conversion
->StructureLocatingMethod
== BySubClassInstanceProducer
) {
141 // Look at SubClass, Instance and ProducerName for a matching node
143 if (CompareGuid (&(StructureNode
->SubClass
), &(RecordHeader
->DataRecordGuid
)) &&
144 StructureNode
->Instance
== DataHeader
->Instance
&&
145 CompareGuid (&(StructureNode
->ProducerName
), &(RecordHeader
->ProducerName
))
147 if (Conversion
->SmbiosType
>= 0x80) {
148 if (StructureNode
->SmbiosType
== ((SMBIOS_STRUCTURE_HDR
*) SrcData
)->Type
) {
151 } else if (StructureNode
->SmbiosType
== Conversion
->SmbiosType
) {
158 // Invalid conversion table entry
164 if (Link
== &mStructureList
|| StructureNode
== NULL
) {
167 // Not found, create a new structure
169 StructureNode
= AllocateZeroPool (sizeof (SMBIOS_STRUCTURE_NODE
));
171 if (StructureNode
== NULL
) {
175 if (Conversion
->StructureLocatingMethod
== BySubclassInstanceSubinstanceProducer
) {
177 // Fill in SubClass, Instance, SubInstance and ProducerName
179 CopyMem (&(StructureNode
->SubClass
), &(RecordHeader
->DataRecordGuid
), sizeof (EFI_GUID
));
180 StructureNode
->Instance
= DataHeader
->Instance
;
181 StructureNode
->SubInstance
= DataHeader
->SubInstance
;
182 CopyMem (&(StructureNode
->ProducerName
), &(RecordHeader
->ProducerName
), sizeof (EFI_GUID
));
184 } else if (Conversion
->StructureLocatingMethod
== BySubClassInstanceProducer
) {
186 // Fill in at SubClass, Instance and ProducerName, mark SubInstance as Non
189 CopyMem (&(StructureNode
->SubClass
), &(RecordHeader
->DataRecordGuid
), sizeof (EFI_GUID
));
190 StructureNode
->Instance
= DataHeader
->Instance
;
191 StructureNode
->SubInstance
= EFI_SUBCLASS_INSTANCE_NON_APPLICABLE
;
192 CopyMem (&(StructureNode
->ProducerName
), &(RecordHeader
->ProducerName
), sizeof (EFI_GUID
));
196 // Allocate the structure instance
198 StructureNode
->StructureSize
= SmbiosGetTypeMinimalLength (Conversion
->SmbiosType
);
201 // StructureSize include the TWO trailing zero byte.
203 if (StructureNode
->StructureSize
< (sizeof(SMBIOS_STRUCTURE
) + 2)) {
207 gBS
->FreePool (StructureNode
);
212 // Assign correct SmbiosType when OEM type and Non-OEM type
214 if (Conversion
->SmbiosType
>= 0x80) {
215 StructureNode
->SmbiosType
= ((SMBIOS_STRUCTURE_HDR
*) SrcData
)->Type
;
217 StructureNode
->SmbiosType
= Conversion
->SmbiosType
;
220 StructureNode
->SmbiosHandle
= SMBIOS_HANDLE_PI_RESERVED
;
221 Status
= SmbiosProtocolCreateRecord (
225 if (EFI_ERROR (Status
)) {
229 // Temporary cache the structrue pointer to Smbios database.
231 StructureNode
->Structure
= GetSmbiosBufferFromHandle (StructureNode
->SmbiosHandle
, StructureNode
->SmbiosType
, NULL
);
233 InitializeListHead (&StructureNode
->LinkDataFixup
);
236 // Insert the Structure Node into the Strucutre List
238 StructureNode
->Signature
= SMBIOS_STRUCTURE_NODE_SIGNATURE
;
239 InsertTailList (&mStructureList
, &(StructureNode
->Link
));
241 StructureCreated
= TRUE
;
247 // Re-calculate the structure pointer to Smbios database.
249 StructureNode
->Structure
= GetSmbiosBufferFromHandle (StructureNode
->SmbiosHandle
, StructureNode
->SmbiosType
, NULL
);
252 // Fill the Structure's field corresponding to this data record
254 if (Conversion
->FieldFillingMethod
== RecordDataUnchangedOffsetSpecified
) {
256 // Field data is just the record data without transforming and
257 // offset is specified directly in the conversion table entry
259 if (Conversion
->FieldOffset
+ SrcDataSize
> StructureNode
->Structure
->Length
) {
261 // Invalid Conversion Table Entry
263 if (StructureCreated
) {
264 ReleaseStructureNode (StructureNode
);
270 CopyMem ((UINT8
*) (StructureNode
->Structure
) + Conversion
->FieldOffset
, SrcData
, SrcDataSize
);
272 } else if (Conversion
->FieldFillingMethod
== ByFunctionWithOffsetSpecified
) {
274 // Field offfset is specified in the conversion table entry, but
275 // record data needs to be transformed to be filled into the field,
276 // so let the FieldFillingFunction do it.
278 if (Conversion
->FieldFillingFunction
== NULL
) {
280 // Invalid Conversion Table Entry
282 if (StructureCreated
) {
283 ReleaseStructureNode (StructureNode
);
289 Status
= Conversion
->FieldFillingFunction (
291 Conversion
->FieldOffset
,
295 if (EFI_ERROR (Status
)) {
296 if (StructureCreated
) {
297 ReleaseStructureNode (StructureNode
);
302 } else if (Conversion
->FieldFillingMethod
== ByFunction
) {
304 // Both field offset and field content are determined by
305 // FieldFillingFunction
307 if (Conversion
->FieldFillingFunction
== NULL
) {
309 // Invalid Conversion Table Entry
311 if (StructureCreated
) {
312 ReleaseStructureNode (StructureNode
);
318 Status
= Conversion
->FieldFillingFunction (
324 if (EFI_ERROR (Status
)) {
325 if (StructureCreated
) {
326 ReleaseStructureNode (StructureNode
);
331 } else if (Conversion
->FieldFillingMethod
== ByFunctionWithWholeDataRecord
) {
333 // Both field offset and field content are determined by
334 // FieldFillingFunction and the function accepts the whole data record
335 // including the data header
337 if (Conversion
->FieldFillingFunction
== NULL
) {
339 // Invalid Conversion Table Entry
341 if (StructureCreated
) {
342 ReleaseStructureNode (StructureNode
);
348 Status
= Conversion
->FieldFillingFunction (
352 RecordHeader
->RecordSize
- RecordHeader
->HeaderSize
354 if (EFI_ERROR (Status
)) {
355 if (StructureCreated
) {
356 ReleaseStructureNode (StructureNode
);
363 // Invalid Conversion Table Entry
365 if (StructureCreated
) {
366 ReleaseStructureNode (StructureNode
);
373 // SmbiosEnlargeStructureBuffer is called to remove and add again
374 // this SMBIOS entry to reflash SMBIOS table in configuration table.
376 SmbiosEnlargeStructureBuffer (
378 StructureNode
->Structure
->Length
,
379 StructureNode
->StructureSize
,
380 StructureNode
->StructureSize
388 Calculate the minimal length for a SMBIOS type. This length maybe not equal
389 to sizeof (SMBIOS_RECORD_STRUCTURE), but defined in conformance chapter in SMBIOS specification.
391 @param Type SMBIOS's type.
393 @return the minimal length of a smbios record.
396 SmbiosGetTypeMinimalLength (
402 for (Index
= 0; mTypeInfoTable
[Index
].MinLength
!= 0; Index
++) {
403 if (mTypeInfoTable
[Index
].Type
== Type
) {
404 return mTypeInfoTable
[Index
].MinLength
;
412 Get pointer of EFI_SMBIOS_PROTOCOL.
414 @return pointer of EFI_SMBIOS_PROTOCOL.
423 if (mSmbiosProtocol
== NULL
) {
424 Status
= gBS
->LocateProtocol (&gEfiSmbiosProtocolGuid
, NULL
, (VOID
*) &mSmbiosProtocol
);
425 ASSERT_EFI_ERROR (Status
);
428 ASSERT (mSmbiosProtocol
!= NULL
);
429 return mSmbiosProtocol
;
433 Create a blank smbios record. The datahub record is only a field of smbios record.
434 So before fill any field from datahub's record. A blank smbios record need to be
437 @param ProducerHandle The produce handle for a datahub record
438 @param StructureNode Point to SMBIOS_STRUCTURE_NODE
440 @retval EFI_OUT_OF_RESOURCES Fail to allocate memory for new blank SMBIOS record.
441 @retval EFI_SUCCESS Success to create blank smbios record.
444 SmbiosProtocolCreateRecord (
445 IN EFI_HANDLE ProducerHandle
, OPTIONAL
446 IN SMBIOS_STRUCTURE_NODE
*StructureNode
449 EFI_SMBIOS_PROTOCOL
*Smbios
;
450 EFI_SMBIOS_TABLE_HEADER
*BlankRecord
;
452 SMBIOS_STRUCTURE_NODE
*RefStructureNode
;
456 SMBIOS_LINK_DATA_FIXUP_NODE
*LinkDataFixupNode
;
457 UINT8
*BufferPointer
;
459 Smbios
= GetSmbiosProtocol();
460 ASSERT (Smbios
!= NULL
);
463 // Prepare a blank smbios record.
465 BlankRecord
= (EFI_SMBIOS_TABLE_HEADER
*) AllocateZeroPool (StructureNode
->StructureSize
);
466 if (BlankRecord
== NULL
) {
467 return EFI_OUT_OF_RESOURCES
;
469 BlankRecord
->Type
= StructureNode
->SmbiosType
;
470 BlankRecord
->Length
= (UINT8
) (StructureNode
->StructureSize
- 2);
473 // Add blank record into SMBIOS database.
475 Status
= Smbios
->Add (Smbios
, NULL
, &StructureNode
->SmbiosHandle
, BlankRecord
);
476 FreePool (BlankRecord
);
479 // Fix up the InterLink node for new added smbios record if some other
480 // existing smbios record want to link this new record's handle.
482 for (Link
= mStructureList
.ForwardLink
; Link
!= &mStructureList
; Link
= Link
->ForwardLink
) {
483 RefStructureNode
= CR (Link
, SMBIOS_STRUCTURE_NODE
, Link
, SMBIOS_STRUCTURE_NODE_SIGNATURE
);
484 for (Link1
= RefStructureNode
->LinkDataFixup
.ForwardLink
; Link1
!= &RefStructureNode
->LinkDataFixup
;) {
485 LinkDataFixupNode
= CR (Link1
, SMBIOS_LINK_DATA_FIXUP_NODE
, Link
, SMBIOS_LINK_DATA_FIXUP_NODE_SIGNATURE
);
487 Link1
= Link1
->ForwardLink
;
489 if ((StructureNode
->SmbiosType
!= LinkDataFixupNode
->TargetType
) ||
490 !(CompareGuid (&StructureNode
->SubClass
, &LinkDataFixupNode
->SubClass
)) ||
491 (StructureNode
->Instance
!= LinkDataFixupNode
->LinkData
.Instance
) ||
492 (StructureNode
->SubInstance
!= LinkDataFixupNode
->LinkData
.SubInstance
)) {
497 // Fill the field with the handle found
499 BufferPointer
= (UINT8
*) (RefStructureNode
->Structure
) + LinkDataFixupNode
->Offset
;
500 *BufferPointer
= (UINT8
) (StructureNode
->SmbiosHandle
& 0xFF);
501 *(BufferPointer
+ 1) = (UINT8
) ((StructureNode
->SmbiosHandle
>> 8) & 0xFF);
502 BufferPointer
= NULL
;
504 RemoveEntryList (Link2
);
505 FreePool (LinkDataFixupNode
);
513 Get pointer of a SMBIOS record's buffer according to its handle.
515 @param Handle The handle of SMBIOS record want to be searched.
516 @param Type The type of SMBIOS record want to be searched.
517 @param ProducerHandle The producer handle of SMBIOS record.
519 @return EFI_SMBIOS_TABLE_HEADER Point to a SMBIOS record's buffer.
521 EFI_SMBIOS_TABLE_HEADER
*
522 GetSmbiosBufferFromHandle (
523 IN EFI_SMBIOS_HANDLE Handle
,
524 IN EFI_SMBIOS_TYPE Type
,
525 IN EFI_HANDLE ProducerHandle OPTIONAL
528 EFI_SMBIOS_PROTOCOL
* Smbios
;
529 EFI_SMBIOS_HANDLE SearchingHandle
;
530 EFI_SMBIOS_TABLE_HEADER
*RecordInSmbiosDatabase
;
533 SearchingHandle
= SMBIOS_HANDLE_PI_RESERVED
;
534 Smbios
= GetSmbiosProtocol();
535 ASSERT (Smbios
!= NULL
);
538 Status
= Smbios
->GetNext (Smbios
, &SearchingHandle
, &Type
, &RecordInSmbiosDatabase
, NULL
);
539 } while ((SearchingHandle
!= Handle
) && (Status
!= EFI_NOT_FOUND
));
541 return RecordInSmbiosDatabase
;
546 Get the full size of smbios structure including optional strings that follow the formatted structure.
548 @param Head Pointer to the beginning of smbios structure.
549 @param Size The returned size.
550 @param NumberOfStrings The returned number of optional strings that follow the formatted structure.
552 @retval EFI_SUCCESS Size retured in Size.
553 @retval EFI_INVALID_PARAMETER Input smbios structure mal-formed or Size is NULL.
558 GetSmbiosStructureSize (
559 IN EFI_SMBIOS_TABLE_HEADER
*Head
,
561 OUT UINT8
*NumberOfStrings
568 if (Size
== NULL
|| NumberOfStrings
== NULL
) {
569 return EFI_INVALID_PARAMETER
;
572 FullSize
= Head
->Length
;
573 CharInStr
= (INT8
*)Head
+ Head
->Length
;
575 *NumberOfStrings
= 0;
578 // look for the two consecutive zeros, check the string limit by the way.
580 while (*CharInStr
!= 0 || *(CharInStr
+1) != 0) {
581 if (*CharInStr
== 0) {
586 for (StrLen
= 0 ; StrLen
< SMBIOS_STRING_MAX_LENGTH
; StrLen
++) {
587 if (*(CharInStr
+StrLen
) == 0) {
592 if (StrLen
== SMBIOS_STRING_MAX_LENGTH
) {
593 return EFI_INVALID_PARAMETER
;
596 // forward the pointer
600 *NumberOfStrings
+= 1;
605 // count ending two zeros.