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

axl_smbios_read_bios_info

AxlSmbiosBiosInfo

1

axl_smbios_read_system_info

AxlSmbiosSystemInfo

2

axl_smbios_read_baseboard

AxlSmbiosBaseboardInfo

3

axl_smbios_read_chassis

AxlSmbiosChassisInfo

4

axl_smbios_read_processor

AxlSmbiosProcessorInfo

8

axl_smbios_read_port_connector

AxlSmbiosPortConnector

9

axl_smbios_read_system_slot

AxlSmbiosSystemSlot

11

axl_smbios_read_oem_strings

AxlSmbiosOemStrings

16

axl_smbios_read_physical_memory_array

AxlSmbiosPhysicalMemoryArray

17

axl_smbios_read_memory_device

AxlSmbiosMemoryDevice

19

axl_smbios_read_memory_array_map

AxlSmbiosMemoryArrayMap

20

axl_smbios_read_memory_device_map

AxlSmbiosMemoryDeviceMap

38

axl_smbios_read_ipmi_device_info

AxlSmbiosIpmiDeviceInfo

41

axl_smbios_read_onboard_device_ext

AxlSmbiosOnboardDeviceExt

42

axl_smbios_read_host_interface

AxlSmbiosHostInterface

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/sysinfo uses SMBIOS to report BIOS, system, baseboard, and processor inventory.

  • src/ipmi/axl-ipmi.c probes 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 one printf argument 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.

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
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.

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
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
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
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
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.

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 Windows wmic csproduct get UUID formats.

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 count with the number of strings the record advertises and strings[] 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 buf and NUL-terminated. If the string (including the NUL) doesn’t fit in buf_cap, the function returns -1 without copying — the caller is expected to retry with a larger buffer rather than receive a silently-truncated value. When required is 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 *required unchanged.

Parameters:
  • index_one_based – 1-based string index per SMBIOS §7.12

  • buf – [out] receives the NUL-terminated string

  • buf_cap – capacity of buf in 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_cap are bad, or buf_cap is 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_NETWORK with a AXL_SMBIOS_HIP_REDFISH_OVER_IP protocol 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[] with protocol_type == AXL_SMBIOS_HIP_REDFISH_OVER_IP.

  • out – receives the parsed fields on success.

Returns:

AXL_OK on success, AXL_ERR if proto is 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” / dmidecode display 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 a dmidecode --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 Length field of the structure). Tools that produce a dmidecode --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->Length to 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.

Public Members

uint8_t Type
uint8_t Length
uint16_t Handle
struct AxlSmbiosBiosInfo
#include <axl-smbios.h>

Type 0 — BIOS Information.

Public Members

const char *vendor
const char *version
const char *release_date
uint8_t major_release

0xFF if firmware didn’t publish

uint8_t minor_release

0xFF if firmware didn’t publish

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)

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).

struct AxlSmbiosChassisInfo
#include <axl-smbios.h>

Type 3 — System Enclosure / Chassis.

Public Members

const char *manufacturer
const char *version
const char *serial_number
const char *asset_tag
uint8_t type

Low 7 bits; 0x80 bit (lock) stripped.

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.

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, …)

struct AxlSmbiosPortConnector
#include <axl-smbios.h>

Type 8 — Port Connector Information.

Public Members

const char *internal_designator
const char *external_designator
uint8_t internal_connector_type

SMBIOS spec Table 8 (e.g. 0x12 = Mini Centronics Type-26)

uint8_t external_connector_type

Same enum.

uint8_t port_type

SMBIOS spec Table 9 (e.g. 0x10 = Network Port)

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.

Public Members

uint8_t count

Number of strings.

const char *strings[16]

1-based: strings[0] is what the spec calls index 1

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
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.

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

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.

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

struct AxlSmbiosHostInterfaceProtocol
#include <axl-smbios.h>

Type 42 — Management Controller Host Interface, one protocol record.

Public Members

uint8_t protocol_type

AXL_SMBIOS_HIP_* value.

uint8_t data_len

length of data

const uint8_t *data

protocol-specific payload (pointer into SMBIOS table)

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

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_len is 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