2 This code produces the Smbios protocol. It also responsible for constructing
3 SMBIOS table into system table.
5 Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
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
;
26 // Chassis for SMBIOS entry point structure that is to be installed into EFI system config table.
28 SMBIOS_TABLE_ENTRY_POINT
*EntryPointStructure
= NULL
;
29 SMBIOS_TABLE_ENTRY_POINT EntryPointStructureData
= {
40 // EntryPointStructureChecksum,TO BE FILLED
44 // EntryPointStructure Length
50 (UINT8
) (FixedPcdGet16 (PcdSmbiosVersion
) >> 8),
54 (UINT8
) (FixedPcdGet16 (PcdSmbiosVersion
) & 0x00ff),
56 // MaxStructureSize, TO BE FILLED
74 // IntermediateAnchorString
84 // IntermediateChecksum, TO BE FILLED
88 // StructureTableLength, TO BE FILLED
92 // StructureTableAddress, TO BE FILLED
96 // NumberOfSmbiosStructures, TO BE FILLED
109 Get the full size of SMBIOS structure including optional strings that follow the formatted structure.
111 @param This The EFI_SMBIOS_PROTOCOL instance.
112 @param Head Pointer to the beginning of SMBIOS structure.
113 @param Size The returned size.
114 @param NumberOfStrings The returned number of optional strings that follow the formatted structure.
116 @retval EFI_SUCCESS Size retured in Size.
117 @retval EFI_INVALID_PARAMETER Input SMBIOS structure mal-formed or Size is NULL.
122 GetSmbiosStructureSize (
123 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
124 IN EFI_SMBIOS_TABLE_HEADER
*Head
,
126 OUT UINTN
*NumberOfStrings
133 if (Size
== NULL
|| NumberOfStrings
== NULL
) {
134 return EFI_INVALID_PARAMETER
;
137 FullSize
= Head
->Length
;
138 CharInStr
= (INT8
*)Head
+ Head
->Length
;
140 *NumberOfStrings
= 0;
143 // look for the two consecutive zeros, check the string limit by the way.
145 while (*CharInStr
!= 0 || *(CharInStr
+1) != 0) {
146 if (*CharInStr
== 0) {
151 if (This
->MajorVersion
< 2 || (This
->MajorVersion
== 2 && This
->MinorVersion
< 7)){
152 for (StrLen
= 0 ; StrLen
< SMBIOS_STRING_MAX_LENGTH
; StrLen
++) {
153 if (*(CharInStr
+StrLen
) == 0) {
158 if (StrLen
== SMBIOS_STRING_MAX_LENGTH
) {
159 return EFI_INVALID_PARAMETER
;
163 // Reference SMBIOS 2.7, chapter 6.1.3, it will have no limit on the length of each individual text string
165 for (StrLen
= 0 ;; StrLen
++) {
166 if (*(CharInStr
+StrLen
) == 0) {
173 // forward the pointer
177 *NumberOfStrings
+= 1;
181 // count ending two zeros.
189 Determin whether an SmbiosHandle has already in use.
191 @param Head Pointer to the beginning of SMBIOS structure.
192 @param Handle A unique handle will be assigned to the SMBIOS record.
194 @retval TRUE Smbios handle already in use.
195 @retval FALSE Smbios handle is NOT used.
200 CheckSmbiosHandleExistance (
202 IN EFI_SMBIOS_HANDLE Handle
206 SMBIOS_HANDLE_ENTRY
*HandleEntry
;
208 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
209 HandleEntry
= SMBIOS_HANDLE_ENTRY_FROM_LINK(Link
);
210 if (HandleEntry
->SmbiosHandle
== Handle
) {
220 Get the max SmbiosHandle that could be use.
222 @param This The EFI_SMBIOS_PROTOCOL instance.
223 @param MaxHandle The max handle that could be assigned to the SMBIOS record.
229 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
230 IN OUT EFI_SMBIOS_HANDLE
*MaxHandle
233 if (This
->MajorVersion
== 2 && This
->MinorVersion
== 0) {
242 Get an SmbiosHandle that could use.
244 @param This The EFI_SMBIOS_PROTOCOL instance.
245 @param SmbiosHandle A unique handle will be assigned to the SMBIOS record.
247 @retval EFI_SUCCESS Smbios handle got.
248 @retval EFI_OUT_OF_RESOURCES Smbios handle is NOT available.
253 GetAvailableSmbiosHandle (
254 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
255 IN OUT EFI_SMBIOS_HANDLE
*Handle
259 SMBIOS_INSTANCE
*Private
;
260 EFI_SMBIOS_HANDLE MaxSmbiosHandle
;
261 EFI_SMBIOS_HANDLE AvailableHandle
;
263 GetMaxSmbiosHandle(This
, &MaxSmbiosHandle
);
265 Private
= SMBIOS_INSTANCE_FROM_THIS (This
);
266 Head
= &Private
->AllocatedHandleListHead
;
267 for (AvailableHandle
= 1; AvailableHandle
< MaxSmbiosHandle
; AvailableHandle
++) {
268 if (!CheckSmbiosHandleExistance(Head
, AvailableHandle
)) {
269 *Handle
= AvailableHandle
;
274 return EFI_OUT_OF_RESOURCES
;
279 Add an SMBIOS record.
281 @param This The EFI_SMBIOS_PROTOCOL instance.
282 @param ProducerHandle The handle of the controller or driver associated with the SMBIOS information. NULL
284 @param SmbiosHandle On entry, if non-zero, the handle of the SMBIOS record. If zero, then a unique handle
285 will be assigned to the SMBIOS record. If the SMBIOS handle is already in use
286 EFI_ALREADY_STARTED is returned and the SMBIOS record is not updated.
287 @param Record The data for the fixed portion of the SMBIOS record. The format of the record is
288 determined by EFI_SMBIOS_TABLE_HEADER.Type. The size of the formatted area is defined
289 by EFI_SMBIOS_TABLE_HEADER.Length and either followed by a double-null (0x0000) or
290 a set of null terminated strings and a null.
292 @retval EFI_SUCCESS Record was added.
293 @retval EFI_OUT_OF_RESOURCES Record was not added due to lack of system resources.
294 @retval EFI_ALREADY_STARTED The SmbiosHandle passed in was already in use.
300 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
301 IN EFI_HANDLE ProducerHandle
, OPTIONAL
302 IN OUT EFI_SMBIOS_HANDLE
*SmbiosHandle
,
303 IN EFI_SMBIOS_TABLE_HEADER
*Record
310 UINTN NumberOfStrings
;
313 SMBIOS_INSTANCE
*Private
;
314 EFI_SMBIOS_ENTRY
*SmbiosEntry
;
315 EFI_SMBIOS_HANDLE MaxSmbiosHandle
;
316 SMBIOS_HANDLE_ENTRY
*HandleEntry
;
317 EFI_SMBIOS_RECORD_HEADER
*InternalRecord
;
319 if (SmbiosHandle
== NULL
) {
320 return EFI_INVALID_PARAMETER
;
323 Private
= SMBIOS_INSTANCE_FROM_THIS (This
);
325 // Check whether SmbiosHandle is already in use
327 Head
= &Private
->AllocatedHandleListHead
;
328 if (*SmbiosHandle
!= 0 && CheckSmbiosHandleExistance(Head
, *SmbiosHandle
)) {
329 return EFI_ALREADY_STARTED
;
333 // when SmbiosHandle is zero, an available handle will be assigned
335 if (*SmbiosHandle
== 0) {
336 Status
= GetAvailableSmbiosHandle(This
, SmbiosHandle
);
337 if (EFI_ERROR(Status
)) {
342 // Check this handle validity
344 GetMaxSmbiosHandle(This
, &MaxSmbiosHandle
);
345 if (*SmbiosHandle
> MaxSmbiosHandle
) {
346 return EFI_INVALID_PARAMETER
;
351 // Calculate record size and string number
353 Status
= GetSmbiosStructureSize(This
, Record
, &StructureSize
, &NumberOfStrings
);
354 if (EFI_ERROR(Status
)) {
359 // Enter into critical section
361 Status
= EfiAcquireLockOrFail (&Private
->DataLock
);
362 if (EFI_ERROR (Status
)) {
366 RecordSize
= sizeof (EFI_SMBIOS_RECORD_HEADER
) + StructureSize
;
367 TotalSize
= sizeof (EFI_SMBIOS_ENTRY
) + RecordSize
;
370 // Allocate internal buffer
372 SmbiosEntry
= AllocateZeroPool (TotalSize
);
373 if (SmbiosEntry
== NULL
) {
374 EfiReleaseLock (&Private
->DataLock
);
375 return EFI_OUT_OF_RESOURCES
;
377 HandleEntry
= AllocateZeroPool (sizeof(SMBIOS_HANDLE_ENTRY
));
378 if (HandleEntry
== NULL
) {
379 EfiReleaseLock (&Private
->DataLock
);
380 return EFI_OUT_OF_RESOURCES
;
384 // Build Handle Entry and insert into linked list
386 HandleEntry
->Signature
= SMBIOS_HANDLE_ENTRY_SIGNATURE
;
387 HandleEntry
->SmbiosHandle
= *SmbiosHandle
;
388 InsertTailList(&Private
->AllocatedHandleListHead
, &HandleEntry
->Link
);
390 InternalRecord
= (EFI_SMBIOS_RECORD_HEADER
*) (SmbiosEntry
+ 1);
391 Raw
= (VOID
*) (InternalRecord
+ 1);
394 // Build internal record Header
396 InternalRecord
->Version
= EFI_SMBIOS_RECORD_HEADER_VERSION
;
397 InternalRecord
->HeaderSize
= (UINT16
) sizeof (EFI_SMBIOS_RECORD_HEADER
);
398 InternalRecord
->RecordSize
= RecordSize
;
399 InternalRecord
->ProducerHandle
= ProducerHandle
;
400 InternalRecord
->NumberOfStrings
= NumberOfStrings
;
402 // Insert record into the internal linked list
404 SmbiosEntry
->Signature
= EFI_SMBIOS_ENTRY_SIGNATURE
;
405 SmbiosEntry
->RecordHeader
= InternalRecord
;
406 SmbiosEntry
->RecordSize
= TotalSize
;
407 InsertTailList (&Private
->DataListHead
, &SmbiosEntry
->Link
);
409 CopyMem (Raw
, Record
, StructureSize
);
410 ((EFI_SMBIOS_TABLE_HEADER
*)Raw
)->Handle
= *SmbiosHandle
;
413 // Some UEFI drivers (such as network) need some information in SMBIOS table.
414 // Here we create SMBIOS table and publish it in
415 // configuration table, so other UEFI drivers can get SMBIOS table from
416 // configuration table without depending on PI SMBIOS protocol.
418 SmbiosTableConstruction ();
421 // Leave critical section
423 EfiReleaseLock (&Private
->DataLock
);
428 Update the string associated with an existing SMBIOS record.
430 @param This The EFI_SMBIOS_PROTOCOL instance.
431 @param SmbiosHandle SMBIOS Handle of structure that will have its string updated.
432 @param StringNumber The non-zero string number of the string to update
433 @param String Update the StringNumber string with String.
435 @retval EFI_SUCCESS SmbiosHandle had its StringNumber String updated.
436 @retval EFI_INVALID_PARAMETER SmbiosHandle does not exist.
437 @retval EFI_UNSUPPORTED String was not added since it's longer than 64 significant characters.
438 @retval EFI_NOT_FOUND The StringNumber.is not valid for this SMBIOS record.
444 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
445 IN EFI_SMBIOS_HANDLE
*SmbiosHandle
,
446 IN UINTN
*StringNumber
,
453 UINTN TargetStrOffset
;
460 SMBIOS_INSTANCE
*Private
;
461 EFI_SMBIOS_ENTRY
*SmbiosEntry
;
462 EFI_SMBIOS_ENTRY
*ResizedSmbiosEntry
;
463 EFI_SMBIOS_HANDLE MaxSmbiosHandle
;
464 EFI_SMBIOS_TABLE_HEADER
*Record
;
465 EFI_SMBIOS_RECORD_HEADER
*InternalRecord
;
468 // Check args validity
470 GetMaxSmbiosHandle(This
, &MaxSmbiosHandle
);
472 if (*SmbiosHandle
> MaxSmbiosHandle
) {
473 return EFI_INVALID_PARAMETER
;
476 if (String
== NULL
) {
480 if (*StringNumber
== 0) {
481 return EFI_NOT_FOUND
;
484 InputStrLen
= AsciiStrLen(String
);
487 // Reference SMBIOS 2.7, chapter 6.1.3, it will have no limit on the length of each individual text string
489 if (This
->MajorVersion
< 2 || (This
->MajorVersion
== 2 && This
->MinorVersion
< 7)) {
490 if (InputStrLen
> SMBIOS_STRING_MAX_LENGTH
) {
491 return EFI_UNSUPPORTED
;
495 Private
= SMBIOS_INSTANCE_FROM_THIS (This
);
497 // Enter into critical section
499 Status
= EfiAcquireLockOrFail (&Private
->DataLock
);
500 if (EFI_ERROR (Status
)) {
504 Head
= &Private
->DataListHead
;
505 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
506 SmbiosEntry
= SMBIOS_ENTRY_FROM_LINK(Link
);
507 Record
= (EFI_SMBIOS_TABLE_HEADER
*)(SmbiosEntry
->RecordHeader
+ 1);
509 if (Record
->Handle
== *SmbiosHandle
) {
511 // Find out the specified SMBIOS record
513 if (*StringNumber
> SmbiosEntry
->RecordHeader
->NumberOfStrings
) {
514 EfiReleaseLock (&Private
->DataLock
);
515 return EFI_NOT_FOUND
;
518 // Point to unformed string section
520 StrStart
= (CHAR8
*) Record
+ Record
->Length
;
522 for (StrIndex
= 1, TargetStrOffset
= 0; StrIndex
< *StringNumber
; StrStart
++, TargetStrOffset
++) {
524 // A string ends in 00h
526 if (*StrStart
== 0) {
531 // String section ends in double-null (0000h)
533 if (*StrStart
== 0 && *(StrStart
+ 1) == 0) {
534 EfiReleaseLock (&Private
->DataLock
);
535 return EFI_NOT_FOUND
;
539 if (*StrStart
== 0) {
545 // Now we get the string target
547 TargetStrLen
= AsciiStrLen(StrStart
);
548 if (InputStrLen
== TargetStrLen
) {
549 AsciiStrCpy(StrStart
, String
);
551 // Some UEFI drivers (such as network) need some information in SMBIOS table.
552 // Here we create SMBIOS table and publish it in
553 // configuration table, so other UEFI drivers can get SMBIOS table from
554 // configuration table without depending on PI SMBIOS protocol.
556 SmbiosTableConstruction ();
557 EfiReleaseLock (&Private
->DataLock
);
562 // Original string buffer size is not exactly match input string length.
563 // Re-allocate buffer is needed.
565 NewEntrySize
= SmbiosEntry
->RecordSize
+ InputStrLen
- TargetStrLen
;
566 ResizedSmbiosEntry
= AllocateZeroPool (NewEntrySize
);
568 if (ResizedSmbiosEntry
== NULL
) {
569 EfiReleaseLock (&Private
->DataLock
);
570 return EFI_OUT_OF_RESOURCES
;
573 InternalRecord
= (EFI_SMBIOS_RECORD_HEADER
*) (ResizedSmbiosEntry
+ 1);
574 Raw
= (VOID
*) (InternalRecord
+ 1);
577 // Build internal record Header
579 InternalRecord
->Version
= EFI_SMBIOS_RECORD_HEADER_VERSION
;
580 InternalRecord
->HeaderSize
= (UINT16
) sizeof (EFI_SMBIOS_RECORD_HEADER
);
581 InternalRecord
->RecordSize
= SmbiosEntry
->RecordHeader
->RecordSize
+ InputStrLen
- TargetStrLen
;
582 InternalRecord
->ProducerHandle
= SmbiosEntry
->RecordHeader
->ProducerHandle
;
583 InternalRecord
->NumberOfStrings
= SmbiosEntry
->RecordHeader
->NumberOfStrings
;
586 // Copy SMBIOS structure and optional strings.
588 CopyMem (Raw
, SmbiosEntry
->RecordHeader
+ 1, Record
->Length
+ TargetStrOffset
);
589 CopyMem ((VOID
*)((UINTN
)Raw
+ Record
->Length
+ TargetStrOffset
), String
, InputStrLen
+ 1);
590 CopyMem ((CHAR8
*)((UINTN
)Raw
+ Record
->Length
+ TargetStrOffset
+ InputStrLen
+ 1),
591 (CHAR8
*)Record
+ Record
->Length
+ TargetStrOffset
+ TargetStrLen
+ 1,
592 SmbiosEntry
->RecordHeader
->RecordSize
- sizeof (EFI_SMBIOS_RECORD_HEADER
) - Record
->Length
- TargetStrOffset
- TargetStrLen
- 1);
597 ResizedSmbiosEntry
->Signature
= EFI_SMBIOS_ENTRY_SIGNATURE
;
598 ResizedSmbiosEntry
->RecordHeader
= InternalRecord
;
599 ResizedSmbiosEntry
->RecordSize
= NewEntrySize
;
600 InsertTailList (Link
->ForwardLink
, &ResizedSmbiosEntry
->Link
);
605 RemoveEntryList(Link
);
606 FreePool(SmbiosEntry
);
608 // Some UEFI drivers (such as network) need some information in SMBIOS table.
609 // Here we create SMBIOS table and publish it in
610 // configuration table, so other UEFI drivers can get SMBIOS table from
611 // configuration table without depending on PI SMBIOS protocol.
613 SmbiosTableConstruction ();
614 EfiReleaseLock (&Private
->DataLock
);
619 EfiReleaseLock (&Private
->DataLock
);
620 return EFI_INVALID_PARAMETER
;
624 Remove an SMBIOS record.
626 @param This The EFI_SMBIOS_PROTOCOL instance.
627 @param SmbiosHandle The handle of the SMBIOS record to remove.
629 @retval EFI_SUCCESS SMBIOS record was removed.
630 @retval EFI_INVALID_PARAMETER SmbiosHandle does not specify a valid SMBIOS record.
636 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
637 IN EFI_SMBIOS_HANDLE SmbiosHandle
643 EFI_SMBIOS_HANDLE MaxSmbiosHandle
;
644 SMBIOS_INSTANCE
*Private
;
645 EFI_SMBIOS_ENTRY
*SmbiosEntry
;
646 SMBIOS_HANDLE_ENTRY
*HandleEntry
;
647 EFI_SMBIOS_TABLE_HEADER
*Record
;
650 // Check args validity
652 GetMaxSmbiosHandle(This
, &MaxSmbiosHandle
);
654 if (SmbiosHandle
> MaxSmbiosHandle
) {
655 return EFI_INVALID_PARAMETER
;
658 Private
= SMBIOS_INSTANCE_FROM_THIS (This
);
660 // Enter into critical section
662 Status
= EfiAcquireLockOrFail (&Private
->DataLock
);
663 if (EFI_ERROR (Status
)) {
667 Head
= &Private
->DataListHead
;
668 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
669 SmbiosEntry
= SMBIOS_ENTRY_FROM_LINK(Link
);
670 Record
= (EFI_SMBIOS_TABLE_HEADER
*)(SmbiosEntry
->RecordHeader
+ 1);
671 if (Record
->Handle
== SmbiosHandle
) {
673 // Remove specified smobios record from DataList
675 RemoveEntryList(Link
);
676 FreePool(SmbiosEntry
);
678 // Remove this handle from AllocatedHandleList
680 Head
= &Private
->AllocatedHandleListHead
;
681 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
682 HandleEntry
= SMBIOS_HANDLE_ENTRY_FROM_LINK(Link
);
683 if (HandleEntry
->SmbiosHandle
== SmbiosHandle
) {
684 RemoveEntryList(Link
);
685 FreePool(HandleEntry
);
690 // Some UEFI drivers (such as network) need some information in SMBIOS table.
691 // Here we create SMBIOS table and publish it in
692 // configuration table, so other UEFI drivers can get SMBIOS table from
693 // configuration table without depending on PI SMBIOS protocol.
695 SmbiosTableConstruction ();
696 EfiReleaseLock (&Private
->DataLock
);
702 // Leave critical section
704 EfiReleaseLock (&Private
->DataLock
);
705 return EFI_INVALID_PARAMETER
;
710 Allow the caller to discover all or some of the SMBIOS records.
712 @param This The EFI_SMBIOS_PROTOCOL instance.
713 @param SmbiosHandle On entry, points to the previous handle of the SMBIOS record. On exit, points to the
714 next SMBIOS record handle. If it is zero on entry, then the first SMBIOS record
715 handle will be returned. If it returns zero on exit, then there are no more SMBIOS records.
716 @param Type On entry it means return the next SMBIOS record of type Type. If a NULL is passed in
717 this functionally it ignored. Type is not modified by the GetNext() function.
718 @param Record On exit, points to the SMBIOS Record consisting of the formatted area followed by
719 the unformatted area. The unformatted area optionally contains text strings.
720 @param ProducerHandle On exit, points to the ProducerHandle registered by Add(). If no ProducerHandle was passed into Add() NULL is returned.
721 If a NULL pointer is passed in no data will be returned
723 @retval EFI_SUCCESS SMBIOS record information was successfully returned in Record.
724 @retval EFI_NOT_FOUND The SMBIOS record with SmbiosHandle was the last available record.
730 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
731 IN OUT EFI_SMBIOS_HANDLE
*SmbiosHandle
,
732 IN EFI_SMBIOS_TYPE
*Type
, OPTIONAL
733 OUT EFI_SMBIOS_TABLE_HEADER
**Record
,
734 OUT EFI_HANDLE
*ProducerHandle OPTIONAL
737 BOOLEAN StartPointFound
;
740 SMBIOS_INSTANCE
*Private
;
741 EFI_SMBIOS_ENTRY
*SmbiosEntry
;
742 EFI_SMBIOS_TABLE_HEADER
*SmbiosTableHeader
;
744 if (SmbiosHandle
== NULL
) {
745 return EFI_INVALID_PARAMETER
;
748 StartPointFound
= FALSE
;
749 Private
= SMBIOS_INSTANCE_FROM_THIS (This
);
750 Head
= &Private
->DataListHead
;
751 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
752 SmbiosEntry
= SMBIOS_ENTRY_FROM_LINK(Link
);
753 SmbiosTableHeader
= (EFI_SMBIOS_TABLE_HEADER
*)(SmbiosEntry
->RecordHeader
+ 1);
756 // If SmbiosHandle is zero, the first matched SMBIOS record handle will be returned
758 if (*SmbiosHandle
== 0) {
759 if ((Type
!= NULL
) && (*Type
!= SmbiosTableHeader
->Type
)) {
763 *SmbiosHandle
= SmbiosTableHeader
->Handle
;
764 *Record
=SmbiosTableHeader
;
765 if (ProducerHandle
!= NULL
) {
766 *ProducerHandle
= SmbiosEntry
->RecordHeader
->ProducerHandle
;
772 // Start this round search from the next SMBIOS handle
774 if (!StartPointFound
&& (*SmbiosHandle
== SmbiosTableHeader
->Handle
)) {
775 StartPointFound
= TRUE
;
779 if (StartPointFound
) {
780 if ((Type
!= NULL
) && (*Type
!= SmbiosTableHeader
->Type
)) {
784 *SmbiosHandle
= SmbiosTableHeader
->Handle
;
785 *Record
= SmbiosTableHeader
;
786 if (ProducerHandle
!= NULL
) {
787 *ProducerHandle
= SmbiosEntry
->RecordHeader
->ProducerHandle
;
795 return EFI_NOT_FOUND
;
800 Allow the caller to discover all of the SMBIOS records.
802 @param This The EFI_SMBIOS_PROTOCOL instance.
803 @param CurrentSmbiosEntry On exit, points to the SMBIOS entry on the list which includes the returned SMBIOS record information.
804 If *CurrentSmbiosEntry is NULL on entry, then the first SMBIOS entry on the list will be returned.
805 @param Record On exit, points to the SMBIOS Record consisting of the formatted area followed by
806 the unformatted area. The unformatted area optionally contains text strings.
808 @retval EFI_SUCCESS SMBIOS record information was successfully returned in Record.
809 *CurrentSmbiosEntry points to the SMBIOS entry which includes the returned SMBIOS record information.
810 @retval EFI_NOT_FOUND There is no more SMBIOS entry.
815 GetNextSmbiosRecord (
816 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
817 IN OUT EFI_SMBIOS_ENTRY
**CurrentSmbiosEntry
,
818 OUT EFI_SMBIOS_TABLE_HEADER
**Record
823 SMBIOS_INSTANCE
*Private
;
824 EFI_SMBIOS_ENTRY
*SmbiosEntry
;
825 EFI_SMBIOS_TABLE_HEADER
*SmbiosTableHeader
;
827 Private
= SMBIOS_INSTANCE_FROM_THIS (This
);
828 if (*CurrentSmbiosEntry
== NULL
) {
830 // Get the beginning of SMBIOS entry.
832 Head
= &Private
->DataListHead
;
835 // Get previous SMBIOS entry and make it as start point.
837 Head
= &(*CurrentSmbiosEntry
)->Link
;
840 Link
= Head
->ForwardLink
;
842 if (Link
== &Private
->DataListHead
) {
844 // If no more SMBIOS entry in the list, return not found.
846 return EFI_NOT_FOUND
;
849 SmbiosEntry
= SMBIOS_ENTRY_FROM_LINK(Link
);
850 SmbiosTableHeader
= (EFI_SMBIOS_TABLE_HEADER
*)(SmbiosEntry
->RecordHeader
+ 1);
851 *Record
= SmbiosTableHeader
;
852 *CurrentSmbiosEntry
= SmbiosEntry
;
857 Assembles SMBIOS table from the SMBIOS protocol. Produce Table
858 Entry Point and return the pointer to it.
860 @param TableEntryPointStructure On exit, points to the SMBIOS entrypoint structure.
862 @retval EFI_SUCCESS Structure created sucessfully.
863 @retval EFI_NOT_READY Some of The SMBIOS records was not available yet.
864 @retval EFI_OUT_OF_RESOURCES No enough memory.
870 OUT VOID
**TableEntryPointStructure
873 UINT8
*BufferPointer
;
877 EFI_SMBIOS_HANDLE SmbiosHandle
;
878 EFI_SMBIOS_PROTOCOL
*SmbiosProtocol
;
879 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
880 EFI_SMBIOS_TABLE_HEADER
*SmbiosRecord
;
881 EFI_SMBIOS_TABLE_END_STRUCTURE EndStructure
;
882 EFI_SMBIOS_ENTRY
*CurrentSmbiosEntry
;
883 UINTN PreAllocatedPages
;
885 Status
= EFI_SUCCESS
;
886 BufferPointer
= NULL
;
889 // Get Smbios protocol to traverse SMBIOS records.
891 SmbiosProtocol
= &mPrivateData
.Smbios
;
893 if (EntryPointStructure
->TableAddress
== 0) {
894 PreAllocatedPages
= 0;
896 PreAllocatedPages
= EFI_SIZE_TO_PAGES (EntryPointStructure
->TableLength
);
900 // Make some statistics about all the structures
902 EntryPointStructure
->NumberOfSmbiosStructures
= 0;
903 EntryPointStructure
->TableLength
= 0;
904 EntryPointStructure
->MaxStructureSize
= 0;
907 // Calculate EPS Table Length
909 CurrentSmbiosEntry
= NULL
;
911 Status
= GetNextSmbiosRecord (SmbiosProtocol
, &CurrentSmbiosEntry
, &SmbiosRecord
);
913 if (Status
== EFI_SUCCESS
) {
914 GetSmbiosStructureSize(SmbiosProtocol
, SmbiosRecord
, &RecordSize
, &NumOfStr
);
916 // Record NumberOfSmbiosStructures, TableLength and MaxStructureSize
918 EntryPointStructure
->NumberOfSmbiosStructures
++;
919 EntryPointStructure
->TableLength
= (UINT16
) (EntryPointStructure
->TableLength
+ RecordSize
);
920 if (RecordSize
> EntryPointStructure
->MaxStructureSize
) {
921 EntryPointStructure
->MaxStructureSize
= (UINT16
) RecordSize
;
924 } while (!EFI_ERROR(Status
));
927 // Create End-Of-Table structure
929 GetMaxSmbiosHandle(SmbiosProtocol
, &SmbiosHandle
);
930 EndStructure
.Header
.Type
= EFI_SMBIOS_TYPE_END_OF_TABLE
;
931 EndStructure
.Header
.Length
= (UINT8
) sizeof (EFI_SMBIOS_TABLE_HEADER
);
932 EndStructure
.Header
.Handle
= SmbiosHandle
;
933 EndStructure
.Tailing
[0] = 0;
934 EndStructure
.Tailing
[1] = 0;
935 EntryPointStructure
->NumberOfSmbiosStructures
++;
936 EntryPointStructure
->TableLength
= (UINT16
) (EntryPointStructure
->TableLength
+ sizeof (EndStructure
));
937 if (sizeof (EndStructure
) > EntryPointStructure
->MaxStructureSize
) {
938 EntryPointStructure
->MaxStructureSize
= (UINT16
) sizeof (EndStructure
);
941 if ((UINTN
) EFI_SIZE_TO_PAGES (EntryPointStructure
->TableLength
) > PreAllocatedPages
) {
943 // If new SMBIOS talbe size exceeds the original pre-allocated page,
944 // it is time to re-allocate memory (below 4GB).
946 if (EntryPointStructure
->TableAddress
!= 0) {
948 // Free the original pre-allocated page
951 (VOID
*)(UINTN
)EntryPointStructure
->TableAddress
,
954 EntryPointStructure
->TableAddress
= 0;
957 PhysicalAddress
= 0xffffffff;
958 Status
= gBS
->AllocatePages (
960 EfiReservedMemoryType
,
961 EFI_SIZE_TO_PAGES (EntryPointStructure
->TableLength
),
964 if (EFI_ERROR (Status
)) {
965 DEBUG ((EFI_D_ERROR
, "SmbiosCreateTable() could not allocate SMBIOS table < 4GB\n"));
966 EntryPointStructure
->TableAddress
= 0;
967 return EFI_OUT_OF_RESOURCES
;
969 EntryPointStructure
->TableAddress
= (UINT32
) PhysicalAddress
;
974 // Assemble the tables
976 BufferPointer
= (UINT8
*) (UINTN
) EntryPointStructure
->TableAddress
;
977 CurrentSmbiosEntry
= NULL
;
979 Status
= GetNextSmbiosRecord (SmbiosProtocol
, &CurrentSmbiosEntry
, &SmbiosRecord
);
981 if (Status
== EFI_SUCCESS
) {
982 GetSmbiosStructureSize(SmbiosProtocol
, SmbiosRecord
, &RecordSize
, &NumOfStr
);
983 CopyMem (BufferPointer
, SmbiosRecord
, RecordSize
);
984 BufferPointer
= BufferPointer
+ RecordSize
;
986 } while (!EFI_ERROR(Status
));
989 // Assemble End-Of-Table structure
991 CopyMem (BufferPointer
, &EndStructure
, sizeof (EndStructure
));
994 // Fixup checksums in the Entry Point Structure
996 EntryPointStructure
->IntermediateChecksum
=
997 CalculateCheckSum8 ((UINT8
*) EntryPointStructure
+ 0x10, EntryPointStructure
->EntryPointLength
- 0x10);
998 EntryPointStructure
->EntryPointStructureChecksum
=
999 CalculateCheckSum8 ((UINT8
*) EntryPointStructure
, EntryPointStructure
->EntryPointLength
);
1002 // Returns the pointer
1004 *TableEntryPointStructure
= EntryPointStructure
;
1010 Create SMBIOS Table and install it to the System Table.
1014 SmbiosTableConstruction (
1021 Status
= SmbiosCreateTable ((VOID
**) &Eps
);
1022 if (!EFI_ERROR (Status
)) {
1023 gBS
->InstallConfigurationTable (&gEfiSmbiosTableGuid
, Eps
);
1029 Driver to produce Smbios protocol and pre-allocate 1 page for the final SMBIOS table.
1031 @param ImageHandle Module's image handle
1032 @param SystemTable Pointer of EFI_SYSTEM_TABLE
1034 @retval EFI_SUCCESS Smbios protocol installed
1035 @retval Other No protocol installed, unload driver.
1040 SmbiosDriverEntryPoint (
1041 IN EFI_HANDLE ImageHandle
,
1042 IN EFI_SYSTEM_TABLE
*SystemTable
1046 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
1048 mPrivateData
.Signature
= SMBIOS_INSTANCE_SIGNATURE
;
1049 mPrivateData
.Smbios
.Add
= SmbiosAdd
;
1050 mPrivateData
.Smbios
.UpdateString
= SmbiosUpdateString
;
1051 mPrivateData
.Smbios
.Remove
= SmbiosRemove
;
1052 mPrivateData
.Smbios
.GetNext
= SmbiosGetNext
;
1053 mPrivateData
.Smbios
.MajorVersion
= (UINT8
) (FixedPcdGet16 (PcdSmbiosVersion
) >> 8);
1054 mPrivateData
.Smbios
.MinorVersion
= (UINT8
) (FixedPcdGet16 (PcdSmbiosVersion
) & 0x00ff);
1056 InitializeListHead (&mPrivateData
.DataListHead
);
1057 InitializeListHead (&mPrivateData
.AllocatedHandleListHead
);
1058 EfiInitializeLock (&mPrivateData
.DataLock
, TPL_NOTIFY
);
1061 // Initialize the EntryPointStructure with initial values.
1062 // Allocate memory (below 4GB).
1064 PhysicalAddress
= 0xffffffff;
1065 Status
= gBS
->AllocatePages (
1067 EfiReservedMemoryType
,
1068 EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_ENTRY_POINT
)),
1071 if (EFI_ERROR (Status
)) {
1072 DEBUG ((EFI_D_ERROR
, "SmbiosDriverEntryPoint() could not allocate EntryPointStructure < 4GB\n"));
1073 Status
= gBS
->AllocatePages (
1075 EfiReservedMemoryType
,
1076 EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_ENTRY_POINT
)),
1079 if (EFI_ERROR (Status
)) {
1080 return EFI_OUT_OF_RESOURCES
;
1084 EntryPointStructure
= (SMBIOS_TABLE_ENTRY_POINT
*) (UINTN
) PhysicalAddress
;
1087 EntryPointStructure
,
1088 &EntryPointStructureData
,
1089 sizeof (SMBIOS_TABLE_ENTRY_POINT
)
1093 // Pre-allocate 1 page for SMBIOS table below 4GB.
1094 // SMBIOS table will be updated when new SMBIOS type is added or
1095 // existing SMBIOS type is updated. If the total size of SMBIOS table exceeds 1 page,
1096 // we will re-allocate new memory when creating whole SMBIOS table.
1098 PhysicalAddress
= 0xffffffff;
1099 Status
= gBS
->AllocatePages (
1101 EfiReservedMemoryType
,
1105 if (EFI_ERROR (Status
)) {
1106 DEBUG ((EFI_D_ERROR
, "SmbiosDriverEntryPoint() could not allocate SMBIOS table < 4GB\n"));
1107 EntryPointStructure
->TableAddress
= 0;
1108 EntryPointStructure
->TableLength
= 0;
1110 EntryPointStructure
->TableAddress
= (UINT32
) PhysicalAddress
;
1111 EntryPointStructure
->TableLength
= EFI_PAGES_TO_SIZE (1);
1115 // Make a new handle and install the protocol
1117 mPrivateData
.Handle
= NULL
;
1118 Status
= gBS
->InstallProtocolInterface (
1119 &mPrivateData
.Handle
,
1120 &gEfiSmbiosProtocolGuid
,
1121 EFI_NATIVE_INTERFACE
,
1122 &mPrivateData
.Smbios