2 This code produces the Smbios protocol. It also responsible for constructing
3 SMBIOS table into system table.
5 Copyright (c) 2009 - 2013, 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
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.
16 #include "SmbiosDxe.h"
20 // Since this driver will only ever produce one instance of the
21 // protocol you are not required to dynamically allocate the PrivateData.
23 SMBIOS_INSTANCE mPrivateData
;
25 UINTN mPreAllocatedPages
= 0;
28 // Chassis for SMBIOS entry point structure that is to be installed into EFI system config table.
30 SMBIOS_TABLE_ENTRY_POINT
*EntryPointStructure
= NULL
;
31 SMBIOS_TABLE_ENTRY_POINT EntryPointStructureData
= {
42 // EntryPointStructureChecksum,TO BE FILLED
46 // EntryPointStructure Length
52 (UINT8
) (FixedPcdGet16 (PcdSmbiosVersion
) >> 8),
56 (UINT8
) (FixedPcdGet16 (PcdSmbiosVersion
) & 0x00ff),
58 // MaxStructureSize, TO BE FILLED
76 // IntermediateAnchorString
86 // IntermediateChecksum, TO BE FILLED
90 // TableLength, TO BE FILLED
94 // TableAddress, TO BE FILLED
98 // NumberOfSmbiosStructures, TO BE FILLED
104 (UINT8
) ((FixedPcdGet16 (PcdSmbiosVersion
) >> 4) & 0xf0)
105 | (UINT8
) (FixedPcdGet16 (PcdSmbiosVersion
) & 0x0f)
112 Get the full size of SMBIOS structure including optional strings that follow the formatted structure.
114 @param This The EFI_SMBIOS_PROTOCOL instance.
115 @param Head Pointer to the beginning of SMBIOS structure.
116 @param Size The returned size.
117 @param NumberOfStrings The returned number of optional strings that follow the formatted structure.
119 @retval EFI_SUCCESS Size retured in Size.
120 @retval EFI_INVALID_PARAMETER Input SMBIOS structure mal-formed or Size is NULL.
125 GetSmbiosStructureSize (
126 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
127 IN EFI_SMBIOS_TABLE_HEADER
*Head
,
129 OUT UINTN
*NumberOfStrings
137 if (Size
== NULL
|| NumberOfStrings
== NULL
) {
138 return EFI_INVALID_PARAMETER
;
141 FullSize
= Head
->Length
;
142 CharInStr
= (INT8
*)Head
+ Head
->Length
;
144 *NumberOfStrings
= 0;
147 // look for the two consecutive zeros, check the string limit by the way.
149 while (*CharInStr
!= 0 || *(CharInStr
+1) != 0) {
150 if (*CharInStr
== 0) {
155 if (This
->MajorVersion
< 2 || (This
->MajorVersion
== 2 && This
->MinorVersion
< 7)){
156 MaxLen
= SMBIOS_STRING_MAX_LENGTH
;
159 // Reference SMBIOS 2.7, chapter 6.1.3, it will have no limit on the length of each individual text string.
160 // However, the length of the entire structure table (including all strings) must be reported
161 // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,
162 // which is a WORD field limited to 65,535 bytes.
164 MaxLen
= SMBIOS_TABLE_MAX_LENGTH
;
167 for (StrLen
= 0 ; StrLen
< MaxLen
; StrLen
++) {
168 if (*(CharInStr
+StrLen
) == 0) {
173 if (StrLen
== MaxLen
) {
174 return EFI_INVALID_PARAMETER
;
178 // forward the pointer
182 *NumberOfStrings
+= 1;
186 // count ending two zeros.
194 Determin whether an SmbiosHandle has already in use.
196 @param Head Pointer to the beginning of SMBIOS structure.
197 @param Handle A unique handle will be assigned to the SMBIOS record.
199 @retval TRUE Smbios handle already in use.
200 @retval FALSE Smbios handle is NOT used.
205 CheckSmbiosHandleExistance (
207 IN EFI_SMBIOS_HANDLE Handle
211 SMBIOS_HANDLE_ENTRY
*HandleEntry
;
213 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
214 HandleEntry
= SMBIOS_HANDLE_ENTRY_FROM_LINK(Link
);
215 if (HandleEntry
->SmbiosHandle
== Handle
) {
225 Get the max SmbiosHandle that could be use.
227 @param This The EFI_SMBIOS_PROTOCOL instance.
228 @param MaxHandle The max handle that could be assigned to the SMBIOS record.
234 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
235 IN OUT EFI_SMBIOS_HANDLE
*MaxHandle
238 if (This
->MajorVersion
== 2 && This
->MinorVersion
== 0) {
247 Get an SmbiosHandle that could use.
249 @param This The EFI_SMBIOS_PROTOCOL instance.
250 @param SmbiosHandle A unique handle will be assigned to the SMBIOS record.
252 @retval EFI_SUCCESS Smbios handle got.
253 @retval EFI_OUT_OF_RESOURCES Smbios handle is NOT available.
258 GetAvailableSmbiosHandle (
259 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
260 IN OUT EFI_SMBIOS_HANDLE
*Handle
264 SMBIOS_INSTANCE
*Private
;
265 EFI_SMBIOS_HANDLE MaxSmbiosHandle
;
266 EFI_SMBIOS_HANDLE AvailableHandle
;
268 GetMaxSmbiosHandle(This
, &MaxSmbiosHandle
);
270 Private
= SMBIOS_INSTANCE_FROM_THIS (This
);
271 Head
= &Private
->AllocatedHandleListHead
;
272 for (AvailableHandle
= 0; AvailableHandle
< MaxSmbiosHandle
; AvailableHandle
++) {
273 if (!CheckSmbiosHandleExistance(Head
, AvailableHandle
)) {
274 *Handle
= AvailableHandle
;
279 return EFI_OUT_OF_RESOURCES
;
284 Add an SMBIOS record.
286 @param This The EFI_SMBIOS_PROTOCOL instance.
287 @param ProducerHandle The handle of the controller or driver associated with the SMBIOS information. NULL
289 @param SmbiosHandle On entry, the handle of the SMBIOS record to add. If FFFEh, then a unique handle
290 will be assigned to the SMBIOS record. If the SMBIOS handle is already in use,
291 EFI_ALREADY_STARTED is returned and the SMBIOS record is not updated.
292 @param Record The data for the fixed portion of the SMBIOS record. The format of the record is
293 determined by EFI_SMBIOS_TABLE_HEADER.Type. The size of the formatted area is defined
294 by EFI_SMBIOS_TABLE_HEADER.Length and either followed by a double-null (0x0000) or
295 a set of null terminated strings and a null.
297 @retval EFI_SUCCESS Record was added.
298 @retval EFI_OUT_OF_RESOURCES Record was not added due to lack of system resources.
299 @retval EFI_ALREADY_STARTED The SmbiosHandle passed in was already in use.
305 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
306 IN EFI_HANDLE ProducerHandle
, OPTIONAL
307 IN OUT EFI_SMBIOS_HANDLE
*SmbiosHandle
,
308 IN EFI_SMBIOS_TABLE_HEADER
*Record
315 UINTN NumberOfStrings
;
318 SMBIOS_INSTANCE
*Private
;
319 EFI_SMBIOS_ENTRY
*SmbiosEntry
;
320 EFI_SMBIOS_HANDLE MaxSmbiosHandle
;
321 SMBIOS_HANDLE_ENTRY
*HandleEntry
;
322 EFI_SMBIOS_RECORD_HEADER
*InternalRecord
;
324 if (SmbiosHandle
== NULL
) {
325 return EFI_INVALID_PARAMETER
;
328 Private
= SMBIOS_INSTANCE_FROM_THIS (This
);
330 // Check whether SmbiosHandle is already in use
332 Head
= &Private
->AllocatedHandleListHead
;
333 if (*SmbiosHandle
!= SMBIOS_HANDLE_PI_RESERVED
&& CheckSmbiosHandleExistance(Head
, *SmbiosHandle
)) {
334 return EFI_ALREADY_STARTED
;
338 // when SmbiosHandle is 0xFFFE, an available handle will be assigned
340 if (*SmbiosHandle
== SMBIOS_HANDLE_PI_RESERVED
) {
341 Status
= GetAvailableSmbiosHandle(This
, SmbiosHandle
);
342 if (EFI_ERROR(Status
)) {
347 // Check this handle validity
349 GetMaxSmbiosHandle(This
, &MaxSmbiosHandle
);
350 if (*SmbiosHandle
> MaxSmbiosHandle
) {
351 return EFI_INVALID_PARAMETER
;
356 // Calculate record size and string number
358 Status
= GetSmbiosStructureSize(This
, Record
, &StructureSize
, &NumberOfStrings
);
359 if (EFI_ERROR(Status
)) {
363 if (EntryPointStructure
->TableLength
+ StructureSize
> SMBIOS_TABLE_MAX_LENGTH
) {
365 // The length of the entire structure table (including all strings) must be reported
366 // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,
367 // which is a WORD field limited to 65,535 bytes.
369 return EFI_OUT_OF_RESOURCES
;
373 // Enter into critical section
375 Status
= EfiAcquireLockOrFail (&Private
->DataLock
);
376 if (EFI_ERROR (Status
)) {
380 RecordSize
= sizeof (EFI_SMBIOS_RECORD_HEADER
) + StructureSize
;
381 TotalSize
= sizeof (EFI_SMBIOS_ENTRY
) + RecordSize
;
384 // Allocate internal buffer
386 SmbiosEntry
= AllocateZeroPool (TotalSize
);
387 if (SmbiosEntry
== NULL
) {
388 EfiReleaseLock (&Private
->DataLock
);
389 return EFI_OUT_OF_RESOURCES
;
391 HandleEntry
= AllocateZeroPool (sizeof(SMBIOS_HANDLE_ENTRY
));
392 if (HandleEntry
== NULL
) {
393 EfiReleaseLock (&Private
->DataLock
);
394 return EFI_OUT_OF_RESOURCES
;
398 // Build Handle Entry and insert into linked list
400 HandleEntry
->Signature
= SMBIOS_HANDLE_ENTRY_SIGNATURE
;
401 HandleEntry
->SmbiosHandle
= *SmbiosHandle
;
402 InsertTailList(&Private
->AllocatedHandleListHead
, &HandleEntry
->Link
);
404 InternalRecord
= (EFI_SMBIOS_RECORD_HEADER
*) (SmbiosEntry
+ 1);
405 Raw
= (VOID
*) (InternalRecord
+ 1);
408 // Build internal record Header
410 InternalRecord
->Version
= EFI_SMBIOS_RECORD_HEADER_VERSION
;
411 InternalRecord
->HeaderSize
= (UINT16
) sizeof (EFI_SMBIOS_RECORD_HEADER
);
412 InternalRecord
->RecordSize
= RecordSize
;
413 InternalRecord
->ProducerHandle
= ProducerHandle
;
414 InternalRecord
->NumberOfStrings
= NumberOfStrings
;
416 // Insert record into the internal linked list
418 SmbiosEntry
->Signature
= EFI_SMBIOS_ENTRY_SIGNATURE
;
419 SmbiosEntry
->RecordHeader
= InternalRecord
;
420 SmbiosEntry
->RecordSize
= TotalSize
;
421 InsertTailList (&Private
->DataListHead
, &SmbiosEntry
->Link
);
423 CopyMem (Raw
, Record
, StructureSize
);
424 ((EFI_SMBIOS_TABLE_HEADER
*)Raw
)->Handle
= *SmbiosHandle
;
427 // Some UEFI drivers (such as network) need some information in SMBIOS table.
428 // Here we create SMBIOS table and publish it in
429 // configuration table, so other UEFI drivers can get SMBIOS table from
430 // configuration table without depending on PI SMBIOS protocol.
432 SmbiosTableConstruction ();
435 // Leave critical section
437 EfiReleaseLock (&Private
->DataLock
);
442 Update the string associated with an existing SMBIOS record.
444 @param This The EFI_SMBIOS_PROTOCOL instance.
445 @param SmbiosHandle SMBIOS Handle of structure that will have its string updated.
446 @param StringNumber The non-zero string number of the string to update
447 @param String Update the StringNumber string with String.
449 @retval EFI_SUCCESS SmbiosHandle had its StringNumber String updated.
450 @retval EFI_INVALID_PARAMETER SmbiosHandle does not exist.
451 @retval EFI_UNSUPPORTED String was not added because it is longer than the SMBIOS Table supports.
452 @retval EFI_NOT_FOUND The StringNumber.is not valid for this SMBIOS record.
458 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
459 IN EFI_SMBIOS_HANDLE
*SmbiosHandle
,
460 IN UINTN
*StringNumber
,
467 UINTN TargetStrOffset
;
474 SMBIOS_INSTANCE
*Private
;
475 EFI_SMBIOS_ENTRY
*SmbiosEntry
;
476 EFI_SMBIOS_ENTRY
*ResizedSmbiosEntry
;
477 EFI_SMBIOS_HANDLE MaxSmbiosHandle
;
478 EFI_SMBIOS_TABLE_HEADER
*Record
;
479 EFI_SMBIOS_RECORD_HEADER
*InternalRecord
;
482 // Check args validity
484 GetMaxSmbiosHandle(This
, &MaxSmbiosHandle
);
486 if (*SmbiosHandle
> MaxSmbiosHandle
) {
487 return EFI_INVALID_PARAMETER
;
490 if (String
== NULL
) {
494 if (*StringNumber
== 0) {
495 return EFI_NOT_FOUND
;
498 InputStrLen
= AsciiStrLen(String
);
500 if (This
->MajorVersion
< 2 || (This
->MajorVersion
== 2 && This
->MinorVersion
< 7)) {
501 if (InputStrLen
> SMBIOS_STRING_MAX_LENGTH
) {
502 return EFI_UNSUPPORTED
;
506 // Reference SMBIOS 2.7, chapter 6.1.3, it will have no limit on the length of each individual text string.
507 // However, the length of the entire structure table (including all strings) must be reported
508 // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,
509 // which is a WORD field limited to 65,535 bytes.
511 if (InputStrLen
> SMBIOS_TABLE_MAX_LENGTH
) {
512 return EFI_UNSUPPORTED
;
516 Private
= SMBIOS_INSTANCE_FROM_THIS (This
);
518 // Enter into critical section
520 Status
= EfiAcquireLockOrFail (&Private
->DataLock
);
521 if (EFI_ERROR (Status
)) {
525 Head
= &Private
->DataListHead
;
526 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
527 SmbiosEntry
= SMBIOS_ENTRY_FROM_LINK(Link
);
528 Record
= (EFI_SMBIOS_TABLE_HEADER
*)(SmbiosEntry
->RecordHeader
+ 1);
530 if (Record
->Handle
== *SmbiosHandle
) {
532 // Find out the specified SMBIOS record
534 if (*StringNumber
> SmbiosEntry
->RecordHeader
->NumberOfStrings
) {
535 EfiReleaseLock (&Private
->DataLock
);
536 return EFI_NOT_FOUND
;
539 // Point to unformed string section
541 StrStart
= (CHAR8
*) Record
+ Record
->Length
;
543 for (StrIndex
= 1, TargetStrOffset
= 0; StrIndex
< *StringNumber
; StrStart
++, TargetStrOffset
++) {
545 // A string ends in 00h
547 if (*StrStart
== 0) {
552 // String section ends in double-null (0000h)
554 if (*StrStart
== 0 && *(StrStart
+ 1) == 0) {
555 EfiReleaseLock (&Private
->DataLock
);
556 return EFI_NOT_FOUND
;
560 if (*StrStart
== 0) {
566 // Now we get the string target
568 TargetStrLen
= AsciiStrLen(StrStart
);
569 if (InputStrLen
== TargetStrLen
) {
570 AsciiStrCpy(StrStart
, String
);
572 // Some UEFI drivers (such as network) need some information in SMBIOS table.
573 // Here we create SMBIOS table and publish it in
574 // configuration table, so other UEFI drivers can get SMBIOS table from
575 // configuration table without depending on PI SMBIOS protocol.
577 SmbiosTableConstruction ();
578 EfiReleaseLock (&Private
->DataLock
);
582 if (EntryPointStructure
->TableLength
+ InputStrLen
- TargetStrLen
> SMBIOS_TABLE_MAX_LENGTH
) {
584 // The length of the entire structure table (including all strings) must be reported
585 // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,
586 // which is a WORD field limited to 65,535 bytes.
588 return EFI_UNSUPPORTED
;
592 // Original string buffer size is not exactly match input string length.
593 // Re-allocate buffer is needed.
595 NewEntrySize
= SmbiosEntry
->RecordSize
+ InputStrLen
- TargetStrLen
;
596 ResizedSmbiosEntry
= AllocateZeroPool (NewEntrySize
);
598 if (ResizedSmbiosEntry
== NULL
) {
599 EfiReleaseLock (&Private
->DataLock
);
600 return EFI_OUT_OF_RESOURCES
;
603 InternalRecord
= (EFI_SMBIOS_RECORD_HEADER
*) (ResizedSmbiosEntry
+ 1);
604 Raw
= (VOID
*) (InternalRecord
+ 1);
607 // Build internal record Header
609 InternalRecord
->Version
= EFI_SMBIOS_RECORD_HEADER_VERSION
;
610 InternalRecord
->HeaderSize
= (UINT16
) sizeof (EFI_SMBIOS_RECORD_HEADER
);
611 InternalRecord
->RecordSize
= SmbiosEntry
->RecordHeader
->RecordSize
+ InputStrLen
- TargetStrLen
;
612 InternalRecord
->ProducerHandle
= SmbiosEntry
->RecordHeader
->ProducerHandle
;
613 InternalRecord
->NumberOfStrings
= SmbiosEntry
->RecordHeader
->NumberOfStrings
;
616 // Copy SMBIOS structure and optional strings.
618 CopyMem (Raw
, SmbiosEntry
->RecordHeader
+ 1, Record
->Length
+ TargetStrOffset
);
619 CopyMem ((VOID
*)((UINTN
)Raw
+ Record
->Length
+ TargetStrOffset
), String
, InputStrLen
+ 1);
620 CopyMem ((CHAR8
*)((UINTN
)Raw
+ Record
->Length
+ TargetStrOffset
+ InputStrLen
+ 1),
621 (CHAR8
*)Record
+ Record
->Length
+ TargetStrOffset
+ TargetStrLen
+ 1,
622 SmbiosEntry
->RecordHeader
->RecordSize
- sizeof (EFI_SMBIOS_RECORD_HEADER
) - Record
->Length
- TargetStrOffset
- TargetStrLen
- 1);
627 ResizedSmbiosEntry
->Signature
= EFI_SMBIOS_ENTRY_SIGNATURE
;
628 ResizedSmbiosEntry
->RecordHeader
= InternalRecord
;
629 ResizedSmbiosEntry
->RecordSize
= NewEntrySize
;
630 InsertTailList (Link
->ForwardLink
, &ResizedSmbiosEntry
->Link
);
635 RemoveEntryList(Link
);
636 FreePool(SmbiosEntry
);
638 // Some UEFI drivers (such as network) need some information in SMBIOS table.
639 // Here we create SMBIOS table and publish it in
640 // configuration table, so other UEFI drivers can get SMBIOS table from
641 // configuration table without depending on PI SMBIOS protocol.
643 SmbiosTableConstruction ();
644 EfiReleaseLock (&Private
->DataLock
);
649 EfiReleaseLock (&Private
->DataLock
);
650 return EFI_INVALID_PARAMETER
;
654 Remove an SMBIOS record.
656 @param This The EFI_SMBIOS_PROTOCOL instance.
657 @param SmbiosHandle The handle of the SMBIOS record to remove.
659 @retval EFI_SUCCESS SMBIOS record was removed.
660 @retval EFI_INVALID_PARAMETER SmbiosHandle does not specify a valid SMBIOS record.
666 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
667 IN EFI_SMBIOS_HANDLE SmbiosHandle
673 EFI_SMBIOS_HANDLE MaxSmbiosHandle
;
674 SMBIOS_INSTANCE
*Private
;
675 EFI_SMBIOS_ENTRY
*SmbiosEntry
;
676 SMBIOS_HANDLE_ENTRY
*HandleEntry
;
677 EFI_SMBIOS_TABLE_HEADER
*Record
;
680 // Check args validity
682 GetMaxSmbiosHandle(This
, &MaxSmbiosHandle
);
684 if (SmbiosHandle
> MaxSmbiosHandle
) {
685 return EFI_INVALID_PARAMETER
;
688 Private
= SMBIOS_INSTANCE_FROM_THIS (This
);
690 // Enter into critical section
692 Status
= EfiAcquireLockOrFail (&Private
->DataLock
);
693 if (EFI_ERROR (Status
)) {
697 Head
= &Private
->DataListHead
;
698 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
699 SmbiosEntry
= SMBIOS_ENTRY_FROM_LINK(Link
);
700 Record
= (EFI_SMBIOS_TABLE_HEADER
*)(SmbiosEntry
->RecordHeader
+ 1);
701 if (Record
->Handle
== SmbiosHandle
) {
703 // Remove specified smobios record from DataList
705 RemoveEntryList(Link
);
706 FreePool(SmbiosEntry
);
708 // Remove this handle from AllocatedHandleList
710 Head
= &Private
->AllocatedHandleListHead
;
711 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
712 HandleEntry
= SMBIOS_HANDLE_ENTRY_FROM_LINK(Link
);
713 if (HandleEntry
->SmbiosHandle
== SmbiosHandle
) {
714 RemoveEntryList(Link
);
715 FreePool(HandleEntry
);
720 // Some UEFI drivers (such as network) need some information in SMBIOS table.
721 // Here we create SMBIOS table and publish it in
722 // configuration table, so other UEFI drivers can get SMBIOS table from
723 // configuration table without depending on PI SMBIOS protocol.
725 SmbiosTableConstruction ();
726 EfiReleaseLock (&Private
->DataLock
);
732 // Leave critical section
734 EfiReleaseLock (&Private
->DataLock
);
735 return EFI_INVALID_PARAMETER
;
740 Allow the caller to discover all or some of the SMBIOS records.
742 @param This The EFI_SMBIOS_PROTOCOL instance.
743 @param SmbiosHandle On entry, points to the previous handle of the SMBIOS record. On exit, points to the
744 next SMBIOS record handle. If it is FFFEh on entry, then the first SMBIOS record
745 handle will be returned. If it returns FFFEh on exit, then there are no more SMBIOS records.
746 @param Type On entry it means return the next SMBIOS record of type Type. If a NULL is passed in
747 this functionally it ignored. Type is not modified by the GetNext() function.
748 @param Record On exit, points to the SMBIOS Record consisting of the formatted area followed by
749 the unformatted area. The unformatted area optionally contains text strings.
750 @param ProducerHandle On exit, points to the ProducerHandle registered by Add(). If no ProducerHandle was passed into Add() NULL is returned.
751 If a NULL pointer is passed in no data will be returned
753 @retval EFI_SUCCESS SMBIOS record information was successfully returned in Record.
754 @retval EFI_NOT_FOUND The SMBIOS record with SmbiosHandle was the last available record.
760 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
761 IN OUT EFI_SMBIOS_HANDLE
*SmbiosHandle
,
762 IN EFI_SMBIOS_TYPE
*Type
, OPTIONAL
763 OUT EFI_SMBIOS_TABLE_HEADER
**Record
,
764 OUT EFI_HANDLE
*ProducerHandle OPTIONAL
767 BOOLEAN StartPointFound
;
770 SMBIOS_INSTANCE
*Private
;
771 EFI_SMBIOS_ENTRY
*SmbiosEntry
;
772 EFI_SMBIOS_TABLE_HEADER
*SmbiosTableHeader
;
774 if (SmbiosHandle
== NULL
) {
775 return EFI_INVALID_PARAMETER
;
778 StartPointFound
= FALSE
;
779 Private
= SMBIOS_INSTANCE_FROM_THIS (This
);
780 Head
= &Private
->DataListHead
;
781 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
782 SmbiosEntry
= SMBIOS_ENTRY_FROM_LINK(Link
);
783 SmbiosTableHeader
= (EFI_SMBIOS_TABLE_HEADER
*)(SmbiosEntry
->RecordHeader
+ 1);
786 // If SmbiosHandle is 0xFFFE, the first matched SMBIOS record handle will be returned
788 if (*SmbiosHandle
== SMBIOS_HANDLE_PI_RESERVED
) {
789 if ((Type
!= NULL
) && (*Type
!= SmbiosTableHeader
->Type
)) {
793 *SmbiosHandle
= SmbiosTableHeader
->Handle
;
794 *Record
=SmbiosTableHeader
;
795 if (ProducerHandle
!= NULL
) {
796 *ProducerHandle
= SmbiosEntry
->RecordHeader
->ProducerHandle
;
802 // Start this round search from the next SMBIOS handle
804 if (!StartPointFound
&& (*SmbiosHandle
== SmbiosTableHeader
->Handle
)) {
805 StartPointFound
= TRUE
;
809 if (StartPointFound
) {
810 if ((Type
!= NULL
) && (*Type
!= SmbiosTableHeader
->Type
)) {
814 *SmbiosHandle
= SmbiosTableHeader
->Handle
;
815 *Record
= SmbiosTableHeader
;
816 if (ProducerHandle
!= NULL
) {
817 *ProducerHandle
= SmbiosEntry
->RecordHeader
->ProducerHandle
;
824 *SmbiosHandle
= SMBIOS_HANDLE_PI_RESERVED
;
825 return EFI_NOT_FOUND
;
830 Allow the caller to discover all of the SMBIOS records.
832 @param This The EFI_SMBIOS_PROTOCOL instance.
833 @param CurrentSmbiosEntry On exit, points to the SMBIOS entry on the list which includes the returned SMBIOS record information.
834 If *CurrentSmbiosEntry is NULL on entry, then the first SMBIOS entry on the list will be returned.
835 @param Record On exit, points to the SMBIOS Record consisting of the formatted area followed by
836 the unformatted area. The unformatted area optionally contains text strings.
838 @retval EFI_SUCCESS SMBIOS record information was successfully returned in Record.
839 *CurrentSmbiosEntry points to the SMBIOS entry which includes the returned SMBIOS record information.
840 @retval EFI_NOT_FOUND There is no more SMBIOS entry.
845 GetNextSmbiosRecord (
846 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
847 IN OUT EFI_SMBIOS_ENTRY
**CurrentSmbiosEntry
,
848 OUT EFI_SMBIOS_TABLE_HEADER
**Record
853 SMBIOS_INSTANCE
*Private
;
854 EFI_SMBIOS_ENTRY
*SmbiosEntry
;
855 EFI_SMBIOS_TABLE_HEADER
*SmbiosTableHeader
;
857 Private
= SMBIOS_INSTANCE_FROM_THIS (This
);
858 if (*CurrentSmbiosEntry
== NULL
) {
860 // Get the beginning of SMBIOS entry.
862 Head
= &Private
->DataListHead
;
865 // Get previous SMBIOS entry and make it as start point.
867 Head
= &(*CurrentSmbiosEntry
)->Link
;
870 Link
= Head
->ForwardLink
;
872 if (Link
== &Private
->DataListHead
) {
874 // If no more SMBIOS entry in the list, return not found.
876 return EFI_NOT_FOUND
;
879 SmbiosEntry
= SMBIOS_ENTRY_FROM_LINK(Link
);
880 SmbiosTableHeader
= (EFI_SMBIOS_TABLE_HEADER
*)(SmbiosEntry
->RecordHeader
+ 1);
881 *Record
= SmbiosTableHeader
;
882 *CurrentSmbiosEntry
= SmbiosEntry
;
887 Assembles SMBIOS table from the SMBIOS protocol. Produce Table
888 Entry Point and return the pointer to it.
890 @param TableEntryPointStructure On exit, points to the SMBIOS entrypoint structure.
892 @retval EFI_SUCCESS Structure created sucessfully.
893 @retval EFI_NOT_READY Some of The SMBIOS records was not available yet.
894 @retval EFI_OUT_OF_RESOURCES No enough memory.
900 OUT VOID
**TableEntryPointStructure
903 UINT8
*BufferPointer
;
907 EFI_SMBIOS_HANDLE SmbiosHandle
;
908 EFI_SMBIOS_PROTOCOL
*SmbiosProtocol
;
909 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
910 EFI_SMBIOS_TABLE_HEADER
*SmbiosRecord
;
911 EFI_SMBIOS_TABLE_END_STRUCTURE EndStructure
;
912 EFI_SMBIOS_ENTRY
*CurrentSmbiosEntry
;
914 Status
= EFI_SUCCESS
;
915 BufferPointer
= NULL
;
918 // Get Smbios protocol to traverse SMBIOS records.
920 SmbiosProtocol
= &mPrivateData
.Smbios
;
923 // Make some statistics about all the structures
925 EntryPointStructure
->NumberOfSmbiosStructures
= 0;
926 EntryPointStructure
->TableLength
= 0;
927 EntryPointStructure
->MaxStructureSize
= 0;
930 // Calculate EPS Table Length
932 CurrentSmbiosEntry
= NULL
;
934 Status
= GetNextSmbiosRecord (SmbiosProtocol
, &CurrentSmbiosEntry
, &SmbiosRecord
);
936 if (Status
== EFI_SUCCESS
) {
937 GetSmbiosStructureSize(SmbiosProtocol
, SmbiosRecord
, &RecordSize
, &NumOfStr
);
939 // Record NumberOfSmbiosStructures, TableLength and MaxStructureSize
941 EntryPointStructure
->NumberOfSmbiosStructures
++;
942 EntryPointStructure
->TableLength
= (UINT16
) (EntryPointStructure
->TableLength
+ RecordSize
);
943 if (RecordSize
> EntryPointStructure
->MaxStructureSize
) {
944 EntryPointStructure
->MaxStructureSize
= (UINT16
) RecordSize
;
947 } while (!EFI_ERROR(Status
));
950 // Create End-Of-Table structure
952 GetMaxSmbiosHandle(SmbiosProtocol
, &SmbiosHandle
);
953 EndStructure
.Header
.Type
= EFI_SMBIOS_TYPE_END_OF_TABLE
;
954 EndStructure
.Header
.Length
= (UINT8
) sizeof (EFI_SMBIOS_TABLE_HEADER
);
955 EndStructure
.Header
.Handle
= SmbiosHandle
;
956 EndStructure
.Tailing
[0] = 0;
957 EndStructure
.Tailing
[1] = 0;
958 EntryPointStructure
->NumberOfSmbiosStructures
++;
959 EntryPointStructure
->TableLength
= (UINT16
) (EntryPointStructure
->TableLength
+ sizeof (EndStructure
));
960 if (sizeof (EndStructure
) > EntryPointStructure
->MaxStructureSize
) {
961 EntryPointStructure
->MaxStructureSize
= (UINT16
) sizeof (EndStructure
);
964 if ((UINTN
) EFI_SIZE_TO_PAGES (EntryPointStructure
->TableLength
) > mPreAllocatedPages
) {
966 // If new SMBIOS talbe size exceeds the original pre-allocated page,
967 // it is time to re-allocate memory (below 4GB).
969 if (EntryPointStructure
->TableAddress
!= 0) {
971 // Free the original pre-allocated page
974 (VOID
*)(UINTN
)EntryPointStructure
->TableAddress
,
977 EntryPointStructure
->TableAddress
= 0;
978 mPreAllocatedPages
= 0;
981 PhysicalAddress
= 0xffffffff;
982 Status
= gBS
->AllocatePages (
984 EfiRuntimeServicesData
,
985 EFI_SIZE_TO_PAGES (EntryPointStructure
->TableLength
),
988 if (EFI_ERROR (Status
)) {
989 DEBUG ((EFI_D_ERROR
, "SmbiosCreateTable() could not allocate SMBIOS table < 4GB\n"));
990 EntryPointStructure
->TableAddress
= 0;
991 return EFI_OUT_OF_RESOURCES
;
993 EntryPointStructure
->TableAddress
= (UINT32
) PhysicalAddress
;
994 mPreAllocatedPages
= EFI_SIZE_TO_PAGES (EntryPointStructure
->TableLength
);
999 // Assemble the tables
1001 ASSERT (EntryPointStructure
->TableAddress
!= 0);
1002 BufferPointer
= (UINT8
*) (UINTN
) EntryPointStructure
->TableAddress
;
1003 CurrentSmbiosEntry
= NULL
;
1005 Status
= GetNextSmbiosRecord (SmbiosProtocol
, &CurrentSmbiosEntry
, &SmbiosRecord
);
1007 if (Status
== EFI_SUCCESS
) {
1008 GetSmbiosStructureSize(SmbiosProtocol
, SmbiosRecord
, &RecordSize
, &NumOfStr
);
1009 CopyMem (BufferPointer
, SmbiosRecord
, RecordSize
);
1010 BufferPointer
= BufferPointer
+ RecordSize
;
1012 } while (!EFI_ERROR(Status
));
1015 // Assemble End-Of-Table structure
1017 CopyMem (BufferPointer
, &EndStructure
, sizeof (EndStructure
));
1020 // Fixup checksums in the Entry Point Structure
1022 EntryPointStructure
->IntermediateChecksum
= 0;
1023 EntryPointStructure
->EntryPointStructureChecksum
= 0;
1025 EntryPointStructure
->IntermediateChecksum
=
1026 CalculateCheckSum8 ((UINT8
*) EntryPointStructure
+ 0x10, EntryPointStructure
->EntryPointLength
- 0x10);
1027 EntryPointStructure
->EntryPointStructureChecksum
=
1028 CalculateCheckSum8 ((UINT8
*) EntryPointStructure
, EntryPointStructure
->EntryPointLength
);
1031 // Returns the pointer
1033 *TableEntryPointStructure
= EntryPointStructure
;
1039 Create SMBIOS Table and install it to the System Table.
1043 SmbiosTableConstruction (
1050 Status
= SmbiosCreateTable ((VOID
**) &Eps
);
1051 if (!EFI_ERROR (Status
)) {
1052 gBS
->InstallConfigurationTable (&gEfiSmbiosTableGuid
, Eps
);
1058 Driver to produce Smbios protocol and pre-allocate 1 page for the final SMBIOS table.
1060 @param ImageHandle Module's image handle
1061 @param SystemTable Pointer of EFI_SYSTEM_TABLE
1063 @retval EFI_SUCCESS Smbios protocol installed
1064 @retval Other No protocol installed, unload driver.
1069 SmbiosDriverEntryPoint (
1070 IN EFI_HANDLE ImageHandle
,
1071 IN EFI_SYSTEM_TABLE
*SystemTable
1075 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
1077 mPrivateData
.Signature
= SMBIOS_INSTANCE_SIGNATURE
;
1078 mPrivateData
.Smbios
.Add
= SmbiosAdd
;
1079 mPrivateData
.Smbios
.UpdateString
= SmbiosUpdateString
;
1080 mPrivateData
.Smbios
.Remove
= SmbiosRemove
;
1081 mPrivateData
.Smbios
.GetNext
= SmbiosGetNext
;
1082 mPrivateData
.Smbios
.MajorVersion
= (UINT8
) (FixedPcdGet16 (PcdSmbiosVersion
) >> 8);
1083 mPrivateData
.Smbios
.MinorVersion
= (UINT8
) (FixedPcdGet16 (PcdSmbiosVersion
) & 0x00ff);
1085 InitializeListHead (&mPrivateData
.DataListHead
);
1086 InitializeListHead (&mPrivateData
.AllocatedHandleListHead
);
1087 EfiInitializeLock (&mPrivateData
.DataLock
, TPL_NOTIFY
);
1090 // Initialize the EntryPointStructure with initial values.
1091 // Allocate memory (below 4GB).
1093 PhysicalAddress
= 0xffffffff;
1094 Status
= gBS
->AllocatePages (
1096 EfiRuntimeServicesData
,
1097 EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_ENTRY_POINT
)),
1100 if (EFI_ERROR (Status
)) {
1101 DEBUG ((EFI_D_ERROR
, "SmbiosDriverEntryPoint() could not allocate EntryPointStructure < 4GB\n"));
1102 Status
= gBS
->AllocatePages (
1104 EfiRuntimeServicesData
,
1105 EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_ENTRY_POINT
)),
1108 if (EFI_ERROR (Status
)) {
1109 return EFI_OUT_OF_RESOURCES
;
1113 EntryPointStructure
= (SMBIOS_TABLE_ENTRY_POINT
*) (UINTN
) PhysicalAddress
;
1116 EntryPointStructure
,
1117 &EntryPointStructureData
,
1118 sizeof (SMBIOS_TABLE_ENTRY_POINT
)
1122 // Pre-allocate 1 page for SMBIOS table below 4GB.
1123 // SMBIOS table will be updated when new SMBIOS type is added or
1124 // existing SMBIOS type is updated. If the total size of SMBIOS table exceeds 1 page,
1125 // we will re-allocate new memory when creating whole SMBIOS table.
1127 PhysicalAddress
= 0xffffffff;
1128 Status
= gBS
->AllocatePages (
1130 EfiRuntimeServicesData
,
1134 if (EFI_ERROR (Status
)) {
1135 DEBUG ((EFI_D_ERROR
, "SmbiosDriverEntryPoint() could not allocate SMBIOS table < 4GB\n"));
1136 EntryPointStructure
->TableAddress
= 0;
1138 EntryPointStructure
->TableAddress
= (UINT32
) PhysicalAddress
;
1139 mPreAllocatedPages
= 1;
1143 // Init TableLength to the length of End-Of-Table structure for SmbiosAdd() called at the first time
1144 // to check the TableLength limitation.
1146 EntryPointStructure
->TableLength
= sizeof (EFI_SMBIOS_TABLE_END_STRUCTURE
);
1149 // Make a new handle and install the protocol
1151 mPrivateData
.Handle
= NULL
;
1152 Status
= gBS
->InstallProtocolInterface (
1153 &mPrivateData
.Handle
,
1154 &gEfiSmbiosProtocolGuid
,
1155 EFI_NATIVE_INTERFACE
,
1156 &mPrivateData
.Smbios