System Management BIOS: Difference between revisions

[unchecked revision][unchecked revision]
Content deleted Content added
Brendan (talk | contribs)
m See also
m Bot: Replace deprecated source tag with syntaxhighlight
 
(11 intermediate revisions by 8 users not shown)
Line 1:
SMBIOS (System Management [[BIOS]] (SMBIOS) is a standard developed by [httphttps://www.dmtf.org DMTF] whose purpose is to deliver information about the hardware, by relying on the system firmware. Once booted, SMBIOS will let the OS access a table that contains a series of entries with various hardware information, separated in different structures of variable length.
The purpose of this standard is to allow the operating system to retrieve information about the PC.
 
It was first designed for Intel, and released in 1995. Nowadays it supports most desktop architectures, and its last specification was published the 21 of July, 2023.
On booting the SMBIOS will put a table somewhere in memory. By parsing this table it is possible to access information about the computer and its capabilities.
 
== Locating the SMBIOS Entry Point TableStructure ==
 
SMBIOS provides a searchable (or querryable) structure called Entry Point Structure (or EPS) that contains a pointer to the SMBIOS Structure Table and some additional information, like its length, version, or number of structures.
The SMBIOS Entry Point Table is located somewhere between the addresses 0xF0000 and 0xFFFFF, and must be on a 16-byte boundary. To find the specific location of the start of the table it is necessary to search that region of memory for the string "_SM_", and then check the structure's checksum (add all bytes and see if the lowest 8 bits of the result are zero).
 
=== Format ===
One example of how this can be done is demonstrated in the below code.
 
{| align="center" cellspacing="2"
| width="50%" valign="top" |
 
{| {{wikitable}}
|+ 32-bit Entry Point Structure Format
! Offset
! Name
! Size
|-
| 0x00 || Anchor String || 4 BYTEs
|-
| 0x04 || Entry Point Checksum || BYTE
|-
| 0x05 || Entry Point Lenght || BYTE
|-
| 0x06 || SMBIOS Major Version || BYTE
|-
| 0x07 || SMBIOS Minor Version || BYTE
|-
| 0x08 || SMBIOS Structure Maximum Size || WORD
|-
| 0x0A || Entry Point Revision || BYTE
|-
| 0x0B || Formatted Area || 5 BYTEs
|-
| 0x10 || Intermediate Anchor String || 5 BYTEs
|-
| 0x15 || Intermediate Checksum || BYTE
|-
| 0x16 || Structure Table Length || WORD
|-
| 0x18 || '''Structure Table Address''' || DWORD
|-
| 0x1C || Number of Structures || WORD
|-
| 0x1E || BCD Revision || BYTE
|}
 
| width="10%" valign="top" |
 
| width="50%" valign="top" |
 
{| {{wikitable}}
|+ 64-bit Entry Point Structure Format
! Offset
! Name
! Size
|-
| 0x00 || Anchor String || 5 BYTEs
|-
| 0x05 || Entry Point Checksum || BYTE
|-
| 0x06 || Entry Point Lenght || BYTE
|-
| 0x07 || SMBIOS Major Version || BYTE
|-
| 0x08 || SMBIOS Minor Version || BYTE
|-
| 0x09 || SMBIOS Docrev || BYTE
|-
| 0x0A || Entry Point Revision || BYTE
|-
| 0x0B || Reserved || BYTE
|-
| 0x0C || Structure Table Maximum Size || DWORD
|-
| 0x10 || '''Structure Table Adress''' || QWORD
|}
 
|}
 
=== Locating the entry point structure ===
 
==== Non-UEFI systems ====
 
Under systems without UEFI, the Entry Point Structure is located somewhere in physical memory from address 0x000F0000 to 0x00FFFFF, with a 16 byte alignment.
 
* In 32-bit architectures, the SMBIOS EPS first contains (with offset 0) a string with the value "_SM_". This is what will help us search the location of the EPS.
 
* In 64-bit architectures, as in 32-bit, it first contains a string, but with the value "_SM3_" (The 3 stands for SMBIOS 3, which is the version in 64-bit machines).
 
This example C code searches the entry point in a 64-bit architecture. All it does is iterate for every 16-byte aligned memory addresses (from 0x000F0000 to 0x000FFFFF) and comparing 4 bytes from that address with the string "_SM3_". To acomplish that, it is needed to verify the checksum value (add all bytes and see if the lowest 8 bits of the result are zero):
 
<syntaxhighlight lang="c">
 
/* Start address */
char *eps = 0x000F0000;
 
<source lang="C">
char *mem = (unsigned char *) 0xF0000;
int length, i;
unsigned charuint8_t checksum = 0;
 
while ((unsigned int) mem < 0x100000) {
while (eps <= (char*) 0x000FFFFF) {
if (mem[0] == '_' && mem[1] == 'S' && mem[2] == 'M' && mem[3] == '_') {
 
length = mem[5];
/* Check Anchor String (64-bit version) */
if (!memcmp(eps, "_SM3_", 5)) {
 
length = eps[5];
checksum = 0;
 
for(i = 0; i < length; i++) {
/* Add all bytes checksum += mem[i];*/
}for (i = 0; i < length; i++)
if( checksum +== 0) breakeps[i];
 
if (checksum == 0)
/* Done! */
break;
}
 
mem += 16;
/* Next 16-byte-aligned address */
eps += 16;
}
</source>
 
</syntaxhighlight>
Now mem contains the address of the Entry Point Table.
 
Some old systems may not have the SMBIOS. So...
Now, ''eps'' contains the address of the Entry Point Structure. Some systems may not have the SMBIOS, so an error check may be a good idea:
<source lang="C">
 
if ((unsigned int) mem == 0x100000) {
<syntaxhighlight lang="c">
panic("No SMBIOS found!");
if ((unsigned int) eps == 0x00100000) {
/* Error, SMBIOS could not be located */
return -1;
}
</syntaxhighlight>
</source>
 
==== UEFI systems ====
== Parsing the Entry Point Table ==
 
On UEFI systems, the search-for-a-string method is not used to obtain the EPS. Instead, it is located by looking in the EFI Configuration Table for the SMBIOS Version 3 GUID (SMBIOS3_TABLE_GUID), which will contain a pointer to the structure.
The entry point table has the following structure
<source lang="C">
struct SMBIOSEntryPoint {
char EntryPointString[4]; //This is _SM_
uchar Checksum; //This value summed with all the values of the table, should be 0 (overflow)
uchar Length; //Length of the Entry Point Table. Since version 2.1 of SMBIOS, this is 0x1F
uchar MajorVersion; //Major Version of SMBIOS
uchar MinorVersion; //Minor Version of SMBIOS
ushort MaxStructureSize; //Maximum size of a SMBIOS Structure (we will se later)
uchar EntryPointRevision; //...
char FormattedArea[5]; //...
char EntryPointString2[5]; //This is _DMI_
uchar Checksum2; //Checksum for values from EntryPointString2 to the end of table
ushort TableLength; //Length of the Table containing all the structures
uint TableAddress; //Address of the Table
ushort NumberOfStructures; //Number of structures in the table
uchar BCDRevision; //Unused
};
</source>
 
This C code shows how that could get implemented using [[GNU-EFI]]:
TableAddress contains the address of the table that contains all the structures with information about the PC.
<syntaxhighlight lang="c">
All of the structures are located from [TableAddress] to [TableAddress + TableLength].
The structures are located directly adjacent to each other in memory, with a new structure beginning as soon as another one ends.
Each structure is composed of a header, a structure specific table, and a string table.
 
/* Will contain the address of the Entry Point Structure */
The format of the header is as follows.
void *SMBIOS_Pointer = NULL;
<source lang="C">
UINTN status = LibGetSystemConfigurationTable(&SMBIOS3TableGuid, (void **)(&SMBIOS_Pointer));
struct SMBIOSHeader {
uchar Type;
uchar Length;
ushort Handle;
};
</source>
 
/* Check all posible errors (maybe is not needed?) */
Located at TableAddress is a SMBIOS header.
if (status != EFI_SUCCESS || SMBIOS_Pointer == NULL ||
The value of Type indicates what element the structure contains information about. (see Header Types section)
CompareMem(SMBIOS_Pointer, "_SM3_", 5) ) {
Length indicates the size of header + data table. The strings are not included in the length.
 
/* Error, SMBIOS could not be located */
Immediately after the end of the header is the data. At the end of the data table (Address + Length), the strings section starts. Each string is NULL terminated and is limited to 64 characters.
return -1;
 
}
eg: the BIOS Struct (Type 0) is like this:
 
<source lang="asm">
</syntaxhighlight>
 
== Structure Table ==
 
Once the EPS is located in memory, information about the SMBIOS table can already be obtained. The most important one is the '''Structure Table Adress''', which is the address of the table that contains all the SMBIOS structures. The structures are located directly adjacent to each other in memory, with a new structure beginning as soon as another one ends. Each structure is composed of a header, a structure specific table, and a string table of variable length.
 
The first SMBIOS header is located at the '''Structure Table Adress'''. The value of ''type'' indicates what element the structure contains information about. ''length'' indicates the size of '''header + data table'''. The strings are not included in the length.
 
<syntaxhighlight lang="c">
struct SMBIOSHeader {
uint8_t type;
uint8_t length;
uint16_t handle;
};
</syntaxhighlight>
 
Immediately after the end of the header, is the data table. At the end of the data table (header address + length), the strings section starts. Each string is NULL terminated and is limited to 64 characters. Strings are referenced within tables by using an index into the string table (index 0 means that the string is effectively a NULL pointer and should be ignored). The first string begins immediately after the data, and the second string begins immediately after that, and so on. The string section itself is terminated by two consecutive zero bytes.
 
So, the end (and therefore the length) of the SMBIOS structure can be calculated by finding the two [[Null Character]]s in the string section. Your code might look like:
<syntaxhighlight lang="c">
size_t smbios_struct_len(struct SMBIOSHeader *hd)
{
size_t i;
const char *strtab = (char *)hd + hd->len;
// Scan until we find a double zero byte
for (i = 1; strtab[i - 1] != '\0' || strtab[i] != '\0'; i++)
;
return hd->len + i + 1;
}
</syntaxhighlight>
 
The final table is denoted by a ''type'' field of value 127.
 
As an example, the BIOS Struct (Type 0) might look like this:
 
<syntaxhighlight lang="asm">
db 0 ; Indicates BIOS Structure Type |
db 13h ; Length of information in bytes | HEADER
Line 96 ⟶ 205:
 
db 0 ; End of structure
</syntaxhighlight>
</source>
 
== Header Types ==
At the end of the BIOS table, another table will start.
The last structure has type 127.
 
= Header Types =
{| class="wikitable"
|-
Line 135 ⟶ 241:
|-
| 19
| Memory Mapped DeviceArray Mapped Address's
|-
| 20
| Memory Device Mapped Address (optional as of SMBIOS 2.5)
|-
| 32
Line 144 ⟶ 253:
 
 
==See Also==
 
===Articles===
* [[ACPI]]
* [[DMI]]
 
===Forum Threads===
* http://www.osdev.org/phpBB2/viewtopic.php?t=16687 Info (saved here through lack of info)
 
===External Links===
* [http://www.dmtf.org/standards/smbios/ SMBIOS Specification]
 
[[Category:X86]]
[[Category:Standards]]
[[Category:Hardware Detection]]