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