2 This code produces the Smbios protocol. It also responsible for constructing
3 SMBIOS table into system table.
5 Copyright (c) 2009 - 2014, 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
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
111 Get the full size of SMBIOS structure including optional strings that follow the formatted structure.
113 @param This The EFI_SMBIOS_PROTOCOL instance.
114 @param Head Pointer to the beginning of SMBIOS structure.
115 @param Size The returned size.
116 @param NumberOfStrings The returned number of optional strings that follow the formatted structure.
118 @retval EFI_SUCCESS Size retured in Size.
119 @retval EFI_INVALID_PARAMETER Input SMBIOS structure mal-formed or Size is NULL.
124 GetSmbiosStructureSize (
125 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
126 IN EFI_SMBIOS_TABLE_HEADER
*Head
,
128 OUT UINTN
*NumberOfStrings
136 if (Size
== NULL
|| NumberOfStrings
== NULL
) {
137 return EFI_INVALID_PARAMETER
;
140 FullSize
= Head
->Length
;
141 CharInStr
= (INT8
*)Head
+ Head
->Length
;
143 *NumberOfStrings
= 0;
146 // look for the two consecutive zeros, check the string limit by the way.
148 while (*CharInStr
!= 0 || *(CharInStr
+1) != 0) {
149 if (*CharInStr
== 0) {
154 if (This
->MajorVersion
< 2 || (This
->MajorVersion
== 2 && This
->MinorVersion
< 7)){
155 MaxLen
= SMBIOS_STRING_MAX_LENGTH
;
158 // Reference SMBIOS 2.7, chapter 6.1.3, it will have no limit on the length of each individual text string.
159 // However, the length of the entire structure table (including all strings) must be reported
160 // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,
161 // which is a WORD field limited to 65,535 bytes.
163 MaxLen
= SMBIOS_TABLE_MAX_LENGTH
;
166 for (StrLen
= 0 ; StrLen
< MaxLen
; StrLen
++) {
167 if (*(CharInStr
+StrLen
) == 0) {
172 if (StrLen
== MaxLen
) {
173 return EFI_INVALID_PARAMETER
;
177 // forward the pointer
181 *NumberOfStrings
+= 1;
185 // count ending two zeros.
193 Determin whether an SmbiosHandle has already in use.
195 @param Head Pointer to the beginning of SMBIOS structure.
196 @param Handle A unique handle will be assigned to the SMBIOS record.
198 @retval TRUE Smbios handle already in use.
199 @retval FALSE Smbios handle is NOT used.
204 CheckSmbiosHandleExistance (
206 IN EFI_SMBIOS_HANDLE Handle
210 SMBIOS_HANDLE_ENTRY
*HandleEntry
;
212 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
213 HandleEntry
= SMBIOS_HANDLE_ENTRY_FROM_LINK(Link
);
214 if (HandleEntry
->SmbiosHandle
== Handle
) {
224 Get the max SmbiosHandle that could be use.
226 @param This The EFI_SMBIOS_PROTOCOL instance.
227 @param MaxHandle The max handle that could be assigned to the SMBIOS record.
233 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
234 IN OUT EFI_SMBIOS_HANDLE
*MaxHandle
237 if (This
->MajorVersion
== 2 && This
->MinorVersion
== 0) {
246 Get an SmbiosHandle that could use.
248 @param This The EFI_SMBIOS_PROTOCOL instance.
249 @param SmbiosHandle A unique handle will be assigned to the SMBIOS record.
251 @retval EFI_SUCCESS Smbios handle got.
252 @retval EFI_OUT_OF_RESOURCES Smbios handle is NOT available.
257 GetAvailableSmbiosHandle (
258 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
259 IN OUT EFI_SMBIOS_HANDLE
*Handle
263 SMBIOS_INSTANCE
*Private
;
264 EFI_SMBIOS_HANDLE MaxSmbiosHandle
;
265 EFI_SMBIOS_HANDLE AvailableHandle
;
267 GetMaxSmbiosHandle(This
, &MaxSmbiosHandle
);
269 Private
= SMBIOS_INSTANCE_FROM_THIS (This
);
270 Head
= &Private
->AllocatedHandleListHead
;
271 for (AvailableHandle
= 0; AvailableHandle
< MaxSmbiosHandle
; AvailableHandle
++) {
272 if (!CheckSmbiosHandleExistance(Head
, AvailableHandle
)) {
273 *Handle
= AvailableHandle
;
278 return EFI_OUT_OF_RESOURCES
;
283 Add an SMBIOS record.
285 @param This The EFI_SMBIOS_PROTOCOL instance.
286 @param ProducerHandle The handle of the controller or driver associated with the SMBIOS information. NULL
288 @param SmbiosHandle On entry, the handle of the SMBIOS record to add. If FFFEh, then a unique handle
289 will be assigned to the SMBIOS record. If the SMBIOS handle is already in use,
290 EFI_ALREADY_STARTED is returned and the SMBIOS record is not updated.
291 @param Record The data for the fixed portion of the SMBIOS record. The format of the record is
292 determined by EFI_SMBIOS_TABLE_HEADER.Type. The size of the formatted area is defined
293 by EFI_SMBIOS_TABLE_HEADER.Length and either followed by a double-null (0x0000) or
294 a set of null terminated strings and a null.
296 @retval EFI_SUCCESS Record was added.
297 @retval EFI_OUT_OF_RESOURCES Record was not added due to lack of system resources.
298 @retval EFI_ALREADY_STARTED The SmbiosHandle passed in was already in use.
304 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
305 IN EFI_HANDLE ProducerHandle
, OPTIONAL
306 IN OUT EFI_SMBIOS_HANDLE
*SmbiosHandle
,
307 IN EFI_SMBIOS_TABLE_HEADER
*Record
314 UINTN NumberOfStrings
;
317 SMBIOS_INSTANCE
*Private
;
318 EFI_SMBIOS_ENTRY
*SmbiosEntry
;
319 EFI_SMBIOS_HANDLE MaxSmbiosHandle
;
320 SMBIOS_HANDLE_ENTRY
*HandleEntry
;
321 EFI_SMBIOS_RECORD_HEADER
*InternalRecord
;
323 if (SmbiosHandle
== NULL
) {
324 return EFI_INVALID_PARAMETER
;
327 Private
= SMBIOS_INSTANCE_FROM_THIS (This
);
329 // Check whether SmbiosHandle is already in use
331 Head
= &Private
->AllocatedHandleListHead
;
332 if (*SmbiosHandle
!= SMBIOS_HANDLE_PI_RESERVED
&& CheckSmbiosHandleExistance(Head
, *SmbiosHandle
)) {
333 return EFI_ALREADY_STARTED
;
337 // when SmbiosHandle is 0xFFFE, an available handle will be assigned
339 if (*SmbiosHandle
== SMBIOS_HANDLE_PI_RESERVED
) {
340 Status
= GetAvailableSmbiosHandle(This
, SmbiosHandle
);
341 if (EFI_ERROR(Status
)) {
346 // Check this handle validity
348 GetMaxSmbiosHandle(This
, &MaxSmbiosHandle
);
349 if (*SmbiosHandle
> MaxSmbiosHandle
) {
350 return EFI_INVALID_PARAMETER
;
355 // Calculate record size and string number
357 Status
= GetSmbiosStructureSize(This
, Record
, &StructureSize
, &NumberOfStrings
);
358 if (EFI_ERROR(Status
)) {
362 if (EntryPointStructure
->TableLength
+ StructureSize
> SMBIOS_TABLE_MAX_LENGTH
) {
364 // The length of the entire structure table (including all strings) must be reported
365 // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,
366 // which is a WORD field limited to 65,535 bytes.
368 return EFI_OUT_OF_RESOURCES
;
372 // Enter into critical section
374 Status
= EfiAcquireLockOrFail (&Private
->DataLock
);
375 if (EFI_ERROR (Status
)) {
379 RecordSize
= sizeof (EFI_SMBIOS_RECORD_HEADER
) + StructureSize
;
380 TotalSize
= sizeof (EFI_SMBIOS_ENTRY
) + RecordSize
;
383 // Allocate internal buffer
385 SmbiosEntry
= AllocateZeroPool (TotalSize
);
386 if (SmbiosEntry
== NULL
) {
387 EfiReleaseLock (&Private
->DataLock
);
388 return EFI_OUT_OF_RESOURCES
;
390 HandleEntry
= AllocateZeroPool (sizeof(SMBIOS_HANDLE_ENTRY
));
391 if (HandleEntry
== NULL
) {
392 EfiReleaseLock (&Private
->DataLock
);
393 return EFI_OUT_OF_RESOURCES
;
397 // Build Handle Entry and insert into linked list
399 HandleEntry
->Signature
= SMBIOS_HANDLE_ENTRY_SIGNATURE
;
400 HandleEntry
->SmbiosHandle
= *SmbiosHandle
;
401 InsertTailList(&Private
->AllocatedHandleListHead
, &HandleEntry
->Link
);
403 InternalRecord
= (EFI_SMBIOS_RECORD_HEADER
*) (SmbiosEntry
+ 1);
404 Raw
= (VOID
*) (InternalRecord
+ 1);
407 // Build internal record Header
409 InternalRecord
->Version
= EFI_SMBIOS_RECORD_HEADER_VERSION
;
410 InternalRecord
->HeaderSize
= (UINT16
) sizeof (EFI_SMBIOS_RECORD_HEADER
);
411 InternalRecord
->RecordSize
= RecordSize
;
412 InternalRecord
->ProducerHandle
= ProducerHandle
;
413 InternalRecord
->NumberOfStrings
= NumberOfStrings
;
415 // Insert record into the internal linked list
417 SmbiosEntry
->Signature
= EFI_SMBIOS_ENTRY_SIGNATURE
;
418 SmbiosEntry
->RecordHeader
= InternalRecord
;
419 SmbiosEntry
->RecordSize
= TotalSize
;
420 InsertTailList (&Private
->DataListHead
, &SmbiosEntry
->Link
);
422 CopyMem (Raw
, Record
, StructureSize
);
423 ((EFI_SMBIOS_TABLE_HEADER
*)Raw
)->Handle
= *SmbiosHandle
;
426 // Some UEFI drivers (such as network) need some information in SMBIOS table.
427 // Here we create SMBIOS table and publish it in
428 // configuration table, so other UEFI drivers can get SMBIOS table from
429 // configuration table without depending on PI SMBIOS protocol.
431 SmbiosTableConstruction ();
434 // Leave critical section
436 EfiReleaseLock (&Private
->DataLock
);
441 Update the string associated with an existing SMBIOS record.
443 @param This The EFI_SMBIOS_PROTOCOL instance.
444 @param SmbiosHandle SMBIOS Handle of structure that will have its string updated.
445 @param StringNumber The non-zero string number of the string to update
446 @param String Update the StringNumber string with String.
448 @retval EFI_SUCCESS SmbiosHandle had its StringNumber String updated.
449 @retval EFI_INVALID_PARAMETER SmbiosHandle does not exist.
450 @retval EFI_UNSUPPORTED String was not added because it is longer than the SMBIOS Table supports.
451 @retval EFI_NOT_FOUND The StringNumber.is not valid for this SMBIOS record.
457 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
458 IN EFI_SMBIOS_HANDLE
*SmbiosHandle
,
459 IN UINTN
*StringNumber
,
466 UINTN TargetStrOffset
;
473 SMBIOS_INSTANCE
*Private
;
474 EFI_SMBIOS_ENTRY
*SmbiosEntry
;
475 EFI_SMBIOS_ENTRY
*ResizedSmbiosEntry
;
476 EFI_SMBIOS_HANDLE MaxSmbiosHandle
;
477 EFI_SMBIOS_TABLE_HEADER
*Record
;
478 EFI_SMBIOS_RECORD_HEADER
*InternalRecord
;
481 // Check args validity
483 GetMaxSmbiosHandle(This
, &MaxSmbiosHandle
);
485 if (*SmbiosHandle
> MaxSmbiosHandle
) {
486 return EFI_INVALID_PARAMETER
;
489 if (String
== NULL
) {
493 if (*StringNumber
== 0) {
494 return EFI_NOT_FOUND
;
497 InputStrLen
= AsciiStrLen(String
);
499 if (This
->MajorVersion
< 2 || (This
->MajorVersion
== 2 && This
->MinorVersion
< 7)) {
500 if (InputStrLen
> SMBIOS_STRING_MAX_LENGTH
) {
501 return EFI_UNSUPPORTED
;
505 // Reference SMBIOS 2.7, chapter 6.1.3, it will have no limit on the length of each individual text string.
506 // However, the length of the entire structure table (including all strings) must be reported
507 // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,
508 // which is a WORD field limited to 65,535 bytes.
510 if (InputStrLen
> SMBIOS_TABLE_MAX_LENGTH
) {
511 return EFI_UNSUPPORTED
;
515 Private
= SMBIOS_INSTANCE_FROM_THIS (This
);
517 // Enter into critical section
519 Status
= EfiAcquireLockOrFail (&Private
->DataLock
);
520 if (EFI_ERROR (Status
)) {
524 Head
= &Private
->DataListHead
;
525 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
526 SmbiosEntry
= SMBIOS_ENTRY_FROM_LINK(Link
);
527 Record
= (EFI_SMBIOS_TABLE_HEADER
*)(SmbiosEntry
->RecordHeader
+ 1);
529 if (Record
->Handle
== *SmbiosHandle
) {
531 // Find out the specified SMBIOS record
533 if (*StringNumber
> SmbiosEntry
->RecordHeader
->NumberOfStrings
) {
534 EfiReleaseLock (&Private
->DataLock
);
535 return EFI_NOT_FOUND
;
538 // Point to unformed string section
540 StrStart
= (CHAR8
*) Record
+ Record
->Length
;
542 for (StrIndex
= 1, TargetStrOffset
= 0; StrIndex
< *StringNumber
; StrStart
++, TargetStrOffset
++) {
544 // A string ends in 00h
546 if (*StrStart
== 0) {
551 // String section ends in double-null (0000h)
553 if (*StrStart
== 0 && *(StrStart
+ 1) == 0) {
554 EfiReleaseLock (&Private
->DataLock
);
555 return EFI_NOT_FOUND
;
559 if (*StrStart
== 0) {
565 // Now we get the string target
567 TargetStrLen
= AsciiStrLen(StrStart
);
568 if (InputStrLen
== TargetStrLen
) {
569 AsciiStrCpy(StrStart
, String
);
571 // Some UEFI drivers (such as network) need some information in SMBIOS table.
572 // Here we create SMBIOS table and publish it in
573 // configuration table, so other UEFI drivers can get SMBIOS table from
574 // configuration table without depending on PI SMBIOS protocol.
576 SmbiosTableConstruction ();
577 EfiReleaseLock (&Private
->DataLock
);
581 if (EntryPointStructure
->TableLength
+ InputStrLen
- TargetStrLen
> SMBIOS_TABLE_MAX_LENGTH
) {
583 // The length of the entire structure table (including all strings) must be reported
584 // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,
585 // which is a WORD field limited to 65,535 bytes.
587 return EFI_UNSUPPORTED
;
591 // Original string buffer size is not exactly match input string length.
592 // Re-allocate buffer is needed.
594 NewEntrySize
= SmbiosEntry
->RecordSize
+ InputStrLen
- TargetStrLen
;
595 ResizedSmbiosEntry
= AllocateZeroPool (NewEntrySize
);
597 if (ResizedSmbiosEntry
== NULL
) {
598 EfiReleaseLock (&Private
->DataLock
);
599 return EFI_OUT_OF_RESOURCES
;
602 InternalRecord
= (EFI_SMBIOS_RECORD_HEADER
*) (ResizedSmbiosEntry
+ 1);
603 Raw
= (VOID
*) (InternalRecord
+ 1);
606 // Build internal record Header
608 InternalRecord
->Version
= EFI_SMBIOS_RECORD_HEADER_VERSION
;
609 InternalRecord
->HeaderSize
= (UINT16
) sizeof (EFI_SMBIOS_RECORD_HEADER
);
610 InternalRecord
->RecordSize
= SmbiosEntry
->RecordHeader
->RecordSize
+ InputStrLen
- TargetStrLen
;
611 InternalRecord
->ProducerHandle
= SmbiosEntry
->RecordHeader
->ProducerHandle
;
612 InternalRecord
->NumberOfStrings
= SmbiosEntry
->RecordHeader
->NumberOfStrings
;
615 // Copy SMBIOS structure and optional strings.
617 CopyMem (Raw
, SmbiosEntry
->RecordHeader
+ 1, Record
->Length
+ TargetStrOffset
);
618 CopyMem ((VOID
*)((UINTN
)Raw
+ Record
->Length
+ TargetStrOffset
), String
, InputStrLen
+ 1);
619 CopyMem ((CHAR8
*)((UINTN
)Raw
+ Record
->Length
+ TargetStrOffset
+ InputStrLen
+ 1),
620 (CHAR8
*)Record
+ Record
->Length
+ TargetStrOffset
+ TargetStrLen
+ 1,
621 SmbiosEntry
->RecordHeader
->RecordSize
- sizeof (EFI_SMBIOS_RECORD_HEADER
) - Record
->Length
- TargetStrOffset
- TargetStrLen
- 1);
626 ResizedSmbiosEntry
->Signature
= EFI_SMBIOS_ENTRY_SIGNATURE
;
627 ResizedSmbiosEntry
->RecordHeader
= InternalRecord
;
628 ResizedSmbiosEntry
->RecordSize
= NewEntrySize
;
629 InsertTailList (Link
->ForwardLink
, &ResizedSmbiosEntry
->Link
);
634 RemoveEntryList(Link
);
635 FreePool(SmbiosEntry
);
637 // Some UEFI drivers (such as network) need some information in SMBIOS table.
638 // Here we create SMBIOS table and publish it in
639 // configuration table, so other UEFI drivers can get SMBIOS table from
640 // configuration table without depending on PI SMBIOS protocol.
642 SmbiosTableConstruction ();
643 EfiReleaseLock (&Private
->DataLock
);
648 EfiReleaseLock (&Private
->DataLock
);
649 return EFI_INVALID_PARAMETER
;
653 Remove an SMBIOS record.
655 @param This The EFI_SMBIOS_PROTOCOL instance.
656 @param SmbiosHandle The handle of the SMBIOS record to remove.
658 @retval EFI_SUCCESS SMBIOS record was removed.
659 @retval EFI_INVALID_PARAMETER SmbiosHandle does not specify a valid SMBIOS record.
665 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
666 IN EFI_SMBIOS_HANDLE SmbiosHandle
672 EFI_SMBIOS_HANDLE MaxSmbiosHandle
;
673 SMBIOS_INSTANCE
*Private
;
674 EFI_SMBIOS_ENTRY
*SmbiosEntry
;
675 SMBIOS_HANDLE_ENTRY
*HandleEntry
;
676 EFI_SMBIOS_TABLE_HEADER
*Record
;
679 // Check args validity
681 GetMaxSmbiosHandle(This
, &MaxSmbiosHandle
);
683 if (SmbiosHandle
> MaxSmbiosHandle
) {
684 return EFI_INVALID_PARAMETER
;
687 Private
= SMBIOS_INSTANCE_FROM_THIS (This
);
689 // Enter into critical section
691 Status
= EfiAcquireLockOrFail (&Private
->DataLock
);
692 if (EFI_ERROR (Status
)) {
696 Head
= &Private
->DataListHead
;
697 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
698 SmbiosEntry
= SMBIOS_ENTRY_FROM_LINK(Link
);
699 Record
= (EFI_SMBIOS_TABLE_HEADER
*)(SmbiosEntry
->RecordHeader
+ 1);
700 if (Record
->Handle
== SmbiosHandle
) {
702 // Remove specified smobios record from DataList
704 RemoveEntryList(Link
);
705 FreePool(SmbiosEntry
);
707 // Remove this handle from AllocatedHandleList
709 Head
= &Private
->AllocatedHandleListHead
;
710 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
711 HandleEntry
= SMBIOS_HANDLE_ENTRY_FROM_LINK(Link
);
712 if (HandleEntry
->SmbiosHandle
== SmbiosHandle
) {
713 RemoveEntryList(Link
);
714 FreePool(HandleEntry
);
719 // Some UEFI drivers (such as network) need some information in SMBIOS table.
720 // Here we create SMBIOS table and publish it in
721 // configuration table, so other UEFI drivers can get SMBIOS table from
722 // configuration table without depending on PI SMBIOS protocol.
724 SmbiosTableConstruction ();
725 EfiReleaseLock (&Private
->DataLock
);
731 // Leave critical section
733 EfiReleaseLock (&Private
->DataLock
);
734 return EFI_INVALID_PARAMETER
;
739 Allow the caller to discover all or some of the SMBIOS records.
741 @param This The EFI_SMBIOS_PROTOCOL instance.
742 @param SmbiosHandle On entry, points to the previous handle of the SMBIOS record. On exit, points to the
743 next SMBIOS record handle. If it is FFFEh on entry, then the first SMBIOS record
744 handle will be returned. If it returns FFFEh on exit, then there are no more SMBIOS records.
745 @param Type On entry it means return the next SMBIOS record of type Type. If a NULL is passed in
746 this functionally it ignored. Type is not modified by the GetNext() function.
747 @param Record On exit, points to the SMBIOS Record consisting of the formatted area followed by
748 the unformatted area. The unformatted area optionally contains text strings.
749 @param ProducerHandle On exit, points to the ProducerHandle registered by Add(). If no ProducerHandle was passed into Add() NULL is returned.
750 If a NULL pointer is passed in no data will be returned
752 @retval EFI_SUCCESS SMBIOS record information was successfully returned in Record.
753 @retval EFI_NOT_FOUND The SMBIOS record with SmbiosHandle was the last available record.
759 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
760 IN OUT EFI_SMBIOS_HANDLE
*SmbiosHandle
,
761 IN EFI_SMBIOS_TYPE
*Type
, OPTIONAL
762 OUT EFI_SMBIOS_TABLE_HEADER
**Record
,
763 OUT EFI_HANDLE
*ProducerHandle OPTIONAL
766 BOOLEAN StartPointFound
;
769 SMBIOS_INSTANCE
*Private
;
770 EFI_SMBIOS_ENTRY
*SmbiosEntry
;
771 EFI_SMBIOS_TABLE_HEADER
*SmbiosTableHeader
;
773 if (SmbiosHandle
== NULL
) {
774 return EFI_INVALID_PARAMETER
;
777 StartPointFound
= FALSE
;
778 Private
= SMBIOS_INSTANCE_FROM_THIS (This
);
779 Head
= &Private
->DataListHead
;
780 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
781 SmbiosEntry
= SMBIOS_ENTRY_FROM_LINK(Link
);
782 SmbiosTableHeader
= (EFI_SMBIOS_TABLE_HEADER
*)(SmbiosEntry
->RecordHeader
+ 1);
785 // If SmbiosHandle is 0xFFFE, the first matched SMBIOS record handle will be returned
787 if (*SmbiosHandle
== SMBIOS_HANDLE_PI_RESERVED
) {
788 if ((Type
!= NULL
) && (*Type
!= SmbiosTableHeader
->Type
)) {
792 *SmbiosHandle
= SmbiosTableHeader
->Handle
;
793 *Record
=SmbiosTableHeader
;
794 if (ProducerHandle
!= NULL
) {
795 *ProducerHandle
= SmbiosEntry
->RecordHeader
->ProducerHandle
;
801 // Start this round search from the next SMBIOS handle
803 if (!StartPointFound
&& (*SmbiosHandle
== SmbiosTableHeader
->Handle
)) {
804 StartPointFound
= TRUE
;
808 if (StartPointFound
) {
809 if ((Type
!= NULL
) && (*Type
!= SmbiosTableHeader
->Type
)) {
813 *SmbiosHandle
= SmbiosTableHeader
->Handle
;
814 *Record
= SmbiosTableHeader
;
815 if (ProducerHandle
!= NULL
) {
816 *ProducerHandle
= SmbiosEntry
->RecordHeader
->ProducerHandle
;
823 *SmbiosHandle
= SMBIOS_HANDLE_PI_RESERVED
;
824 return EFI_NOT_FOUND
;
829 Allow the caller to discover all of the SMBIOS records.
831 @param This The EFI_SMBIOS_PROTOCOL instance.
832 @param CurrentSmbiosEntry On exit, points to the SMBIOS entry on the list which includes the returned SMBIOS record information.
833 If *CurrentSmbiosEntry is NULL on entry, then the first SMBIOS entry on the list will be returned.
834 @param Record On exit, points to the SMBIOS Record consisting of the formatted area followed by
835 the unformatted area. The unformatted area optionally contains text strings.
837 @retval EFI_SUCCESS SMBIOS record information was successfully returned in Record.
838 *CurrentSmbiosEntry points to the SMBIOS entry which includes the returned SMBIOS record information.
839 @retval EFI_NOT_FOUND There is no more SMBIOS entry.
844 GetNextSmbiosRecord (
845 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
846 IN OUT EFI_SMBIOS_ENTRY
**CurrentSmbiosEntry
,
847 OUT EFI_SMBIOS_TABLE_HEADER
**Record
852 SMBIOS_INSTANCE
*Private
;
853 EFI_SMBIOS_ENTRY
*SmbiosEntry
;
854 EFI_SMBIOS_TABLE_HEADER
*SmbiosTableHeader
;
856 Private
= SMBIOS_INSTANCE_FROM_THIS (This
);
857 if (*CurrentSmbiosEntry
== NULL
) {
859 // Get the beginning of SMBIOS entry.
861 Head
= &Private
->DataListHead
;
864 // Get previous SMBIOS entry and make it as start point.
866 Head
= &(*CurrentSmbiosEntry
)->Link
;
869 Link
= Head
->ForwardLink
;
871 if (Link
== &Private
->DataListHead
) {
873 // If no more SMBIOS entry in the list, return not found.
875 return EFI_NOT_FOUND
;
878 SmbiosEntry
= SMBIOS_ENTRY_FROM_LINK(Link
);
879 SmbiosTableHeader
= (EFI_SMBIOS_TABLE_HEADER
*)(SmbiosEntry
->RecordHeader
+ 1);
880 *Record
= SmbiosTableHeader
;
881 *CurrentSmbiosEntry
= SmbiosEntry
;
886 Assembles SMBIOS table from the SMBIOS protocol. Produce Table
887 Entry Point and return the pointer to it.
889 @param TableEntryPointStructure On exit, points to the SMBIOS entrypoint structure.
891 @retval EFI_SUCCESS Structure created sucessfully.
892 @retval EFI_NOT_READY Some of The SMBIOS records was not available yet.
893 @retval EFI_OUT_OF_RESOURCES No enough memory.
899 OUT VOID
**TableEntryPointStructure
902 UINT8
*BufferPointer
;
906 EFI_SMBIOS_HANDLE SmbiosHandle
;
907 EFI_SMBIOS_PROTOCOL
*SmbiosProtocol
;
908 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
909 EFI_SMBIOS_TABLE_HEADER
*SmbiosRecord
;
910 EFI_SMBIOS_TABLE_END_STRUCTURE EndStructure
;
911 EFI_SMBIOS_ENTRY
*CurrentSmbiosEntry
;
913 Status
= EFI_SUCCESS
;
914 BufferPointer
= NULL
;
917 // Get Smbios protocol to traverse SMBIOS records.
919 SmbiosProtocol
= &mPrivateData
.Smbios
;
922 // Make some statistics about all the structures
924 EntryPointStructure
->NumberOfSmbiosStructures
= 0;
925 EntryPointStructure
->TableLength
= 0;
926 EntryPointStructure
->MaxStructureSize
= 0;
929 // Calculate EPS Table Length
931 CurrentSmbiosEntry
= NULL
;
933 Status
= GetNextSmbiosRecord (SmbiosProtocol
, &CurrentSmbiosEntry
, &SmbiosRecord
);
935 if (Status
== EFI_SUCCESS
) {
936 GetSmbiosStructureSize(SmbiosProtocol
, SmbiosRecord
, &RecordSize
, &NumOfStr
);
938 // Record NumberOfSmbiosStructures, TableLength and MaxStructureSize
940 EntryPointStructure
->NumberOfSmbiosStructures
++;
941 EntryPointStructure
->TableLength
= (UINT16
) (EntryPointStructure
->TableLength
+ RecordSize
);
942 if (RecordSize
> EntryPointStructure
->MaxStructureSize
) {
943 EntryPointStructure
->MaxStructureSize
= (UINT16
) RecordSize
;
946 } while (!EFI_ERROR(Status
));
949 // Create End-Of-Table structure
951 GetMaxSmbiosHandle(SmbiosProtocol
, &SmbiosHandle
);
952 EndStructure
.Header
.Type
= EFI_SMBIOS_TYPE_END_OF_TABLE
;
953 EndStructure
.Header
.Length
= (UINT8
) sizeof (EFI_SMBIOS_TABLE_HEADER
);
954 EndStructure
.Header
.Handle
= SmbiosHandle
;
955 EndStructure
.Tailing
[0] = 0;
956 EndStructure
.Tailing
[1] = 0;
957 EntryPointStructure
->NumberOfSmbiosStructures
++;
958 EntryPointStructure
->TableLength
= (UINT16
) (EntryPointStructure
->TableLength
+ sizeof (EndStructure
));
959 if (sizeof (EndStructure
) > EntryPointStructure
->MaxStructureSize
) {
960 EntryPointStructure
->MaxStructureSize
= (UINT16
) sizeof (EndStructure
);
963 if ((UINTN
) EFI_SIZE_TO_PAGES (EntryPointStructure
->TableLength
) > mPreAllocatedPages
) {
965 // If new SMBIOS talbe size exceeds the original pre-allocated page,
966 // it is time to re-allocate memory (below 4GB).
968 if (EntryPointStructure
->TableAddress
!= 0) {
970 // Free the original pre-allocated page
973 (VOID
*)(UINTN
)EntryPointStructure
->TableAddress
,
976 EntryPointStructure
->TableAddress
= 0;
977 mPreAllocatedPages
= 0;
980 PhysicalAddress
= 0xffffffff;
981 Status
= gBS
->AllocatePages (
983 EfiRuntimeServicesData
,
984 EFI_SIZE_TO_PAGES (EntryPointStructure
->TableLength
),
987 if (EFI_ERROR (Status
)) {
988 DEBUG ((EFI_D_ERROR
, "SmbiosCreateTable() could not allocate SMBIOS table < 4GB\n"));
989 EntryPointStructure
->TableAddress
= 0;
990 return EFI_OUT_OF_RESOURCES
;
992 EntryPointStructure
->TableAddress
= (UINT32
) PhysicalAddress
;
993 mPreAllocatedPages
= EFI_SIZE_TO_PAGES (EntryPointStructure
->TableLength
);
998 // Assemble the tables
1000 ASSERT (EntryPointStructure
->TableAddress
!= 0);
1001 BufferPointer
= (UINT8
*) (UINTN
) EntryPointStructure
->TableAddress
;
1002 CurrentSmbiosEntry
= NULL
;
1004 Status
= GetNextSmbiosRecord (SmbiosProtocol
, &CurrentSmbiosEntry
, &SmbiosRecord
);
1006 if (Status
== EFI_SUCCESS
) {
1007 GetSmbiosStructureSize(SmbiosProtocol
, SmbiosRecord
, &RecordSize
, &NumOfStr
);
1008 CopyMem (BufferPointer
, SmbiosRecord
, RecordSize
);
1009 BufferPointer
= BufferPointer
+ RecordSize
;
1011 } while (!EFI_ERROR(Status
));
1014 // Assemble End-Of-Table structure
1016 CopyMem (BufferPointer
, &EndStructure
, sizeof (EndStructure
));
1019 // Fixup checksums in the Entry Point Structure
1021 EntryPointStructure
->IntermediateChecksum
= 0;
1022 EntryPointStructure
->EntryPointStructureChecksum
= 0;
1024 EntryPointStructure
->IntermediateChecksum
=
1025 CalculateCheckSum8 ((UINT8
*) EntryPointStructure
+ 0x10, EntryPointStructure
->EntryPointLength
- 0x10);
1026 EntryPointStructure
->EntryPointStructureChecksum
=
1027 CalculateCheckSum8 ((UINT8
*) EntryPointStructure
, EntryPointStructure
->EntryPointLength
);
1030 // Returns the pointer
1032 *TableEntryPointStructure
= EntryPointStructure
;
1038 Create SMBIOS Table and install it to the System Table.
1042 SmbiosTableConstruction (
1049 Status
= SmbiosCreateTable ((VOID
**) &Eps
);
1050 if (!EFI_ERROR (Status
)) {
1051 gBS
->InstallConfigurationTable (&gEfiSmbiosTableGuid
, Eps
);
1057 Driver to produce Smbios protocol and pre-allocate 1 page for the final SMBIOS table.
1059 @param ImageHandle Module's image handle
1060 @param SystemTable Pointer of EFI_SYSTEM_TABLE
1062 @retval EFI_SUCCESS Smbios protocol installed
1063 @retval Other No protocol installed, unload driver.
1068 SmbiosDriverEntryPoint (
1069 IN EFI_HANDLE ImageHandle
,
1070 IN EFI_SYSTEM_TABLE
*SystemTable
1074 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
1076 mPrivateData
.Signature
= SMBIOS_INSTANCE_SIGNATURE
;
1077 mPrivateData
.Smbios
.Add
= SmbiosAdd
;
1078 mPrivateData
.Smbios
.UpdateString
= SmbiosUpdateString
;
1079 mPrivateData
.Smbios
.Remove
= SmbiosRemove
;
1080 mPrivateData
.Smbios
.GetNext
= SmbiosGetNext
;
1081 mPrivateData
.Smbios
.MajorVersion
= (UINT8
) (PcdGet16 (PcdSmbiosVersion
) >> 8);
1082 mPrivateData
.Smbios
.MinorVersion
= (UINT8
) (PcdGet16 (PcdSmbiosVersion
) & 0x00ff);
1083 EntryPointStructureData
.MajorVersion
= mPrivateData
.Smbios
.MajorVersion
;
1084 EntryPointStructureData
.MinorVersion
= mPrivateData
.Smbios
.MinorVersion
;
1085 EntryPointStructureData
.SmbiosBcdRevision
= (UINT8
) ((PcdGet16 (PcdSmbiosVersion
) >> 4) & 0xf0) | (UINT8
) (PcdGet16 (PcdSmbiosVersion
) & 0x0f);
1087 InitializeListHead (&mPrivateData
.DataListHead
);
1088 InitializeListHead (&mPrivateData
.AllocatedHandleListHead
);
1089 EfiInitializeLock (&mPrivateData
.DataLock
, TPL_NOTIFY
);
1092 // Initialize the EntryPointStructure with initial values.
1093 // Allocate memory (below 4GB).
1095 PhysicalAddress
= 0xffffffff;
1096 Status
= gBS
->AllocatePages (
1098 EfiRuntimeServicesData
,
1099 EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_ENTRY_POINT
)),
1102 if (EFI_ERROR (Status
)) {
1103 DEBUG ((EFI_D_ERROR
, "SmbiosDriverEntryPoint() could not allocate EntryPointStructure < 4GB\n"));
1104 Status
= gBS
->AllocatePages (
1106 EfiRuntimeServicesData
,
1107 EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_ENTRY_POINT
)),
1110 if (EFI_ERROR (Status
)) {
1111 return EFI_OUT_OF_RESOURCES
;
1115 EntryPointStructure
= (SMBIOS_TABLE_ENTRY_POINT
*) (UINTN
) PhysicalAddress
;
1118 EntryPointStructure
,
1119 &EntryPointStructureData
,
1120 sizeof (SMBIOS_TABLE_ENTRY_POINT
)
1124 // Pre-allocate 1 page for SMBIOS table below 4GB.
1125 // SMBIOS table will be updated when new SMBIOS type is added or
1126 // existing SMBIOS type is updated. If the total size of SMBIOS table exceeds 1 page,
1127 // we will re-allocate new memory when creating whole SMBIOS table.
1129 PhysicalAddress
= 0xffffffff;
1130 Status
= gBS
->AllocatePages (
1132 EfiRuntimeServicesData
,
1136 if (EFI_ERROR (Status
)) {
1137 DEBUG ((EFI_D_ERROR
, "SmbiosDriverEntryPoint() could not allocate SMBIOS table < 4GB\n"));
1138 EntryPointStructure
->TableAddress
= 0;
1140 EntryPointStructure
->TableAddress
= (UINT32
) PhysicalAddress
;
1141 mPreAllocatedPages
= 1;
1145 // Init TableLength to the length of End-Of-Table structure for SmbiosAdd() called at the first time
1146 // to check the TableLength limitation.
1148 EntryPointStructure
->TableLength
= sizeof (EFI_SMBIOS_TABLE_END_STRUCTURE
);
1151 // Make a new handle and install the protocol
1153 mPrivateData
.Handle
= NULL
;
1154 Status
= gBS
->InstallProtocolInterface (
1155 &mPrivateData
.Handle
,
1156 &gEfiSmbiosProtocolGuid
,
1157 EFI_NATIVE_INTERFACE
,
1158 &mPrivateData
.Smbios