Porting Guide

AXL Porting Guide

How to port UEFI applications and drivers from EDK2 to the AXL SDK. Covers the dependency audit across AximCode consumer projects, AXL’s protocol abstraction strategy, and step-by-step porting instructions.

Last updated: April 2026


What AXL Already Covers

These EDK2 dependencies have AXL equivalents and apps can port today:

EDK2

AXL

Used by

AllocatePool/FreePool

axl_malloc/free

Everything

Print(L”…”)

axl_printf

Everything

CopyMem/SetMem/ZeroMem

axl_memcpy/memset

Everything

ShellOpenFileByName/ReadFile/CloseFile

axl_fopen/fread/fclose

Hexdump, Grep, Find, MkRd

ShellGetFileInfo

axl_file_info

Hexdump, Grep, Find

FileHandleFindFirst/Next

axl_dir_open/read/close

Grep, Find

ShellCommandLineParse

axl_args_parse

All apps

AsciiStr*/StrCmp/StrLen

axl_str* / standard C

Everything

utf8 to/from ucs2

axl_utf8_to_ucs2/ucs2_to_utf8

Everything

GOP->Blt

axl_gfx_*

SoftBMC Splash, RemoteKVM

TCP4 protocol

axl_tcp_*

SoftBMC HttpServer, httpfs

HTTP client/server

axl_http_*

Fetch, httpfs CmdServe, SoftBMC

SMBIOS tables

axl_smbios_*

SysInfo, SoftBMC HwInfo

Shell env/cwd

axl_getenv/setenv/chdir

Shell integration

Driver load/connect

axl_driver_*

httpfs CmdMount

System reset

axl_reset

SoftBMC PowerControl

Map refresh

axl_map_refresh

httpfs CmdMount

Event loop + timers

axl_loop_*

SoftBMC, httpfs

Deferred work

axl_defer

SoftBMC event handling

Pub/sub events

axl_signal_*

SoftBMC module decoupling

Buffer pool

axl_buf_pool_*

SoftBMC VNC tiles

Async AP work

axl_async_*

SoftBMC firmware update

File seek/tell/eof

axl_fseek/ftell/feof

General file I/O

mkdir/rmdir

axl_dir_mkdir/rmdir

General

File delete/rename

axl_file_delete/rename

General

String search

axl_strstr_len/strrstr

General

Prefix/suffix test

axl_str_has_prefix/suffix

General

String comparison

axl_strcmp0/strcasecmp/strncasecmp

General

String array ops

axl_strv_contains/equal

General


What’s Missing — By Priority

Tier 1: Needed by 2+ projects (high value)

Missing API

Needed by

What it does

Effort

UEFI variable access

SoftBMC Config, SysInfo

gRT->GetVariable/SetVariable for persistent config, Secure Boot info

Medium

Protocol locate/enumerate

SoftBMC, httpfs, SysInfo, NetInfo

gBS->LocateProtocol, LocateHandleBuffer, HandleProtocol

Medium

Device path helpers

httpfs CmdMount, MkRd

FileDevicePath, IsDevicePathEnd, NextDevicePathNode

Medium

UDP socket

SoftBMC (SNMP, Syslog)

Send/receive UDP datagrams

Medium

Tier 2: Needed by 1 project, critical for it

Missing API

Needed by

What it does

Effort

Protocol install/uninstall

httpfs WebDavFsDxe driver

gBS->InstallMultipleProtocolInterfaces

Medium

EFI_FILE_PROTOCOL types

httpfs driver

Type definitions for the protocol the driver implements

Low

EFI_SIMPLE_FILE_SYSTEM_PROTOCOL

httpfs driver

The protocol the driver installs

Low

Physical memory

MkRd

AllocatePages/FreePages

Low

RAM disk protocol

MkRd, SoftBMC VirtualMedia

Register memory as a disk

Low

Network init (DHCP/IP config)

SoftBMC Network, httpfs NetworkLib

Full NIC init with DHCP

High

Tier 3: Nice to have / can work around

Missing API

Needed by

Workaround

PCI/ACPI/USB/TPM enumeration

SoftBMC HwInfo

Limit to SMBIOS-only

HII database (UEFI Setup)

SoftBMC UefiSetup

Replace with web-based config

Ctrl-C / break flag

Grep, Find

Drop or poll stdin

gRT->GetTime (wall clock)

SoftBMC, httpfs cache

axl_time_* (partial)

Spinlocks

SoftBMC RemoteKVM

Refactor for single-threaded event model


App-Level Porting Readiness

uefi-devkit

App

Status

Blocker

Effort

Hexdump

DONE

None

Done

Fetch

Ready

None — just Print to printf + AXL_APP

Low

Grep

Ready

None — has axl_dir_read, just needs Print cleanup

Low

Find

Ready

Replace ShellCommandLineParse with axl_args

Low

SysInfo

Almost

Needs UEFI variable access (gRT->GetVariable)

Medium

MkRd

Blocked

Needs RAM disk + physical memory + device paths

Very High

NetInfo

Blocked

Needs raw network protocols (SNP, IP4, ICMP)

Very High

httpfs

Component

Status

Blocker

Effort

CmdServe

Ready

Already uses AXL HTTP server, minor cleanup

Low

CmdMount

Blocked

Protocol locate + device paths + driver loading

High

WebDavFsDxe driver

Blocked

Protocol install, FILE_PROTOCOL implementation

Very High

FileTransferLib

Blocked

SimpleFileSystem protocol discovery

High

NetworkLib

Blocked

SNP, DHCP4, IP4Config2, ServiceBinding

Very High

JsonLib

Ready

Minimal UEFI dependency (string ops only)

Low

SoftBMC

Module

Status

Blocker

Effort

Core logic (JSON, crypto, strings)

Ready

None

Low

HTTP/WebSocket server

Ready

Event model needs axl_loop rework

Medium

TCP utilities

Ready

axl_tcp covers this

Low

TLS/mbedtls

Ready

Works with axl_tcp

Low

Graphics/Splash

Ready

axl_gfx covers GOP

Low

RemoteKVM (VNC)

Mostly ready

Needs spinlock rework

Medium

Config

Blocked

UEFI variable access

Medium

Network init

Blocked

DHCP, SimpleNetwork protocols

Very High

File operations

Ready

axl_io covers this

Low

SMBIOS

Partial

Read works, protocol lookup missing

Low

Alert (SMTP, Webhook)

Ready

TCP/HTTP based

Low

Alert (SNMP, Syslog)

Blocked

Needs UDP

Medium

HwInfo (PCI, ACPI, USB, TPM)

Blocked

Protocol enumeration

High

UefiSetup (HII)

Not portable

Replace with web-based config

N/A

VirtualMedia

Blocked

RAM disk protocol

High

OsBoot

Not portable

Firmware-specific

N/A

UDP utilities

Blocked

No axl_udp API

Medium

Console wrapper

Not portable

Simplify for serial

N/A

Shell integration

Not portable

Remove or externalize

N/A



Projects That Will Never Fully Port

Some features are inherently UEFI-specific and can’t be abstracted:

  • HII Setup Browser (SoftBMC) — replace with web-based config

  • OS Boot management (SoftBMC) — firmware-specific

  • PCI/ACPI/USB/TPM hardware enumeration — protocol-specific

  • UEFI Shell dynamic commands (SoftBMC) — Shell-specific

  • Console Extended Input (SoftBMC) — replace with serial/TTY

These should be replaced with alternative implementations rather than abstracted.


ipmitool (uefi-ipmitool)

Structure

  • Application (IpmiTool/) — Shell app with subcommands (mc, chassis, raw, sdr, sensor, fru, sel, lan, sol, user, probe)

  • IpmiCommandLib — IPMI command framing and response parsing

  • IpmiTransportLib — Low-level transport (KCS via I/O ports, SSIF via SMBus/I2C)

Dependencies

Component

Status

Blocker

IpmiTool.c (entry)

Ready

None — AXL_APP

All Cmd*.c (subcommands)

Ready

Just Print to printf

IpmiCommandLib

Ready

Just memory/string ops

IpmiFormat.c

Ready

Just AsciiSPrint to snprintf

IpmiKcs.c (KCS transport)

Blocked

Needs I/O port access

IpmiSsif.c (SSIF transport)

Blocked

Needs I2C/SMBus protocol

IpmiDetect.c (BMC detection)

Partial

SMBIOS works, SMBus probe blocked

Unique missing APIs

Missing

Used in

What it does

I/O port access (IoRead8/IoWrite8)

IpmiKcs.c

Direct x86 in/out instructions for KCS

I2C/SMBus protocol

IpmiSsif.c, CmdProbe.c

SMBus communication with BMC

Strategy: AxlIpmi module

Rather than porting ipmitool’s transport layer as-is, AXL will absorb IPMI as a first-class module (like SMBIOS). The consumer never sees KCS registers or SMBus framing — just typed IPMI commands.

See “BMC Access Modules” section below for the full API design.


BMC Access Modules (Planned)

AXL will provide two complementary modules for BMC access:

AxlIpmi — Legacy BMC access (IPMI over KCS/SSIF)

Header: axl/axl-ipmi.h Source: src/ipmi/axl-ipmi.c, axl-ipmi-kcs.c, axl-ipmi-ssif.c

Hides all transport complexity. BMC detection via SMBIOS Type 38 (IPMI Device Information) auto-selects KCS vs SSIF and discovers the base address. The consumer never knows which transport is used.

// Low-level: send raw IPMI command
int axl_ipmi_raw(
    uint8_t      netfn,       // network function
    uint8_t      cmd,         // command code
    const void  *req,         // request data (NULL OK)
    size_t       req_len,
    void        *resp,        // response buffer
    size_t      *resp_len     // [in/out] buffer size / actual size
);

// High-level convenience functions
int axl_ipmi_get_device_id(AxlIpmiDeviceId *info);
int axl_ipmi_get_sensor_reading(uint8_t sensor_num,
                                 AxlIpmiSensorReading *reading);
int axl_ipmi_get_sdr_entry(uint16_t record_id, void *buf,
                            size_t *len, uint16_t *next_id);
int axl_ipmi_get_sel_entry(uint16_t record_id, void *buf,
                            size_t *len, uint16_t *next_id);
int axl_ipmi_chassis_status(AxlIpmiChassisStatus *status);
int axl_ipmi_chassis_control(uint8_t action);
int axl_ipmi_get_fru_data(uint8_t fru_id, uint16_t offset,
                           void *buf, size_t len);

Transport internals (hidden from consumer):

  • KCS — I/O port based (x86: in/out instructions at BMC base address, typically 0xCA2). Requires new backend function axl_backend_io_read8/write8. ARM uses MMIO instead.

  • SSIF — SMBus/I2C based. Requires I2C protocol types in uefi-manifest.json and a backend wrapper.

  • Auto-detection — SMBIOS Type 38 record specifies interface type (KCS=1, SSIF=4) and base address. axl_smbios_find(38) already works.

Backend additions needed:

// I/O port access (x86 only, MMIO on ARM)
uint8_t  axl_backend_io_read8(uint16_t port);
void     axl_backend_io_write8(uint16_t port, uint8_t value);

// I2C/SMBus (for SSIF transport)
int      axl_backend_smbus_read_block(uint8_t addr, uint8_t cmd,
                                       void *buf, size_t *len);
int      axl_backend_smbus_write_block(uint8_t addr, uint8_t cmd,
                                        const void *buf, size_t len);

ipmitool becomes a thin CLI wrapper:

#include <axl.h>

int main(int argc, char **argv) {
    AxlArgs *args = axl_args_parse(argc, argv, opts);
    const char *subcmd = axl_args_pos(args, 0);

    if (axl_strcmp(subcmd, "mc") == 0) {
        AxlIpmiDeviceId id;
        axl_ipmi_get_device_id(&id);
        axl_printf("Device ID: 0x%02x, FW: %d.%02d\n",
                   id.device_id, id.fw_major, id.fw_minor);
    } else if (axl_strcmp(subcmd, "sensor") == 0) {
        // iterate SDR, read each sensor...
    }
    // ...
}

AxlRedfish — Modern BMC access (Redfish over HTTPS/JSON)

Header: axl/axl-redfish.h Source: src/redfish/axl-redfish.c

Built on top of AXL’s existing HTTP client + JSON parser. Adds Redfish session management (X-Auth-Token), standard URI patterns, and typed result structures.

// Session management
AxlRedfishSession *axl_redfish_connect(
    const char *host,      // BMC hostname or IP
    const char *username,
    const char *password
);
void axl_redfish_close(AxlRedfishSession *session);

// Generic resource access (any Redfish URI)
int axl_redfish_get(AxlRedfishSession *s, const char *uri,
                     AxlJsonDoc *doc);
int axl_redfish_patch(AxlRedfishSession *s, const char *uri,
                       const char *json_body);
int axl_redfish_post(AxlRedfishSession *s, const char *uri,
                      const char *json_body,
                      char *location, size_t loc_size);
int axl_redfish_delete(AxlRedfishSession *s, const char *uri);

// High-level convenience (typed results)
int axl_redfish_get_system_info(AxlRedfishSession *s,
                                 AxlRedfishSystemInfo *info);
int axl_redfish_get_thermal(AxlRedfishSession *s,
                             AxlRedfishThermal *thermal);
int axl_redfish_get_power(AxlRedfishSession *s,
                           AxlRedfishPower *power);
int axl_redfish_get_bmc_info(AxlRedfishSession *s,
                              AxlRedfishManagerInfo *info);
int axl_redfish_chassis_reset(AxlRedfishSession *s,
                               const char *reset_type);
int axl_redfish_get_event_log(AxlRedfishSession *s,
                               AxlRedfishLogEntry *entries,
                               size_t *count);

No new backend support needed — Redfish is pure HTTP+JSON+TLS, all of which AXL already provides:

  • axl_http_client_new / axl_http_request — HTTP transport

  • axl_json_parse / axl_json_get_string — JSON parsing

  • TLS via mbedtls (SoftBMC already integrates this)

Redfish standard URIs:

URI

What it returns

/redfish/v1/

Service root

/redfish/v1/Systems/1

System info (model, serial, power state)

/redfish/v1/Chassis/1/Thermal

Temperatures, fans

/redfish/v1/Chassis/1/Power

Power supplies, consumption

/redfish/v1/Managers/1

BMC info (firmware version, network)

/redfish/v1/Systems/1/LogServices/SEL/Entries

Event log

/redfish/v1/SessionService/Sessions

Session management

SoftBMC integration: SoftBMC currently implements the Redfish server side. AxlRedfish provides the client side — useful for tools that query a real or simulated BMC.

Comparison

Feature

AxlIpmi

AxlRedfish

Protocol

Binary over KCS/SSIF

HTTP+JSON over TCP/TLS

Latency

Microseconds (local bus)

Milliseconds (network)

Scope

Local BMC only

Local or remote BMC

Features

Sensors, SEL, FRU, chassis

Full system management

Complexity

Hardware transport

HTTP client

New code

Transport layer + backend

Thin wrapper over existing HTTP+JSON

TLS needed

No

Yes (for production)


Protocol Abstraction Strategy

The Problem

In UEFI, almost everything is accessed through protocols. Want to read a file? Locate EFI_SHELL_PROTOCOL. Want to draw pixels? Locate EFI_GRAPHICS_OUTPUT_PROTOCOL. Want network? Locate EFI_TCP4_SERVICE_BINDING_PROTOCOL, create a child handle, configure it, connect…

This is the biggest barrier to writing UEFI apps — consumers shouldn’t need to know about GUIDs, handles, LocateProtocol, or service binding.

AXL’s Approach: Hide Protocols Behind Purpose-Built APIs

AXL already does this for several protocols:

What the consumer writes

What AXL does behind the scenes

axl_fopen("file.txt", "r")

Locates Shell protocol, calls OpenFileByName

axl_gfx_fill_rect(...)

Locates GOP protocol, calls Blt

axl_tcp_connect(host, port, &sock)

Locates TCP4 ServiceBinding, creates child, configures, connects

axl_smbios_find(type)

Locates SMBIOS protocol (or walks config table), iterates entries

axl_getenv("PATH")

Locates Shell protocol, calls GetEnv, converts UCS-2 to UTF-8

axl_printf("hello")

Locates ConOut, converts UTF-8 to UCS-2, calls OutputString

The pattern: the backend locates the protocol lazily on first use, caches it in a static variable, and the consumer never sees a GUID, handle, or EFI_STATUS.

Three Categories of Protocol Usage

Category 1: “I need a specific service”

Examples: read a file, draw pixels, get an env var, query SMBIOS.

Strategy: Purpose-built AXL API per service. The consumer calls axl_gfx_* or axl_fopen and the protocol is completely invisible. This is what AXL does today. Each new service (UEFI variables, UDP sockets, etc.) gets its own clean API.

// Consumer code — no protocols visible:
char *val = axl_getenv("PATH");
AxlGfxInfo info; axl_gfx_get_info(&info);
int rc = axl_uefi_var_get("SecureBoot", &guid, buf, &size);

Category 2: “I need to enumerate handles”

Examples: list all mounted filesystems, find all NICs, discover available block devices.

Strategy: Higher-level query APIs that return meaningful results, not raw handles. Instead of exposing LocateHandleBuffer (which leaks the handle/protocol model), provide task-specific queries:

// Instead of:
//   gBS->LocateHandleBuffer(&gEfiSimpleFileSystemProtocolGuid, ...)
//   for each handle: gBS->OpenProtocol(...) → get volume label
//
// Provide:
size_t count;
AxlVolume *vols = axl_volume_list(&count);
for (size_t i = 0; i < count; i++) {
    printf("  %s: %s (%llu bytes)\n",
           vols[i].name, vols[i].label, vols[i].size);
}
axl_volume_list_free(vols);

The consumer gets names, paths, and sizes — not handles and GUIDs.

Category 3: “I AM a protocol provider” (drivers)

Examples: httpfs WebDavFsDxe installs EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.

Strategy: AXL provides types, helpers, and wrappers — but the driver model is inherently visible. A driver that installs a protocol IS the protocol; there’s no way to fully hide the UEFI driver model from its author. But AXL can:

  • Provide all protocol type definitions (via uefi-manifest.json)

  • Provide install/uninstall wrappers:

    axl_protocol_install(&handle, &my_guid, &my_protocol_vtable);
    axl_protocol_uninstall(handle, &my_guid, &my_protocol_vtable);
    
  • Provide helper macros for the boilerplate (signature validation, container-of derivation)

  • Provide the CRT0 for driver entry points (axl-cc --type driver)

The driver author still understands the UEFI driver binding model, but AXL handles the mechanical parts.

Design Principle

For applications: protocol access is invisible. AXL provides purpose-built APIs. Consumers never see GUIDs, handles, or LocateProtocol.

For drivers: AXL provides the types and helpers, but the driver model is inherently visible. The driver author writes protocol implementation functions; AXL handles installation and boilerplate.


How to Port an EDK2 App to axl-cc

Step 1: Replace the entry point

EDK2:

EFI_STATUS EFIAPI MyAppMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *ST) {
    // Manual ShellParameters protocol access for argc/argv
    gBS->OpenProtocol(ImageHandle, &gEfiShellParametersProtocolGuid, ...);
    ...
}

AXL:

#include <axl.h>

int main(int argc, char **argv) {
    // argc/argv provided automatically by AXL_APP macro
    ...
}

Step 2: Replace Print with axl_printf

EDK2: Print(L"%s: %d bytes\n", FileName, Size);

AXL: axl_printf("%s: %d bytes\n", filename, size);

Note: AXL uses UTF-8 everywhere. No L"" wide strings, no CHAR16.

Step 3: Replace memory functions

EDK2

AXL

AllocatePool(size)

axl_malloc(size)

AllocateZeroPool(size)

axl_calloc(1, size)

FreePool(ptr)

axl_free(ptr)

CopyMem(dst, src, n)

axl_memcpy(dst, src, n)

SetMem(dst, n, val)

axl_memset(dst, val, n) (note: arg order differs)

ZeroMem(dst, n)

axl_memset(dst, 0, n)

Step 4: Replace string functions

EDK2

AXL / standard C

AsciiStrLen(s)

axl_strlen(s)

AsciiStrCmp(a, b)

axl_strcmp(a, b)

AsciiStrCpyS(dst, sz, src)

axl_strlcpy(dst, src, sz)

AsciiSPrint(buf, sz, fmt, ...)

axl_snprintf(buf, sz, fmt, ...)

AsciiStrDecimalToUint64(s)

axl_strtou64(s)

StrLen(s) (wide)

Convert to UTF-8 first, then axl_strlen

StrCmp(a, b) (wide)

Convert to UTF-8 first, then axl_strcmp

Step 5: Replace file I/O

EDK2

AXL

ShellOpenFileByName(path, &h, mode, 0)

axl_fopen(utf8_path, "r")

ShellReadFile(h, &size, buf)

axl_fread(buf, 1, size, stream)

ShellWriteFile(h, &size, buf)

axl_fwrite(buf, 1, size, stream)

ShellCloseFile(&h)

axl_fclose(stream)

ShellGetFileInfo(h)

axl_file_info(path, &info)

ShellSetFilePosition(h, pos)

axl_fseek(stream, pos, AXL_SEEK_SET)

ShellIsDirectory(path)

axl_file_is_dir(path)

FileHandleFindFirstFile(h, &entry)

axl_dir_open(path) + axl_dir_read(dir, &entry)

Step 6: Replace types

EDK2

Standard C

VOID

void

BOOLEAN

bool

UINTN

size_t

UINT8/16/32/64

uint8_t/16/32/64_t

CHAR8

char

CHAR16

unsigned short (or convert to UTF-8)

EFI_STATUS

int (0 = success, -1 = error)

STATIC

static

IN/OUT/OPTIONAL

Remove (documentation only)

EFIAPI

Remove (AXL handles calling convention)

Step 7: Build with axl-cc

# Install SDK
./scripts/install.sh --prefix /opt/axl-sdk

# Build
/opt/axl-sdk/bin/axl-cc myapp.c -o myapp.efi

# Test in QEMU
./scripts/run-qemu.sh myapp.efi

Reference: Hexdump port

See uefi-devkit/DevKitPkg/Hexdump/Hexdump.c for a complete example of a ported application. Original: 202 lines with 8 EDK2 headers. Ported: 158 lines with #include <axl.h>. Binary: 19KB.