SMBIOS基础

1.概念

SMBIOS(System Management BIOS)是主板或系统制造者以标准格式显示产品管理信息所需遵循的统一规范。

2.组成

DMI(Desktop Management Interface, DMI)是帮助收集电脑系统信息的管理系统,DMI信息的收集必须在严格遵照SMBIOS规范的前提下进行。DMI设计适用于任何的平台和操作系统。DMI充当了管理工具和系统层之间接口的角色。它建立了标准的可管理系统更加方便了电脑厂商和用户对系统的了解。

DMI主要组成部分MIF(Management Information Format)数据库,存储所有电脑系统和配件有关的信息。

3.SMBIOS的访问方式

  1. 即插即用功能接口访问SmBios(基本不使用)

2.基于表结构的方式访问SmBios

表内容是table entry point的数据

位置

名称

长度

描述

00H

关键字

4BYTE

固定是”_SM_”

04H

校验和

1BYTE

用于校验数据

05H

表结构长度

1BYTE

Entry Point Structure表的长度

06H

Major版本号

1BYTE

用于判断SMBIOS版本

07H

Minor版本号

1BYTE

用于判断SMBIOS版本

08H

表结构大小

2BYTE

用于即插即用接口方法获得数据表结构长度

0AH

EPS修正

1BYTE

0B-0FH

格式区域

5BYTE

存放解释EPS修正的信息

10H

关键字

5BYTE

固定为“_DMI_”

15H

校验和

1BYTE

Intermediate Entry Point Structure (IEPS)的校验和

16H

结构表长度

2BYTE

SMBIOS 结构表的长度

18H

结构表地址

4BYTE

SMBIOS 结构表的真实内存位置

1CH

结构表个数

2BYTE

SMBIOS结构表数目

1EH

Smbios BCD修正

1BYTE

typedef struct {
  UINT8     AnchorString[4];
  UINT8     EntryPointStructureChecksum;
  UINT8     EntryPointLength;
  UINT8     MajorVersion;
  UINT8     MinorVersion;
  UINT16    MaxStructureSize;
  UINT8     EntryPointRevision;
  UINT8     FormattedArea[5];
  UINT8     IntermediateAnchorString[5];
  UINT8     IntermediateChecksum;
  UINT16    TableLength;
  UINT32    TableAddress;
  UINT16    NumberOfSmbiosStructures;
  UINT8     SmbiosBcdRevision;
} SMBIOS_TABLE_ENTRY_POINT;

typedef struct {
  UINT8     AnchorString[5];
  UINT8     EntryPointStructureChecksum;
  UINT8     EntryPointLength;
  UINT8     MajorVersion;
  UINT8     MinorVersion;
  UINT8     DocRev;
  UINT8     EntryPointRevision;
  UINT8     Reserved;
  UINT32    TableMaximumSize;
  UINT64    TableAddress;
} SMBIOS_TABLE_3_0_ENTRY_POINT;

(1)非EFI是在固定的物理内存中寻找EPS表(0x000F0000-0x000FFFFF)

(2)UEFI访问EPS表可通过GUID(gEfiSmbiosTableGuid/gEfiSmbios3TableGuid)直接指向EPS表

在访问时,先找到Entry Point Structre(EPS)表,在EPS表中包含了一些相应的字段以及SMBIOS table的地址,通过这个地址即可找到SMBIOS table。(这里值得注意的是UEFI中,EPS表是存储在system table中的 ps:这里只贴了一些简易的代码)

  SMBIOS_TABLE_ENTRY_POINT        *SmbiosTable;
  SMBIOS_TABLE_3_0_ENTRY_POINT    *Smbios3Table;

  mbiosTable        = NULL;
  Smbios3Table       = NULL;
  SmbiosTableAddress = NULL;
  TableLength        = 0;

  if (mSmbios->MajorVersion >= 3) {
    Status = EfiGetSystemConfigurationTable (
               &gEfiSmbios3TableGuid,
               (VOID **)&Smbios3Table
               );
    if (!EFI_ERROR (Status)) {
      DEBUG ((DEBUG_INFO, "Smbios3Table:\n"));
      DEBUG ((
        DEBUG_INFO,
        "  AnchorString                - '%c%c%c%c%c'\n",
        Smbios3Table->AnchorString[0],
        Smbios3Table->AnchorString[1],
        Smbios3Table->AnchorString[2],
        Smbios3Table->AnchorString[3],
        Smbios3Table->AnchorString[4]
        ));
      DEBUG ((DEBUG_INFO, "  EntryPointStructureChecksum - 0x%02x\n", Smbios3Table->EntryPointStructureChecksum));
      DEBUG ((DEBUG_INFO, "  EntryPointLength            - 0x%02x\n", Smbios3Table->EntryPointLength));
      DEBUG ((DEBUG_INFO, "  MajorVersion                - 0x%02x\n", Smbios3Table->MajorVersion));
      DEBUG ((DEBUG_INFO, "  MinorVersion                - 0x%02x\n", Smbios3Table->MinorVersion));
      DEBUG ((DEBUG_INFO, "  DocRev                      - 0x%02x\n", Smbios3Table->DocRev));
      DEBUG ((DEBUG_INFO, "  EntryPointRevision          - 0x%02x\n", Smbios3Table->EntryPointRevision));
      DEBUG ((DEBUG_INFO, "  TableMaximumSize            - 0x%08x\n", Smbios3Table->TableMaximumSize));
      DEBUG ((DEBUG_INFO, "  TableAddress                - 0x%016lx\n", Smbios3Table->TableAddress));
    }
  }

  if (Smbios3Table == NULL) {
    Status = EfiGetSystemConfigurationTable (
               &gEfiSmbiosTableGuid,
               (VOID **)&SmbiosTable
               );
    if (!EFI_ERROR (Status)) {
      DEBUG ((DEBUG_INFO, "SmbiosTable:\n"));
      DEBUG ((
        DEBUG_INFO,
        "  AnchorString                - '%c%c%c%c'\n",
        SmbiosTable->AnchorString[0],
        SmbiosTable->AnchorString[1],
        SmbiosTable->AnchorString[2],
        SmbiosTable->AnchorString[3]
        ));
      DEBUG ((DEBUG_INFO, "  EntryPointStructureChecksum - 0x%02x\n", SmbiosTable->EntryPointStructureChecksum));
      DEBUG ((DEBUG_INFO, "  EntryPointLength            - 0x%02x\n", SmbiosTable->EntryPointLength));
      DEBUG ((DEBUG_INFO, "  MajorVersion                - 0x%02x\n", SmbiosTable->MajorVersion));
      DEBUG ((DEBUG_INFO, "  MinorVersion                - 0x%02x\n", SmbiosTable->MinorVersion));
      DEBUG ((DEBUG_INFO, "  MaxStructureSize            - 0x%08x\n", SmbiosTable->MaxStructureSize));
      DEBUG ((DEBUG_INFO, "  EntryPointRevision          - 0x%02x\n", SmbiosTable->EntryPointRevision));
      DEBUG ((
        DEBUG_INFO,
        "  FormattedArea               - '%c%c%c%c%c'\n",
        SmbiosTable->FormattedArea[0],
        SmbiosTable->FormattedArea[1],
        SmbiosTable->FormattedArea[2],
        SmbiosTable->FormattedArea[3],
        SmbiosTable->FormattedArea[4]
        ));
      DEBUG ((
        DEBUG_INFO,
        "  IntermediateAnchorString    - '%c%c%c%c%c'\n",
        SmbiosTable->IntermediateAnchorString[0],
        SmbiosTable->IntermediateAnchorString[1],
        SmbiosTable->IntermediateAnchorString[2],
        SmbiosTable->IntermediateAnchorString[3],
        SmbiosTable->IntermediateAnchorString[4]
        ));
      DEBUG ((DEBUG_INFO, "  IntermediateChecksum        - 0x%02x\n", SmbiosTable->IntermediateChecksum));
      DEBUG ((DEBUG_INFO, "  TableLength                 - 0x%04x\n", SmbiosTable->TableLength));
      DEBUG ((DEBUG_INFO, "  TableAddress                - 0x%08x\n", SmbiosTable->TableAddress));
      DEBUG ((DEBUG_INFO, "  NumberOfSmbiosStructures    - 0x%04x\n", SmbiosTable->NumberOfSmbiosStructures));
      DEBUG ((DEBUG_INFO, "  SmbiosBcdRevision           - 0x%02x\n", SmbiosTable->SmbiosBcdRevision));
    }
  }

4. SMBIOS Type格式解析

SMBIOS基础_第1张图片

以SMBIOS type 1(系统信息)为例,红色区域是每一个 SMBIOS条目的header部分,这部分是必须的,且格式一致(这里的length只是格式区域的长度)

///
/// The Smbios structure header.
///
typedef struct {
  SMBIOS_TYPE      Type;
  UINT8            Length;
  SMBIOS_HANDLE    Handle;
} SMBIOS_STRUCTURE;

蓝色区域则是SMBIOS规范中定义的type类型的具体信息 data区域;,每个type都有各自的区域,存储着不同的信息,规范定义了所有基本的type类型具体内容可自行查询规范

typedef struct {
  SMBIOS_STRUCTURE       Hdr;
  SMBIOS_TABLE_STRING    Manufacturer;
  SMBIOS_TABLE_STRING    ProductName;
  SMBIOS_TABLE_STRING    Version;
  SMBIOS_TABLE_STRING    SerialNumber;
  GUID                   Uuid;
  UINT8                  WakeUpType; ///< The enumeration value from MISC_SYSTEM_WAKEUP_TYPE.
  SMBIOS_TABLE_STRING    SKUNumber;
  SMBIOS_TABLE_STRING    Family;
} SMBIOS_TABLE_TYPE1;

每一个SMBIOS记录都包含两个部分,第一部分是smbios规范定义的,格式区域,另一部分是非规范定义,一般用来存放SMBIOS记录中的全部字符串内容,每一个记录必须以0000h作为结束标志。

字符串是不定长的,每个字符串是以00结尾,整个字符串区域也是以00结尾,所以找到00 00,整个字符串区域就全部就全部结束。

SMBIOS基础_第2张图片

5.uefi提供的针对SMBIOS增删改查的API

//新增 type
typedef
EFI_STATUS
(EFIAPI *EFI_SMBIOS_ADD)(
  IN CONST      EFI_SMBIOS_PROTOCOL     *This,
  IN            EFI_HANDLE              ProducerHandle OPTIONAL,
  IN OUT        EFI_SMBIOS_HANDLE       *SmbiosHandle,
  IN            EFI_SMBIOS_TABLE_HEADER *Record
  );

//更新type中的string
typedef
EFI_STATUS
(EFIAPI *EFI_SMBIOS_UPDATE_STRING)(
  IN CONST EFI_SMBIOS_PROTOCOL *This,
  IN       EFI_SMBIOS_HANDLE   *SmbiosHandle,
  IN       UINTN               *StringNumber,
  IN       CHAR8               *String
  );

//移除某一个handle
typedef
EFI_STATUS
(EFIAPI *EFI_SMBIOS_REMOVE)(
  IN CONST EFI_SMBIOS_PROTOCOL *This,
  IN       EFI_SMBIOS_HANDLE   SmbiosHandle
  );

//查询type
typedef
EFI_STATUS
(EFIAPI *EFI_SMBIOS_GET_NEXT)(
  IN     CONST EFI_SMBIOS_PROTOCOL     *This,
  IN OUT       EFI_SMBIOS_HANDLE       *SmbiosHandle,
  IN           EFI_SMBIOS_TYPE         *Type              OPTIONAL,
  OUT          EFI_SMBIOS_TABLE_HEADER **Record,
  OUT          EFI_HANDLE              *ProducerHandle    OPTIONAL
  );

struct _EFI_SMBIOS_PROTOCOL {
  EFI_SMBIOS_ADD              Add;
  EFI_SMBIOS_UPDATE_STRING    UpdateString;
  EFI_SMBIOS_REMOVE           Remove;
  EFI_SMBIOS_GET_NEXT         GetNext;
  UINT8                       MajorVersion; 
  UINT8                       MinorVersion; 
};

//通过下述GUID locate protocol调用上述的各类方法操作SMBIOS table
extern EFI_GUID  gEfiSmbiosProtocolGuid;

6.疑问?

(1)通过EPS表找到的第一个type是type 0吗?

实践出真知!!

(2)所有的type是连续存储的吗?

应该是的,可通过计算长度连续扫描出所有的type,getnext函数貌似就是通过计算长度在初始地址上偏移去查询next type

(3)UEFI提供的接口实际上是怎么增删改查的?内存中的变化是怎样的?

下期解析,暂时还没搞很清楚

7.补充

shell下查看smbios: Smbiosview -t X

linux下查看smbios:dmidecode -t X

X是你要查看的type的号

你可能感兴趣的:(UEFI,服务器)