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
108 Get the full size of SMBIOS structure including optional strings that follow the formatted structure.
110 @param This The EFI_SMBIOS_PROTOCOL instance.
111 @param Head Pointer to the beginning of SMBIOS structure.
112 @param Size The returned size.
113 @param NumberOfStrings The returned number of optional strings that follow the formatted structure.
115 @retval EFI_SUCCESS Size retured in Size.
116 @retval EFI_INVALID_PARAMETER Input SMBIOS structure mal-formed or Size is NULL.
121 GetSmbiosStructureSize (
122 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
123 IN EFI_SMBIOS_TABLE_HEADER
*Head
,
125 OUT UINTN
*NumberOfStrings
132 if (Size
== NULL
|| NumberOfStrings
== NULL
) {
133 return EFI_INVALID_PARAMETER
;
136 FullSize
= Head
->Length
;
137 CharInStr
= (INT8
*)Head
+ Head
->Length
;
139 *NumberOfStrings
= 0;
142 // look for the two consecutive zeros, check the string limit by the way.
144 while (*CharInStr
!= 0 || *(CharInStr
+1) != 0) {
145 if (*CharInStr
== 0) {
150 if (This
->MajorVersion
< 2 || (This
->MajorVersion
== 2 && This
->MinorVersion
< 7)){
151 for (StrLen
= 0 ; StrLen
< SMBIOS_STRING_MAX_LENGTH
; StrLen
++) {
152 if (*(CharInStr
+StrLen
) == 0) {
157 if (StrLen
== SMBIOS_STRING_MAX_LENGTH
) {
158 return EFI_INVALID_PARAMETER
;
162 // Reference SMBIOS 2.7, chapter 6.1.3, it will have no limit on the length of each individual text string
164 for (StrLen
= 0 ;; StrLen
++) {
165 if (*(CharInStr
+StrLen
) == 0) {
172 // forward the pointer
176 *NumberOfStrings
+= 1;
180 // count ending two zeros.
188 Determin whether an SmbiosHandle has already in use.
190 @param Head Pointer to the beginning of SMBIOS structure.
191 @param Handle A unique handle will be assigned to the SMBIOS record.
193 @retval TRUE Smbios handle already in use.
194 @retval FALSE Smbios handle is NOT used.
199 CheckSmbiosHandleExistance (
201 IN EFI_SMBIOS_HANDLE Handle
205 SMBIOS_HANDLE_ENTRY
*HandleEntry
;
207 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
208 HandleEntry
= SMBIOS_HANDLE_ENTRY_FROM_LINK(Link
);
209 if (HandleEntry
->SmbiosHandle
== Handle
) {
219 Get the max SmbiosHandle that could be use.
221 @param This The EFI_SMBIOS_PROTOCOL instance.
222 @param MaxHandle The max handle that could be assigned to the SMBIOS record.
228 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
229 IN OUT EFI_SMBIOS_HANDLE
*MaxHandle
232 if (This
->MajorVersion
== 2 && This
->MinorVersion
== 0) {
241 Get an SmbiosHandle that could use.
243 @param This The EFI_SMBIOS_PROTOCOL instance.
244 @param SmbiosHandle A unique handle will be assigned to the SMBIOS record.
246 @retval EFI_SUCCESS Smbios handle got.
247 @retval EFI_OUT_OF_RESOURCES Smbios handle is NOT available.
252 GetAvailableSmbiosHandle (
253 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
254 IN OUT EFI_SMBIOS_HANDLE
*Handle
258 SMBIOS_INSTANCE
*Private
;
259 EFI_SMBIOS_HANDLE MaxSmbiosHandle
;
260 EFI_SMBIOS_HANDLE AvailableHandle
;
262 GetMaxSmbiosHandle(This
, &MaxSmbiosHandle
);
264 Private
= SMBIOS_INSTANCE_FROM_THIS (This
);
265 Head
= &Private
->AllocatedHandleListHead
;
266 for (AvailableHandle
= 1; AvailableHandle
< MaxSmbiosHandle
; AvailableHandle
++) {
267 if (!CheckSmbiosHandleExistance(Head
, AvailableHandle
)) {
268 *Handle
= AvailableHandle
;
273 return EFI_OUT_OF_RESOURCES
;
278 Add an SMBIOS record.
280 @param This The EFI_SMBIOS_PROTOCOL instance.
281 @param ProducerHandle The handle of the controller or driver associated with the SMBIOS information. NULL
283 @param SmbiosHandle On entry, if non-zero, the handle of the SMBIOS record. If zero, then a unique handle
284 will be assigned to the SMBIOS record. If the SMBIOS handle is already in use
285 EFI_ALREADY_STARTED is returned and the SMBIOS record is not updated.
286 @param Record The data for the fixed portion of the SMBIOS record. The format of the record is
287 determined by EFI_SMBIOS_TABLE_HEADER.Type. The size of the formatted area is defined
288 by EFI_SMBIOS_TABLE_HEADER.Length and either followed by a double-null (0x0000) or
289 a set of null terminated strings and a null.
291 @retval EFI_SUCCESS Record was added.
292 @retval EFI_OUT_OF_RESOURCES Record was not added due to lack of system resources.
293 @retval EFI_ALREADY_STARTED The SmbiosHandle passed in was already in use.
299 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
300 IN EFI_HANDLE ProducerHandle
, OPTIONAL
301 IN OUT EFI_SMBIOS_HANDLE
*SmbiosHandle
,
302 IN EFI_SMBIOS_TABLE_HEADER
*Record
309 UINTN NumberOfStrings
;
312 SMBIOS_INSTANCE
*Private
;
313 EFI_SMBIOS_ENTRY
*SmbiosEntry
;
314 EFI_SMBIOS_HANDLE MaxSmbiosHandle
;
315 SMBIOS_HANDLE_ENTRY
*HandleEntry
;
316 EFI_SMBIOS_RECORD_HEADER
*InternalRecord
;
318 if (SmbiosHandle
== NULL
) {
319 return EFI_INVALID_PARAMETER
;
322 Private
= SMBIOS_INSTANCE_FROM_THIS (This
);
324 // Check whether SmbiosHandle is already in use
326 Head
= &Private
->AllocatedHandleListHead
;
327 if (*SmbiosHandle
!= 0 && CheckSmbiosHandleExistance(Head
, *SmbiosHandle
)) {
328 return EFI_ALREADY_STARTED
;
332 // when SmbiosHandle is zero, an available handle will be assigned
334 if (*SmbiosHandle
== 0) {
335 Status
= GetAvailableSmbiosHandle(This
, SmbiosHandle
);
336 if (EFI_ERROR(Status
)) {
341 // Check this handle validity
343 GetMaxSmbiosHandle(This
, &MaxSmbiosHandle
);
344 if (*SmbiosHandle
> MaxSmbiosHandle
) {
345 return EFI_INVALID_PARAMETER
;
350 // Calculate record size and string number
352 Status
= GetSmbiosStructureSize(This
, Record
, &StructureSize
, &NumberOfStrings
);
353 if (EFI_ERROR(Status
)) {
358 // Enter into critical section
360 Status
= EfiAcquireLockOrFail (&Private
->DataLock
);
361 if (EFI_ERROR (Status
)) {
365 RecordSize
= sizeof (EFI_SMBIOS_RECORD_HEADER
) + StructureSize
;
366 TotalSize
= sizeof (EFI_SMBIOS_ENTRY
) + RecordSize
;
369 // Allocate internal buffer
371 SmbiosEntry
= AllocateZeroPool (TotalSize
);
372 if (SmbiosEntry
== NULL
) {
373 EfiReleaseLock (&Private
->DataLock
);
374 return EFI_OUT_OF_RESOURCES
;
376 HandleEntry
= AllocateZeroPool (sizeof(SMBIOS_HANDLE_ENTRY
));
377 if (HandleEntry
== NULL
) {
378 EfiReleaseLock (&Private
->DataLock
);
379 return EFI_OUT_OF_RESOURCES
;
383 // Build Handle Entry and insert into linked list
385 HandleEntry
->Signature
= SMBIOS_HANDLE_ENTRY_SIGNATURE
;
386 HandleEntry
->SmbiosHandle
= *SmbiosHandle
;
387 InsertTailList(&Private
->AllocatedHandleListHead
, &HandleEntry
->Link
);
389 InternalRecord
= (EFI_SMBIOS_RECORD_HEADER
*) (SmbiosEntry
+ 1);
390 Raw
= (VOID
*) (InternalRecord
+ 1);
393 // Build internal record Header
395 InternalRecord
->Version
= EFI_SMBIOS_RECORD_HEADER_VERSION
;
396 InternalRecord
->HeaderSize
= (UINT16
) sizeof (EFI_SMBIOS_RECORD_HEADER
);
397 InternalRecord
->RecordSize
= RecordSize
;
398 InternalRecord
->ProducerHandle
= ProducerHandle
;
399 InternalRecord
->NumberOfStrings
= NumberOfStrings
;
401 // Insert record into the internal linked list
403 SmbiosEntry
->Signature
= EFI_SMBIOS_ENTRY_SIGNATURE
;
404 SmbiosEntry
->RecordHeader
= InternalRecord
;
405 SmbiosEntry
->RecordSize
= TotalSize
;
406 InsertTailList (&Private
->DataListHead
, &SmbiosEntry
->Link
);
408 CopyMem (Raw
, Record
, StructureSize
);
409 ((EFI_SMBIOS_TABLE_HEADER
*)Raw
)->Handle
= *SmbiosHandle
;
412 // Some UEFI drivers (such as network) need some information in SMBIOS table.
413 // Here we create SMBIOS table and publish it in
414 // configuration table, so other UEFI drivers can get SMBIOS table from
415 // configuration table without depending on PI SMBIOS protocol.
417 SmbiosTableConstruction ();
420 // Leave critical section
422 EfiReleaseLock (&Private
->DataLock
);
427 Update the string associated with an existing SMBIOS record.
429 @param This The EFI_SMBIOS_PROTOCOL instance.
430 @param SmbiosHandle SMBIOS Handle of structure that will have its string updated.
431 @param StringNumber The non-zero string number of the string to update
432 @param String Update the StringNumber string with String.
434 @retval EFI_SUCCESS SmbiosHandle had its StringNumber String updated.
435 @retval EFI_INVALID_PARAMETER SmbiosHandle does not exist.
436 @retval EFI_UNSUPPORTED String was not added since it's longer than 64 significant characters.
437 @retval EFI_NOT_FOUND The StringNumber.is not valid for this SMBIOS record.
443 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
444 IN EFI_SMBIOS_HANDLE
*SmbiosHandle
,
445 IN UINTN
*StringNumber
,
452 UINTN TargetStrOffset
;
459 SMBIOS_INSTANCE
*Private
;
460 EFI_SMBIOS_ENTRY
*SmbiosEntry
;
461 EFI_SMBIOS_ENTRY
*ResizedSmbiosEntry
;
462 EFI_SMBIOS_HANDLE MaxSmbiosHandle
;
463 EFI_SMBIOS_TABLE_HEADER
*Record
;
464 EFI_SMBIOS_RECORD_HEADER
*InternalRecord
;
467 // Check args validity
469 GetMaxSmbiosHandle(This
, &MaxSmbiosHandle
);
471 if (*SmbiosHandle
> MaxSmbiosHandle
) {
472 return EFI_INVALID_PARAMETER
;
475 if (String
== NULL
) {
479 if (*StringNumber
== 0) {
480 return EFI_NOT_FOUND
;
483 InputStrLen
= AsciiStrLen(String
);
486 // Reference SMBIOS 2.7, chapter 6.1.3, it will have no limit on the length of each individual text string
488 if (This
->MajorVersion
< 2 || (This
->MajorVersion
== 2 && This
->MinorVersion
< 7)) {
489 if (InputStrLen
> SMBIOS_STRING_MAX_LENGTH
) {
490 return EFI_UNSUPPORTED
;
494 Private
= SMBIOS_INSTANCE_FROM_THIS (This
);
496 // Enter into critical section
498 Status
= EfiAcquireLockOrFail (&Private
->DataLock
);
499 if (EFI_ERROR (Status
)) {
503 Head
= &Private
->DataListHead
;
504 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
505 SmbiosEntry
= SMBIOS_ENTRY_FROM_LINK(Link
);
506 Record
= (EFI_SMBIOS_TABLE_HEADER
*)(SmbiosEntry
->RecordHeader
+ 1);
508 if (Record
->Handle
== *SmbiosHandle
) {
510 // Find out the specified SMBIOS record
512 if (*StringNumber
> SmbiosEntry
->RecordHeader
->NumberOfStrings
) {
513 EfiReleaseLock (&Private
->DataLock
);
514 return EFI_NOT_FOUND
;
517 // Point to unformed string section
519 StrStart
= (CHAR8
*) Record
+ Record
->Length
;
521 for (StrIndex
= 1, TargetStrOffset
= 0; StrIndex
< *StringNumber
; StrStart
++, TargetStrOffset
++) {
523 // A string ends in 00h
525 if (*StrStart
== 0) {
530 // String section ends in double-null (0000h)
532 if (*StrStart
== 0 && *(StrStart
+ 1) == 0) {
533 EfiReleaseLock (&Private
->DataLock
);
534 return EFI_NOT_FOUND
;
538 if (*StrStart
== 0) {
544 // Now we get the string target
546 TargetStrLen
= AsciiStrLen(StrStart
);
547 if (InputStrLen
== TargetStrLen
) {
548 AsciiStrCpy(StrStart
, String
);
550 // Some UEFI drivers (such as network) need some information in SMBIOS table.
551 // Here we create SMBIOS table and publish it in
552 // configuration table, so other UEFI drivers can get SMBIOS table from
553 // configuration table without depending on PI SMBIOS protocol.
555 SmbiosTableConstruction ();
556 EfiReleaseLock (&Private
->DataLock
);
561 // Original string buffer size is not exactly match input string length.
562 // Re-allocate buffer is needed.
564 NewEntrySize
= SmbiosEntry
->RecordSize
+ InputStrLen
- TargetStrLen
;
565 ResizedSmbiosEntry
= AllocateZeroPool (NewEntrySize
);
567 if (ResizedSmbiosEntry
== NULL
) {
568 EfiReleaseLock (&Private
->DataLock
);
569 return EFI_OUT_OF_RESOURCES
;
572 InternalRecord
= (EFI_SMBIOS_RECORD_HEADER
*) (ResizedSmbiosEntry
+ 1);
573 Raw
= (VOID
*) (InternalRecord
+ 1);
576 // Build internal record Header
578 InternalRecord
->Version
= EFI_SMBIOS_RECORD_HEADER_VERSION
;
579 InternalRecord
->HeaderSize
= (UINT16
) sizeof (EFI_SMBIOS_RECORD_HEADER
);
580 InternalRecord
->RecordSize
= SmbiosEntry
->RecordHeader
->RecordSize
+ InputStrLen
- TargetStrLen
;
581 InternalRecord
->ProducerHandle
= SmbiosEntry
->RecordHeader
->ProducerHandle
;
582 InternalRecord
->NumberOfStrings
= SmbiosEntry
->RecordHeader
->NumberOfStrings
;
585 // Copy SMBIOS structure and optional strings.
587 CopyMem (Raw
, SmbiosEntry
->RecordHeader
+ 1, Record
->Length
+ TargetStrOffset
);
588 CopyMem ((VOID
*)((UINTN
)Raw
+ Record
->Length
+ TargetStrOffset
), String
, InputStrLen
+ 1);
589 CopyMem ((CHAR8
*)((UINTN
)Raw
+ Record
->Length
+ TargetStrOffset
+ InputStrLen
+ 1),
590 (CHAR8
*)Record
+ Record
->Length
+ TargetStrOffset
+ TargetStrLen
+ 1,
591 SmbiosEntry
->RecordHeader
->RecordSize
- sizeof (EFI_SMBIOS_RECORD_HEADER
) - Record
->Length
- TargetStrOffset
- TargetStrLen
- 1);
596 ResizedSmbiosEntry
->Signature
= EFI_SMBIOS_ENTRY_SIGNATURE
;
597 ResizedSmbiosEntry
->RecordHeader
= InternalRecord
;
598 ResizedSmbiosEntry
->RecordSize
= NewEntrySize
;
599 InsertTailList (Link
->ForwardLink
, &ResizedSmbiosEntry
->Link
);
604 RemoveEntryList(Link
);
605 FreePool(SmbiosEntry
);
607 // Some UEFI drivers (such as network) need some information in SMBIOS table.
608 // Here we create SMBIOS table and publish it in
609 // configuration table, so other UEFI drivers can get SMBIOS table from
610 // configuration table without depending on PI SMBIOS protocol.
612 SmbiosTableConstruction ();
613 EfiReleaseLock (&Private
->DataLock
);
618 EfiReleaseLock (&Private
->DataLock
);
619 return EFI_INVALID_PARAMETER
;
623 Remove an SMBIOS record.
625 @param This The EFI_SMBIOS_PROTOCOL instance.
626 @param SmbiosHandle The handle of the SMBIOS record to remove.
628 @retval EFI_SUCCESS SMBIOS record was removed.
629 @retval EFI_INVALID_PARAMETER SmbiosHandle does not specify a valid SMBIOS record.
635 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
636 IN EFI_SMBIOS_HANDLE SmbiosHandle
642 EFI_SMBIOS_HANDLE MaxSmbiosHandle
;
643 SMBIOS_INSTANCE
*Private
;
644 EFI_SMBIOS_ENTRY
*SmbiosEntry
;
645 SMBIOS_HANDLE_ENTRY
*HandleEntry
;
646 EFI_SMBIOS_TABLE_HEADER
*Record
;
649 // Check args validity
651 GetMaxSmbiosHandle(This
, &MaxSmbiosHandle
);
653 if (SmbiosHandle
> MaxSmbiosHandle
) {
654 return EFI_INVALID_PARAMETER
;
657 Private
= SMBIOS_INSTANCE_FROM_THIS (This
);
659 // Enter into critical section
661 Status
= EfiAcquireLockOrFail (&Private
->DataLock
);
662 if (EFI_ERROR (Status
)) {
666 Head
= &Private
->DataListHead
;
667 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
668 SmbiosEntry
= SMBIOS_ENTRY_FROM_LINK(Link
);
669 Record
= (EFI_SMBIOS_TABLE_HEADER
*)(SmbiosEntry
->RecordHeader
+ 1);
670 if (Record
->Handle
== SmbiosHandle
) {
672 // Remove specified smobios record from DataList
674 RemoveEntryList(Link
);
675 FreePool(SmbiosEntry
);
677 // Remove this handle from AllocatedHandleList
679 Head
= &Private
->AllocatedHandleListHead
;
680 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
681 HandleEntry
= SMBIOS_HANDLE_ENTRY_FROM_LINK(Link
);
682 if (HandleEntry
->SmbiosHandle
== SmbiosHandle
) {
683 RemoveEntryList(Link
);
684 FreePool(HandleEntry
);
689 // Some UEFI drivers (such as network) need some information in SMBIOS table.
690 // Here we create SMBIOS table and publish it in
691 // configuration table, so other UEFI drivers can get SMBIOS table from
692 // configuration table without depending on PI SMBIOS protocol.
694 SmbiosTableConstruction ();
695 EfiReleaseLock (&Private
->DataLock
);
701 // Leave critical section
703 EfiReleaseLock (&Private
->DataLock
);
704 return EFI_INVALID_PARAMETER
;
709 Allow the caller to discover all or some of the SMBIOS records.
711 @param This The EFI_SMBIOS_PROTOCOL instance.
712 @param SmbiosHandle On entry, points to the previous handle of the SMBIOS record. On exit, points to the
713 next SMBIOS record handle. If it is zero on entry, then the first SMBIOS record
714 handle will be returned. If it returns zero on exit, then there are no more SMBIOS records.
715 @param Type On entry it means return the next SMBIOS record of type Type. If a NULL is passed in
716 this functionally it ignored. Type is not modified by the GetNext() function.
717 @param Record On exit, points to the SMBIOS Record consisting of the formatted area followed by
718 the unformatted area. The unformatted area optionally contains text strings.
719 @param ProducerHandle On exit, points to the ProducerHandle registered by Add(). If no ProducerHandle was passed into Add() NULL is returned.
720 If a NULL pointer is passed in no data will be returned
722 @retval EFI_SUCCESS SMBIOS record information was successfully returned in Record.
723 @retval EFI_NOT_FOUND The SMBIOS record with SmbiosHandle was the last available record.
729 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
730 IN OUT EFI_SMBIOS_HANDLE
*SmbiosHandle
,
731 IN EFI_SMBIOS_TYPE
*Type
, OPTIONAL
732 OUT EFI_SMBIOS_TABLE_HEADER
**Record
,
733 OUT EFI_HANDLE
*ProducerHandle OPTIONAL
736 BOOLEAN StartPointFound
;
739 SMBIOS_INSTANCE
*Private
;
740 EFI_SMBIOS_ENTRY
*SmbiosEntry
;
741 EFI_SMBIOS_TABLE_HEADER
*SmbiosTableHeader
;
743 if (SmbiosHandle
== NULL
) {
744 return EFI_INVALID_PARAMETER
;
747 StartPointFound
= FALSE
;
748 Private
= SMBIOS_INSTANCE_FROM_THIS (This
);
749 Head
= &Private
->DataListHead
;
750 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
751 SmbiosEntry
= SMBIOS_ENTRY_FROM_LINK(Link
);
752 SmbiosTableHeader
= (EFI_SMBIOS_TABLE_HEADER
*)(SmbiosEntry
->RecordHeader
+ 1);
755 // If SmbiosHandle is zero, the first matched SMBIOS record handle will be returned
757 if (*SmbiosHandle
== 0) {
758 if ((Type
!= NULL
) && (*Type
!= SmbiosTableHeader
->Type
)) {
762 *SmbiosHandle
= SmbiosTableHeader
->Handle
;
763 *Record
=SmbiosTableHeader
;
764 if (ProducerHandle
!= NULL
) {
765 *ProducerHandle
= SmbiosEntry
->RecordHeader
->ProducerHandle
;
771 // Start this round search from the next SMBIOS handle
773 if (!StartPointFound
&& (*SmbiosHandle
== SmbiosTableHeader
->Handle
)) {
774 StartPointFound
= TRUE
;
778 if (StartPointFound
) {
779 if ((Type
!= NULL
) && (*Type
!= SmbiosTableHeader
->Type
)) {
783 *SmbiosHandle
= SmbiosTableHeader
->Handle
;
784 *Record
= SmbiosTableHeader
;
785 if (ProducerHandle
!= NULL
) {
786 *ProducerHandle
= SmbiosEntry
->RecordHeader
->ProducerHandle
;
794 return EFI_NOT_FOUND
;
799 Allow the caller to discover all of the SMBIOS records.
801 @param This The EFI_SMBIOS_PROTOCOL instance.
802 @param CurrentSmbiosEntry On exit, points to the SMBIOS entry on the list which includes the returned SMBIOS record information.
803 If *CurrentSmbiosEntry is NULL on entry, then the first SMBIOS entry on the list will be returned.
804 @param Record On exit, points to the SMBIOS Record consisting of the formatted area followed by
805 the unformatted area. The unformatted area optionally contains text strings.
807 @retval EFI_SUCCESS SMBIOS record information was successfully returned in Record.
808 *CurrentSmbiosEntry points to the SMBIOS entry which includes the returned SMBIOS record information.
809 @retval EFI_NOT_FOUND There is no more SMBIOS entry.
814 GetNextSmbiosRecord (
815 IN CONST EFI_SMBIOS_PROTOCOL
*This
,
816 IN OUT EFI_SMBIOS_ENTRY
**CurrentSmbiosEntry
,
817 OUT EFI_SMBIOS_TABLE_HEADER
**Record
822 SMBIOS_INSTANCE
*Private
;
823 EFI_SMBIOS_ENTRY
*SmbiosEntry
;
824 EFI_SMBIOS_TABLE_HEADER
*SmbiosTableHeader
;
826 Private
= SMBIOS_INSTANCE_FROM_THIS (This
);
827 if (*CurrentSmbiosEntry
== NULL
) {
829 // Get the beginning of SMBIOS entry.
831 Head
= &Private
->DataListHead
;
834 // Get previous SMBIOS entry and make it as start point.
836 Head
= &(*CurrentSmbiosEntry
)->Link
;
839 Link
= Head
->ForwardLink
;
841 if (Link
== &Private
->DataListHead
) {
843 // If no more SMBIOS entry in the list, return not found.
845 return EFI_NOT_FOUND
;
848 SmbiosEntry
= SMBIOS_ENTRY_FROM_LINK(Link
);
849 SmbiosTableHeader
= (EFI_SMBIOS_TABLE_HEADER
*)(SmbiosEntry
->RecordHeader
+ 1);
850 *Record
= SmbiosTableHeader
;
851 *CurrentSmbiosEntry
= SmbiosEntry
;
856 Assembles SMBIOS table from the SMBIOS protocol. Produce Table
857 Entry Point and return the pointer to it.
859 @param TableEntryPointStructure On exit, points to the SMBIOS entrypoint structure.
861 @retval EFI_SUCCESS Structure created sucessfully.
862 @retval EFI_NOT_READY Some of The SMBIOS records was not available yet.
863 @retval EFI_OUT_OF_RESOURCES No enough memory.
869 OUT VOID
**TableEntryPointStructure
872 UINT8
*BufferPointer
;
876 EFI_SMBIOS_HANDLE SmbiosHandle
;
877 EFI_SMBIOS_PROTOCOL
*SmbiosProtocol
;
878 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
879 EFI_SMBIOS_TABLE_HEADER
*SmbiosRecord
;
880 EFI_SMBIOS_TABLE_END_STRUCTURE EndStructure
;
881 EFI_SMBIOS_ENTRY
*CurrentSmbiosEntry
;
882 UINTN PreAllocatedPages
;
884 Status
= EFI_SUCCESS
;
885 BufferPointer
= NULL
;
888 // Get Smbios protocol to traverse SMBIOS records.
890 SmbiosProtocol
= &mPrivateData
.Smbios
;
892 PreAllocatedPages
= EFI_SIZE_TO_PAGES (EntryPointStructure
->TableLength
);
895 // Make some statistics about all the structures
897 EntryPointStructure
->NumberOfSmbiosStructures
= 0;
898 EntryPointStructure
->TableLength
= 0;
899 EntryPointStructure
->MaxStructureSize
= 0;
902 // Calculate EPS Table Length
904 CurrentSmbiosEntry
= NULL
;
906 Status
= GetNextSmbiosRecord (SmbiosProtocol
, &CurrentSmbiosEntry
, &SmbiosRecord
);
908 if (Status
== EFI_SUCCESS
) {
909 GetSmbiosStructureSize(SmbiosProtocol
, SmbiosRecord
, &RecordSize
, &NumOfStr
);
911 // Record NumberOfSmbiosStructures, TableLength and MaxStructureSize
913 EntryPointStructure
->NumberOfSmbiosStructures
++;
914 EntryPointStructure
->TableLength
= (UINT16
) (EntryPointStructure
->TableLength
+ RecordSize
);
915 if (RecordSize
> EntryPointStructure
->MaxStructureSize
) {
916 EntryPointStructure
->MaxStructureSize
= (UINT16
) RecordSize
;
919 } while (!EFI_ERROR(Status
));
922 // Create End-Of-Table structure
924 GetMaxSmbiosHandle(SmbiosProtocol
, &SmbiosHandle
);
925 EndStructure
.Header
.Type
= EFI_SMBIOS_TYPE_END_OF_TABLE
;
926 EndStructure
.Header
.Length
= (UINT8
) sizeof (EFI_SMBIOS_TABLE_HEADER
);
927 EndStructure
.Header
.Handle
= SmbiosHandle
;
928 EndStructure
.Tailing
[0] = 0;
929 EndStructure
.Tailing
[1] = 0;
930 EntryPointStructure
->NumberOfSmbiosStructures
++;
931 EntryPointStructure
->TableLength
= (UINT16
) (EntryPointStructure
->TableLength
+ sizeof (EndStructure
));
932 if (sizeof (EndStructure
) > EntryPointStructure
->MaxStructureSize
) {
933 EntryPointStructure
->MaxStructureSize
= (UINT16
) sizeof (EndStructure
);
936 if (EFI_SIZE_TO_PAGES (EntryPointStructure
->TableLength
) > PreAllocatedPages
) {
938 // If new SMBIOS talbe size exceeds the original pre-allocated page,
939 // it is time to re-allocate memory (below 4GB).
941 if (EntryPointStructure
->TableAddress
!= 0) {
943 // Free the original pre-allocated page
946 (VOID
*)(UINTN
)EntryPointStructure
->TableAddress
,
949 EntryPointStructure
->TableAddress
= 0;
952 PhysicalAddress
= 0xffffffff;
953 Status
= gBS
->AllocatePages (
955 EfiReservedMemoryType
,
956 EFI_SIZE_TO_PAGES (EntryPointStructure
->TableLength
),
959 if (EFI_ERROR (Status
)) {
960 return EFI_OUT_OF_RESOURCES
;
962 EntryPointStructure
->TableAddress
= (UINT32
) PhysicalAddress
;
966 // Assemble the tables
968 BufferPointer
= (UINT8
*) (UINTN
) EntryPointStructure
->TableAddress
;
969 CurrentSmbiosEntry
= NULL
;
971 Status
= GetNextSmbiosRecord (SmbiosProtocol
, &CurrentSmbiosEntry
, &SmbiosRecord
);
973 if (Status
== EFI_SUCCESS
) {
974 GetSmbiosStructureSize(SmbiosProtocol
, SmbiosRecord
, &RecordSize
, &NumOfStr
);
975 CopyMem (BufferPointer
, SmbiosRecord
, RecordSize
);
976 BufferPointer
= BufferPointer
+ RecordSize
;
978 } while (!EFI_ERROR(Status
));
981 // Assemble End-Of-Table structure
983 CopyMem (BufferPointer
, &EndStructure
, sizeof (EndStructure
));
986 // Fixup checksums in the Entry Point Structure
988 EntryPointStructure
->IntermediateChecksum
=
989 CalculateCheckSum8 ((UINT8
*) EntryPointStructure
+ 0x10, EntryPointStructure
->EntryPointLength
- 0x10);
990 EntryPointStructure
->EntryPointStructureChecksum
=
991 CalculateCheckSum8 ((UINT8
*) EntryPointStructure
, EntryPointStructure
->EntryPointLength
);
994 // Returns the pointer
996 *TableEntryPointStructure
= EntryPointStructure
;
1002 Create SMBIOS Table and install it to the System Table.
1006 SmbiosTableConstruction (
1013 Status
= SmbiosCreateTable ((VOID
**) &Eps
);
1014 if (!EFI_ERROR (Status
)) {
1015 gBS
->InstallConfigurationTable (&gEfiSmbiosTableGuid
, Eps
);
1021 Driver to produce Smbios protocol and pre-allocate 1 page for the final SMBIOS table.
1023 @param ImageHandle Module's image handle
1024 @param SystemTable Pointer of EFI_SYSTEM_TABLE
1026 @retval EFI_SUCCESS Smbios protocol installed
1027 @retval Other No protocol installed, unload driver.
1032 SmbiosDriverEntryPoint (
1033 IN EFI_HANDLE ImageHandle
,
1034 IN EFI_SYSTEM_TABLE
*SystemTable
1038 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
1040 mPrivateData
.Signature
= SMBIOS_INSTANCE_SIGNATURE
;
1041 mPrivateData
.Smbios
.Add
= SmbiosAdd
;
1042 mPrivateData
.Smbios
.UpdateString
= SmbiosUpdateString
;
1043 mPrivateData
.Smbios
.Remove
= SmbiosRemove
;
1044 mPrivateData
.Smbios
.GetNext
= SmbiosGetNext
;
1045 mPrivateData
.Smbios
.MajorVersion
= (UINT8
) (FixedPcdGet16 (PcdSmbiosVersion
) >> 8);
1046 mPrivateData
.Smbios
.MinorVersion
= (UINT8
) (FixedPcdGet16 (PcdSmbiosVersion
) & 0x00ff);
1048 InitializeListHead (&mPrivateData
.DataListHead
);
1049 InitializeListHead (&mPrivateData
.AllocatedHandleListHead
);
1050 EfiInitializeLock (&mPrivateData
.DataLock
, TPL_NOTIFY
);
1053 // Initialize the EntryPointStructure with initial values.
1054 // Allocate memory (below 4GB).
1056 PhysicalAddress
= 0xffffffff;
1057 Status
= gBS
->AllocatePages (
1059 EfiReservedMemoryType
,
1060 EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_ENTRY_POINT
)),
1063 if (EFI_ERROR (Status
)) {
1064 return EFI_OUT_OF_RESOURCES
;
1067 EntryPointStructure
= (SMBIOS_TABLE_ENTRY_POINT
*) (UINTN
) PhysicalAddress
;
1070 EntryPointStructure
,
1071 &EntryPointStructureData
,
1072 sizeof (SMBIOS_TABLE_ENTRY_POINT
)
1076 // Pre-allocate 1 page for SMBIOS table below 4GB.
1077 // SMBIOS table will be updated when new SMBIOS type is added or
1078 // existing SMBIOS type is updated. If the total size of SMBIOS table exceeds 1 page,
1079 // we will re-allocate new memory when creating whole SMBIOS table.
1081 PhysicalAddress
= 0xffffffff;
1082 Status
= gBS
->AllocatePages (
1084 EfiReservedMemoryType
,
1088 if (EFI_ERROR (Status
)) {
1089 FreePages ((VOID
*) EntryPointStructure
, EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_ENTRY_POINT
)));
1090 EntryPointStructure
= NULL
;
1091 return EFI_OUT_OF_RESOURCES
;
1094 EntryPointStructure
->TableAddress
= (UINT32
) PhysicalAddress
;
1095 EntryPointStructure
->TableLength
= EFI_PAGES_TO_SIZE (1);
1098 // Make a new handle and install the protocol
1100 mPrivateData
.Handle
= NULL
;
1101 Status
= gBS
->InstallProtocolInterface (
1102 &mPrivateData
.Handle
,
1103 &gEfiSmbiosProtocolGuid
,
1104 EFI_NATIVE_INTERFACE
,
1105 &mPrivateData
.Smbios