AxlRamDisk — FAT RAM disks over EFI_RAM_DISK_PROTOCOL

FAT RAM disks over EFI_RAM_DISK_PROTOCOL.

Header: <axl/axl-ramdisk.h>. A RAM disk is a block of allocated memory registered with the firmware as a virtual block device, FAT-formatted so the firmware binds its filesystem driver and the volume appears as an fsN: mapping — scratch space, file staging, or the backing store of a virtual-media feature.

This module is the create/list/destroy orchestration lifted out of the mkrd tool (FAT16/FAT32 formatters, page allocation, Register / Unregister, volume enumeration, the duplicate-label check) so any consumer reuses it instead of copying ~250 lines from a tool. mkrd is now a thin CLI over it.

// Ensure the protocol is available (firmware -> disk -> embedded
// fallback), then create a 64 MB disk labelled "SCRATCH".
axl_ramdisk_ensure_driver(NULL, 0, NULL);
void *dp = NULL;
if (axl_ramdisk_create("SCRATCH", 64, &dp) == AXL_OK) {
    // ... fsN: now resolves to the new FAT volume ...
}

EFI_RAM_DISK_PROTOCOL is optional in UEFI 2.6+ and absent on some firmware. axl_ramdisk_ensure_driver resolves it in order: already published → a RamDiskDxe.efi found on a mounted volume → an embedded RamDiskDxe image supplied by the caller. The embedded image is a parameter (not baked into libaxl.a) so only binaries that want the fallback carry the ~tens-of-KB blob; declare it with AXL_EMBED_DECLARE

  • the build’s blob-embedding rule and pass AXL_EMBED_DATA / AXL_EMBED_SIZE (see tools/mkrd.c). A vendored RamDiskDxe.efi per arch lives in third_party/edk2/.

The registered device path embeds the backing memory’s physical address (VirtualDisk(0x...,...)), which is wherever AllocatePages lands and varies run to run — it is not stable across boots or binaries. The stable cross-boot handle is the FAT label, which is why axl_ramdisk_destroy keys on it.

Registering a pre-populated image (virtual media)

axl_ramdisk_register_image registers an already-populated, page-aligned buffer without formatting — for mounting an uploaded .iso / .img as a virtual block device (the iDRAC “Virtual Media” shape). AxlRamDiskKind picks the firmware-recognized type GUID: AXL_RAMDISK_CDROM (gEfiVirtualCdGuid, an El Torito CD-ROM for a bootable ISO) or AXL_RAMDISK_DISK (gEfiVirtualDiskGuid, a raw disk image). It connects controllers so the firmware binds its block / FAT / ISO9660 drivers and the device enumerates.

// Mount an uploaded ISO as a bootable virtual CD-ROM.
uint64_t pages = (size + 4095) / 4096, phys = 0;
axl_alloc_pages(pages, &phys);
void *img = (void *)(uintptr_t)phys;
// ... read the .iso bytes into img (e.g. via axl_file_view) ...
void *dp = NULL;
axl_ramdisk_register_image(img, size, AXL_RAMDISK_CDROM, &dp);
// ... device now enumerates / is bootable ...
axl_ramdisk_unregister(dp);
axl_free_pages(phys, pages);   // caller owns the buffer

Ownership differs from create/destroy: the image buffer is caller-owned and not copied, so it must stay valid until axl_ramdisk_unregister, and the caller frees it (axl_free_pages) afterward — unregister only detaches the device.

Scope is create / list / destroy / register-image of the device; reading and writing its files is <axl/axl-fs.h> over the resulting fsN:.

API Reference

Create, enumerate, and destroy FAT RAM disks over EFI_RAM_DISK_PROTOCOL.

A RAM disk is a block of allocated memory registered with the firmware as a virtual block device, FAT-formatted so the firmware binds its filesystem driver and the volume appears as an fsN: mapping. Useful for scratch space, staging files a tool produces, or the backing store of a virtual-media feature.

// Make the protocol available (embedded fallback optional), then
// create a 64 MB disk labelled "SCRATCH".
axl_ramdisk_ensure_driver(NULL, 0, NULL);
void *dp = NULL;
if (axl_ramdisk_create("SCRATCH", 64, &dp) == AXL_OK) {
    // ... fsN: now resolves to the new FAT volume ...
}

EFI_RAM_DISK_PROTOCOL is optional in UEFI 2.6+ and absent on some firmware; axl_ramdisk_ensure_driver loads a RamDiskDxe driver when the firmware doesn’t already publish it. The orchestration here is lifted from the mkrd tool so any consumer reuses it instead of copying the FAT formatters and the driver-ensure flow.

Scope is create / list / destroy of the device. Reading and writing the disk’s files is <axl/axl-fs.h> over the resulting fsN:.

Enums

enum AxlRamDiskKind

Image kind for axl_ramdisk_register_image — the RAM-disk type GUID the firmware sees.

An El Torito CD-ROM (a bootable .iso, exposed as a CD device) or a raw hard-disk image (a .img, exposed as a block device).

Values:

enumerator AXL_RAMDISK_DISK

gEfiVirtualDiskGuid — raw block image

enumerator AXL_RAMDISK_CDROM

gEfiVirtualCdGuid — El Torito CD-ROM

Functions

int axl_ramdisk_ensure_driver(const unsigned char *dxe_image, size_t dxe_image_size, const char *override_name)

Ensure EFI_RAM_DISK_PROTOCOL is available.

Resolves the protocol in order: (1) already published by the firmware, (2) a RamDiskDxe driver found on a mounted volume, (3) the embedded image supplied here. Wraps axl_driver_ensure_with_embedded for the RAM-disk GUID — the non-trivial firmware/disk/embedded fallback every RAM-disk consumer needs.

The embedded image is a parameter rather than baked into the library so binaries that never make a RAM disk don’t carry the ~tens-of-KB RamDiskDxe.efi blob. Consumers wanting the embedded fallback declare the blob with AXL_EMBED_DECLARE / the build’s blob-embedding rule and pass AXL_EMBED_DATA / AXL_EMBED_SIZE (see the mkrd tool).

When override_name is set, the disk search uses it and the embedded fallback is not used (matches axl_driver_ensure_with_embedded).

Parameters:
  • dxe_image – embedded RamDiskDxe.efi bytes, or NULL to skip the embedded fallback

  • dxe_image_size – length of dxe_image (0 if NULL)

  • override_name – driver filename to search instead of “RamDiskDxe.efi” (NULL for the default)

Returns:

AXL_OK if the protocol is now available, AXL_ERR if every resolution step failed.

int axl_ramdisk_create(const char *label, size_t size_mb, void **dev_path_out)

Allocate, FAT-format, and register a RAM disk.

Allocates size_mb of page-aligned memory, formats it FAT16 (size_mb <= 512) or FAT32 (larger) with label as the volume label, and registers it via EFI_RAM_DISK_PROTOCOL. Blocks ~0.5s for the firmware to bind its FAT driver, then refreshes the volume map so the disk is immediately enumerable and reachable as fsN: (relevant for a consumer creating one at boot).

Requires the protocol — call axl_ramdisk_ensure_driver first (or run on firmware that publishes it). size_mb must be in the range 1..32768; values outside it return AXL_ERR. Idempotent on the label: if a RAM disk with label already exists, returns AXL_OK without allocating again and sets dev_path_out to the existing disk’s device path.

Note the registered device path embeds the backing memory’s physical address (e.g. VirtualDisk(0x17F5D000,...)), which is wherever the allocation lands — it varies run to run, so it is not stable across boots or binaries. (The stable cross-boot handle is the label, which is why axl_ramdisk_destroy keys on it.) The returned device path is firmware-owned and valid until this disk is destroyed.

Parameters:
  • label – FAT volume label (uppercased, truncated to 11 chars)

  • size_mb – disk size in MB (1..32768)

  • dev_path_out – [out] firmware-owned device path, or NULL if unwanted (do not free)

Returns:

AXL_OK on success (or an existing same-label disk), AXL_ERR if the protocol is unavailable, size_mb is out of range, allocation fails, or registration fails.

int axl_ramdisk_destroy(const char *label)

Destroy a RAM disk by FAT label.

Unregisters the matching RAM disk and frees its backing memory. The label match is case-insensitive and ignores trailing padding; label is truncated to the stored 11-char FAT label before comparing, so passing the same (possibly long) label given to axl_ramdisk_create matches.

Parameters:
  • label – FAT volume label to destroy

Returns:

AXL_OK on success, AXL_ERR if the protocol is unavailable or no RAM disk with label is found.

int axl_ramdisk_list(AxlRamDisk *out, size_t cap, size_t *count)

List the registered RAM disks.

Fills out with up to cap descriptors and writes the total to count. (out == NULL / cap == 0 reports the count only.) An empty result is success with *count == 0.

Parameters:
  • out – output array (may be NULL to count only)

  • cap – capacity of out

  • count – [out] number of RAM disks found

Returns:

AXL_OK on success, AXL_ERR on bad arguments.

int axl_ramdisk_register_image(void *image, uint64_t size_bytes, AxlRamDiskKind kind, void **dev_path_out)

Register an already-populated, page-aligned image buffer as a typed RAM disk via EFI_RAM_DISK_PROTOCOL — WITHOUT formatting.

Unlike axl_ramdisk_create (which allocates and FAT-formats a blank scratch disk), this registers caller-owned memory verbatim, so an uploaded OS image boots as-is: the image carries its own filesystem (ISO9660 for a CD-ROM, a partition / FAT image for a disk). kind selects the firmware-recognized type GUID — CD-ROM vs raw disk. After registering, the firmware’s controllers are connected so it binds its block / FAT / ISO9660 drivers and the device enumerates (a bootable image becomes a boot option). The connect is global (equivalent to the shell’s connect -r) — heavier than a targeted connect, but it only binds drivers, never unbinds, so it does not disturb controllers already in use (e.g. a running server’s NICs).

Ownership: image is caller-owned and is NOT copied — it must be page-aligned (allocate with axl_alloc_pages) and MUST stay valid until axl_ramdisk_unregister. The caller frees it (with axl_free_pages) AFTER unregistering — this call never takes ownership of the memory (contrast axl_ramdisk_create / axl_ramdisk_destroy, which own and free the disk they allocate).

Requires the protocol — call axl_ramdisk_ensure_driver first (or run on firmware that publishes it). The returned device path is firmware-owned (do not free) and valid until axl_ramdisk_unregister. Note it embeds the backing memory’s physical address, so it is not stable across boots; it is the handle you pass back to unregister.

Parameters:
  • image – page-aligned image bytes (caller-owned; keep valid until unregister)

  • size_bytes – image length in bytes

  • kind – CD-ROM vs raw disk type GUID

  • dev_path_out – [out] firmware-owned device path (do not free), or NULL if unwanted

Returns:

AXL_OK on success, or AXL_ERR if the protocol is unavailable, image is NULL, size_bytes is 0, kind is invalid, or registration fails.

int axl_ramdisk_unregister(void *dev_path)

Unregister a RAM disk by the device path returned from axl_ramdisk_register_image.

Unregisters the device via EFI_RAM_DISK_PROTOCOL. Does NOT free the backing memory — the caller frees its axl_alloc_pages buffer afterward (the symmetric who-allocates-frees contract; contrast axl_ramdisk_destroy, which owns and frees the FAT disk it created).

Parameters:
  • dev_path – device path from axl_ramdisk_register_image

Returns:

AXL_OK on success, or AXL_ERR if dev_path is NULL, the protocol is unavailable, or no RAM disk matches dev_path.

struct AxlRamDisk
#include <axl-ramdisk.h>

A registered RAM disk, as reported by axl_ramdisk_list.

Public Members

char label[16]

FAT volume label (NUL-terminated; “” if unlabeled)

uint64_t start_addr

physical address of the backing memory

uint64_t size_bytes

backing size in bytes

void *device_path

firmware-owned EFI device path (do not free); valid until this disk is destroyed