AxlIpmi – Local BMC access
AxlIpmi — local BMC access
Local BMC access via IPMI transports (KCS, SSIF, EDKII vendor
protocol, Dell vendor protocol), auto-selected from SMBIOS Type 38
plus firmware protocol discovery. AxlIpmi gives UEFI apps a single
axl_ipmi_raw() entry point that abstracts away which physical
interface is attached.
Transports
Kind |
Mechanism |
Typical platform |
|---|---|---|
|
x86 I/O ports via |
x86 servers |
|
SMBus / I2C via |
ARM servers |
|
|
firmware with MdeModulePkg IPMI stack |
|
|
Dell platforms with iDRAC |
Auto-detect priority (highest → lowest): EDKII protocol → Dell
protocol → SMBIOS Type 38 (KCS/SSIF) → x86 default KCS at
0x0CA2/0x0CA3.
Phase 2 implements KCS only. The other transports attach to the same vtable in subsequent commits.
Usage
#include <axl/axl-ipmi.h>
AXL_AUTOPTR(AxlIpmiSession) ipmi = axl_ipmi_session_new();
if (ipmi == NULL) {
axl_error("No IPMI transport available");
return -1;
}
// Get Device ID: NetFn=0x06 (App), Cmd=0x01
uint8_t resp[16];
size_t resp_len = sizeof(resp);
if (axl_ipmi_raw(ipmi, 0x06, 0x01, NULL, 0, resp, &resp_len) != 0) {
axl_error("IPMI send failed");
return -1;
}
if (resp[0] != 0x00) {
axl_warning("IPMI completion code 0x%02x", resp[0]);
return -1;
}
// resp[1]..resp[resp_len-1] carry the response body.
AXL_AUTOPTR frees the session and closes the underlying transport
at scope exit. No explicit axl_ipmi_session_free() needed on the
happy path.
Layout
src/ipmi/
├── axl-ipmi.c core dispatcher + session + auto-detect
├── axl-ipmi-internal.h transport vtable + session layout
├── axl-ipmi-kcs.c KCS transport (Phase 2)
└── axl-ipmi-{ssif,edkii,dell,cmd,format}.c upcoming phases
Typed command wrappers (get_device_id, chassis_status, sdr, sel,
fru, sensor) and the IpmiFormat.c-equivalent enum-to-string
helpers land in Phase 5, together with their unit tests.
Transport hazards
These are documented upstream in the uefi-ipmitool port the module is based on; recording them here as well since they shape the module’s internals:
KCS FSM is blocking, polled, 5-second timeout per request. Safe in the current call sites (same pattern as AxlSmbios) but not usable inside AxlLoop without yielding.
SSIF 60 ms inter-command delay is enforced at the transport layer. Bulk operations (listing 150+ SDR records on iDRAC/Nvidia Grace) hang without it.
SSIF multi-part framing required for responses > 32 bytes.
Dell protocol synthesizes a
CC=0x00completion code byte because the vendor firmware drops it from the response buffer.
API Reference
Typedefs
-
typedef struct AxlIpmiSession AxlIpmiSession
AxlIpmiSession:
Opaque handle for a selected IPMI transport. Created via axl_ipmi_session_new() and freed with axl_ipmi_session_free().
-
typedef int (*AxlIpmiSendRaw)(void *user_data, uint8_t netfn, uint8_t cmd, const uint8_t *req, size_t req_len, uint8_t *resp, size_t *resp_len)
Send-raw callback. Same shape as axl_ipmi_raw() minus the session argument; the caller’s user_data is passed through instead.
Enums
-
enum AxlIpmiTransport
Transport kind currently driving a session.
Values:
-
enumerator AXL_IPMI_TRANSPORT_UNKNOWN
No transport available.
-
enumerator AXL_IPMI_TRANSPORT_KCS
Keyboard Controller Style (x86 I/O ports)
-
enumerator AXL_IPMI_TRANSPORT_SSIF
SMBus System Interface (I2C)
-
enumerator AXL_IPMI_TRANSPORT_EDKII
EDKII IPMI_PROTOCOL (firmware provides)
-
enumerator AXL_IPMI_TRANSPORT_DELL
Dell EFI_IPMI_TRANSPORT.
-
enumerator AXL_IPMI_TRANSPORT_UNKNOWN
-
enum AxlIpmiChassisAction
Chassis Control action (Chassis 0x02).
Values:
-
enumerator AXL_IPMI_CHASSIS_POWER_DOWN
-
enumerator AXL_IPMI_CHASSIS_POWER_UP
-
enumerator AXL_IPMI_CHASSIS_POWER_CYCLE
-
enumerator AXL_IPMI_CHASSIS_HARD_RESET
-
enumerator AXL_IPMI_CHASSIS_PULSE_DIAG
-
enumerator AXL_IPMI_CHASSIS_SOFT_SHUTDOWN
-
enumerator AXL_IPMI_CHASSIS_POWER_DOWN
Functions
-
AxlIpmiSession *axl_ipmi_session_new(void)
Open an IPMI session against the local BMC.
Auto-detects the best available transport in priority order:
EDKII IPMI_PROTOCOL (gIpmiProtocolGuid)
Dell EFI_IPMI_TRANSPORT (gDellIpmiProtocolGuid)
SMBIOS Type 38 — KCS on x86 (I/O at 0x0CA2/0x0CA3 by default) or SSIF on ARM (slave 0x20 by default)
- Returns:
session handle, or NULL if no transport is available.
-
void axl_ipmi_session_free(AxlIpmiSession *session)
Free an IPMI session. NULL-safe.
- Parameters:
session – session to free (NULL-safe)
-
AxlIpmiTransport axl_ipmi_session_transport(const AxlIpmiSession *session)
Return the transport kind this session is using.
- Parameters:
session – session (NULL returns UNKNOWN)
-
uint8_t axl_ipmi_session_last_cc(const AxlIpmiSession *session)
Return the IPMI completion code from the most recent typed command call on any session.
Lets callers distinguish an IPMI-level failure (non-zero CC from the BMC) from a transport-level failure (no response, timeout, LocateProtocol fail) when a typed wrapper returns -1. On a successful call the completion code is 0x00.
UEFI is single-threaded so the tracked CC is process-global; the session parameter is accepted for API-shape consistency but the value does not vary per-session in this implementation.
- Parameters:
session – session (accepted but ignored)
- Returns:
last-observed completion code, or 0x00 if no typed command has been invoked yet.
-
int axl_ipmi_raw(AxlIpmiSession *session, uint8_t netfn, uint8_t cmd, const uint8_t *req, size_t req_len, uint8_t *resp, size_t *resp_len)
Send a raw IPMI command and receive its response.
Every typed wrapper is built on top of this. netfn is unshifted (0x06 for App, 0x00 for Chassis, etc.). The response buffer receives the completion code as its first byte.
resp_len is in/out: on entry holds the buffer capacity; on success receives the number of bytes actually written.
- Parameters:
session – session returned by axl_ipmi_session_new
netfn – network function (unshifted)
cmd – command byte
req – request data bytes (may be NULL if req_len == 0)
req_len – request data length in bytes
resp – (out) response bytes; resp[0] is completion code
resp_len – in/out: buffer size -> actual bytes written
- Returns:
0 on success (transport completed the transaction; check resp[0] for the IPMI completion code). -1 on transport error or invalid arguments.
-
AxlIpmiSession *axl_ipmi_session_new_with_callback(AxlIpmiTransport transport_kind, AxlIpmiSendRaw send_raw, void *user_data)
Open an IPMI session backed by a caller-supplied transport callback.
Useful for unit tests (inject canned responses) and for pluggable out-of-process transports (IPMI-over-LAN, test rigs, etc.) that aren’t baked into the auto-detect chain.
- Parameters:
transport_kind – label reported by axl_ipmi_session_transport
send_raw – callback invoked for each command
user_data – passed through to send_raw
- Returns:
session handle, or NULL on allocation failure.
-
int axl_ipmi_get_device_id(AxlIpmiSession *session, AxlIpmiDeviceId *out)
-
int axl_ipmi_get_chassis_status(AxlIpmiSession *session, AxlIpmiChassisStatus *out)
-
int axl_ipmi_chassis_control(AxlIpmiSession *session, AxlIpmiChassisAction action)
-
int axl_ipmi_bmc_cold_reset(AxlIpmiSession *session)
Send a BMC Cold Reset (App 0x02).
Full BMC reboot. The BMC is unresponsive to further IPMI for 20–30 seconds afterward; callers should plan a retry delay.
- Returns:
0 on success.
-
int axl_ipmi_bmc_warm_reset(AxlIpmiSession *session)
Send a BMC Warm Reset (App 0x03).
Resets BMC state without full reboot. Not all BMCs implement this — expect CC 0xC1 “Invalid command” on some platforms.
- Returns:
0 on success.
-
int axl_ipmi_sel_info(AxlIpmiSession *session, AxlIpmiSelInfo *out)
-
int axl_ipmi_sel_get_entry(AxlIpmiSession *session, uint16_t record_id, AxlIpmiSelEntry *out)
- Parameters:
record_id – 0x0000 = first, 0xFFFF = last
-
int axl_ipmi_sdr_info(AxlIpmiSession *session, AxlIpmiSdrInfo *out)
-
int axl_ipmi_sdr_get(AxlIpmiSession *session, uint16_t record_id, uint16_t *next_record_id, uint8_t *buf, size_t *len)
Fetch one SDR record’s bytes.
len is in/out: buffer capacity in, actual record size out. The typed SDR layouts (full sensor / compact sensor / entity / etc.) are defined in the IPMI spec; callers decode the returned bytes based on the SDR header’s record type.
- Returns:
0 on success; *next_record_id receives the record id to pass on the next call (0xFFFF after the last record).
-
int axl_ipmi_get_sensor_reading(AxlIpmiSession *session, uint8_t sensor_num, AxlIpmiSensorReading *out)
-
int axl_ipmi_fru_info(AxlIpmiSession *session, uint8_t fru_id, AxlIpmiFruInfo *out)
-
int axl_ipmi_fru_read(AxlIpmiSession *session, uint8_t fru_id, uint16_t offset, uint8_t *buf, size_t *len)
Read a chunk of FRU data.
FRU areas are typically hundreds to a few thousand bytes; callers loop this helper with a 16-byte chunk size (SSIF sweet spot).
len is in/out: buffer capacity on entry, bytes actually read on return.
- Returns:
0 on success.
-
const char *axl_ipmi_completion_code_string(uint8_t cc)
Human-readable name for an IPMI completion code.
Covers the standard codes from IPMI v2.0 Table 5-2. Unknown codes fall through to a generic “device-specific / OEM” label.
- Parameters:
cc – completion code byte (resp[0])
- Returns:
static string; never NULL.
-
const char *axl_ipmi_sensor_type_string(uint8_t sensor_type)
Human-readable name for an IPMI sensor type.
Covers type codes 0x01-0x2C from IPMI v2.0 Table 42-3. Unknown codes return “Unknown”.
- Returns:
static string; never NULL.
-
int axl_ipmi_probe(AxlIpmiProbe *out)
Populate out with a snapshot of IPMI-related firmware state. Always succeeds (fields are zero-filled when the corresponding feature isn’t present).
- Returns:
0 on success, -1 only on NULL argument.
-
const char *axl_ipmi_entity_id_string(uint8_t entity_id)
Human-readable name for an IPMI entity ID.
Covers the common entity IDs from IPMI v2.0 Table 43-13.
- Returns:
static string; never NULL.
-
struct AxlIpmiDeviceId
- #include <axl-ipmi.h>
Decoded Get Device ID response (App 0x01).
Public Members
-
uint8_t device_id
-
uint8_t device_revision
bits 0-3 revision, bit 7 = SDR support
-
uint8_t firmware_major
bits 0-6 major rev; bit 7 = device busy
-
uint8_t firmware_minor
BCD minor rev.
-
uint8_t ipmi_version
BCD: bits 3:0 major, bits 7:4 minor.
-
uint8_t device_support
bitmask of functions supported
-
uint32_t manufacturer_id
24-bit IANA manufacturer ID
-
uint16_t product_id
-
uint32_t aux_firmware_rev
0 if not provided
-
uint8_t device_id
-
struct AxlIpmiChassisStatus
- #include <axl-ipmi.h>
Decoded Get Chassis Status response (Chassis 0x01).
-
struct AxlIpmiSelInfo
- #include <axl-ipmi.h>
Decoded Get SEL Info response (Storage 0x40).
-
struct AxlIpmiSelEntry
- #include <axl-ipmi.h>
One SEL entry (Storage 0x43).
The
recordfield is filled with the raw 16 bytes per IPMI spec Table 32-1; decoding the specific event type is up to the caller (or the format helpers that land in a later phase).
-
struct AxlIpmiSdrInfo
- #include <axl-ipmi.h>
Decoded Get SDR Repository Info response (Storage 0x20).
-
struct AxlIpmiSensorReading
- #include <axl-ipmi.h>
Decoded Get Sensor Reading response (Sensor 0x2D).
Raw reading conversion into engineering units requires the sensor’s SDR record (for m, b, exponent); callers that want scaled values look up the SDR once and compute
(reading * m + b) * 10^expper IPMI spec 36.3.
-
struct AxlIpmiFruInfo
- #include <axl-ipmi.h>
Decoded FRU Inventory Area Info response (Storage 0x10).
-
struct AxlIpmiProbe
- #include <axl-ipmi.h>
Result of
axl_ipmi_probe().Describes which IPMI-adjacent firmware protocols are present, what SMBIOS Type 38 says about the BMC interface, and how many I2C Master handles are available. Intended for diagnostics when
axl_ipmi_session_new()can’t find a working transport — lets a tool print a summary of “what the firmware exposes” without needing direct access to UEFI protocol lookup.Public Members
-
bool edkii_ipmi_protocol
gIpmiProtocolGuid
-
bool dell_ipmi_transport
gDellIpmiProtocolGuid
-
bool ami_dxe_ipmi_transport
AMI IpmiPkg DXE variant.
-
bool ami_smm_ipmi_transport
AMI IpmiPkg SMM variant.
-
bool intel_sm_ipmi_transport
Intel ServerManagementPkg.
-
bool mu_ipmi_transport2
Microsoft Project Mu.
-
bool smbus_hc_protocol
EFI_SMBUS_HC_PROTOCOL.
-
bool i2c_master_protocol
EFI_I2C_MASTER_PROTOCOL (any)
-
bool dell_idrac_interface
Dell iDRAC (non-IPMI)
-
bool smbios_type38_present
-
uint8_t smbios_interface_type
1=KCS 2=SMIC 3=BT 4=SSIF
-
uint8_t smbios_i2c_slave
8-bit wire address from SMBIOS
-
uint64_t smbios_base_address
KCS: low bit = I/O vs memory.
-
size_t i2c_master_handle_count
-
bool edkii_ipmi_protocol