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 |
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 位基地址 |
Intermediate Anchor String 和 Number of SMBIOS Structures 字段。结构数量需要遍历整个结构表才能确定。同时,Structure Table Address 扩展为 8 字节,支持 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 字符串存储格式
- 字符串区域从
Header + Length位置开始。 - 每个字符串以
\0(空字节)结尾,连续存放。 - 整个字符串区域以 两个连续的空字节(
\0\0)结束。 - 如果格式化区域中所有字符串字段的值均为 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 指向双空字节,解析结束
}
2.4 结构表终止标记
SMBIOS 结构表的最后一个结构必须是 Type 127(End-of-Table)。该结构没有格式化区域(Length 固定为 4),也没有字符串区域。操作系统遍历结构表时,遇到 Type 127 即停止解析。
Length 字段的合法性。如果 Length < 4,说明结构表已损坏,应立即停止解析并返回错误。此外,Type 127 的 Handle 通常设为 0xFFFF,表示无效引用。
2.5 本章小结
- Entry Point 是访问 SMBIOS 结构表的入口,32 位和 64 位格式在锚定字符串、地址宽度和字段数量上存在差异。
- 结构表头 由 Type、Length、Handle 三个字段组成,Handle 用于跨结构引用。
- 字符串机制 采用 1-based 索引和双空字节终止符,解析时需严格按索引跳过字符串。
- Type 127 作为结构表的结束标记,是遍历终止的关键条件。