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_PROTOCOL
                  NULL,
                  (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,不成功为非0
    return 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;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值