]> git.proxmox.com Git - mirror_edk2.git/blob - EdkCompatibilityPkg/Compatibility/PiSmbiosRecordOnDataHubSmbiosRecordThunk/Translate.c
Clean up the hard code offset in MdePkg BaseLib Ia32 Thunk16.S and EcpPkg GlueLib...
[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 - 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
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 == BySubclassInstanceSubinstanceProducer) {
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 == BySubClassInstanceProducer) {
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 || StructureNode == NULL) {
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 == BySubclassInstanceSubinstanceProducer) {
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 == BySubClassInstanceProducer) {
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
200 //
201 // StructureSize include the TWO trailing zero byte.
202 //
203 if (StructureNode->StructureSize < (sizeof(SMBIOS_STRUCTURE) + 2)) {
204 //
205 // Invalid Type
206 //
207 gBS->FreePool (StructureNode);
208 goto Done;
209 }
210
211 //
212 // Assign correct SmbiosType when OEM type and Non-OEM type
213 //
214 if (Conversion->SmbiosType >= 0x80) {
215 StructureNode->SmbiosType = ((SMBIOS_STRUCTURE_HDR *) SrcData)->Type;
216 } else {
217 StructureNode->SmbiosType = Conversion->SmbiosType;
218 }
219
220 StructureNode->SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
221 Status = SmbiosProtocolCreateRecord (
222 NULL,
223 StructureNode
224 );
225 if (EFI_ERROR (Status)) {
226 goto Done;
227 }
228 //
229 // Temporary cache the structrue pointer to Smbios database.
230 //
231 StructureNode->Structure = GetSmbiosBufferFromHandle (StructureNode->SmbiosHandle, StructureNode->SmbiosType, NULL);
232
233 InitializeListHead (&StructureNode->LinkDataFixup);
234
235 //
236 // Insert the Structure Node into the Strucutre List
237 //
238 StructureNode->Signature = SMBIOS_STRUCTURE_NODE_SIGNATURE;
239 InsertTailList (&mStructureList, &(StructureNode->Link));
240
241 StructureCreated = TRUE;
242
243 }
244
245
246 //
247 // Re-calculate the structure pointer to Smbios database.
248 //
249 StructureNode->Structure = GetSmbiosBufferFromHandle (StructureNode->SmbiosHandle, StructureNode->SmbiosType, NULL);
250
251 //
252 // Fill the Structure's field corresponding to this data record
253 //
254 if (Conversion->FieldFillingMethod == RecordDataUnchangedOffsetSpecified) {
255 //
256 // Field data is just the record data without transforming and
257 // offset is specified directly in the conversion table entry
258 //
259 if (Conversion->FieldOffset + SrcDataSize > StructureNode->Structure->Length) {
260 //
261 // Invalid Conversion Table Entry
262 //
263 if (StructureCreated) {
264 ReleaseStructureNode (StructureNode);
265 }
266
267 goto Done;
268 }
269
270 CopyMem ((UINT8 *) (StructureNode->Structure) + Conversion->FieldOffset, SrcData, SrcDataSize);
271
272 } else if (Conversion->FieldFillingMethod == ByFunctionWithOffsetSpecified) {
273 //
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.
277 //
278 if (Conversion->FieldFillingFunction == NULL) {
279 //
280 // Invalid Conversion Table Entry
281 //
282 if (StructureCreated) {
283 ReleaseStructureNode (StructureNode);
284 }
285
286 goto Done;
287 }
288
289 Status = Conversion->FieldFillingFunction (
290 StructureNode,
291 Conversion->FieldOffset,
292 SrcData,
293 (UINT32) SrcDataSize
294 );
295 if (EFI_ERROR (Status)) {
296 if (StructureCreated) {
297 ReleaseStructureNode (StructureNode);
298 }
299
300 goto Done;
301 }
302 } else if (Conversion->FieldFillingMethod == ByFunction) {
303 //
304 // Both field offset and field content are determined by
305 // FieldFillingFunction
306 //
307 if (Conversion->FieldFillingFunction == NULL) {
308 //
309 // Invalid Conversion Table Entry
310 //
311 if (StructureCreated) {
312 ReleaseStructureNode (StructureNode);
313 }
314
315 goto Done;
316 }
317
318 Status = Conversion->FieldFillingFunction (
319 StructureNode,
320 0,
321 SrcData,
322 (UINT32) SrcDataSize
323 );
324 if (EFI_ERROR (Status)) {
325 if (StructureCreated) {
326 ReleaseStructureNode (StructureNode);
327 }
328
329 goto Done;
330 }
331 } else if (Conversion->FieldFillingMethod == ByFunctionWithWholeDataRecord) {
332 //
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
336 //
337 if (Conversion->FieldFillingFunction == NULL) {
338 //
339 // Invalid Conversion Table Entry
340 //
341 if (StructureCreated) {
342 ReleaseStructureNode (StructureNode);
343 }
344
345 goto Done;
346 }
347
348 Status = Conversion->FieldFillingFunction (
349 StructureNode,
350 0,
351 DataHeader,
352 RecordHeader->RecordSize - RecordHeader->HeaderSize
353 );
354 if (EFI_ERROR (Status)) {
355 if (StructureCreated) {
356 ReleaseStructureNode (StructureNode);
357 }
358
359 goto Done;
360 }
361 } else {
362 //
363 // Invalid Conversion Table Entry
364 //
365 if (StructureCreated) {
366 ReleaseStructureNode (StructureNode);
367 }
368
369 goto Done;
370 }
371
372 //
373 // SmbiosEnlargeStructureBuffer is called to remove and add again
374 // this SMBIOS entry to reflash SMBIOS table in configuration table.
375 //
376 SmbiosEnlargeStructureBuffer (
377 StructureNode,
378 StructureNode->Structure->Length,
379 StructureNode->StructureSize,
380 StructureNode->StructureSize
381 );
382 }
383 Done:
384 return ;
385 }
386
387 /**
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.
390
391 @param Type SMBIOS's type.
392
393 @return the minimal length of a smbios record.
394 **/
395 UINT32
396 SmbiosGetTypeMinimalLength (
397 IN UINT8 Type
398 )
399 {
400 UINTN Index;
401
402 for (Index = 0; mTypeInfoTable[Index].MinLength != 0; Index++) {
403 if (mTypeInfoTable[Index].Type == Type) {
404 return mTypeInfoTable[Index].MinLength;
405 }
406 }
407
408 return 0;
409 }
410
411 /**
412 Get pointer of EFI_SMBIOS_PROTOCOL.
413
414 @return pointer of EFI_SMBIOS_PROTOCOL.
415 **/
416 EFI_SMBIOS_PROTOCOL*
417 GetSmbiosProtocol(
418 VOID
419 )
420 {
421 EFI_STATUS Status;
422
423 if (mSmbiosProtocol == NULL) {
424 Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID*) &mSmbiosProtocol);
425 ASSERT_EFI_ERROR (Status);
426 }
427
428 ASSERT (mSmbiosProtocol != NULL);
429 return mSmbiosProtocol;
430 }
431
432 /**
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
435 created.
436
437 @param ProducerHandle The produce handle for a datahub record
438 @param StructureNode Point to SMBIOS_STRUCTURE_NODE
439
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.
442 **/
443 EFI_STATUS
444 SmbiosProtocolCreateRecord (
445 IN EFI_HANDLE ProducerHandle, OPTIONAL
446 IN SMBIOS_STRUCTURE_NODE *StructureNode
447 )
448 {
449 EFI_SMBIOS_PROTOCOL *Smbios;
450 EFI_SMBIOS_TABLE_HEADER *BlankRecord;
451 EFI_STATUS Status;
452 SMBIOS_STRUCTURE_NODE *RefStructureNode;
453 LIST_ENTRY *Link;
454 LIST_ENTRY *Link1;
455 LIST_ENTRY *Link2;
456 SMBIOS_LINK_DATA_FIXUP_NODE *LinkDataFixupNode;
457 UINT8 *BufferPointer;
458
459 Smbios = GetSmbiosProtocol();
460 ASSERT (Smbios != NULL);
461
462 //
463 // Prepare a blank smbios record.
464 //
465 BlankRecord = (EFI_SMBIOS_TABLE_HEADER*) AllocateZeroPool (StructureNode->StructureSize);
466 if (BlankRecord == NULL) {
467 return EFI_OUT_OF_RESOURCES;
468 }
469 BlankRecord->Type = StructureNode->SmbiosType;
470 BlankRecord->Length = (UINT8) (StructureNode->StructureSize - 2);
471
472 //
473 // Add blank record into SMBIOS database.
474 //
475 Status = Smbios->Add (Smbios, NULL, &StructureNode->SmbiosHandle, BlankRecord);
476 FreePool (BlankRecord);
477
478 //
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.
481 //
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);
486 Link2 = Link1;
487 Link1 = Link1->ForwardLink;
488
489 if ((StructureNode->SmbiosType != LinkDataFixupNode->TargetType) ||
490 !(CompareGuid (&StructureNode->SubClass, &LinkDataFixupNode->SubClass)) ||
491 (StructureNode->Instance != LinkDataFixupNode->LinkData.Instance) ||
492 (StructureNode->SubInstance != LinkDataFixupNode->LinkData.SubInstance)) {
493 continue;
494 }
495
496 //
497 // Fill the field with the handle found
498 //
499 BufferPointer = (UINT8 *) (RefStructureNode->Structure) + LinkDataFixupNode->Offset;
500 *BufferPointer = (UINT8) (StructureNode->SmbiosHandle & 0xFF);
501 *(BufferPointer + 1) = (UINT8) ((StructureNode->SmbiosHandle >> 8) & 0xFF);
502 BufferPointer = NULL;
503
504 RemoveEntryList (Link2);
505 FreePool (LinkDataFixupNode);
506 }
507 }
508
509 return Status;
510 }
511
512 /**
513 Get pointer of a SMBIOS record's buffer according to its handle.
514
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.
518
519 @return EFI_SMBIOS_TABLE_HEADER Point to a SMBIOS record's buffer.
520 **/
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
526 )
527 {
528 EFI_SMBIOS_PROTOCOL* Smbios;
529 EFI_SMBIOS_HANDLE SearchingHandle;
530 EFI_SMBIOS_TABLE_HEADER *RecordInSmbiosDatabase;
531 EFI_STATUS Status;
532
533 SearchingHandle = SMBIOS_HANDLE_PI_RESERVED;
534 Smbios = GetSmbiosProtocol();
535 ASSERT (Smbios != NULL);
536
537 do {
538 Status = Smbios->GetNext (Smbios, &SearchingHandle, &Type, &RecordInSmbiosDatabase, NULL);
539 } while ((SearchingHandle != Handle) && (Status != EFI_NOT_FOUND));
540
541 return RecordInSmbiosDatabase;
542 }
543
544 /**
545
546 Get the full size of smbios structure including optional strings that follow the formatted structure.
547
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.
551
552 @retval EFI_SUCCESS Size retured in Size.
553 @retval EFI_INVALID_PARAMETER Input smbios structure mal-formed or Size is NULL.
554
555 **/
556 EFI_STATUS
557 EFIAPI
558 GetSmbiosStructureSize (
559 IN EFI_SMBIOS_TABLE_HEADER *Head,
560 OUT UINT32 *Size,
561 OUT UINT8 *NumberOfStrings
562 )
563 {
564 UINT32 FullSize;
565 UINT8 StrLen;
566 INT8* CharInStr;
567
568 if (Size == NULL || NumberOfStrings == NULL) {
569 return EFI_INVALID_PARAMETER;
570 }
571
572 FullSize = Head->Length;
573 CharInStr = (INT8*)Head + Head->Length;
574 *Size = FullSize;
575 *NumberOfStrings = 0;
576 StrLen = 0;
577 //
578 // look for the two consecutive zeros, check the string limit by the way.
579 //
580 while (*CharInStr != 0 || *(CharInStr+1) != 0) {
581 if (*CharInStr == 0) {
582 *Size += 1;
583 CharInStr++;
584 }
585
586 for (StrLen = 0 ; StrLen < SMBIOS_STRING_MAX_LENGTH; StrLen++) {
587 if (*(CharInStr+StrLen) == 0) {
588 break;
589 }
590 }
591
592 if (StrLen == SMBIOS_STRING_MAX_LENGTH) {
593 return EFI_INVALID_PARAMETER;
594 }
595 //
596 // forward the pointer
597 //
598 CharInStr += StrLen;
599 *Size += StrLen;
600 *NumberOfStrings += 1;
601
602 }
603
604 //
605 // count ending two zeros.
606 //
607 *Size += 2;
608 return EFI_SUCCESS;
609 }