本文主要是介绍UEFI——Shell下读取SMBIOS信息,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一、SMBIOS简介
SMBIOS的全称为System Management BIOS,它不是一个BIOS,只是与BIOS相关。它是一个规范,定义了BIOS传递给操作系统的系统管理信息。它也表示了一系列的数据结构,包含了各类信息,由BIOS启动过程中创建并放在特定的内存,之后操作系统可以拿来用。
整个 SMBIOS_STRUCTURE
结构体定义了 SMBIOS 表中的一个基本单元。每个 SMBIOS 结构都包含一个类型、长度和句柄,后面跟着与该类型相关的特定数据。这些结构体被组织成一个链表,可以在系统启动时由系统固件、操作系统或管理工具读取,以获取系统的硬件配置和管理信息。
typedef struct {SMBIOS_TYPE Type;UINT8 Length;SMBIOS_HANDLE Handle;
} SMBIOS_STRUCTURE;
二、Shell下读取SMBIOS信息
首先介绍结构体_EFI_SMBIOS_PROTOCOL,用于定义在EFI应用程序和驱动程序中管理SMBIOS表的接口。其代码原型为:
struct _EFI_SMBIOS_PROTOCOL {EFI_SMBIOS_ADD Add; //添加SMBIOS记录EFI_SMBIOS_UPDATE_STRING UpdateString;EFI_SMBIOS_REMOVE Remove;EFI_SMBIOS_GET_NEXT GetNext;UINT8 MajorVersion; ///< The major revision of the SMBIOS specification supported.UINT8 MinorVersion; ///< The minor revision of the SMBIOS specification supported.
};
其中添加SMBIOS记录的为EFI_SMBIOS_ADD,
typedef
EFI_STATUS
(EFIAPI *EFI_SMBIOS_ADD)(IN CONST EFI_SMBIOS_PROTOCOL *This, //手动添加的This指针,始终指向当前的EFI_SMBIOS_PROTOCOL实例IN EFI_HANDLE ProducerHandle OPTIONAL, //与 SMBIOS 信息关联的控制器或驱动程序的句柄。NULL 表示没有句柄。IN OUT EFI_SMBIOS_HANDLE *SmbiosHandle, //输出参数,要添加的 SMBIOS 记录的句柄。如果为 FFFEh,则将为 SMBIOS 记录分配唯一句柄。如果 SMBIOS 句柄已在使用中,则会返回 EFI_ALREADY_STARTED,并且不会更新 SMBIOS 记录。IN EFI_SMBIOS_TABLE_HEADER *Record //SMBIOS记录的固定部分的数据);
更新SMBIOS信息字符串用EFI_SMBIOS_UPDATE_STRING
typedef
EFI_STATUS
(EFIAPI *EFI_SMBIOS_UPDATE_STRING)(IN CONST EFI_SMBIOS_PROTOCOL *This, //EFI_SMBIOS_PROTOCOL实例IN EFI_SMBIOS_HANDLE *SmbiosHandle, //要更新字符串的SMBIOS句柄IN UINTN *StringNumber, //要更新的字符串IN CHAR8 *String //用于更新的字符串);
删除SMBIOS记录用EFI_SMBIOS_REMOVE
typedef
EFI_STATUS
(EFIAPI *EFI_SMBIOS_REMOVE)(IN CONST EFI_SMBIOS_PROTOCOL *This,IN EFI_SMBIOS_HANDLE SmbiosHandle //要删除的SMBIOS记录的句柄);
允许调用者查找全部或部分SMBIOS记录用EFI_SMBIOS_GET_NEXT
typedef
EFI_STATUS
(EFIAPI *EFI_SMBIOS_GET_NEXT)(IN CONST EFI_SMBIOS_PROTOCOL *This,IN OUT EFI_SMBIOS_HANDLE *SmbiosHandle, //进入时,指向 SMBIOS 记录的上一个句柄。退出时,指向下一个 SMBIOS 记录句柄。如果输入时为 FFFEh,则将返回第一个 SMBIOS 记录句柄。如果它在退出时返回 FFFEh,则没有更多的 SMBIOS 记录。IN EFI_SMBIOS_TYPE *Type OPTIONAL, //进入时,它指向要返回的下一条 SMBIOS 记录的类型。如果为 NULL,则表示将返回任何类型的下一条记录。此函数不会修改 Type。OUT EFI_SMBIOS_TABLE_HEADER **Record, //输出参数,退出时,指向指向 SMBIOS 记录的指针,该记录由格式化区域和未格式化区域组成。未格式化区域(可选)包含文本字符串。OUT EFI_HANDLE *ProducerHandle OPTIONAL //输出参数,带有 SmbiosHandle 的 SMBIOS 记录是最后一条可用记录。);
在使用SMBIOSProtocol的时候,首先通过LocateProtocol找到实例
Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, //gEfiSmbiosProtocolGuid是一个全局变量,用于唯一标识EFI_SMBIOS_PROTOCOLNULL,(VOID**)&Smbios //输出参数,指向找到的EFI_SMBIOS_PROCOTOL实例);
宏定义SMBIOS_HANDLE_PI_RESERVED设定了一个特定的值0xFFFE,这个值在SMBIOS协议中被保留用于特定的目的,SMBIOS_HANDLE通常是一个唯一标识符,用在SMBIOS表中引起特定的SMBIOS结构
//根据SMBIOS 2.7版本的6.1.2章节,以及UEFI平台初始化规范,宏定义SMBIOS_HANDLE_PI_RESERVED 设置为 0xFFFE,当 EFI_SMBIOS_PROTOCOL.Add() 函数的 Handle 参数被设置为 0xFFFE 时,它指示固件自动分配一个未被使用的句柄号给新的 SMBIOS 结构。这意味着调用者不需要指定具体的句柄号,而是由固件来选择一个合适的、未被占用的句柄号。
//0xFFFE这个值不会被用作任何其他目的,它专门用作自动分配句柄号
#define SMBIOS_HANDLE_PI_RESERVED 0xFFFE
完整代码如下:
#include <uefi.h>
#include <Library/UefiLib.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Protocol/Smbios.h>EFI_STATUS
EFIAPI
MyHelloWorldSmbiosAppEntry(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE *SystemTable
)
{ EFI_STATUS Status = EFI_SUCCESS;EFI_SMBIOS_PROTOCOL *Smbios;EFI_SMBIOS_HANDLE SmbiosHandle;EFI_SMBIOS_TABLE_HEADER *Record;DEBUG ((EFI_D_ERROR , "[MyHelloWorldSmbios] MyHelloWorldSmbiosAppEntry Start..\n"));//// Find the SMBIOS protocol//Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid,NULL,(VOID**)&Smbios);if (EFI_ERROR (Status)) { //需要注意的是EFI_SUCCESS通常被定义为0,即成功为0,不成功为非0return Status;}SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;Status = Smbios->GetNext (Smbios, &SmbiosHandle, NULL, &Record, NULL);while (!EFI_ERROR(Status)) {DEBUG ((EFI_D_ERROR, "[MyHelloWorldSmbios] %d ..\n", Record->Type));// if (Record->Type == SMBIOS_TYPE_BIOS_INFORMATION) {// Type0Record = (SMBIOS_TABLE_TYPE0 *) Record;// StrIndex = Type0Record->BiosVersion;// GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type0Record + Type0Record->Hdr.Length), StrIndex, &NewString);// FirmwareVersionString = (CHAR16 *) PcdGetPtr (PcdFirmwareVersionString);// if (*FirmwareVersionString != 0x0000 ) {// FreePool (NewString);// NewString = (CHAR16 *) PcdGetPtr (PcdFirmwareVersionString);// UiCustomizeFrontPageBanner (3, TRUE, &NewString);// HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_BIOS_VERSION), NewString, NULL);// } else {// UiCustomizeFrontPageBanner (3, TRUE, &NewString);// HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_BIOS_VERSION), NewString, NULL);// FreePool (NewString);// }// }Status = Smbios->GetNext (Smbios, &SmbiosHandle, NULL, &Record, NULL);}DEBUG ((EFI_D_ERROR, "[MyHelloWorldSmbios] MyHelloWorldSmbiosAppEntry End..\n"));return Status;
}
这篇关于UEFI——Shell下读取SMBIOS信息的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!