SMBIO spec:
SMBIOS Specification (dmtf.org)
https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.5.0.pdf
SMBIOS
SMBIOS(System Management BIOS)是一种标准化的系统信息数据结构,旨在提供有关计算机硬件配置、系统功能和管理信息的详细描述。SMBIOS是由DMI(Desktop Management Interface)规范化组织制定的,旨在帮助系统管理员和应用
程序开发人员获取有关计算机系统的信息。
简单列一下Spec 中常用的SMBIOS Type,不详细介绍 ,本文主要着重于SMBIOS的生成和解析
不同的Type存储不同的信息,这些信息是BIOS提供OS的一个表,OS的部分配置会参考Smbios。
SMBIOS信息如何生成存取和访问呢?
SystemTable中会存储一些Table ,其中就包括Smbios的EntryTable,顺便提一下还包括ACPI的Entry Table
如何生成;那就是BIOS中去Install相关的Table ,会申请一段内存,然后更新信息到Smbios的存储空间中
EFI_SYSTEM_TABLE 中包含 EFI_CONFIGURATION_TABLE *ConfigurationTable;
通过以下方式就可以获取到Smbios Table的地址
EFI_STATUS
EFIAPI
EfiGetSystemConfigurationTable (
IN EFI_GUID *TableGuid,
OUT VOID **Table
)
{
EFI_SYSTEM_TABLE *SystemTable;
UINTN Index;
ASSERT (TableGuid != NULL);
ASSERT (Table != NULL);
SystemTable = gST;
*Table = NULL;
for (Index = 0; Index < SystemTable->NumberOfTableEntries; Index++) {
if (CompareGuid (TableGuid, &(SystemTable->ConfigurationTable[Index].VendorGuid))) {
*Table = SystemTable->ConfigurationTable[Index].VendorTable;
return EFI_SUCCESS;
}
}
return EFI_NOT_FOUND;
}
SMBIOS 3.0Table的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;
通过标准的Protocol 就可以获取到对应的 TableAddress
从起始地址打印一段地址就是SMBIOS 存储空间的内容了,可以看到SMBIOS 是一段连续的内存空间,
每个Type 和每个Type 的中间是通过两个Ascall 0 0 隔开的,每个Type中若有String 字段,String字段通过一个0 隔开
EFI_STATUS
EFIAPI
FindSMBIOS(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
SMBIOS_TABLE_ENTRY_POINT *SmbiosTable;
SMBIOS_TABLE_3_0_ENTRY_POINT *Smbios3Table;
EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Table;
EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;
UINT64 address;
UINT8 value;
UINT8 count;
Status = EfiGetSystemConfigurationTable (
&gEfiSmbiosTableGuid,
(VOID **)&SmbiosTable
);
Print (L"SmbiosTable status: %r\r\n", Status);
Status = EfiGetSystemConfigurationTable (
&gEfiSmbios3TableGuid,
(VOID **)&Smbios3Table
);
Print (L"Smbios3Table status: %r\r\n", Status);
Print (L"MajorVersion :%x MinorVersion:%x\r\n", Smbios3Table->MajorVersion,Smbios3Table->MinorVersion);
Print (L"Smbios3Table TableAddress: %x\r\n", Smbios3Table->TableAddress);
address=Smbios3Table->TableAddress;
count=0;
for(UINT64 index=0;index<0x1ff;index++)
{
value= Mmioread8(address+index);
DEBUG ((DEBUG_ERROR, "%x ", value));
count++;
if(count==16)
{
count=0;
DEBUG ((DEBUG_ERROR, "\n ", value));
}
}
Status = EfiGetSystemConfigurationTable (&gEfiAcpiTableGuid, (VOID **)&Rsdp);
Print (L"gEfiAcpiTableGuid status: %r\r\n", Status);
}
打印SMBIOS 空间如下对比Shell下的SMBIOSVIEW信息相同,SMBIOSVIEW 也是相同方式去获取和解析,这是一种方式。
还有一种是传统的SMBIOS 存储在内存地址F0000-FFFFF中
匹配 _smi_ 字符串 然后匹配 _DMI_ 找到EPS Table的地址 EPS的address + length 就是SMBIOS Table Entry 的地址
VOID MySmBiosInit(EFI_HII_HANDLE HiiHandle, UINT16 Class)
{
CHAR16 Type0Data[50]={0};
CHAR16 Type1Data[50]={0};
UINT32 realaddress;
UINT32 smaddr;
UINT32 SmbiosTableaddr;
UINT32 SmbiosLength;
UINT32 Dataindex;
realaddress=0xf0000; //find 0xf0000-0xfffff _SM_
while(realaddress<0xfffff)
{
if(MyReadaddr32(realaddress)==0x5f4d535f)//find_SM_
{
DEBUG((DEBUG_ERROR, "Hyl:SmBiosaddr find _SM_ success "));
if((MyReadaddr32(realaddress+16)==0x494d445f)&&(MyReadaddr8(realaddress+20)==0x5f))//find_DMI_
{
smaddr=realaddress;
DEBUG((DEBUG_ERROR, "Hyl:SmBiosaddr find _DMI_success "));
break;
}
}
realaddress = realaddress + 4;
}
SmbiosTableaddr=MyReadaddr32(smaddr+0x18); //EPSTABLE adde
SmbiosLength= ((MyReadaddr32(SmbiosTableaddr) )&0x0000ff00 )>>8;
realaddress=SmbiosTableaddr+SmbiosLength;
Dataindex=0;
while(1)
{
if( MyReadaddr8(realaddress)==0&&MyReadaddr8(realaddress+1)==0)
{
break;
}
if( MyReadaddr8(realaddress)>0)
{
Type0Data[Dataindex]=MyReadaddr8(realaddress);
Dataindex++;
}
if( MyReadaddr8(realaddress)==0)
{
Type0Data[Dataindex]=0x2e ;
Dataindex++;
}
realaddress++;
}
InitString( HiiHandle, STRING_TOKEN(STR_SMBIOS_VALUE0),L"SMBIOSTYPE0:%s" ,Type0Data);
}
举例分析Type1
需要注意的是STRING 类型的信息 ,这个offset位置代表的是第几个String,而不是描述信息,所有String类型的描述信息都在smbiostype* 的后面开始通过0 隔开
Type1的offset1 length 为 1B ,也就是说1B 开始才是String的开始
Offset 4 Manufacturer STRING 01 代表第1个string
Offset 5 Product Name STRING 02代表第2个string
Offset 6 Version STRING 03代表第2个string
Offset 7 Serial Number STRING 04代表第3个string
Offset 1B-6A 为String信息
68 74 74 70 3A 2F 2F 77 77 77 2E 74 69
61 6E 6F 63 6F 72 65 2E 6F 72 67 2F 65 64 6B 32
2F 0 45 6D 75 6C 61 74 6F 72 50 6B 67 0 31 2E
30 0 53 79 73 74 65 6D 20 53 65 72 69 61 6C 23
0 53 79 73 74 65 6D 20 53 4B 55 23 0 65 64 6B
32 0 0
第一个string , 0为两个String的分隔符
68 74 74 70 3A 2F 2F 77 77 77 2E 74 69
61 6E 6F 63 6F 72 65 2E 6F 72 67 2F 65 64 6B 32
2F
AscalL 对应的字符串就是 http://www.tianocore.org/edk2/。
后面String相同方式解析
二进制 | 十进制 | 十六进制 | 字符/缩写 | 解释 |
00000000 | 0 | 00 | NUL (NULL) | 空字符 |
00000001 | 1 | 01 | SOH (Start Of Headling) | 标题开始 |
00000010 | 2 | 02 | STX (Start Of Text) | 正文开始 |
00000011 | 3 | 03 | ETX (End Of Text) | 正文结束 |
00000100 | 4 | 04 | EOT (End Of Transmission) | 传输结束 |
00000101 | 5 | 05 | ENQ (Enquiry) | 请求 |
00000110 | 6 | 06 | ACK (Acknowledge) | 回应/响应/收到通知 |
00000111 | 7 | 07 | BEL (Bell) | 响铃 |
00001000 | 8 | 08 | BS (Backspace) | 退格 |
00001001 | 9 | 09 | HT (Horizontal Tab) | 水平制表符 |
00001010 | 10 | 0A | LF/NL(Line Feed/New Line) | 换行键 |
00001011 | 11 | 0B | VT (Vertical Tab) | 垂直制表符 |
00001100 | 12 | 0C | FF/NP (Form Feed/New Page) | 换页键 |
00001101 | 13 | 0D | CR (Carriage Return) | 回车键 |
00001110 | 14 | 0E | SO (Shift Out) | 不用切换 |
00001111 | 15 | 0F | SI (Shift In) | 启用切换 |
00010000 | 16 | 10 | DLE (Data Link Escape) | 数据链路转义 |
00010001 | 17 | 11 | DC1/XON (Device Control 1/Transmission On) | 设备控制1/传输开始 |
00010010 | 18 | 12 | DC2 (Device Control 2) | 设备控制2 |
00010011 | 19 | 13 | DC3/XOFF (Device Control 3/Transmission Off) | 设备控制3/传输中断 |
00010100 | 20 | 14 | DC4 (Device Control 4) | 设备控制4 |
00010101 | 21 | 15 | NAK (Negative Acknowledge) | 无响应/非正常响应/拒绝接收 |
00010110 | 22 | 16 | SYN (Synchronous Idle) | 同步空闲 |
00010111 | 23 | 17 | ETB (End of Transmission Block) | 传输块结束/块传输终止 |
00011000 | 24 | 18 | CAN (Cancel) | 取消 |
00011001 | 25 | 19 | EM (End of Medium) | 已到介质末端/介质存储已满/介质中断 |
00011010 | 26 | 1A | SUB (Substitute) | 替补/替换 |
00011011 | 27 | 1B | ESC (Escape) | 逃离/取消 |
00011100 | 28 | 1C | FS (File Separator) | 文件分割符 |
00011101 | 29 | 1D | GS (Group Separator) | 组分隔符/分组符 |
00011110 | 30 | 1E | RS (Record Separator) | 记录分离符 |
00011111 | 31 | 1F | US (Unit Separator) | 单元分隔符 |
00100000 | 32 | 20 | (Space) | 空格 |
00100001 | 33 | 21 | ! |
|
00100010 | 34 | 22 | " |
|
00100011 | 35 | 23 | # |
|
00100100 | 36 | 24 | $ |
|
00100101 | 37 | 25 | % |
|
00100110 | 38 | 26 | & |
|
00100111 | 39 | 27 | ' |
|
00101000 | 40 | 28 | ( |
|
00101001 | 41 | 29 | ) |
|
00101010 | 42 | 2A | * |
|
00101011 | 43 | 2B | + |
|
00101100 | 44 | 2C | , |
|
00101101 | 45 | 2D | - |
|
00101110 | 46 | 2E | . |
|
00101111 | 47 | 2F | / |
|
00110000 | 48 | 30 | 0 |
|
00110001 | 49 | 31 | 1 |
|
00110010 | 50 | 32 | 2 |
|
00110011 | 51 | 33 | 3 |
|
00110100 | 52 | 34 | 4 |
|
00110101 | 53 | 35 | 5 |
|
00110110 | 54 | 36 | 6 |
|
00110111 | 55 | 37 | 7 |
|
00111000 | 56 | 38 | 8 |
|
00111001 | 57 | 39 | 9 |
|
00111010 | 58 | 3A | : |
|
00111011 | 59 | 3B | ; |
|
00111100 | 60 | 3C | < |
|
00111101 | 61 | 3D | = |
|
00111110 | 62 | 3E | > |
|
00111111 | 63 | 3F | ? |
|
01000000 | 64 | 40 | @ |
|
01000001 | 65 | 41 | A |
|
01000010 | 66 | 42 | B |
|
01000011 | 67 | 43 | C |
|
01000100 | 68 | 44 | D |
|
01000101 | 69 | 45 | E |
|
01000110 | 70 | 46 | F |
|
01000111 | 71 | 47 | G |
|
01001000 | 72 | 48 | H |
|
01001001 | 73 | 49 | I |
|
01001010 | 74 | 4A | J |
|
01001011 | 75 | 4B | K |
|
01001100 | 76 | 4C | L |
|
01001101 | 77 | 4D | M |
|
01001110 | 78 | 4E | N |
|
01001111 | 79 | 4F | O |
|
01010000 | 80 | 50 | P |
|
01010001 | 81 | 51 | Q |
|
01010010 | 82 | 52 | R |
|
01010011 | 83 | 53 | S |
|
01010100 | 84 | 54 | T |
|
01010101 | 85 | 55 | U |
|
01010110 | 86 | 56 | V |
|
01010111 | 87 | 57 | W |
|
01011000 | 88 | 58 | X |
|
01011001 | 89 | 59 | Y |
|
01011010 | 90 | 5A | Z |
|
01011011 | 91 | 5B | [ |
|
01011100 | 92 | 5C | \ |
|
01011101 | 93 | 5D | ] |
|
01011110 | 94 | 5E | ^ |
|
01011111 | 95 | 5F | _ |
|
01100000 | 96 | 60 | ` |
|
01100001 | 97 | 61 | a |
|
01100010 | 98 | 62 | b |
|
01100011 | 99 | 63 | c |
|
01100100 | 100 | 64 | d |
|
01100101 | 101 | 65 | e |
|
01100110 | 102 | 66 | f |
|
01100111 | 103 | 67 | g |
|
01101000 | 104 | 68 | h |
|
01101001 | 105 | 69 | i |
|
01101010 | 106 | 6A | j |
|
01101011 | 107 | 6B | k |
|
01101100 | 108 | 6C | l |
|
01101101 | 109 | 6D | m |
|
01101110 | 110 | 6E | n |
|
01101111 | 111 | 6F | o |
|
01110000 | 112 | 70 | p |
|
01110001 | 113 | 71 | q |
|
01110010 | 114 | 72 | r |
|
01110011 | 115 | 73 | s |
|
01110100 | 116 | 74 | t |
|
01110101 | 117 | 75 | u |
|
01110110 | 118 | 76 | v |
|
01110111 | 119 | 77 | w |
|
01111000 | 120 | 78 | x |
|
01111001 | 121 | 79 | y |
|
01111010 | 122 | 7A | z |
|
01111011 | 123 | 7B | { |
|
01111100 | 124 | 7C | | |
|
01111101 | 125 | 7D | } |
|
01111110 | 126 | 7E | ~ |
|
01111111 | 127 | 7F | DEL (Delete) | 删除 |
标准 ASCII 编码一览表
0 0 为两个Smbios Type 的分隔符,每个Smbios Type 有相同的Header部
///
/// The Smbios structure header.
///
typedef struct {
SMBIOS_TYPE Type;
UINT8 Length;
SMBIOS_HANDLE Handle;
} SMBIOS_STRUCTURE;
根据Length 信息就可以确定String的起点 ,0 0 分隔符就是一个Type的结尾标志