1 /** @file
2 Translate the DataHub records via EFI_DATA_HUB_PROTOCOL to Smbios recorders
3 via EFI_SMBIOS_PROTOCOL.
4
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
10
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.
13
14 **/
15
16 #include "Thunk.h"
17
18 EFI_SMBIOS_PROTOCOL *mSmbiosProtocol = NULL;
19
20 /**
21 Release the structure Node.
22
23 @param StructureNode Point to SMBIOS_STRUCTURE_NODE which will be removed.
24 **/
25 VOID
ReleaseStructureNode(SMBIOS_STRUCTURE_NODE * StructureNode)26 ReleaseStructureNode (
27 SMBIOS_STRUCTURE_NODE *StructureNode
28 )
29 {
30 EFI_SMBIOS_PROTOCOL *Smbios;
31
32 RemoveEntryList (&(StructureNode->Link));
33 Smbios = GetSmbiosProtocol();
34 ASSERT (Smbios != NULL);
35 Smbios->Remove (Smbios, StructureNode->SmbiosHandle);
36 gBS->FreePool (StructureNode);
37 }
38
39 /**
40 Process a datahub's record and find corresponding translation way to translate
41 to SMBIOS record.
42
43 @param Record Point to datahub record.
44 **/
45 VOID
SmbiosProcessDataRecord(IN EFI_DATA_RECORD_HEADER * Record)46 SmbiosProcessDataRecord (
47 IN EFI_DATA_RECORD_HEADER *Record
48 )
49 {
50 EFI_DATA_RECORD_HEADER *RecordHeader;
51 EFI_SUBCLASS_TYPE1_HEADER *DataHeader;
52 UINTN Index;
53 SMBIOS_CONVERSION_TABLE_ENTRY *Conversion;
54 UINT8 *SrcData;
55 UINTN SrcDataSize;
56 LIST_ENTRY *Link;
57 SMBIOS_STRUCTURE_NODE *StructureNode;
58 BOOLEAN StructureCreated;
59 EFI_STATUS Status;
60
61 Conversion = NULL;
62 StructureNode = NULL;
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);
68
69 if (DataHeader->HeaderSize != sizeof (EFI_SUBCLASS_TYPE1_HEADER) ||
70 DataHeader->Instance == EFI_SUBCLASS_INSTANCE_RESERVED ||
71 DataHeader->SubInstance == EFI_SUBCLASS_INSTANCE_RESERVED
72 ) {
73 //
74 // Invalid Data Record
75 //
76 goto Done;
77 }
78
79 Index = 0;
80 while(TRUE) {
81 //
82 // Find a matching entry in the conversion table for this
83 // (SubClass, RecordNumber) pair
84 //
85 for (; !CompareGuid (&(mConversionTable[Index].SubClass), &gZeroGuid); Index++) {
86 if (CompareGuid (
87 &(mConversionTable[Index].SubClass),
88 &(RecordHeader->DataRecordGuid)
89 )) {
90 if (mConversionTable[Index].RecordType == DataHeader->RecordType) {
91 break;
92 }
93 }
94 }
95
96 if (CompareGuid (&(mConversionTable[Index].SubClass), &gZeroGuid)) {
97 //
98 // We cannot find a matching entry in conversion table,
99 // this means this data record cannot be used for SMBIOS.
100 // Just skip it.
101 //
102 goto Done;
103 }
104
105 Conversion = &mConversionTable[Index++];
106
107 //
108 // Find corresponding structure in the Structure List
109 //
110 for (Link = mStructureList.ForwardLink; Link != &mStructureList; Link = Link->ForwardLink) {
111
112 StructureNode = CR (
113 Link,
114 SMBIOS_STRUCTURE_NODE,
115 Link,
116 SMBIOS_STRUCTURE_NODE_SIGNATURE
117 );
118
119 if (Conversion->StructureLocatingMethod == BySubclassInstanceSubinstanceProducer) {
120 //
121 // Look at SubClass, Instance, SubInstance and ProducerName for a matching
122 // node
123 //
124 if (CompareGuid (&(StructureNode->SubClass), &(RecordHeader->DataRecordGuid)) &&
125 StructureNode->Instance == DataHeader->Instance &&
126 StructureNode->SubInstance == DataHeader->SubInstance &&
127 CompareGuid (&(StructureNode->ProducerName), &(RecordHeader->ProducerName))
128 ) {
129 if (Conversion->SmbiosType >= 0x80) {
130 if (StructureNode->SmbiosType == ((SMBIOS_STRUCTURE_HDR *) SrcData)->Type) {
131 break;
132 }
133 } else if (StructureNode->SmbiosType == Conversion->SmbiosType) {
134 break;
135 }
136 }
137
138 } else if (Conversion->StructureLocatingMethod == BySubClassInstanceProducer) {
139 //
140 // Look at SubClass, Instance and ProducerName for a matching node
141 //
142 if (CompareGuid (&(StructureNode->SubClass), &(RecordHeader->DataRecordGuid)) &&
143 StructureNode->Instance == DataHeader->Instance &&
144 CompareGuid (&(StructureNode->ProducerName), &(RecordHeader->ProducerName))
145 ) {
146 if (Conversion->SmbiosType >= 0x80) {
147 if (StructureNode->SmbiosType == ((SMBIOS_STRUCTURE_HDR *) SrcData)->Type) {
148 break;
149 }
150 } else if (StructureNode->SmbiosType == Conversion->SmbiosType) {
151 break;
152 }
153 }
154
155 } else {
156 //
157 // Invalid conversion table entry
158 //
159 goto Done;
160 }
161 }
162
163 if (Link == &mStructureList || StructureNode == NULL) {
164
165 //
166 // Not found, create a new structure
167 //
168 StructureNode = AllocateZeroPool (sizeof (SMBIOS_STRUCTURE_NODE));
169
170 if (StructureNode == NULL) {
171 goto Done;
172 }
173
174 if (Conversion->StructureLocatingMethod == BySubclassInstanceSubinstanceProducer) {
175 //
176 // Fill in SubClass, Instance, SubInstance and ProducerName
177 //
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));
182
183 } else if (Conversion->StructureLocatingMethod == BySubClassInstanceProducer) {
184 //
185 // Fill in at SubClass, Instance and ProducerName, mark SubInstance as Non
186 // Applicable
187 //
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));
192
193 }
194 //
195 // Allocate the structure instance
196 //
197 StructureNode->StructureSize = SmbiosGetTypeMinimalLength (Conversion->SmbiosType);
198
199 //
200 // StructureSize include the TWO trailing zero byte.
201 //
202 if (StructureNode->StructureSize < (sizeof(SMBIOS_STRUCTURE) + 2)) {
203 //
204 // Invalid Type
205 //
206 gBS->FreePool (StructureNode);
207 goto Done;
208 }
209
210 //
211 // Assign correct SmbiosType when OEM type and Non-OEM type
212 //
213 if (Conversion->SmbiosType >= 0x80) {
214 StructureNode->SmbiosType = ((SMBIOS_STRUCTURE_HDR *) SrcData)->Type;
215 } else {
216 StructureNode->SmbiosType = Conversion->SmbiosType;
217 }
218
219 StructureNode->SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
220 Status = SmbiosProtocolCreateRecord (
221 NULL,
222 StructureNode
223 );
224 if (EFI_ERROR (Status)) {
225 goto Done;
226 }
227 //
228 // Temporary cache the structrue pointer to Smbios database.
229 //
230 StructureNode->Structure = GetSmbiosBufferFromHandle (StructureNode->SmbiosHandle, StructureNode->SmbiosType, NULL);
231
232 InitializeListHead (&StructureNode->LinkDataFixup);
233
234 //
235 // Insert the Structure Node into the Strucutre List
236 //
237 StructureNode->Signature = SMBIOS_STRUCTURE_NODE_SIGNATURE;
238 InsertTailList (&mStructureList, &(StructureNode->Link));
239
240 StructureCreated = TRUE;
241
242 }
243
244
245 //
246 // Re-calculate the structure pointer to Smbios database.
247 //
248 StructureNode->Structure = GetSmbiosBufferFromHandle (StructureNode->SmbiosHandle, StructureNode->SmbiosType, NULL);
249
250 //
251 // Fill the Structure's field corresponding to this data record
252 //
253 if (Conversion->FieldFillingMethod == RecordDataUnchangedOffsetSpecified) {
254 //
255 // Field data is just the record data without transforming and
256 // offset is specified directly in the conversion table entry
257 //
258 if (Conversion->FieldOffset + SrcDataSize > StructureNode->Structure->Length) {
259 //
260 // Invalid Conversion Table Entry
261 //
262 if (StructureCreated) {
263 ReleaseStructureNode (StructureNode);
264 }
265
266 goto Done;
267 }
268
269 CopyMem ((UINT8 *) (StructureNode->Structure) + Conversion->FieldOffset, SrcData, SrcDataSize);
270
271 } else if (Conversion->FieldFillingMethod == ByFunctionWithOffsetSpecified) {
272 //
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.
276 //
277 if (Conversion->FieldFillingFunction == NULL) {
278 //
279 // Invalid Conversion Table Entry
280 //
281 if (StructureCreated) {
282 ReleaseStructureNode (StructureNode);
283 }
284
285 goto Done;
286 }
287
288 Status = Conversion->FieldFillingFunction (
289 StructureNode,
290 Conversion->FieldOffset,
291 SrcData,
292 (UINT32) SrcDataSize
293 );
294 if (EFI_ERROR (Status)) {
295 if (StructureCreated) {
296 ReleaseStructureNode (StructureNode);
297 }
298
299 goto Done;
300 }
301 } else if (Conversion->FieldFillingMethod == ByFunction) {
302 //
303 // Both field offset and field content are determined by
304 // FieldFillingFunction
305 //
306 if (Conversion->FieldFillingFunction == NULL) {
307 //
308 // Invalid Conversion Table Entry
309 //
310 if (StructureCreated) {
311 ReleaseStructureNode (StructureNode);
312 }
313
314 goto Done;
315 }
316
317 Status = Conversion->FieldFillingFunction (
318 StructureNode,
319 0,
320 SrcData,
321 (UINT32) SrcDataSize
322 );
323 if (EFI_ERROR (Status)) {
324 if (StructureCreated) {
325 ReleaseStructureNode (StructureNode);
326 }
327
328 goto Done;
329 }
330 } else if (Conversion->FieldFillingMethod == ByFunctionWithWholeDataRecord) {
331 //
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
335 //
336 if (Conversion->FieldFillingFunction == NULL) {
337 //
338 // Invalid Conversion Table Entry
339 //
340 if (StructureCreated) {
341 ReleaseStructureNode (StructureNode);
342 }
343
344 goto Done;
345 }
346
347 Status = Conversion->FieldFillingFunction (
348 StructureNode,
349 0,
350 DataHeader,
351 RecordHeader->RecordSize - RecordHeader->HeaderSize
352 );
353 if (EFI_ERROR (Status)) {
354 if (StructureCreated) {
355 ReleaseStructureNode (StructureNode);
356 }
357
358 goto Done;
359 }
360 } else {
361 //
362 // Invalid Conversion Table Entry
363 //
364 if (StructureCreated) {
365 ReleaseStructureNode (StructureNode);
366 }
367
368 goto Done;
369 }
370
371 //
372 // SmbiosEnlargeStructureBuffer is called to remove and add again
373 // this SMBIOS entry to reflash SMBIOS table in configuration table.
374 //
375 SmbiosEnlargeStructureBuffer (
376 StructureNode,
377 StructureNode->Structure->Length,
378 StructureNode->StructureSize,
379 StructureNode->StructureSize
380 );
381 }
382 Done:
383 return ;
384 }
385
386 /**
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.
389
390 @param Type SMBIOS's type.
391
392 @return the minimal length of a smbios record.
393 **/
394 UINT32
SmbiosGetTypeMinimalLength(IN UINT8 Type)395 SmbiosGetTypeMinimalLength (
396 IN UINT8 Type
397 )
398 {
399 UINTN Index;
400
401 for (Index = 0; mTypeInfoTable[Index].MinLength != 0; Index++) {
402 if (mTypeInfoTable[Index].Type == Type) {
403 return mTypeInfoTable[Index].MinLength;
404 }
405 }
406
407 return 0;
408 }
409
410 /**
411 Get pointer of EFI_SMBIOS_PROTOCOL.
412
413 @return pointer of EFI_SMBIOS_PROTOCOL.
414 **/
415 EFI_SMBIOS_PROTOCOL*
GetSmbiosProtocol(VOID)416 GetSmbiosProtocol(
417 VOID
418 )
419 {
420 EFI_STATUS Status;
421
422 if (mSmbiosProtocol == NULL) {
423 Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID*) &mSmbiosProtocol);
424 ASSERT_EFI_ERROR (Status);
425 }
426
427 ASSERT (mSmbiosProtocol != NULL);
428 return mSmbiosProtocol;
429 }
430
431 /**
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
434 created.
435
436 @param ProducerHandle The produce handle for a datahub record
437 @param StructureNode Point to SMBIOS_STRUCTURE_NODE
438
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.
441 **/
442 EFI_STATUS
SmbiosProtocolCreateRecord(IN EFI_HANDLE ProducerHandle,OPTIONAL IN SMBIOS_STRUCTURE_NODE * StructureNode)443 SmbiosProtocolCreateRecord (
444 IN EFI_HANDLE ProducerHandle, OPTIONAL
445 IN SMBIOS_STRUCTURE_NODE *StructureNode
446 )
447 {
448 EFI_SMBIOS_PROTOCOL *Smbios;
449 EFI_SMBIOS_TABLE_HEADER *BlankRecord;
450 EFI_STATUS Status;
451 SMBIOS_STRUCTURE_NODE *RefStructureNode;
452 LIST_ENTRY *Link;
453 LIST_ENTRY *Link1;
454 LIST_ENTRY *Link2;
455 SMBIOS_LINK_DATA_FIXUP_NODE *LinkDataFixupNode;
456 UINT8 *BufferPointer;
457
458 Smbios = GetSmbiosProtocol();
459 ASSERT (Smbios != NULL);
460
461 //
462 // Prepare a blank smbios record.
463 //
464 BlankRecord = (EFI_SMBIOS_TABLE_HEADER*) AllocateZeroPool (StructureNode->StructureSize);
465 if (BlankRecord == NULL) {
466 return EFI_OUT_OF_RESOURCES;
467 }
468 BlankRecord->Type = StructureNode->SmbiosType;
469 BlankRecord->Length = (UINT8) (StructureNode->StructureSize - 2);
470
471 //
472 // Add blank record into SMBIOS database.
473 //
474 Status = Smbios->Add (Smbios, NULL, &StructureNode->SmbiosHandle, BlankRecord);
475 FreePool (BlankRecord);
476
477 //
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.
480 //
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);
485 Link2 = Link1;
486 Link1 = Link1->ForwardLink;
487
488 if ((StructureNode->SmbiosType != LinkDataFixupNode->TargetType) ||
489 !(CompareGuid (&StructureNode->SubClass, &LinkDataFixupNode->SubClass)) ||
490 (StructureNode->Instance != LinkDataFixupNode->LinkData.Instance) ||
491 (StructureNode->SubInstance != LinkDataFixupNode->LinkData.SubInstance)) {
492 continue;
493 }
494
495 //
496 // Fill the field with the handle found
497 //
498 BufferPointer = (UINT8 *) (RefStructureNode->Structure) + LinkDataFixupNode->Offset;
499 *BufferPointer = (UINT8) (StructureNode->SmbiosHandle & 0xFF);
500 *(BufferPointer + 1) = (UINT8) ((StructureNode->SmbiosHandle >> 8) & 0xFF);
501 BufferPointer = NULL;
502
503 RemoveEntryList (Link2);
504 FreePool (LinkDataFixupNode);
505 }
506 }
507
508 return Status;
509 }
510
511 /**
512 Get pointer of a SMBIOS record's buffer according to its handle.
513
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.
517
518 @return EFI_SMBIOS_TABLE_HEADER Point to a SMBIOS record's buffer.
519 **/
520 EFI_SMBIOS_TABLE_HEADER*
GetSmbiosBufferFromHandle(IN EFI_SMBIOS_HANDLE Handle,IN EFI_SMBIOS_TYPE Type,IN EFI_HANDLE ProducerHandle OPTIONAL)521 GetSmbiosBufferFromHandle (
522 IN EFI_SMBIOS_HANDLE Handle,
523 IN EFI_SMBIOS_TYPE Type,
524 IN EFI_HANDLE ProducerHandle OPTIONAL
525 )
526 {
527 EFI_SMBIOS_PROTOCOL* Smbios;
528 EFI_SMBIOS_HANDLE SearchingHandle;
529 EFI_SMBIOS_TABLE_HEADER *RecordInSmbiosDatabase;
530 EFI_STATUS Status;
531
532 SearchingHandle = SMBIOS_HANDLE_PI_RESERVED;
533 Smbios = GetSmbiosProtocol();
534 ASSERT (Smbios != NULL);
535
536 do {
537 Status = Smbios->GetNext (Smbios, &SearchingHandle, &Type, &RecordInSmbiosDatabase, NULL);
538 } while ((SearchingHandle != Handle) && (Status != EFI_NOT_FOUND));
539
540 return RecordInSmbiosDatabase;
541 }
542
543 /**
544
545 Get the full size of smbios structure including optional strings that follow the formatted structure.
546
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.
550
551 @retval EFI_SUCCESS Size retured in Size.
552 @retval EFI_INVALID_PARAMETER Input smbios structure mal-formed or Size is NULL.
553
554 **/
555 EFI_STATUS
556 EFIAPI
GetSmbiosStructureSize(IN EFI_SMBIOS_TABLE_HEADER * Head,OUT UINT32 * Size,OUT UINT8 * NumberOfStrings)557 GetSmbiosStructureSize (
558 IN EFI_SMBIOS_TABLE_HEADER *Head,
559 OUT UINT32 *Size,
560 OUT UINT8 *NumberOfStrings
561 )
562 {
563 UINT32 FullSize;
564 UINT8 StrLen;
565 INT8* CharInStr;
566
567 if (Size == NULL || NumberOfStrings == NULL) {
568 return EFI_INVALID_PARAMETER;
569 }
570
571 FullSize = Head->Length;
572 CharInStr = (INT8*)Head + Head->Length;
573 *Size = FullSize;
574 *NumberOfStrings = 0;
575 StrLen = 0;
576 //
577 // look for the two consecutive zeros, check the string limit by the way.
578 //
579 while (*CharInStr != 0 || *(CharInStr+1) != 0) {
580 if (*CharInStr == 0) {
581 *Size += 1;
582 CharInStr++;
583 }
584
585 for (StrLen = 0 ; StrLen < SMBIOS_STRING_MAX_LENGTH; StrLen++) {
586 if (*(CharInStr+StrLen) == 0) {
587 break;
588 }
589 }
590
591 if (StrLen == SMBIOS_STRING_MAX_LENGTH) {
592 return EFI_INVALID_PARAMETER;
593 }
594 //
595 // forward the pointer
596 //
597 CharInStr += StrLen;
598 *Size += StrLen;
599 *NumberOfStrings += 1;
600
601 }
602
603 //
604 // count ending two zeros.
605 //
606 *Size += 2;
607 return EFI_SUCCESS;
608 }
609