AxlBlock — block-device enumeration + media descriptors

Block-device enumeration via EFI_BLOCK_IO_PROTOCOL.

Header: <axl/axl-block.h>. This is the low-level counterpart to <axl/axl-fs.h>: AxlFs gives path-based file access over mounted volumes, while AxlBlock enumerates the underlying raw block devices (disks, partitions, CD-ROMs, RAM disks) and reports each one’s media descriptor — geometry and media state. Scope is enumeration + the media readout; block read/write is out of scope (use AxlFs for data).

Lazy on first call: AxlBlock locates the firmware-installed block-I/O handles once with LocateHandleBuffer and caches the set for the image lifetime. On platforms with no block devices every call returns NULL / AXL_ERR cleanly.

Cursor-style enumeration matches axl_usb_next / axl_acpi_find_next, but returns the firmware AxlHandle directly so position is recovered from the handle you pass back — there is no hidden shared cursor, so independent (even nested) walks over the cached set don’t interfere:

AxlHandle h = NULL;
while ((h = axl_block_next(h)) != NULL) {
    AxlBlockMedia m;
    if (axl_block_get_media(h, &m) == AXL_OK && m.media_present) {
        uint64_t capacity = (m.last_block + 1) * m.block_size;
        axl_printf("block dev: %u-byte sectors, %llu bytes%s\n",
                   m.block_size, (unsigned long long)capacity,
                   m.read_only ? " (read-only)" : "");
    }
}

Device-path text needs no extra API: the same AxlHandle resolves through the existing axl_handle_get_protocol(h, "device-path", ...)

  • axl_device_path_to_text() (both in <axl/axl-sys.h>).

Fields in AxlBlockMedia are raw readouts of EFI_BLOCK_IO_MEDIA; the caller derives presentation values (capacity, device type). The geometry fields (block_size, last_block) are meaningful only when media_present is true — an empty removable slot may report stale or zero values.

API Reference

Block-device enumeration and media descriptors.

Enumerates the handles that publish the firmware’s block-I/O protocol (raw block devices: disks, partitions, CD-ROMs, RAM disks) and exposes each device’s media descriptor as a typed struct. This is the low-level counterpart to <axl/axl-fs.h>: AxlFs gives path-based file access over mounted volumes, while AxlBlock enumerates the underlying block devices and reports their geometry and media state.

Cursor-style iteration matches the other platform readers (AxlPci, AxlUsb, AxlAcpi). axl_block_next walks the block handles; the returned AxlHandle feeds the typed reader below:

AxlHandle h = NULL;
while ((h = axl_block_next(h)) != NULL) {
    AxlBlockMedia m;
    if (axl_block_get_media(h, &m) == AXL_OK && m.media_present) {
        uint64_t capacity = (m.last_block + 1) * m.block_size;
        // ... report device ...
    }
}

Device-path text needs no new API: the same AxlHandle resolves through the existing axl_handle_get_protocol(h, "device-path", ...) + axl_device_path_to_text() (both in <axl/axl-sys.h>).

Scope is enumeration + the media descriptor. Block read/write is out of scope — diagnostic and inventory tools need the device list and geometry, not a block-level I/O path (use AxlFs for data access).

Functions

AxlHandle axl_block_next(AxlHandle prev)

Iterate handles publishing the block-I/O protocol.

Cursor-style enumeration: pass NULL to get the first block handle, then pass each returned handle back to get the next. Returns NULL once the enumeration is exhausted (including when no block devices exist).

The handle set is snapshotted from the firmware on the first call and cached for the image lifetime (like AxlUsb) — a device hot-added afterward will not appear; the cache mirrors the boot device set. Position is recovered from the handle you pass back, not from a hidden shared cursor, so iteration carries no global state: passing NULL — or any handle not in the cached set — starts again from the first device, and independent walks (even nested ones over the same stable set) do not interfere.

The returned handle is owned by the firmware — do not free it. It is valid to pass to axl_block_get_media and to axl_handle_get_protocol(h, "device-path", ...).

Parameters:
  • prev – previous handle, or NULL to start

Returns:

next block-I/O handle, or NULL at end of enumeration.

int axl_block_get_media(AxlHandle handle, AxlBlockMedia *out)

Read a block device’s media descriptor.

Parameters:
  • handle – handle from axl_block_next

  • out – [out] populated on success

Returns:

AXL_OK on success, AXL_ERR if handle does not publish the block-I/O protocol or out is NULL.

struct AxlBlockMedia
#include <axl-block.h>

Media descriptor for a block device.

Typed projection of the firmware’s EFI_BLOCK_IO_MEDIA. Fields are raw readouts; the consumer derives presentation values such as capacity ((last_block + 1) * block_size) and device type.

The geometry fields (block_size, last_block) are meaningful only when media_present is true — for an empty removable slot (CD-ROM, card reader) the firmware may report stale or zero values, so capacity must be computed only after checking media_present.

Physical-geometry and alignment fields the firmware also tracks (IoAlign, and the revision-gated LowestAlignedLba / LogicalBlocksPerPhysicalBlock / OptimalTransferLengthGranularity) are intentionally omitted: they require gating on the media revision and matter only to a block-level I/O path, which is out of scope for enumeration.

Public Members

uint32_t media_id

media ID; a change between reads of the same handle means the media was swapped (cached geometry is then stale)

bool removable_media

the media is removable (CD-ROM, USB stick), not that the device is hot-pluggable

bool media_present

media is currently present and accessible

bool logical_partition

handle is a logical partition, not a whole device

bool read_only

media is write-protected

bool write_caching

device has a write-back cache enabled

uint32_t block_size

logical (not physical) block size in bytes

uint64_t last_block

LBA of the last addressable block (count = last_block + 1); valid only when media_present.