Home | History | Annotate | Download | only in PiSmbiosRecordOnDataHubSmbiosRecordThunk
      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
     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
     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
    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*
    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
    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*
    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
    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