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