SMBIOS(System Management BIOS)是主板或系统制造者以标准格式显示产品管理信息所需遵循的统一规范。
DMI(Desktop Management Interface, DMI)是帮助收集电脑系统信息的管理系统,DMI信息的收集必须在严格遵照SMBIOS规范的前提下进行。DMI设计适用于任何的平台和操作系统。DMI充当了管理工具和系统层之间接口的角色。它建立了标准的可管理系统更加方便了电脑厂商和用户对系统的了解。
DMI主要组成部分MIF(Management Information Format)数据库,存储所有电脑系统和配件有关的信息。
即插即用功能接口访问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));
}
}
以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,整个字符串区域就全部就全部结束。
//新增 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;
(1)通过EPS表找到的第一个type是type 0吗?
实践出真知!!
(2)所有的type是连续存储的吗?
应该是的,可通过计算长度连续扫描出所有的type,getnext函数貌似就是通过计算长度在初始地址上偏移去查询next type
(3)UEFI提供的接口实际上是怎么增删改查的?内存中的变化是怎样的?
下期解析,暂时还没搞很清楚
shell下查看smbios: Smbiosview -t X
linux下查看smbios:dmidecode -t X
X是你要查看的type的号