2. SMBIOS 数据结构基础:Entry Point、结构表头与字符串机制

SMBIOS 的数据组织采用“入口点(Entry Point)→ 结构表(Structure Table)→ 字符串区域(String Area)”的三层架构。理解这三层的格式与约束,是解析和生成 SMBIOS 信息的基石。本章将逐一拆解每个部分的字段含义、字节对齐规则以及字符串的索引寻址方式。

2.1 SMBIOS Entry Point 结构

Entry Point 是系统固件(BIOS/UEFI)向操作系统暴露 SMBIOS 结构表的“门户”。它通常位于物理内存的特定区域(如 BIOS 固件区域或 ACPI 的 RSDT/XSDT 表中)。根据 SMBIOS 规范版本,Entry Point 分为 32 位(SMBIOS 2.x/3.0 兼容)和 64 位(SMBIOS 3.1.0+)两种格式。

2.1.1 32 位 Entry Point(SMBIOS 2.x / 3.0 兼容)

该结构固定为 31 字节,以锚定字符串 “_SM_” 开头。操作系统通过扫描内存中的 “_SM_” 签名来定位该结构。

偏移(字节) 长度(字节) 字段名 说明
00h 4 Anchor String 固定为 “_SM_”
04h 1 Entry Point Structure Checksum 整个 Entry Point 结构的校验和,使所有字节和为 0
05h 1 Entry Point Length 固定为 31(1Fh)
06h 1 SMBIOS Major Version 主版本号,如 3
07h 1 SMBIOS Minor Version 次版本号,如 5
08h 2 Maximum Structure Size 最大结构体的大小(字节),用于分配缓冲区
0Ah 1 Entry Point Revision 修订版本,通常为 0
0Bh 5 Formatted Area 保留区域,通常全为 0
10h 4 Intermediate Anchor String 固定为 “_DMI_”
14h 1 Intermediate Checksum 从偏移 10h 开始的校验和
15h 2 Structure Table Length 所有结构表的总长度(字节)
17h 4 Structure Table Address 结构表在物理内存中的 32 位基地址
1Bh 2 Number of SMBIOS Structures 结构表中包含的结构总数
1Dh 1 SMBIOS BCD Revision BCD 格式的版本号,如 0x35 表示 3.5
校验和计算技巧: 32 位 Entry Point 包含两个校验和:Entry Point Structure Checksum 覆盖整个 31 字节;Intermediate Checksum 仅覆盖从 Intermediate Anchor String 开始的 15 字节。操作系统通常先验证第一个校验和,再验证第二个,以确保 Entry Point 未被破坏。

2.1.2 64 位 Entry Point(SMBIOS 3.1.0+)

为适应 64 位系统和大内存空间,SMBIOS 3.1.0 引入了 64 位 Entry Point。其锚定字符串为 “_SM3_”,结构大小为 24 字节。

偏移(字节) 长度(字节) 字段名 说明
00h 5 Anchor String 固定为 “_SM3_”
05h 1 Entry Point Structure Checksum 整个 Entry Point 的校验和
06h 1 Entry Point Length 固定为 24(18h)
07h 1 SMBIOS Major Version 主版本号
08h 1 SMBIOS Minor Version 次版本号
09h 1 Doc Rev 文档修订版本
0Ah 1 Entry Point Revision 修订版本,通常为 1
0Bh 1 Reserved 保留,必须为 0
0Ch 4 Structure Table Maximum Size 结构表的最大长度(字节)
10h 8 Structure Table Address 结构表在物理内存中的 64 位基地址
关键区别: 64 位 Entry Point 不再包含 Intermediate Anchor String 和 Number of SMBIOS Structures 字段。结构数量需要遍历整个结构表才能确定。同时,Structure Table Address 扩展为 8 字节,支持 64 位物理地址。
SMBIOS Entry Point 结构对比(32位 vs 64位) 32位 Entry Point(31字节) Anchor String “_SM_” (4B) Checksum + Length + Version (4B) Max Structure Size + Revision + Formatted (8B) Intermediate Anchor “_DMI_” (5B) Table Address (4B) + Count (2B) + BCD (1B) 64位 Entry Point(24字节) Anchor String “_SM3_” (5B) Checksum + Length + Version + DocRev (4B) Entry Point Revision + Reserved (2B) Structure Table Max Size (4B) Table Address (8B) — 64位物理地址

2.2 结构表头格式(Structure Header)

SMBIOS 结构表由一系列连续的结构体组成,每个结构体都以一个 4 字节的固定表头开始。表头之后是格式化区域(Formatted Area)和可选的字符串区域。

偏移(字节) 长度(字节) 字段名 说明
00h 1 Type 结构类型编号(0~127 为规范定义,128~255 为 OEM 自定义)
01h 1 Length 格式化区域的长度(字节),不包括字符串区域
02h 2 Handle 唯一标识符,用于结构间的交叉引用(如 BIOS 特性与物理内存关联)
常见误解: Length 字段仅表示格式化区域的大小,不包含字符串区域。字符串区域从 Header + Length 位置开始,并以双空字节(\0\0)结束。解析时务必使用 Length 跳过格式化区域,再处理字符串。

2.2.1 Handle 的作用与分配规则

Handle 是一个 16 位无符号整数,用于唯一标识每个 SMBIOS 结构。操作系统或管理软件通过 Handle 来引用特定结构(例如,Type 41 的 Associated Handle 字段指向 Type 3 的 Handle)。

  • 唯一性: 同一结构表中,每个结构的 Handle 必须唯一。
  • 分配策略: 固件通常从 0x0000 开始递增分配,但规范不强制连续。
  • 特殊值: 0xFFFF 表示“未使用”或“无效引用”。

2.3 字符串机制详解

SMBIOS 的字符串区域是紧跟在格式化区域之后的变长部分。它采用 索引引用 的方式:格式化区域中的字符串字段存储的是 字符串编号(1-based),而不是直接存储字符串指针或偏移量。

2.3.1 字符串存储格式

  1. 字符串区域从 Header + Length 位置开始。
  2. 每个字符串以 \0(空字节)结尾,连续存放。
  3. 整个字符串区域以 两个连续的空字节(\0\0)结束。
  4. 如果格式化区域中所有字符串字段的值均为 0(表示空字符串),则字符串区域可以省略,仅保留双空字节。

2.3.2 索引寻址规则

假设格式化区域中某个字段的值为 N:

  • 若 N = 0:表示该字段没有对应的字符串,引用方应显示空字符串或默认值。
  • 若 N > 0:表示第 N 个字符串。从字符串区域起始位置开始,跳过前 N-1 个 \0 结尾的字符串,第 N 个字符串即为目标。
示例: 假设字符串区域为 "BIOS Vendor\0BIOS Version\0\0",则索引 1 对应 "BIOS Vendor",索引 2 对应 "BIOS Version"。索引 3 将指向双空字节,返回空字符串。

2.3.3 字符串区域解析流程

解析一个 SMBIOS 结构时,字符串区域的遍历算法如下:

// 伪代码:解析 SMBIOS 结构中的字符串
void parse_strings(uint8_t *structure_start, uint8_t length) {
    uint8_t *str_area = structure_start + length;  // 跳过格式化区域
    int index = 1;
    
    while (*str_area != '\0' || *(str_area + 1) != '\0') {
        // 当前字符串从 str_area 开始,直到遇到 '\0'
        printf("String[%d]: %s\n", index, str_area);
        str_area += strlen(str_area) + 1;  // 跳过当前字符串及其结尾 '\0'
        index++;
    }
    // 此时 str_area 指向双空字节,解析结束
}
SMBIOS 结构表布局:表头 + 格式化区域 + 字符串区域 结构表头 Type (1B) Length (1B) Handle (2B) 共 4 字节 格式化区域 字段1: 字符串索引=2 字段2: 数值字段 字段3: 字符串索引=1 长度由 Length 字段指定 字符串区域 String[1]: "BIOS Vendor" String[2]: "BIOS Version" String[3]: "Release Date" 以 \0\0 结束

2.4 结构表终止标记

SMBIOS 结构表的最后一个结构必须是 Type 127(End-of-Table)。该结构没有格式化区域(Length 固定为 4),也没有字符串区域。操作系统遍历结构表时,遇到 Type 127 即停止解析。

开发提示: 在实现 SMBIOS 解析器时,务必检查 Length 字段的合法性。如果 Length < 4,说明结构表已损坏,应立即停止解析并返回错误。此外,Type 127 的 Handle 通常设为 0xFFFF,表示无效引用。

2.5 本章小结

  • Entry Point 是访问 SMBIOS 结构表的入口,32 位和 64 位格式在锚定字符串、地址宽度和字段数量上存在差异。
  • 结构表头 由 Type、Length、Handle 三个字段组成,Handle 用于跨结构引用。
  • 字符串机制 采用 1-based 索引和双空字节终止符,解析时需严格按索引跳过字符串。
  • Type 127 作为结构表的结束标记,是遍历终止的关键条件。