2 Translate the DataHub records via EFI_DATA_HUB_PROTOCOL to Smbios recorders
3 via EFI_SMBIOS_PROTOCOL.
5 Copyright (c) 2009, Intel Corporation
6 All rights reserved. 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
== BY_SUBCLASS_INSTANCE_SUBINSTANCE_PRODUCER
) {
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
== BY_SUBCLASS_INSTANCE_PRODUCER
) {
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
) {
167 // Not found, create a new structure
169 StructureNode
= AllocateZeroPool (sizeof (SMBIOS_STRUCTURE_NODE
));
171 if (!StructureNode
) {
175 if (Conversion
->StructureLocatingMethod
== BY_SUBCLASS_INSTANCE_SUBINSTANCE_PRODUCER
) {
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
== BY_SUBCLASS_INSTANCE_PRODUCER
) {
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
);
199 StructureNode
->SmbiosType
= Conversion
->SmbiosType
;
202 // StructureSize include the TWO trailing zero byte.
204 if (StructureNode
->StructureSize
< (sizeof(SMBIOS_STRUCTURE
) + 2)) {
208 gBS
->FreePool (StructureNode
);
212 StructureNode
->SmbiosType
= Conversion
->SmbiosType
;
213 StructureNode
->SmbiosHandle
= 0;
214 Status
= SmbiosProtocolCreateRecord (
218 if (EFI_ERROR (Status
)) {
222 // Temporary cache the structrue pointer to Smbios database.
224 StructureNode
->Structure
= GetSmbiosBufferFromHandle (StructureNode
->SmbiosHandle
, StructureNode
->SmbiosType
, NULL
);
226 InitializeListHead (&StructureNode
->LinkDataFixup
);
229 // Insert the Structure Node into the Strucutre List
231 StructureNode
->Signature
= SMBIOS_STRUCTURE_NODE_SIGNATURE
;
232 InsertTailList (&mStructureList
, &(StructureNode
->Link
));
234 StructureCreated
= TRUE
;
240 // Re-calculate the structure pointer to Smbios database.
242 StructureNode
->Structure
= GetSmbiosBufferFromHandle (StructureNode
->SmbiosHandle
, StructureNode
->SmbiosType
, NULL
);
245 // Fill the Structure's field corresponding to this data record
247 if (Conversion
->FieldFillingMethod
== RECORD_DATA_UNCHANGED_OFFSET_SPECIFIED
) {
249 // Field data is just the record data without transforming and
250 // offset is specified directly in the conversion table entry
252 if (Conversion
->FieldOffset
+ SrcDataSize
> StructureNode
->Structure
->Length
) {
254 // Invalid Conversion Table Entry
256 if (StructureCreated
) {
257 ReleaseStructureNode (StructureNode
);
263 CopyMem ((UINT8
*) (StructureNode
->Structure
) + Conversion
->FieldOffset
, SrcData
, SrcDataSize
);
265 } else if (Conversion
->FieldFillingMethod
== BY_FUNCTION_WITH_OFFSET_SPECIFIED
) {
267 // Field offfset is specified in the conversion table entry, but
268 // record data needs to be transformed to be filled into the field,
269 // so let the FieldFillingFunction do it.
271 if (!(Conversion
->FieldFillingFunction
)) {
273 // Invalid Conversion Table Entry
275 if (StructureCreated
) {
276 ReleaseStructureNode (StructureNode
);
282 Status
= Conversion
->FieldFillingFunction (
284 Conversion
->FieldOffset
,
288 if (EFI_ERROR (Status
)) {
289 if (StructureCreated
) {
290 ReleaseStructureNode (StructureNode
);
295 } else if (Conversion
->FieldFillingMethod
== BY_FUNCTION
) {
297 // Both field offset and field content are determined by
298 // FieldFillingFunction
300 if (!(Conversion
->FieldFillingFunction
)) {
302 // Invalid Conversion Table Entry
304 if (StructureCreated
) {
305 ReleaseStructureNode (StructureNode
);
311 Status
= Conversion
->FieldFillingFunction (
317 if (EFI_ERROR (Status
)) {
318 if (StructureCreated
) {
319 ReleaseStructureNode (StructureNode
);
324 } else if (Conversion
->FieldFillingMethod
== BY_FUNCTION_WITH_WHOLE_DATA_RECORD
) {
326 // Both field offset and field content are determined by
327 // FieldFillingFunction and the function accepts the whole data record
328 // including the data header
330 if (!(Conversion
->FieldFillingFunction
)) {
332 // Invalid Conversion Table Entry
334 if (StructureCreated
) {
335 ReleaseStructureNode (StructureNode
);
341 Status
= Conversion
->FieldFillingFunction (
345 RecordHeader
->RecordSize
- RecordHeader
->HeaderSize
347 if (EFI_ERROR (Status
)) {
348 if (StructureCreated
) {
349 ReleaseStructureNode (StructureNode
);
356 // Invalid Conversion Table Entry
358 if (StructureCreated
) {
359 ReleaseStructureNode (StructureNode
);
370 Calculate the minimal length for a SMBIOS type. This length maybe not equal
371 to sizeof (SMBIOS_RECORD_STRUCTURE), but defined in conformance chapter in SMBIOS specification.
373 @param Type SMBIOS's type.
375 @return the minimal length of a smbios record.
378 SmbiosGetTypeMinimalLength (
384 for (Index
= 0; mTypeInfoTable
[Index
].MinLength
!= 0; Index
++) {
385 if (mTypeInfoTable
[Index
].Type
== Type
) {
386 return mTypeInfoTable
[Index
].MinLength
;
394 Get pointer of EFI_SMBIOS_PROTOCOL.
396 @return pointer of EFI_SMBIOS_PROTOCOL.
405 if (mSmbiosProtocol
== NULL
) {
406 Status
= gBS
->LocateProtocol (&gEfiSmbiosProtocolGuid
, NULL
, (VOID
*) &mSmbiosProtocol
);
407 ASSERT_EFI_ERROR (Status
);
410 ASSERT (mSmbiosProtocol
!= NULL
);
411 return mSmbiosProtocol
;
415 Create a blank smbios record. The datahub record is only a field of smbios record.
416 So before fill any field from datahub's record. A blank smbios record need to be
419 @param ProducerHandle The produce handle for a datahub record
420 @param StructureNode Point to SMBIOS_STRUCTURE_NODE
422 @retval EFI_OUT_OF_RESOURCES Fail to allocate memory for new blank SMBIOS record.
423 @retval EFI_SUCCESS Success to create blank smbios record.
426 SmbiosProtocolCreateRecord (
427 IN EFI_HANDLE ProducerHandle
, OPTIONAL
428 IN SMBIOS_STRUCTURE_NODE
*StructureNode
431 EFI_SMBIOS_PROTOCOL
*Smbios
;
432 EFI_SMBIOS_TABLE_HEADER
*BlankRecord
;
434 SMBIOS_STRUCTURE_NODE
*RefStructureNode
;
438 SMBIOS_LINK_DATA_FIXUP_NODE
*LinkDataFixupNode
;
439 UINT8
*BufferPointer
;
441 Smbios
= GetSmbiosProtocol();
442 ASSERT (Smbios
!= NULL
);
445 // Prepare a blank smbios record.
447 BlankRecord
= (EFI_SMBIOS_TABLE_HEADER
*) AllocateZeroPool (StructureNode
->StructureSize
);
448 if (BlankRecord
== NULL
) {
449 return EFI_OUT_OF_RESOURCES
;
451 BlankRecord
->Type
= StructureNode
->SmbiosType
;
452 BlankRecord
->Length
= (UINT8
) (StructureNode
->StructureSize
- 2);
455 // Add blank record into SMBIOS database.
457 Status
= Smbios
->Add (Smbios
, NULL
, &StructureNode
->SmbiosHandle
, BlankRecord
);
458 FreePool (BlankRecord
);
461 // Fix up the InterLink node for new added smbios record if some other
462 // existing smbios record want to link this new record's handle.
464 for (Link
= mStructureList
.ForwardLink
; Link
!= &mStructureList
; Link
= Link
->ForwardLink
) {
465 RefStructureNode
= CR (Link
, SMBIOS_STRUCTURE_NODE
, Link
, SMBIOS_STRUCTURE_NODE_SIGNATURE
);
466 for (Link1
= RefStructureNode
->LinkDataFixup
.ForwardLink
; Link1
!= &RefStructureNode
->LinkDataFixup
;) {
467 LinkDataFixupNode
= CR (Link1
, SMBIOS_LINK_DATA_FIXUP_NODE
, Link
, SMBIOS_LINK_DATA_FIXUP_NODE_SIGNATURE
);
469 Link1
= Link1
->ForwardLink
;
471 if ((StructureNode
->SmbiosType
!= LinkDataFixupNode
->TargetType
) ||
472 !(CompareGuid (&StructureNode
->SubClass
, &LinkDataFixupNode
->SubClass
)) ||
473 (StructureNode
->Instance
!= LinkDataFixupNode
->LinkData
.Instance
) ||
474 (StructureNode
->SubInstance
!= LinkDataFixupNode
->LinkData
.SubInstance
)) {
479 // Fill the field with the handle found
481 BufferPointer
= (UINT8
*) (RefStructureNode
->Structure
) + LinkDataFixupNode
->Offset
;
482 *BufferPointer
= (UINT8
) (StructureNode
->SmbiosHandle
& 0xFF);
483 *(BufferPointer
+ 1) = (UINT8
) ((StructureNode
->SmbiosHandle
>> 8) & 0xFF);
484 BufferPointer
= NULL
;
486 RemoveEntryList (Link2
);
487 FreePool (LinkDataFixupNode
);
495 Get pointer of a SMBIOS record's buffer according to its handle.
497 @param Handle The handle of SMBIOS record want to be searched.
498 @param Type The type of SMBIOS record want to be searched.
499 @param ProducerHandle The producer handle of SMBIOS record.
501 @return EFI_SMBIOS_TABLE_HEADER Point to a SMBIOS record's buffer.
503 EFI_SMBIOS_TABLE_HEADER
*
504 GetSmbiosBufferFromHandle (
505 IN EFI_SMBIOS_HANDLE Handle
,
506 IN EFI_SMBIOS_TYPE Type
,
507 IN EFI_HANDLE ProducerHandle OPTIONAL
510 EFI_SMBIOS_PROTOCOL
* Smbios
;
511 EFI_SMBIOS_HANDLE SearchingHandle
;
512 EFI_SMBIOS_TABLE_HEADER
*RecordInSmbiosDatabase
;
516 Smbios
= GetSmbiosProtocol();
517 ASSERT (Smbios
!= NULL
);
520 Status
= Smbios
->GetNext (Smbios
, &SearchingHandle
, &Type
, &RecordInSmbiosDatabase
, NULL
);
521 } while ((SearchingHandle
!= Handle
) && (Status
!= EFI_NOT_FOUND
));
523 return RecordInSmbiosDatabase
;
528 Get the full size of smbios structure including optional strings that follow the formatted structure.
530 @param Head Pointer to the beginning of smbios structure.
531 @param Size The returned size.
532 @param NumberOfStrings The returned number of optional strings that follow the formatted structure.
534 @retval EFI_SUCCESS Size retured in Size.
535 @retval EFI_INVALID_PARAMETER Input smbios structure mal-formed or Size is NULL.
540 GetSmbiosStructureSize (
541 IN EFI_SMBIOS_TABLE_HEADER
*Head
,
543 OUT UINT8
*NumberOfStrings
550 if (Size
== NULL
|| NumberOfStrings
== NULL
) {
551 return EFI_INVALID_PARAMETER
;
554 FullSize
= Head
->Length
;
555 CharInStr
= (INT8
*)Head
+ Head
->Length
;
557 *NumberOfStrings
= 0;
560 // look for the two consecutive zeros, check the string limit by the way.
562 while (*CharInStr
!= 0 || *(CharInStr
+1) != 0) {
563 if (*CharInStr
== 0) {
568 for (StrLen
= 0 ; StrLen
< SMBIOS_STRING_MAX_LENGTH
; StrLen
++) {
569 if (*(CharInStr
+StrLen
) == 0) {
574 if (StrLen
== SMBIOS_STRING_MAX_LENGTH
) {
575 return EFI_INVALID_PARAMETER
;
578 // forward the pointer
582 *NumberOfStrings
+= 1;
587 // count ending two zeros.