AxlSmbios — SMBIOS table access
SMBIOS table lookup and string extraction.
The SMBIOS spec defines a set of typed records — BIOS info, System info, Baseboard, Processor, Memory Array, etc. — that firmware publishes via the UEFI SMBIOS protocol. AxlSmbios provides a small, stable API for walking that table and pulling strings out of records.
Headers:
<axl/axl-smbios.h>— Table lookup, header walking, string extraction
Overview
#include <axl.h>
#include <axl/axl-smbios.h>
// Find the BIOS Information record (SMBIOS Type 0)
AxlSmbiosHeader *hdr = axl_smbios_find(AXL_SMBIOS_TYPE_BIOS_INFO);
if (hdr) {
const char *vendor = axl_smbios_get_string_utf8(hdr, 1); // vendor
const char *version = axl_smbios_get_string_utf8(hdr, 2); // version
axl_printf("BIOS: %s %s\n", vendor, version);
}
The table header is a fixed-length record followed by a
double-NUL-terminated list of ASCII strings referenced by 1-based
index from within the record. axl_smbios_get_string_utf8 resolves
those string indices to plain C strings.
Iterating All Records
To visit every record the firmware published — regardless of type:
AxlSmbiosHeader *h = NULL;
while ((h = axl_smbios_next(h)) != NULL) {
axl_printf("Type %u Handle 0x%04x Length %u\n",
h->Type, h->Handle, h->Length);
}
To iterate every record of a specific type (useful for enumerating
DIMMs, CPU cores, cache levels, etc.), use axl_smbios_find_next:
// Walk every Memory Device (Type 17) — one per DIMM slot
AxlSmbiosHeader *h = NULL;
while ((h = axl_smbios_find_next(AXL_SMBIOS_TYPE_MEMORY_DEVICE, h)) != NULL) {
// process DIMM record...
}
Common Type Constants
Use the AXL_SMBIOS_TYPE_* enum instead of bare type numbers — the
code reads better and greps cleaner. The enum covers the most common
records (BIOS, System, Baseboard, Chassis, Processor, Cache, Port
Connector, System Slots, OEM Strings, BIOS Language, Physical Memory
Array, Memory Device, Memory Array Mapped Address, Memory Device
Mapped Address, System Boot, IPMI Device, Onboard Devices Extended,
Management Host Interface, end-of-table sentinel, etc.). For
rarely-used types (SMBIOS defines ~45), bare numbers are still fine.
Typed Readers
For records the SDK has typed-reader support for, prefer them over hand-walking the raw header — they’re length-aware (won’t UB on short records firmware from older spec versions emits) and surface “not published” via documented sentinels per field.
AxlSmbiosBiosInfo bi;
if (axl_smbios_read_bios_info(&bi) == 0) {
axl_printf("%s %s (%u.%u)\n",
bi.vendor, bi.version, bi.major_release, bi.minor_release);
}
AxlSmbiosHeader *h = NULL;
while ((h = axl_smbios_find_next(AXL_SMBIOS_TYPE_SYSTEM_SLOTS, h))) {
AxlSmbiosSystemSlot sl;
if (axl_smbios_read_system_slot(h, &sl) == 0) {
axl_printf("Slot %s: bus %02x:%02x\n",
sl.designation, sl.bus, sl.device_function);
}
}
Available readers:
Type |
Reader |
Struct |
|---|---|---|
0 |
|
|
1 |
|
|
2 |
|
|
3 |
|
|
4 |
|
|
8 |
|
|
9 |
|
|
11 |
|
|
16 |
|
|
17 |
|
|
19 |
|
|
20 |
|
|
38 |
|
|
41 |
|
|
42 |
|
|
Reading the Spec Version
unsigned char major, minor;
if (axl_smbios_version(&major, &minor) == 0) {
axl_printf("SMBIOS %u.%u\n", major, minor);
}
Useful for gating on fields that were added in later spec revisions (e.g. several Type 17 Memory Device fields are post-2.7).
Consumers
tools/sysinfouses SMBIOS to report BIOS, system, baseboard, and processor inventory.src/ipmi/axl-ipmi.cprobes SMBIOS Type 38 (IPMI Device Information) during transport auto-detection.
String Accessors
Two flavors:
axl_smbios_get_string_utf8(hdr, idx)— returns a pointer directly into the SMBIOS table memory (which persists for the life of the app via the UEFI configuration table). Reentrant — safe to call twice in oneprintfargument list.axl_smbios_copy_string_utf8(hdr, idx, buf, buf_size)— copies into a caller buffer, length-bounded with safe truncation, always NUL-terminates. Returns the byte count written. Use this when you need a writable copy or want explicit truncation control.
The legacy axl_smbios_get_string(hdr, idx) returns UCS-2 in a
static buffer and is kept for back-compat; new code should use the
UTF-8 variants.
Type 11 OEM Strings — convenience accessor
For the common “fetch the OEM string at index N” pattern,
axl_smbios_get_oem_string(idx, buf, buf_cap, *required) walks
every Type 11 record in firmware order, treats their strings as
one contiguous 1-based list, and copies the requested string into
the caller’s buffer:
char product_id[64];
size_t need = 0;
if (axl_smbios_get_oem_string(/*1-based*/ 1, product_id,
sizeof(product_id), &need) == 0) {
axl_printf("OEM string 1: %s\n", product_id);
}
A too-small buffer returns -1 without copying — the call refuses
to truncate silently. When *required is non-NULL it is set to
the byte count needed (string length + NUL), letting callers
size a follow-up allocation exactly:
size_t need = 0;
if (axl_smbios_get_oem_string(1, NULL, 0, &need) == -1 && need > 0) {
char *buf = axl_malloc(need);
axl_smbios_get_oem_string(1, buf, need, NULL);
/* ... */
axl_free(buf);
}
Most platforms ship a single Type 11 record; the multi-record path
is robustness for firmware that splits OEM strings across records.
Other failure modes (no Type 11 record, index out of range, bad
buffer) leave *required unchanged. Callers that want raw
(count, strings[]) arrays can still use
axl_smbios_read_oem_strings(hdr, *out) after locating a header
with axl_smbios_find(AXL_SMBIOS_TYPE_OEM_STRINGS).
Spec-Value Decoders
Type 9 (System Slots) carries enumerated values for slot type, bus width, and current usage. The SDK ships pure-spec lookup tables so consumers don’t reinvent the decoder (and so spec additions like EDSFF E1.S/E1.L, OCP NIC 3.0, PCIe Gen 5/6 propagate via SDK bumps):
AxlSmbiosSystemSlot sl;
if (axl_smbios_read_system_slot(h, &sl) == 0) {
const char *t = axl_smbios_slot_type_str(sl.slot_type); // "PCIe Gen 5 x16"
const char *w = axl_smbios_slot_width_str(sl.slot_data_bus_width); // "16x"
const char *u = axl_smbios_slot_usage_str(sl.current_usage); // "InUse"
axl_printf("%s %s %s%s\n", sl.designation,
t ? t : "(unknown)",
w ? w : "(unknown)",
u ? u : "(unknown)");
}
Unknown values return NULL so callers can fall back to printing raw
“0x%02X”. Strings match SMBIOS 3.7 Table 12 exactly (e.g.
slot_usage_str(0x05) returns “Unavailable”); vendor-specific
renderings (e.g. an OEM that wants “CPU NOT INSTALLED” for
socket-associated 0x05 slots) belong in consumer code, which can
read AxlSmbiosSystemSlot.current_usage directly and translate.
axl_smbios_chassis_class(type) classifies the Type 3 chassis byte
into a coarse AxlSmbiosChassisClass (DESKTOP / NOTEBOOK / SERVER /
EMBEDDED / OTHER / UNKNOWN). Two pitfalls worth knowing:
0x18 (“Sealed-case PC”) is DESKTOP, not server; 0x23 (“Mini PC” per
SMBIOS 3.7) is EMBEDDED, not IoT Gateway. Vendor-specific server
detection (sysId tables, PCI audio probes) lives in consumer code
on top.
Walking the Table
axl_smbios_find(type) returns the first record of a given type;
axl_smbios_find_next(type, prev) walks all records of that type
(pass NULL for the first call); axl_smbios_next(prev) walks every
record regardless of type. All terminate at the Type 127
end-of-table sentinel.
API Reference
Enums
-
enum AxlSmbiosTableType
Common SMBIOS table types. Values match the SMBIOS specification; use these constants instead of bare numbers for readability.
Values:
-
enumerator AXL_SMBIOS_TYPE_BIOS_INFO
BIOS Information.
-
enumerator AXL_SMBIOS_TYPE_SYSTEM_INFO
System Information (manufacturer, product, UUID)
-
enumerator AXL_SMBIOS_TYPE_BASEBOARD
Baseboard / Module.
-
enumerator AXL_SMBIOS_TYPE_CHASSIS
System Enclosure / Chassis.
-
enumerator AXL_SMBIOS_TYPE_PROCESSOR
Processor.
-
enumerator AXL_SMBIOS_TYPE_CACHE
Cache.
-
enumerator AXL_SMBIOS_TYPE_PORT_CONNECTOR
Port Connector.
-
enumerator AXL_SMBIOS_TYPE_SYSTEM_SLOTS
System Slots.
-
enumerator AXL_SMBIOS_TYPE_OEM_STRINGS
OEM Strings.
-
enumerator AXL_SMBIOS_TYPE_BIOS_LANGUAGE
BIOS Language Information.
-
enumerator AXL_SMBIOS_TYPE_PHYSICAL_MEMORY
Physical Memory Array.
-
enumerator AXL_SMBIOS_TYPE_PHYSICAL_MEMORY_ARRAY
Alias matching the spec’s full name.
-
enumerator AXL_SMBIOS_TYPE_MEMORY_DEVICE
Memory Device (per DIMM)
-
enumerator AXL_SMBIOS_TYPE_MEMORY_ARRAY_MAP
Memory Array Mapped Address.
-
enumerator AXL_SMBIOS_TYPE_MEMORY_DEVICE_MAP
Memory Device Mapped Address.
-
enumerator AXL_SMBIOS_TYPE_SYSTEM_BOOT
System Boot Information.
-
enumerator AXL_SMBIOS_TYPE_IPMI_DEVICE_INFO
IPMI Device Information (transport, address)
-
enumerator AXL_SMBIOS_TYPE_ONBOARD_DEVICE_EXT
Onboard Devices Extended Information.
-
enumerator AXL_SMBIOS_TYPE_MGMT_HOST_INTERFACE
Management Controller Host Interface (Redfish, OEM, …)
-
enumerator AXL_SMBIOS_TYPE_END
End-of-table sentinel.
-
enumerator AXL_SMBIOS_TYPE_BIOS_INFO
-
enum AxlSmbiosIpmiInterface
IPMI interface type codes (Type 38 offset 0x04).
Values:
-
enumerator AXL_SMBIOS_IPMI_UNKNOWN
-
enumerator AXL_SMBIOS_IPMI_KCS
-
enumerator AXL_SMBIOS_IPMI_SMIC
-
enumerator AXL_SMBIOS_IPMI_BT
-
enumerator AXL_SMBIOS_IPMI_SSIF
-
enumerator AXL_SMBIOS_IPMI_UNKNOWN
-
enum AxlSmbiosHostIfaceType
Management Controller Host Interface types (Type 42 offset 0x04).
Values:
-
enumerator AXL_SMBIOS_HIF_KCS
Keyboard Controller Style.
-
enumerator AXL_SMBIOS_HIF_UART_8250
-
enumerator AXL_SMBIOS_HIF_UART_16450
-
enumerator AXL_SMBIOS_HIF_UART_16550
-
enumerator AXL_SMBIOS_HIF_UART_16650
-
enumerator AXL_SMBIOS_HIF_UART_16750
-
enumerator AXL_SMBIOS_HIF_UART_16850
-
enumerator AXL_SMBIOS_HIF_NETWORK
Network Host Interface (used for Redfish)
-
enumerator AXL_SMBIOS_HIF_OEM
OEM-defined.
-
enumerator AXL_SMBIOS_HIF_KCS
-
enum AxlSmbiosHostIfaceProtocol
Management Controller Host Interface protocols (Type 42 protocol record).
Values:
-
enumerator AXL_SMBIOS_HIP_IPMI
-
enumerator AXL_SMBIOS_HIP_MCTP
-
enumerator AXL_SMBIOS_HIP_REDFISH_OVER_IP
Requires SMBIOS 3.2+.
-
enumerator AXL_SMBIOS_HIP_OEM
-
enumerator AXL_SMBIOS_HIP_IPMI
-
enum AxlSmbiosBoardType
SMBIOS Type 2 BoardType values (Table 14). The canonical “is this a server blade?” detector —
BoardType == 3. Type 3 chassis 0x1C/0x1D blade bits are unreliable on some OEM firmware (see ADDF/Libs/SAL/AddfSAL.cpp:fIsBladeSmbios), so callers wanting blade detection should always check Type 2 BoardType, not Type 3. 0x00 is our “not published” sentinel (record too short to carry the BoardType byte at offset 0x0D, rare since the field has been part of Type 2 since spec 2.0). 0x02 is the spec’s explicit “Unknown” — semantically distinct, but we expose both via the same UNKNOWN enum and let callers compare the raw byte against 0x02 directly if they care.Values:
-
enumerator AXL_SMBIOS_BOARD_TYPE_UNKNOWN
-
enumerator AXL_SMBIOS_BOARD_TYPE_OTHER
-
enumerator AXL_SMBIOS_BOARD_TYPE_SPEC_UNKNOWN
-
enumerator AXL_SMBIOS_BOARD_TYPE_SERVER_BLADE
-
enumerator AXL_SMBIOS_BOARD_TYPE_CONNECTIVITY_SWITCH
-
enumerator AXL_SMBIOS_BOARD_TYPE_SYS_MGMT_MODULE
-
enumerator AXL_SMBIOS_BOARD_TYPE_PROCESSOR_MODULE
-
enumerator AXL_SMBIOS_BOARD_TYPE_IO_MODULE
-
enumerator AXL_SMBIOS_BOARD_TYPE_MEMORY_MODULE
-
enumerator AXL_SMBIOS_BOARD_TYPE_DAUGHTER_BOARD
-
enumerator AXL_SMBIOS_BOARD_TYPE_MOTHERBOARD
-
enumerator AXL_SMBIOS_BOARD_TYPE_PROC_MEM_MODULE
-
enumerator AXL_SMBIOS_BOARD_TYPE_PROC_IO_MODULE
-
enumerator AXL_SMBIOS_BOARD_TYPE_INTERCONNECT_BOARD
-
enumerator AXL_SMBIOS_BOARD_TYPE_UNKNOWN
-
enum AxlSmbiosRedfishHostIpAssignment
SMBIOS Type 42 — Redfish-over-IP protocol-data assignment types.
Values:
-
enumerator AXL_SMBIOS_REDFISH_HOST_IP_UNKNOWN
-
enumerator AXL_SMBIOS_REDFISH_HOST_IP_STATIC
-
enumerator AXL_SMBIOS_REDFISH_HOST_IP_DHCP
-
enumerator AXL_SMBIOS_REDFISH_HOST_IP_AUTOCONFIG
-
enumerator AXL_SMBIOS_REDFISH_HOST_IP_HOST_SELECTED
-
enumerator AXL_SMBIOS_REDFISH_HOST_IP_UNKNOWN
-
enum AxlSmbiosRedfishIpFormat
SMBIOS Type 42 — Redfish-over-IP IP-address-format byte.
Values:
-
enumerator AXL_SMBIOS_REDFISH_IP_FORMAT_UNKNOWN
-
enumerator AXL_SMBIOS_REDFISH_IP_FORMAT_IPV4
-
enumerator AXL_SMBIOS_REDFISH_IP_FORMAT_IPV6
-
enumerator AXL_SMBIOS_REDFISH_IP_FORMAT_UNKNOWN
-
enum AxlSmbiosChassisClass
Coarse classification of an SMBIOS Type 3 chassis type byte. Pure-spec interpretation; vendor-specific overrides (e.g. “is server” detection that uses sysId tables or PCI audio-device probes on top of the spec class) live in consumer code.
Values:
-
enumerator AXL_SMBIOS_CHASSIS_CLASS_UNKNOWN
-
enumerator AXL_SMBIOS_CHASSIS_CLASS_DESKTOP
(also 0x18 Sealed-case PC — desktop, NOT server)
0x03/04/05/06/07 — desktop / SFF / mini-tower / tower
-
enumerator AXL_SMBIOS_CHASSIS_CLASS_NOTEBOOK
0x08/09/0A/0C/0E/1E/1F/20 — portable / laptop / notebook / docking / sub-notebook / tablet / convertible / detachable
-
enumerator AXL_SMBIOS_CHASSIS_CLASS_SERVER
pizza box / blade / blade enclosure
0x17/19/1B/1C/1D — rack / multi-system /
-
enumerator AXL_SMBIOS_CHASSIS_CLASS_EMBEDDED
0x23 Mini PC (per SMBIOS 3.7)
0x21 IoT Gateway, 0x22 Embedded PC,
-
enumerator AXL_SMBIOS_CHASSIS_CLASS_OTHER
Recognized chassis type outside the above buckets.
-
enumerator AXL_SMBIOS_CHASSIS_CLASS_UNKNOWN
Functions
-
int axl_smbios_read_bios_info(AxlSmbiosBiosInfo *out)
Read Type 0 (BIOS Information) from the SMBIOS table.
- Returns:
AXL_OK on success, AXL_ERR if no Type 0 record is present.
-
int axl_smbios_format_uuid(const uint8_t bytes[16], char out[37])
Format a 16-byte SMBIOS UUID as a canonical string.
SMBIOS §7.2.1 (System UUID) specifies that the first three fields (Data1: 4 bytes, Data2: 2 bytes, Data3: 2 bytes) are stored little-endian, while the remaining 8 bytes (Data4: 2 bytes + Node: 6 bytes) are stored big-endian. The canonical printed form applies the field-order swap on the first three fields, so a raw memory dump differs from the printed string. Output matches the
dmidecode(Linux) and Windowswmic csproduct get UUIDformats.- Parameters:
bytes – raw 16 bytes from the SMBIOS Type 1 UUID field
out – output buffer of at least 37 bytes (36 + NUL)
- Returns:
AXL_OK on success, AXL_ERR on NULL args.
-
int axl_smbios_read_system_info(AxlSmbiosSystemInfo *out)
Read Type 1 (System Information) from the SMBIOS table.
- Returns:
AXL_OK on success, AXL_ERR if no Type 1 record is present.
-
int axl_smbios_read_baseboard(AxlSmbiosBaseboardInfo *out)
Read Type 2 (Baseboard Information) from the SMBIOS table.
- Returns:
AXL_OK on success, AXL_ERR if no Type 2 record is present.
-
int axl_smbios_read_chassis(AxlSmbiosChassisInfo *out)
Read Type 3 (System Enclosure / Chassis) from the SMBIOS table.
- Returns:
AXL_OK on success, AXL_ERR if no Type 3 record is present.
-
int axl_smbios_read_processor(AxlSmbiosHeader *hdr, AxlSmbiosProcessorInfo *out)
Read a Type 4 (Processor) record the caller already located.
Firmware publishes one Type 4 per socket. Enumerate with
axl_smbios_find_next(AXL_SMBIOS_TYPE_PROCESSOR, prev)and call this for each result.- Returns:
AXL_OK on success, AXL_ERR if hdr is NULL or the wrong record type.
-
int axl_smbios_read_memory_device(AxlSmbiosHeader *hdr, AxlSmbiosMemoryDevice *out)
Read a Type 17 (Memory Device) record the caller already located.
Firmware publishes one Type 17 per DIMM slot (populated or not). Enumerate with
axl_smbios_find_next(AXL_SMBIOS_TYPE_MEMORY_DEVICE, prev)and call this for each result.- Returns:
AXL_OK on success, AXL_ERR if hdr is NULL or the wrong record type.
-
int axl_smbios_read_port_connector(AxlSmbiosHeader *hdr, AxlSmbiosPortConnector *out)
Read a Type 8 (Port Connector) record the caller already located.
Firmware publishes one Type 8 per physical connector. Enumerate with
axl_smbios_find_next(AXL_SMBIOS_TYPE_PORT_CONNECTOR, prev)and call this for each result.- Returns:
AXL_OK on success, AXL_ERR if hdr is NULL, wrong type, or too short.
-
int axl_smbios_read_system_slot(AxlSmbiosHeader *hdr, AxlSmbiosSystemSlot *out)
Read a Type 9 (System Slot) record the caller already located.
Length-aware: fields added in spec 2.6 / 3.2 / 3.4 fall through to the documented sentinels (0xFFFF / 0xFF / 0) when the firmware’s record is too short to carry them.
- Returns:
AXL_OK on success, AXL_ERR if hdr is NULL, wrong type, or too short.
-
int axl_smbios_read_oem_strings(AxlSmbiosHeader *hdr, AxlSmbiosOemStrings *out)
Read a Type 11 (OEM Strings) record the caller already located.
Populates
countwith the number of strings the record advertises andstrings[]with pointers into the SMBIOS table memory (valid for the life of the app). Caps at 16 entries — anything beyond is ignored.- Returns:
AXL_OK on success, AXL_ERR if hdr is NULL or wrong type.
-
int axl_smbios_get_oem_string(uint8_t index_one_based, char *buf, size_t buf_cap, size_t *required)
Read one Type 11 OEM string by 1-based global index.
Walks Type 11 records in firmware order and treats the strings across all records as one contiguous 1-based list. Index 1 is the first string of the first Type 11 record; if that record publishes 4 strings, index 5 is the first string of the second record, and so on. Most platforms ship a single Type 11 record; this is mostly a robustness convenience for callers that don’t want to enumerate records themselves.
On success the string is copied into
bufand NUL-terminated. If the string (including the NUL) doesn’t fit inbuf_cap, the function returns -1 without copying — the caller is expected to retry with a larger buffer rather than receive a silently-truncated value. Whenrequiredis non-NULL it is set to the byte count needed (string length + 1 for the NUL), letting callers size a follow-up allocation exactly. Other failure modes (no Type 11 record, index out of range, bad args) leave*requiredunchanged.- Parameters:
index_one_based – 1-based string index per SMBIOS §7.12
buf – [out] receives the NUL-terminated string
buf_cap – capacity of
bufin bytes (must be >= 1)required – [out, NULL OK] byte count needed (string + NUL) on too-small
- Returns:
AXL_OK on success, AXL_ERR if no Type 11 record exists, the index is out of range,
buf/buf_capare bad, orbuf_capis too small for the matched string.
-
int axl_smbios_read_physical_memory_array(AxlSmbiosHeader *hdr, AxlSmbiosPhysicalMemoryArray *out)
Read a Type 16 (Physical Memory Array) record.
Resolves the 32→64-bit max-capacity fallback automatically.
- Returns:
AXL_OK on success, AXL_ERR if hdr is NULL, wrong type, or too short.
-
int axl_smbios_read_memory_array_map(AxlSmbiosHeader *hdr, AxlSmbiosMemoryArrayMap *out)
Read a Type 19 (Memory Array Mapped Address) record.
Resolves the 32→64-bit address fallback automatically.
- Returns:
AXL_OK on success, AXL_ERR if hdr is NULL, wrong type, or too short.
-
int axl_smbios_read_memory_device_map(AxlSmbiosHeader *hdr, AxlSmbiosMemoryDeviceMap *out)
Read a Type 20 (Memory Device Mapped Address) record.
Resolves the 32→64-bit address fallback automatically.
- Returns:
AXL_OK on success, AXL_ERR if hdr is NULL, wrong type, or too short.
-
int axl_smbios_read_onboard_device_ext(AxlSmbiosHeader *hdr, AxlSmbiosOnboardDeviceExt *out)
Read a Type 41 (Onboard Devices Extended) record.
- Returns:
AXL_OK on success, AXL_ERR if hdr is NULL, wrong type, or too short.
-
int axl_smbios_read_ipmi_device_info(AxlSmbiosIpmiDeviceInfo *out)
Read Type 38 (IPMI Device Information).
Firmware publishes at most one Type 38 record (the single BMC). This is what AxlIpmi’s transport auto-detector reads to decide between KCS, SMIC, BT, and SSIF.
- Returns:
AXL_OK on success, AXL_ERR if no Type 38 record is present.
-
int axl_smbios_read_host_interface(AxlSmbiosHeader *hdr, AxlSmbiosHostInterface *out)
Read a Type 42 (Management Controller Host Interface) record.
Firmware may publish multiple Type 42 records (one per interface); enumerate with
axl_smbios_find_next(AXL_SMBIOS_TYPE_MGMT_HOST_INTERFACE, prev)and call this for each result. Requires SMBIOS 3.0 or later for the modern variable-length layout; older spec versions of Type 42 are not supported and return -1.- Returns:
AXL_OK on success, AXL_ERR if hdr is NULL, wrong type, or the record layout is too old to decode.
-
int axl_smbios_find_redfish_host_interface(AxlSmbiosHeader **hdr_out, AxlSmbiosHostInterface *iface_out)
Find the first Type 42 record advertising Redfish over IP.
Scans Type 42s for
interface_type == AXL_SMBIOS_HIF_NETWORKwith aAXL_SMBIOS_HIP_REDFISH_OVER_IPprotocol entry. Common use: an in-band tool that wants to talk Redfish to the local BMC without network probing.- Parameters:
hdr_out – optional — receives the matching Type 42 header
iface_out – optional — receives the parsed interface (typed reader output)
- Returns:
AXL_OK on success, AXL_ERR if nothing matches.
-
int axl_smbios_read_redfish_over_ip(const AxlSmbiosHostInterfaceProtocol *proto, AxlSmbiosRedfishOverIp *out)
Decode the protocol-specific data of a Redfish-over-IP record.
- Parameters:
proto – a protocol record from
AxlSmbiosHostInterface.protocols[]withprotocol_type == AXL_SMBIOS_HIP_REDFISH_OVER_IP.out – receives the parsed fields on success.
- Returns:
AXL_OK on success, AXL_ERR if
protois NULL, wrong protocol type, or the data is too short for the fixed Redfish-over-IP layout (91 bytes + hostname).
-
int axl_smbios_get_system_uuid(uint8_t out[16])
Get the system UUID with the endian-swap SMBIOS requires applied.
SMBIOS stores the UUID’s first three fields little-endian on the wire (since spec 2.6), but the RFC 4122 “standard” /
dmidecodedisplay form expects big-endian. This helper returns the RFC 4122 byte order so you can feed the result to anything expecting canonical UUID bytes.- Returns:
AXL_OK on success, AXL_ERR if no Type 1 record or UUID is unset (all 0x00 or all 0xFF per the spec’s “not present” markers).
-
unsigned short *axl_smbios_get_string(AxlSmbiosHeader *hdr, unsigned char string_index)
Get a string from an SMBIOS table’s string area (UCS-2).
Returns a pointer to a static 128-char unsigned short buffer — caller must use the value before the next call (not reentrant).
- Parameters:
hdr – SMBIOS table header
string_index – 1-based string index (0 returns empty string)
- Returns:
pointer to static unsigned short buffer.
-
const char *axl_smbios_get_string_utf8(AxlSmbiosHeader *hdr, unsigned char string_index)
Get a string from an SMBIOS table’s string area (UTF-8).
Returns a direct pointer into the SMBIOS table memory, which persists for the life of the app. Reentrant — multiple calls in one printf are safe.
- Parameters:
hdr – SMBIOS table header
string_index – 1-based string index (0 returns “”)
- Returns:
pointer into the SMBIOS table, or “” if not found.
-
size_t axl_smbios_copy_string_utf8(AxlSmbiosHeader *hdr, uint8_t string_index, char *buf, size_t buf_size)
Copy a string from an SMBIOS table’s string area into a caller buffer.
Reentrant alternative for callers that want a writable copy or need length-bounded handling. Truncates safely on overflow and always NUL-terminates if buf_size > 0.
- Parameters:
hdr – SMBIOS table header
string_index – 1-based string index (0 writes empty + returns 0)
buf – destination buffer
buf_size – destination buffer capacity
- Returns:
number of bytes written (excluding the terminating NUL), or 0 if the string was not found / hdr is NULL / string_index is 0. When the source string would be longer than buf_size - 1, the return value is buf_size - 1 (the truncated length).
-
int axl_smbios_table_range(uint8_t **out_start, uint8_t **out_end)
Get the address range of the raw SMBIOS structure table.
Returns the [start, end) byte range of the contiguous SMBIOS structure region as published by firmware (SMBIOS3 entry point’s
TableAddress/TableMaximumSize, or the SMBIOS 2.x equivalent).Tools that need the typed lookups (
axl_smbios_find, etc.) don’t need this. Callers that want to dump the raw bytes — e.g. fixture capture (mkfixture) producing admidecode --dump-bin-compatible blob, or a snapshot tool — use this to know how many bytes the firmware exposed without re-implementing the EFI Configuration Table walk.Both out parameters must be non-NULL.
- Parameters:
out_start – [out] receives start of structure region (inclusive)
out_end – [out] receives end of structure region (exclusive)
- Returns:
AXL_OK on success; AXL_ERR if the firmware did not publish an SMBIOS table or either out pointer is NULL.
-
int axl_smbios_entry_point(uint8_t **out_base, size_t *out_size)
Get the SMBIOS entry-point structure bytes.
Returns the address and size of the SMBIOS entry-point structure itself (24 bytes for SMBIOS3, 31 bytes for SMBIOS 2.x — the
Lengthfield of the structure). Tools that produce admidecode --dump-bin-compatible blob concatenate this with the table data from axl_smbios_table_range to write the standard file format that QEMU’s-smbios file=consumes.Both out parameters must be non-NULL.
- Parameters:
out_base – [out] receives entry-point base
out_size – [out] receives entry-point structure size in bytes
- Returns:
AXL_OK on success; AXL_ERR if the firmware did not publish an SMBIOS table or either out pointer is NULL.
-
AxlSmbiosHeader *axl_smbios_find(unsigned char type)
Find the first SMBIOS table of a given type.
- Parameters:
type – SMBIOS table type (e.g. 0 for BIOS, 1 for System)
- Returns:
pointer to table header, or NULL if not found.
-
AxlSmbiosHeader *axl_smbios_find_next(unsigned char type, AxlSmbiosHeader *prev)
Find the next SMBIOS table of a given type after prev.
Pass NULL as prev to find the first (same as axl_smbios_find). Use in a loop to enumerate all tables of a type:
AxlSmbiosHeader *h = NULL; while ((h = axl_smbios_find_next(17, h)) != NULL) { // process each Type 17 (Memory Device) entry }
- Parameters:
type – SMBIOS table type
prev – previous result (NULL to start from beginning)
- Returns:
pointer to next table header, or NULL if no more.
-
AxlSmbiosHeader *axl_smbios_next(AxlSmbiosHeader *prev)
Iterate every SMBIOS record regardless of type.
Pass NULL for the first call; pass the previous result for subsequent calls. Returns NULL when there are no more records. Walks the table in the order firmware published it, stopping at the Type 127 end-of-table sentinel.
AxlSmbiosHeader *h = NULL; while ((h = axl_smbios_next(h)) != NULL) { axl_printf("Type %u Handle 0x%04x Length %u\n", h->Type, h->Handle, h->Length); }
- Parameters:
prev – previous result (NULL to start from beginning)
- Returns:
pointer to next table header, or NULL if no more.
-
size_t axl_smbios_strings_byte_len(AxlSmbiosHeader *hdr)
Byte length of an SMBIOS record’s string-region payload.
Walks from
hdr->Lengthto the spec’s end-of-region double-NUL (0x00 0x00) and returns the number of bytes in the strings region — including each string’s NUL terminator, excluding the final extra NUL that ends the region.For records with zero strings (formatted area immediately followed by the two-byte 0x00 0x00 sentinel), returns 0. NULL hdr returns 0.
Useful for “raw record” dumps that need to know the full record span on disk including its inline strings.
- Parameters:
hdr – SMBIOS table header
- Returns:
byte count of the strings region (may be 0).
-
const char *axl_smbios_slot_type_str(uint8_t type)
Slot type code → display string.
Covers the full SMBIOS Table 13 enumeration including modern additions tracked by recent vendor fixes:
PCIe Gen 1..6 (legacy 0xA1-0xA6, Gen 2-6 at 0xA7-0xBF)
0x25 — M.2 Socket 3 (Mech Key M) Gen 5 (the historical “Gen 4 vs Gen 5” mismapping fixed upstream in dmidecode aab01c48d)
0x26 / 0x27 / 0x28 — OCP NIC 3.0 SFF / LFF / Prior to 3.0 (dmidecode commit 0c558a930)
0x29 / 0x2A — EDSFF E1.S / E1.L
0x2B / 0x2C — EDSFF E3.S / E3.L
0x22 / 0x23 / 0x24 / 0x25 — M.2 Mech Keys A / E / B / M
0x06 / 0x07 / 0x0F — PCI / PCI-X / AGP
- Parameters:
type – SMBIOS Type 9 slot_type field
- Returns:
static string, or NULL if type isn’t a recognized value.
-
const char *axl_smbios_slot_width_str(uint8_t bw)
Slot data-bus width code → display string (“1x”, “8x”, “16x”, …).
SMBIOS Table 11. Returns NULL for unknown values.
- Parameters:
bw – SMBIOS Type 9 slot_data_bus_width field
-
const char *axl_smbios_slot_usage_str(uint8_t cu)
Slot current-usage code → display string.
SMBIOS Table 12. Returns “Other” / “Unknown” / “Empty” / “InUse” / “Unavailable” — strings match the SMBIOS 3.7 spec. Vendor-specific renderings (e.g. “CPU NOT INSTALLED” for socket-associated 0x05 slots) belong in consumer code; read AxlSmbiosSystemSlot.current_usage and translate. Returns NULL for unknown values.
- Parameters:
cu – SMBIOS Type 9 current_usage field
-
AxlSmbiosChassisClass axl_smbios_chassis_class(uint8_t type)
Classify SMBIOS Type 3 chassis type into a coarse class.
Pure-spec interpretation of the chassis-type byte. Strips the high 0x80 lock bit before classifying. See AxlSmbiosChassisClass for the bucket assignments.
Pitfalls worth knowing:
0x18 (“Sealed-case PC”) is desktop/SFF, not server.
0x23 (“Mini PC” per SMBIOS 3.7) is EMBEDDED, not IoT Gateway.
- Parameters:
type – SMBIOS Type 3 type byte (lock bit allowed; will be stripped)
- Returns:
matching AxlSmbiosChassisClass, or AXL_SMBIOS_CHASSIS_CLASS_UNKNOWN if type is 0 / out of range / explicitly the spec’s “Unknown” (0x02).
-
int axl_smbios_version(unsigned char *major, unsigned char *minor)
Report the SMBIOS specification version published by firmware.
Useful for gating features on the spec version — some Type 17 Memory Device fields were added in SMBIOS 2.7, and Type 43 TPM Device requires 3.1 or later.
- Parameters:
major – written with major version (e.g. 3)
minor – written with minor version (e.g. 1)
- Returns:
AXL_OK on success, AXL_ERR if no SMBIOS table was found.
-
struct AxlSmbiosHeader
- #include <axl-smbios.h>
SMBIOS table header (standard C types, matches SMBIOS spec layout).
axl-smbios.h:
UEFI SMBIOS helpers — string extraction and table lookup.
-
struct AxlSmbiosBiosInfo
- #include <axl-smbios.h>
Type 0 — BIOS Information.
-
struct AxlSmbiosSystemInfo
- #include <axl-smbios.h>
Type 1 — System Information.
Public Members
-
const char *manufacturer
-
const char *product_name
-
const char *version
-
const char *serial_number
-
const char *sku
NULL if not published (spec 2.4+)
-
const char *family
NULL if not published (spec 2.4+)
-
uint8_t uuid[16]
RFC 4122 byte order (see note below)
-
bool has_uuid
false if UUID field is unset (all 0x00 or 0xFF)
-
const char *manufacturer
-
struct AxlSmbiosBaseboardInfo
- #include <axl-smbios.h>
Type 2 — Baseboard Information.
Public Members
-
const char *manufacturer
-
const char *product_name
-
const char *version
-
const char *serial_number
-
const char *asset_tag
-
uint8_t board_type
SMBIOS spec Table 14 (AXL_SMBIOS_BOARD_TYPE_*). 0 if firmware didn’t publish (record too short to carry the field at offset 0x0D, which is rare — the field has been part of Type 2 since spec 2.0).
-
const char *manufacturer
-
struct AxlSmbiosChassisInfo
- #include <axl-smbios.h>
Type 3 — System Enclosure / Chassis.
-
struct AxlSmbiosProcessorInfo
- #include <axl-smbios.h>
Type 4 — Processor.
Public Members
-
const char *socket_designation
-
const char *manufacturer
-
const char *version
-
const char *serial_number
-
const char *asset_tag
-
const char *part_number
-
uint8_t family
SMBIOS processor-family code.
-
uint16_t current_speed_mhz
-
uint16_t max_speed_mhz
-
uint8_t core_count
0 if not published (spec 2.5+)
-
uint8_t thread_count
0 if not published
-
uint8_t status
CPU socket populated + enabled bits.
-
const char *socket_designation
-
struct AxlSmbiosMemoryDevice
- #include <axl-smbios.h>
Type 17 — Memory Device (per DIMM slot).
Public Members
-
const char *device_locator
-
const char *bank_locator
-
const char *manufacturer
-
const char *part_number
-
const char *serial_number
-
const char *asset_tag
-
uint32_t size_mb
0 if slot is empty
-
uint16_t speed_mhz
0 if unknown
-
uint8_t memory_type
SMBIOS memory type (DDR4=0x1A, DDR5=0x22, …)
-
const char *device_locator
-
struct AxlSmbiosPortConnector
- #include <axl-smbios.h>
Type 8 — Port Connector Information.
-
struct AxlSmbiosSystemSlot
- #include <axl-smbios.h>
Type 9 — System Slots. Spec-version-creep poster child: fields beyond offset 0x0C arrived in 2.6, 3.2, and 3.4. Sentinels distinguish “not
published” from real values:
segment_group / bus / device_function: 0xFFFF / 0xFF when not in record
data_bus_width_base / peer_grouping_count: 0 when not in record
current_usage uses spec values 0x03..0x05. The typed reader returns the raw byte, so callers that want a vendor-specific rendering (e.g. “CPU NOT INSTALLED” for socket-associated 0x05 slots) can translate downstream.
Public Members
-
const char *designation
-
uint8_t slot_type
PCI/PCIe variant (SMBIOS spec Table 11)
-
uint8_t slot_data_bus_width
0x08=1x..0x0E=32x (decoded width via the standard table)
-
uint8_t current_usage
0x03=Available, 0x04=InUse, 0x05=Unavailable
-
uint8_t slot_length
-
uint16_t slot_id
-
uint16_t segment_group
0xFFFF if not published (spec 2.6+ field)
-
uint8_t bus
0xFF if not published
-
uint8_t device_function
0xFF if not published; bits 7:3 = device, bits 2:0 = function
-
uint8_t data_bus_width_base
SMBIOS 3.2+ field; 0 if not published.
-
uint8_t peer_grouping_count
SMBIOS 3.2+ field; 0 if not published.
-
struct AxlSmbiosOemStrings
- #include <axl-smbios.h>
Type 11 — OEM Strings. Each string is accessed by 1-based index in the SMBIOS spec; the typed reader exposes them as an array for ergonomics. Real systems publish 4-8 entries; the cap of 16 covers everything we’ve seen in the wild.
-
struct AxlSmbiosPhysicalMemoryArray
- #include <axl-smbios.h>
Type 16 — Physical Memory Array. The 32→64-bit max-capacity fallback is resolved internally: max_capacity_bytes is always populated correctly.
Public Members
-
uint8_t location
0x03=System board, 0x0A=PC Card, …
-
uint8_t use
0x03=System Memory, 0x04=Video, …
-
uint8_t ecc_type
-
uint64_t max_capacity_bytes
Resolves the 32→64-bit fallback (uses ExtendedMaxCapacity at offset 0x0F when MaxCapacity field == 0x80000000). 0 if the sentinel is set but the record is too short to carry the Extended field.
-
uint16_t error_handle
0xFFFE = no error info, 0xFFFF = unknown
-
uint16_t num_devices
-
uint8_t location
-
struct AxlSmbiosMemoryArrayMap
- #include <axl-smbios.h>
Type 19 — Memory Array Mapped Address. The 32→64-bit address fallback is resolved internally via the ExtendedStartingAddress / ExtendedEndingAddress fields (spec 2.7+, used when the 32-bit fields == 0xFFFFFFFF). When the sentinel is set but the record is too short to carry the Extended field (malformed firmware), the address is reported as 0 rather than the literal 4 TB - 1 KB the sentinel × 1024 would produce.
Public Members
-
uint64_t starting_address
Byte address (resolved from extended field if needed); 0 = unresolvable.
-
uint64_t ending_address
Byte address (resolved from extended field if needed); 0 = unresolvable.
-
uint16_t array_handle
Handle of the Type 16 record this maps.
-
uint8_t partition_width
Number of Type 17s feeding this region.
-
uint64_t starting_address
-
struct AxlSmbiosMemoryDeviceMap
- #include <axl-smbios.h>
Type 20 — Memory Device Mapped Address. Same 64-bit fallback story as Type 19.
Public Members
-
uint64_t starting_address
Byte address (resolved from extended field if needed); 0 = unresolvable.
-
uint64_t ending_address
Byte address (resolved from extended field if needed); 0 = unresolvable.
-
uint16_t device_handle
Handle of the Type 17 record this maps.
-
uint16_t array_map_handle
Handle of the Type 19 record this is a child of.
-
uint8_t partition_row_pos
0xFF = N/A
-
uint8_t interleave_position
0 = non-interleaved, 0xFF = unknown
-
uint8_t interleave_data_depth
0xFF = unknown
-
uint64_t starting_address
-
struct AxlSmbiosOnboardDeviceExt
- #include <axl-smbios.h>
Type 41 — Onboard Devices Extended Information.
Public Members
-
const char *reference_designation
-
uint8_t device_type
Bit 7 = Status (0=Disabled, 1=Enabled), low 7 bits = type (0x05=Ethernet, 0x07=SAS, etc.)
-
uint8_t device_type_instance
1-based per-type index
-
uint16_t segment_group
-
uint8_t bus
-
uint8_t device_function
Packed: bits 7:3 = device, bits 2:0 = function.
-
const char *reference_designation
-
struct AxlSmbiosIpmiDeviceInfo
- #include <axl-smbios.h>
Type 38 — IPMI Device Information.
Public Members
-
uint8_t interface_type
AXL_SMBIOS_IPMI_* (KCS, SMIC, BT, SSIF, …)
-
uint8_t spec_major
IPMI spec revision major (high nibble of byte 0x05)
-
uint8_t spec_minor
IPMI spec revision minor (low nibble of byte 0x05)
-
uint8_t i2c_target_address
BMC slave address on SMBus/SSIF (0 if N/A)
-
uint8_t nv_storage_address
NV storage device address (0xFF = none)
-
uint64_t base_address
Interface base address (I/O or MMIO, see is_memory_mapped)
-
bool is_memory_mapped
true = MMIO, false = I/O port
-
uint8_t interrupt_number
0 = no interrupt
-
uint8_t interface_type
-
struct AxlSmbiosHostInterfaceProtocol
- #include <axl-smbios.h>
Type 42 — Management Controller Host Interface, one protocol record.
-
struct AxlSmbiosHostInterface
- #include <axl-smbios.h>
Type 42 — Management Controller Host Interface.
Public Members
-
uint8_t interface_type
AXL_SMBIOS_HIF_*.
-
uint8_t interface_data_len
length of
interface_data
-
const uint8_t *interface_data
interface-specific bytes (pointer into SMBIOS table)
-
uint8_t protocol_count
number of entries in
protocols
-
AxlSmbiosHostInterfaceProtocol protocols[8]
capped at 8 — real firmware emits 1-2
-
uint8_t interface_type
-
struct AxlSmbiosRedfishOverIp
- #include <axl-smbios.h>
Decoded Redfish-over-IP protocol record (SMBIOS 3.x §7.43.3).
Hostname pointer is into the SMBIOS table (caller must not free).
hostname_lenis the byte count emitted by firmware; the run is NUL-terminated only if firmware chose to terminate it.Public Members
-
uint8_t service_uuid[16]
-
AxlSmbiosRedfishHostIpAssignment host_ip_assignment
-
AxlSmbiosRedfishIpFormat host_ip_format
-
uint8_t host_ip_address[16]
IPv4 in first 4 bytes if format==IPv4.
-
uint8_t host_ip_mask[16]
-
uint8_t service_ip_discovery
same enum as host_ip_assignment
-
AxlSmbiosRedfishIpFormat service_ip_format
-
uint8_t service_ip_address[16]
-
uint8_t service_ip_mask[16]
-
uint16_t service_port
-
uint32_t service_vlan_id
-
uint8_t hostname_len
-
const char *hostname
pointer into the SMBIOS table; not necessarily NUL-terminated
-
uint8_t service_uuid[16]