OVERVIEW

SMBIOS全拼System Management BIOS, 是通过系统固件传递管理信息的标准。应用在PC上,即是主板或系统制造厂商以标准格式显示产品信息所遵循的统一规范。

主板厂商或OEM厂商生产的PC,出厂前都会按照SMBIOS标准将相关信息写入BIOS中。比如OEM客制化信息等。
SMBIOS信息也会记录很多硬件信息, 比如CPU型号, 缓存, 内存大小等等

  • SMBIOS由DMTF组织管理和维护。DMTF是一个工业化组织,通过与领先科技公司的开放与协作简化网络访问技术的可管理性。DMTF创建和推动全球采用互操作管理标准,并且提供实施使得管理各种传统的和新兴的技术,包括云、虚拟化、网络及基础设施。其组织成员包括Intel、AMD、Cisco、Dell、Microsoft、HP、Lenovo等。
  • SMBIOS最初的设计是采用英特尔®处理器架构系统,然而现在SMBIOS支持IA32(X86)、x64(x86-64、Intel64、AMD64EM64T)、Intel® Itanium® architecture、32-bit ARM(Aarch32)及64-bit ARM(Aarch64)等。

SMBIOS 结构 smbios机型_ios

BIOS的访问

目前主流的访问方式都是基于表结构的访问方式。基于表结构访问SMBIOS的过程是先找到 Entry Point Structure (EPS)表,然后通过Entry Point Structure (EPS)表的数据找到SMBIOS结构表。

EPS分为两种:Original SMBIOS 2.1(32-bit) entry point / SMBIOS 3.0(64-bit) entry point

为了兼容已经存在的SMBIOS解析器,目前pc都会提供32-bit entry point,SMBIOS 2.1(32-bit) Entry Point查询方式:(软件为RW-Everything)

  • Non-UEFI系统,在物理内存地址空间000F0000h-000FFFFFh,搜索关键字“SM”,其后16个byte是关键字“DMI”,得到EPS表。
  • UEFI系统,在EFI Configuration Table中搜索EPS table。
    #define SMBIOS_TABLE_GUID { 0xeb9d2d31, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } }

    EPS offset 0x18是Structure Table Address, 这个地址开始存放structure table。

Entry Point Structure:
SMBIOS结构表的起始地址、总长度、个数都可以从EPS中获取到。每个表都有一个相同的4个byte的header格式,如下。
每个结构都分为格式区域和字符串区域,格式区域就是一些本结构的信息,字符串区域是紧随在格式区域后的一个区域。结构01h处标识的结构长度仅是格式区域的长度,字符串区域的长度是不固定的。每个字符串以00h结束,整个字符区域也以00h结束。
SMBIOS包含多个表结构,每个表的意义不同。从SMBIOS version 2.3开始要求包含一些基本的表结构,如Type0 BIOS Information、Type1 System Information、Type3 System Enclosure、Type4 Processor Information等。具体的structures和data,参见SMBIOS spec。

SMBIOS 3.0 (64-bit) Entry Point Structure

位置

名称

长度

描述

00H

关键字

5Byte

“_SM3_指定为五个ASCII字符(5F 53 4D 33 5F)。”

05H

校验和

1Byte

用于校验数据,对于入口点长度字节,EPS中的值从偏移量00h开始求和。

06H

表结构长度

1Byte

入口点结构的长度,从锚定字符串字段开始,以字节为单位,目前为18h

07H

Major 版本号

1Byte

用于判断SMBIOS版本

08H

Minor 版本号

1Byte

用于判断SMBIOS 版本

09H

表结构大小

2Byte

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

0AH

入口点修改

1Byte

在该结构中实现的EPS修订,并确定了0Bh及以上偏移量的格式如下:01h入口点基于SMBIOS 3.0定义;02h-FFh根据本规范保留分配 每修订01h定义偏移0Ch-17h

0B

预留区域

1Byte

根据该规范保留为赋值,设置为0

0CH

结构表最大尺寸

DWORD

SMBIOS结构表的最大大小,由结构表地址指向,以字节为单位。实际大小保证小于或等于最大大小。

10H

结构表地址

QWORD

只读SMBIOS结构表的64位物理起始地址,可以从任何64位地址开始。此区域包含全部打包在一起的SMBIOS结构。

Required structures and data

Type类型

名称

含义

Type 0

BIOS 信息

结构表中只有一个结构。BIOS Version和BIOS Release Date字符串是非空的;日期字段使用4位数字的年份(例如,1999)。所有其他字段反映完整的BIOS支持信息。

Type 1

系统信息

制造商和产品名称字符串是非空的。UUID字段标识系统的非零UUID值。“唤醒类型”字段标识唤醒源,不能为“未知”。结构表中只有一个结构。

Type 2

基板或模块单元信息

制造商、产品名、版本、序列号、资产标签、特征标志、基板在底架上的位置、底架句柄、基板类型、包含的对象句柄个数、包含的个各对象句柄。

Type 3

系统外围或底架

制造商、类型、版本、序列号、资产标签号、启动状态、供电电源状态、热量状态、安全状态、 OEM 定义信息、高度、电源线个数、包含的单元个数、包含的单元记录长度、包含的各个单元、 SKU 号。

Type 4

处理器信息

插座指示、处理器类型、处理器家族、制造商、 ID 、版本、电压伏特数、外部时钟频率 (MHz) 、最大速率 (MHz) 、当前速率、状态、处理器升级、 L1 级缓存信息结构的句柄、 L2 级缓存信息结构的句柄、 L3 级缓存信息结构的句柄、序列号、资产标签、部件号码、内核个数、激活的内核个数、线程个数、处理器特征、处理器家族 2 。

Type 7

高速缓存信息

插座指示、缓存配置、最大缓存容量、已安装的容量、支持的 SRAM 类型、当前 SRAM 类型、缓存速率、纠错类型、系统缓存类型、关联性。

Type 8

端口连接器信息

例如并口、串口、键盘、鼠标器端口等都属于端口连接器。包含的信息有内部引用指示符、内部连接器类型、外部引用指示符、外部引用类型、端口类型。

Type 9

系统插槽

插槽指示符、插槽类型、插槽数据总线宽度、当前是否在使用、插槽长度、插槽 ID 、插槽特征 1 、插槽牲 2 、段组编号、总线编号、设备 / 函数编号。

Type 11

OEM 字符串

由 OEM 指定的描述字符串。

Type 12

系统配置选项

用来配置基板跳线和开关的信息字符串。

Type 13

BIOS 语言信息

可安装的语言、标志位字节、保留的 15 字节、当前语言。这里的语言是指英语、法语、汉语等国家语言,而不是计算机编程语言。

Type 14

组相联

组名、本项的类型、本结构的句柄。级相联用于指明某些部件的布局或层次,例如指明两个 CPU 共享一个外部缓存系统。

Type 15

系统事件日志

事件日志存放在非易失性的存储单元中,占据固定长度的区域, 以 一个固定长度(和特定于厂商)的头部开始,后跟一个或多个可变长度的日志记录。应用程序可以通过周期性地读取系统事件日志结构(通过它的句柄)并在日志改 变标记中搜索日志的更新,以实现事件日志改变通知。

Type 16

物理存储器阵列

位置(系统板卡或附加板卡上)、存储功能、内存纠错、最大容量、存储错误信息句柄、存储设备数目、已扩展的最大容量。

Type 17

存储设备

用于描述物理存储器阵列中的单个存储设备。在物理存储器阵列中的句柄、存储错误信息句柄、存储总宽度、数据宽度、存储容量、形体尺寸、设备集、设备定位 器、记忆槽定位器、存储器类型、类型额外细节、速率、制造商、序列号、资产标签、部件号码、属性标志、已扩展的容量、已配置的存储时钟速率。

Type 18

32-bit 错误信息

错误类型、错误粒度、错误操作、特定于制造商的错误表现、存储阵列错误地址、设备错误地址、错误解析。

Type 19

存储阵列映射地址

起始地址、结束地址、存储阵列句柄、分区宽度、已扩展的起始地址、已扩展的结束地址。

Type 20

存储设备映射地址

起始地址、结束地址、存储设备句柄、存储阵列映射地址句柄、分区行位置、交叉位置、交叉的数据深度、已扩展的起始地址、已扩展的结束地址。

Type 21

内置指针设备

指针设备类型、接口类型、按钮个数。

Type 22

智能电池

位置、制造商、制造日期、序列号、设备名、设备化学属性、设计容量、设计电压伏特数、 SBDS 版本号、电池数据的最大错误百分比、 SBDS 序列号、 SBDS 制造日期、 SBDS 设备化学属性、设计容量倍增因子、特定于 OEM 的信息。

Type 32

系统引导信息

保留域 (00h) 、引导状态描述 (10 字节 ) 。引导状态描述主要有“没有检测到错误”、“没有可引导的媒介”、“操作系统载入失败”、“ BIOS 硬件检测失败”、“操作系统硬件检测失败”、“用户请求引导(通过一个按键)”、“违反系统安全”、“预先请求映像(通过 PXE 引导)”、“系统监控记时器激活,导致系统重启”,特定于厂商引导状态描述等。

Type 38

IPMI 设备信息

BMC 接口类型、 IPMI 规范修改版本、 I2C 从地址、 NV 存储设备地址、基地址、基地址修饰符 / 中断信息、中断号。

Type 126

不活动指示

用来表明某个 SMBIOS 结构当前不活动,因此不应用被上层的软件使用。它没有字符串区域,只有结构头部(即三个头部域类型、长度、句柄)。

Type 127

表格结束指示

表示整个 SMBIOS 结构表的结束。它也只有结构头部,没有字符串区域。

BIOS Information (Type 0) structure

位置

名称

长度

描述

00H

TYPE号

1Byte

结构的TYPE号,此处是0

01H

长度

1Byte

TYPE 0格式区域长度,一般为14H,也有13H

02H

句柄

2Byte

本结构的句柄,一般为0000H

04H

BIOS厂商信息

1Byte

此处是BIOS卖方信息,可能是OEM厂商名,一般为01H,代表紧随格式区域后的字符串区域的第二个字符串

05H

BIOS版本

1Byte

BIOS版本号,一般为02H,代表字符串区域的第二个字符

06H

BIOS开始地址段

2Byte

用于计算机常驻BIOS镜像大小计算,方法为 (10000H-BIOS开始地址段) * 16

08H

BIOS发布日期

1Byte

一般为03H,表示字符区第三个字符串表示字符区第三个字符串

09H

BIOS rom size

1Byte

计算方法为(n +1 )*64K ,n 为此处读出数值为(n +1 )×64K ,n 为此处读出数值

0AH

BIOS 特征

8Byte

Bios 的功能支持特征,如PCI,PCMCIA,FLASH 等

12H

BIOS 特征扩展

不定

为将来支持的功能预留的可选空间。当前的扩展字节数由偏移量1 - 12h中的长度表示。

14H

BIOS 版本主号

1Byte

标识系统BIOS的主要版本;每次发布给定系统的System BIOS更新时,此字段或System BIOS Minor Release字段或两者都会更新。

15H

BIOS 版本从号

1Byte

标识系统BIOS的小版本;例如,版本10.22的值是16h,版本2.1的值是01h。

16H

内置控制器固件的版主号

1Byte

确定嵌入式控制器固件的主要版本;例如,对于修订10.22,该值为0Ah,对于修订2.1,该值为02h。

17H

内置控制器固件的版从号

1Byte

如果系统没有可现场升级的嵌入式控制器固件,则取值为0FFh。

UEFI code中提供一个SmbiosDxe driver,为SMBIOS table提供接口函数,包括add、update、remove等function。Locate protocol后可以对SMBIOS table进行操作。

/**

  Driver to produce Smbios protocol and pre-allocate 1 page for the final SMBIOS table.

  @param ImageHandle     Module's image handle
  @param SystemTable     Pointer of EFI_SYSTEM_TABLE

  @retval EFI_SUCCESS    Smbios protocol installed
  @retval Other          No protocol installed, unload driver.

**/
EFI_STATUS
EFIAPI
SmbiosDriverEntryPoint (
  IN EFI_HANDLE           ImageHandle,
  IN EFI_SYSTEM_TABLE     *SystemTable
  )
{
  EFI_STATUS            Status;

  mPrivateData.Signature                = SMBIOS_INSTANCE_SIGNATURE;
  mPrivateData.Smbios.Add               = SmbiosAdd;
  mPrivateData.Smbios.UpdateString      = SmbiosUpdateString;
  mPrivateData.Smbios.Remove            = SmbiosRemove;
  mPrivateData.Smbios.GetNext           = SmbiosGetNext;
  mPrivateData.Smbios.MajorVersion      = (UINT8) (PcdGet16 (PcdSmbiosVersion) >> 8);
  mPrivateData.Smbios.MinorVersion      = (UINT8) (PcdGet16 (PcdSmbiosVersion) & 0x00ff);

  InitializeListHead (&mPrivateData.DataListHead);
  InitializeListHead (&mPrivateData.AllocatedHandleListHead);
  EfiInitializeLock (&mPrivateData.DataLock, TPL_NOTIFY);

  //
  // Make a new handle and install the protocol
  //
  mPrivateData.Handle = NULL;
  Status = gBS->InstallProtocolInterface (
                  &mPrivateData.Handle,
                  &gEfiSmbiosProtocolGuid,
                  EFI_NATIVE_INTERFACE,
                  &mPrivateData.Smbios
                  );

  return Status;
}
Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **) &mSmbios);
  ASSERT_EFI_ERROR (Status);
  DEBUG ((DEBUG_INFO, "The Smbios Table Version: %x.%x\n", mSmbios->MajorVersion, mSmbios->MinorVersion));

  if (mSmbios->MajorVersion < 2 || (mSmbios->MajorVersion == 2 && mSmbios->MinorVersion < 7)){
    mMaxLen = SMBIOS_STRING_MAX_LENGTH;
  } else if (mSmbios->MajorVersion < 3) {
    //
    // Reference SMBIOS 2.7, chapter 6.1.3, it will have no limit on the length of each individual text string.
    // However, the length of the entire structure table (including all strings) must be reported
    // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,
    // which is a WORD field limited to 65,535 bytes.
    //
    mMaxLen = SMBIOS_TABLE_MAX_LENGTH;
  } else {
    //
    // SMBIOS 3.0 defines the Structure table maximum size as DWORD field limited to 0xFFFFFFFF bytes.
    // Locate the end of string as long as possible.
    //
    mMaxLen = SMBIOS_3_0_TABLE_MAX_LENGTH;
  }

UEFI spec在其配置表中提供了SMBIOS EPS table。通过在EFI Configuration Table中搜索SMBIOS_TABLE_GUID可以方便的得到EPS table,进而查找SMBIOS表。

for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
    if (CompareGuid (TableGuid, &(gST->ConfigurationTable[Index].VendorGuid))) {
      *Table = gST->ConfigurationTable[Index].VendorTable;
      return EFI_SUCCESS;
    }
  }