Library Design

AXL — AximCode Library for UEFI

A GLib-inspired C library that makes UEFI application development look and feel like writing Linux C code. Applications use snake_case axl_ functions and never touch EDK2 headers directly.

Name: AXL = AximCode Library. Pronounced “axle.”

Related: UdkLib-Design.md covers the current networking stack (UdkLib Phases 1-10). AXL is the next evolution — a rename and expansion of UdkLib into a full platform abstraction layer. The existing UdkLib modules (Log, Data, Util, Loop, Task, Net) will be renamed to AXL and gain the POSIX-style API described here.

Vision

#include <axl.h>

int axl_main(int argc, char **argv)
{
    axl_printf("Hello from %s\n", argv[0]);

    AxlStream *f = axl_fopen("fs0:/data.txt", "r");
    char *line = axl_readline(f);
    axl_printf("first line: %s\n", line);
    axl_free(line);
    axl_fclose(f);

    return 0;
}

No gBS, no Print(), no AllocatePool(), no CHAR16, no PascalCase, no wide strings. AXL is UTF-8 everywhere, like GLib. EDK2 is the backend.

API Style: GLib for UEFI

AXL is a GLib-style library. All new public API uses the same naming pattern as GLib: types are AxlPascalCase (like GHashTable), functions are axl_snake_case (like g_hash_table_new). This is the only API that applications use.

#include <axl.h>

AxlHashTable *h = axl_hash_table_new_str();
axl_hash_table_insert(h, "key", value);
char *v = axl_hash_table_lookup(h, "key");
axl_hash_table_free(h);

All new code — library modules, application code, tests — must use this style. No new PascalCase EDK2-style functions.

EDK2-style layer (legacy, internal only)

Library/AxlLib.h contains the original EDK2-style internals (PascalCase, UEFI types). This layer is frozen — no new functions are added to it. It exists only because the internal implementation hasn’t been migrated yet (Phase S5). Applications never include it unless they need direct UEFI protocol access (SMBIOS, RAM disk).

What AXL Provides

Already implemented (EDK2 internals, POSIX wrappers pending Phase S5)

Category

Target API (axl.h)

GLib equivalent

Hash table

axl_hash_table_new, axl_hash_table_insert, axl_hash_table_lookup

g_hash_table_new

Dynamic array

axl_array_new, axl_array_append, axl_array_get

g_array_new

Strings

axl_strdup, axl_strsplit, axl_strjoin

g_strdup, g_strsplit

JSON

axl_json_parse, axl_json_build

json-glib

Event loop

axl_loop_new, axl_loop_run, axl_loop_quit

g_main_loop_new

Arg parsing

axl_args_parse, axl_args_flag

g_option_context_new

Logging

axl_log, axl_debug, axl_warning

g_log, g_debug

File I/O

axl_file_read_all, axl_file_write_all

g_file_get_contents

Task pool

axl_task_pool_new, axl_task_submit

g_thread_pool_new

TCP sockets

axl_tcp_connect, axl_tcp_listen

g_socket_new

HTTP server

axl_http_server_new, axl_http_server_route

libsoup

HTTP client

axl_http_get, axl_http_post

libsoup

URL parsing

axl_url_parse

g_uri_parse

These modules are fully working internally using EDK2-style names (AxlHashNew, AxlArrayAppend, etc.). Phase S5 wraps them with the axl_ public API shown above.

New (this document)

Category

POSIX-style (axl.h)

Purpose

Memory

axl_malloc, axl_free, axl_realloc

Allocation with leak tracking

String builder

axl_string_*

Mutable auto-growing strings

I/O streams

axl_fopen, axl_fclose, axl_fread, axl_fwrite

Stream abstraction

Printf

axl_printf, axl_fprintf, axl_asprintf

Console and stream output

Conversion

axl_utf8_to_ucs2, axl_base64_encode

Encoding utilities

Phases

Phase

Module

Scope

Depends On

R

Rename

UdkLib -> AXL (all symbols, files, packages)

None

S1

axl_mem

axl_malloc/free/realloc, leak tracking

Rename

S2

axl_string

Mutable strings, format, convert, base64

S1

S3

axl_io

Streams, printf, readline

S1, S2

S4

AXL_APP

Entry point macro, int main(argc, argv)

S1-S3

M1

Migrate AxlLog

GLib-style logging API

S1-S3

M2

Migrate AxlData

Hash, Array, String, JSON

M1

M3

Migrate AxlUtil

File, Path, Args, HexDump, Time

M1, M2

M4

Migrate AxlLoop

Event loop, timers

M1

M5

Migrate AxlTask

Worker pool, arena

M1, M4

M6

Migrate AxlNet

TCP, HTTP, URL

M1-M5


Phase R: Rename UdkLib to AXL

Global rename across all repositories. Mechanical, no logic changes.

Symbol renames

Old

New

UDK_ prefix (types)

AXL_

Udk prefix (functions)

Axl

UdkLib (package)

AxlLib

UdkLib.h

AxlLib.h

UdkLib.dec

AxlLib.dec

UdkNet.h

AxlNet.h

UdkSmbios.h

AxlSmbios.h

UDK_LOG_DOMAIN

AXL_LOG_DOMAIN

UdkLogLib, UdkDataLib, etc.

AxlLogLib, AxlDataLib, etc.

Directory renames

Old

New

UdkLib/

AxlLib/

UdkLib/Log/

AxlLib/Log/

UdkLib/Data/

AxlLib/Data/

UdkLib/Util/

AxlLib/Util/

UdkLib/Loop/

AxlLib/Loop/

UdkLib/Task/

AxlLib/Task/

UdkLib/Net/

AxlLib/Net/

Affected repositories

  • uefi-devkit — AxlLib source, DevKitPkg consumers, docs

  • httpfs — HttpFsPkg.dsc references, WebDavFsDxe consumer

  • softbmc — SoftBmcPkg.dsc references, all consumers

  • uefi-ipmitool — IpmiToolPkg.dsc references

Approach

  1. Rename directory UdkLib/ -> AxlLib/

  2. Sed all files: UDK_ -> AXL_, Udk -> Axl, UdkLib -> AxlLib

  3. Rename header files

  4. Update all .dsc/.inf/.dec files

  5. Build + test all projects

  6. Update external repos (httpfs, softbmc, ipmitool)


Phase S1: axl_mem

POSIX-style allocation wrappers with dmalloc-inspired debug features. Internal EDK2 code continues to use AllocatePool/FreePool directly until Phase S5 migration.

API (axl.h)

void *axl_malloc(size_t size);
void *axl_calloc(size_t count, size_t size);
void *axl_realloc(void *ptr, size_t size);
void  axl_free(void *ptr);
char *axl_strdup(const char *s);
void *axl_memdup(const void *src, size_t size);

#define axl_new(Type)              ((Type *)axl_calloc(1, sizeof(Type)))
#define axl_new_array(Type, Count) ((Type *)axl_calloc((Count), sizeof(Type)))

Debug features (dmalloc-inspired, DEBUG builds only)

All debug features compile in via AXL_MEM_DEBUG (set automatically in DEBUG builds). RELEASE builds have only the size header for realloc.

Feature

Pattern

Purpose

Fence-post guards

0xC0C0AB1B head/mid, 0xFACADE69 tail

Detect buffer underflow/overflow

Alloc fill

0xDA

Expose use-before-init

Free fill

0xDF

Expose use-after-free

File/line tracking

__FILE__, __LINE__ via macros

Pinpoint leak and corruption sources

Leak report

axl_mem_dump_leaks()

Log all unfreed with file:line

Fence validation

axl_mem_check(ptr)

Validate a pointer’s fence-posts on demand

Stats

axl_mem_get_stats()

Live count/bytes + lifetime totals

The public API functions are macros that inject __FILE__/__LINE__ and call _impl functions internally.

The size tracking trick

POSIX realloc(ptr, new_size) doesn’t take old size. EDK2’s ReallocatePool(old_size, new_size, ptr) requires it. Solution:

[hidden header: UINTN alloc_size][user data...]
                                  ^-- returned pointer

axl_malloc(n) allocates n + header_size, stores n in the header, returns pointer past it. axl_realloc reads the header to get old size, allocates new, copies, frees old. axl_free backs up to the header before calling FreePool.

Memory layout (DEBUG)

[UINTN: fence_head 0xC0C0AB1B]
[UINTN: alloc_size            ]
[CHAR8*: file pointer         ]
[UINTN: line number           ]
[UINTN: fence_mid  0xC0C0AB1B]
[user data ... padded to UINTN]
[UINTN: fence_tail 0xFACADE69]

Memory layout (RELEASE)

[UINTN: alloc_size            ]
[user data ......................]

No EDK2-style wrappers

There is no AxlAlloc/AxlFree layer. Internal EDK2-style code uses AllocatePool/AllocateZeroPool/FreePool directly. Phase S5 migrates internals straight to axl_malloc/axl_free. UEFI protocol buffers that are passed to/from UEFI APIs stay as raw AllocatePool since UEFI may free them.


Phase S2: axl_string

Mutable auto-growing string buffers. Works with char * (UTF-8), consistent with the rest of the AXL API.

POSIX-style API (axl.h)

typedef struct AxlString AxlStrBuf;

AxlString *axl_string_new(void);
AxlString *axl_string_new_size(size_t reserve);

void        axl_string_append(AxlString *b, const char *s);
void        axl_string_append_n(AxlString *b, const char *data, size_t len);
void        axl_string_append_printf(AxlString *b, const char *fmt, ...);
void        axl_string_putc(AxlString *b, char c);

const char *axl_string_str(AxlString *b);
size_t      axl_string_len(AxlString *b);
char       *axl_string_steal(AxlString *b);  // caller owns string

void        axl_string_clear(AxlString *b);  // reset, keep alloc
void        axl_string_free(AxlString *b);

// Convenience: format into a new string (like asprintf)
char *axl_asprintf(const char *fmt, ...);

Conversion utilities

// UTF-8 <-> UCS-2 conversion (internal use, exposed for UEFI protocol interop)
// Newly allocated, caller frees.
unsigned short *axl_utf8_to_ucs2(const char *s);
char           *axl_ucs2_to_utf8(const unsigned short *s);

// Base64
char *axl_base64_encode(const void *data, size_t size);
int   axl_base64_decode(const char *b64, void **data, size_t *size);

// Number parsing (handles 0x prefix for hex)
uint64_t axl_strtou64(const char *s);

Phase S3: axl_io

Stream-based I/O. Every target (console, file, buffer) is an axl_stream with read/write/printf/close.

POSIX-style API (axl.h)

typedef struct AxlStream AxlStream;

// Standard streams (initialized at startup)
extern AxlStream *axl_stdout;
extern AxlStream *axl_stderr;
extern AxlStream *axl_stdin;

// File streams
AxlStream *axl_fopen(const char *path, const char *mode);  // "r", "w", "a"
void        axl_fclose(AxlStream *s);

// Buffer streams (in-memory, auto-growing)
AxlStream *axl_bufopen(void);
const void *axl_bufdata(AxlStream *s, size_t *size);
void       *axl_bufsteal(AxlStream *s, size_t *size);

// Read/Write
size_t axl_fread(void *buf, size_t size, size_t count, AxlStream *s);
size_t axl_fwrite(const void *buf, size_t size, size_t count, AxlStream *s);
char  *axl_readline(AxlStream *s);  // caller frees, NULL at EOF

// Printf family
int axl_printf(const char *fmt, ...);            // -> stdout
int axl_eprintf(const char *fmt, ...);           // -> stderr
int axl_fprintf(AxlStream *s, const char *fmt, ...);  // -> any stream

Format specifiers

AXL has its own printf engine (axl_vformat) using standard C va_arg. Format specifiers follow standard C printf conventions:

Specifier

Type

%s

char * (UTF-8 string)

%d, %i

int (signed decimal)

%u

unsigned int

%x, %X

unsigned int (hex)

%ld, %lu, %lx

long / unsigned long

%lld, %llu, %llx

long long / unsigned long long

%zu

size_t

%c

char

%p

void * (pointer)

%%

literal %

Width (%10d), zero-padding (%08x), left-align (%-20s), precision (%.5s), and * width/precision from args are supported.

Use __attribute__((format(printf, N, M))) for compile-time checking.

Stream internals

typedef size_t (*AxlWriteFn)(void *ctx, const void *data, size_t size);
typedef size_t (*AxlReadFn)(void *ctx, void *buf, size_t size);
typedef void   (*AxlCloseFn)(void *ctx);

struct AxlStream {
    void        *ctx;
    AxlWriteFn  write;
    AxlReadFn   read;
    AxlCloseFn  close;
};

Extensible: serial port, network socket, UEFI variable backends can be added by providing the vtable functions.


Phase S4: axl.h and axl_main

The top-level header and entry point that ties everything together.

axl.h

Single include that pulls in the full POSIX-style API:

#ifndef AXL_H_
#define AXL_H_

#include <stddef.h>       // size_t
#include <stdint.h>       // uint64_t, etc.
#include <stdbool.h>      // bool

// Memory
void *axl_malloc(size_t size);
void *axl_calloc(size_t count, size_t size);
void *axl_realloc(void *ptr, size_t size);
void  axl_free(void *ptr);
char *axl_strdup(const char *s);
void *axl_memdup(const void *src, size_t size);
#define axl_new(Type)              ((Type *)axl_calloc(1, sizeof(Type)))
#define axl_new_array(Type, Count) ((Type *)axl_calloc((Count), sizeof(Type)))

// I/O
typedef struct AxlStream AxlStream;
extern AxlStream *axl_stdout;
extern AxlStream *axl_stderr;
extern AxlStream *axl_stdin;
int   axl_printf(const char *fmt, ...);
int   axl_fprintf(AxlStream *s, const char *fmt, ...);
char *axl_asprintf(const char *fmt, ...);
// ... etc.

// Data structures — GLib-style hash table (see GHashTable docs)
typedef struct AxlHashTable AxlHashTable;
AxlHashTable *axl_hash_table_new(void);                         // string keys, copied
AxlHashTable *axl_hash_table_new_full(AxlHashFunc, AxlEqualFunc,
                                      AxlDestroyNotify key_free,
                                      AxlDestroyNotify val_free); // generic keys
int       axl_hash_table_insert(AxlHashTable *h, const void *key, void *val);
int       axl_hash_table_replace(AxlHashTable *h, const void *key, void *val);
void     *axl_hash_table_lookup(AxlHashTable *h, const void *key);
bool      axl_hash_table_contains(AxlHashTable *h, const void *key);
bool      axl_hash_table_remove(AxlHashTable *h, const void *key);
bool      axl_hash_table_steal(AxlHashTable *h, const void *key);
size_t    axl_hash_table_foreach_remove(AxlHashTable *h, ...);
// Iterator: AxlHashTableIter with iter_init, iter_next, iter_remove

#endif

axl_main entry point

// In axl.h
#define AXL_APP(main_func)                                    \
  EFI_STATUS EFIAPI _AxlEntry(                                \
    EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {  \
    _axl_init(ImageHandle, SystemTable);                      \
    int argc; char **argv;                                    \
    _axl_get_args(&argc, &argv);                              \
    int rc = main_func(argc, argv);                           \
    _axl_cleanup();                                           \
    return (rc == 0) ? EFI_SUCCESS : EFI_ABORTED;             \
  }

// App code:
#include <axl.h>

int my_main(int argc, char **argv)
{
    axl_printf("Hello %s\n", argv[1]);
    return 0;
}

AXL_APP(my_main)

The AXL_APP macro:

  1. Defines the real UEFI entry point (PascalCase, hidden)

  2. Initializes AXL (stdout/stderr/stdin streams, memory subsystem)

  3. Converts UEFI CHAR16 **Argv to C char **argv

  4. Calls the user’s main function with C-style argc/argv

  5. Cleans up and returns EFI_STATUS

Apps never see EFI_HANDLE, EFI_SYSTEM_TABLE, or EFIAPI.


Phase S5: Migration

Rename all UdkLib internals to AXL and rewrite apps to use axl.h.

Internal rename

All UdkLib source files: UDK_ -> AXL_, Udk -> Axl. The EDK2-style API (Library/AxlLib.h) is the internal layer. The POSIX-style API (axl.h) wraps it.

App migration example

Before (current):

#include "SysInfo.h"  // pulls in Uefi.h, UefiLib.h, ShellLib.h, ...

BOOLEAN gVerbose = FALSE;
STATIC CONST UDK_OPT_DEF mOpts[] = { ... };

EFI_STATUS EFIAPI SysInfoMain(EFI_HANDLE Img, EFI_SYSTEM_TABLE *ST)
{
    EFI_SHELL_PARAMETERS_PROTOCOL *P;
    gBS->OpenProtocol(Img, &gEfiShellParametersProtocolGuid, ...);
    UDK_ARGS *Args;
    UdkArgsParse(P->Argc, P->Argv, mOpts, &Args);
    if (UdkArgsFlag(Args, 'v')) gVerbose = TRUE;
    Print(L"CPU: %s\n", CpuName);
    UdkArgsFree(Args);
    return EFI_SUCCESS;
}

After:

#include <axl.h>

static bool verbose = false;
static AxlOptopts[] = {
    { 'v', NULL,      AXL_OPT_FLAG, NULL, "Verbose output" },
    { 'h', "--help",  AXL_OPT_FLAG, NULL, "Show help" },
    { 0 }
};

int sysinfo_main(int argc, char **argv)
{
    AxlArgs *args = axl_args_parse(argc, argv, opts);
    if (axl_args_flag(args, 'h')) { axl_args_usage("SysInfo", "[section]", opts); }
    verbose = axl_args_flag(args, 'v');
    axl_printf("CPU: %s\n", cpu_name);
    axl_args_free(args);
    return 0;
}

AXL_APP(sysinfo_main)

Migration Phases (M1–M6)

Migrate each internal EDK2-style module to GLib-style. For each module the work is:

  1. Create axl/<module>.h header with GLib-style declarations

  2. Rename functions: AxlFooaxl_foo

  3. Rename types: keep AxlPascalCase (already correct)

  4. Switch allocations: AllocatePoolaxl_malloc, FreePoolaxl_free

  5. Switch logging: axl_error/Printaxl_printerr

  6. Switch strings: CHAR8 *char *, UINTNsize_t

  7. Rename source files: AxlFoo.caxl-foo.c

  8. Update tests to use new API names

  9. Remove old declarations from Library/AxlLib.h

  10. Update consumer projects (uefi-devkit, httpfs, uefi-ipmitool, softbmc)

Backwards compatibility during migration

Each phase provides a compatibility header Library/AxlLib.h with #define macros mapping old names to new:

/* Temporary compat — remove after all consumers are updated */
#define AxlHashNew()          axl_hash_table_new_str()
#define AxlHashFree(h)        axl_hash_table_free(h)
#define AxlHashSet(h, k, v)   axl_hash_table_insert((h), (k), (v))

This lets consumer projects migrate incrementally rather than requiring a flag-day update across all repos. Compat macros are removed once all consumers have switched.

Consumer projects to update

Project

Repo

Modules used

Notes

uefi-devkit

aximcode/uefi-devkit

Log, Data, Util, Loop, Task, Net

Heaviest consumer — all modules

httpfs

aximcode/httpfs

Log, Data, Loop, Net

WebDavFsDxe uses Hash + HttpClient; HttpFS uses Loop + HttpServer

uefi-ipmitool

aximcode/uefi-ipmitool

(none yet)

Does not currently use AxlLib

softbmc

aximcode/softbmc

Log, Data, Util, Loop, Net

Not yet migrated

For each migration phase, the “Consumer project changes” subsection lists exactly what each project needs. All projects need AxlFormatLib added to their DSC (done in M1).

M1: Migrate AxlLog ✓

Logging is the foundation — every other module depends on it.

Old API (AxlLib.h):

AxlLogFull(level, domain, func, line, fmt, ...);
AxlLogSetLevel(level);
AxlLogAddHandler(handler, data);

New API (axl/axl-log.h):

axl_log_set_level(level);
axl_log_add_handler(handler, data);
/* Convenience macros unchanged: axl_error, axl_info, etc.
   — these are macros, not functions, and stay uppercase
   because they inject __func__/__LINE__ */

Implementation notes:

  • AxlFormatLib extracted as zero-dependency library (breaks Log↔Data cycle)

  • Ring buffer and file handler keep AllocatePool/FreePool (breaks Log↔Mem cycle)

  • File handler keeps ShellLib (breaks Log↔IO cycle)

  • Format engine switched from PrintLib (%a) to axl_vformat (%s)

  • __attribute__((format(printf,...))) on axl_log_full — catches mismatches at compile time

  • AxlLogFileAttach(CHAR16*) replaced by axl_log_file_attach(char*) — no compat macro (signature changed, callers must update)

Consumer project changes for M1:

  • All projects: add AxlFormatLib to .dsc [LibraryClasses]: AxlFormatLib|src/format/AxlFormat.inf

  • All projects using axl_error/axl_info with %a format: change to %s

  • All projects using %u/%d/%x with UINTN/INTN: change to %llu/%lld/%llx

  • All projects calling AxlLogFileAttach(L"..."): change to axl_log_file_attach("...")

  • All projects defining AXL_LOG_HANDLER callbacks: update signature from VOID EFIAPI (UINTN, CONST CHAR8*, CONST CHAR8*, VOID*) to void (int, const char*, const char*, void*)

  • httpfs: no code changes needed (does not call log macros with format args or define handler callbacks). DSC needs AxlFormatLib line added.

  • uefi-ipmitool: no changes needed (does not use AxlLib)

M2: Migrate AxlData ✓

Hash table, dynamic array, string utilities, JSON.

Old: AxlHashNew, AxlArrayAppend, AxlStrDup, AxlJsonParse New: axl_hash_table_new, axl_array_append, axl_strdup (already exists), axl_json_parse

Consumer project changes for M2:

  • httpfs (WebDavFsDxe): uses AxlHashNew, AxlHashSet, AxlHashFree, AXL_HASH_TABLE. Compat macros cover function renames. Type rename AXL_HASH_TABLEAxlHashTable needs a compat #define.

  • uefi-devkit: uses hash, array, string, JSON extensively. Compat macros cover most usage; manual migration of type names may be needed.

M3: Migrate AxlUtil

File I/O, path utils, args, hex dump, time.

Old: AxlFileReadAll, AxlPathBasename, AxlArgsParse New: axl_file_read_all (→ merge with axl_file_get_contents), axl_path_get_basename, axl_args_parse

Consumer project changes for M3:

  • AxlFile paths switch from CHAR16* to char* (UTF-8). All consumers using AxlFileReadAll/AxlFileWriteAll with wide paths must convert. No compat macro possible (signature change).

  • AxlArgs switches from CHAR16** argv to char** argv. Apps using AXL_APP() already get char** argv; legacy entry points need conversion.

  • uefi-devkit: heavy user of AxlArgs and AxlFile — most impacted project.

M4: Migrate AxlLoop

Event loop, timers, idle dispatch.

Old: AxlLoopNew, AxlLoopRun, AxlLoopAddTimer New: axl_loop_new, axl_loop_run, axl_loop_add_timer

Consumer project changes for M4:

  • httpfs (HttpFS serve command): uses AxlLoop for HTTP server event loop. Compat macros cover function renames. Callback types (AXL_CALLBACK, AXL_KEY_CALLBACK) will be renamed — compat #define needed.

  • uefi-devkit: several tools use AxlLoop. Same compat approach.

Event Loop Architecture

AxlLoop is a GLib-style event loop with multiple source types:

Source

API

Behavior

Timer

axl_loop_add_timer

Repeating at fixed interval

Timeout

axl_loop_add_timeout

One-shot, auto-removed

Keypress

axl_loop_add_key_press

Console input

Idle

axl_loop_add_idle

Fires every iteration

Protocol

axl_loop_add_protocol_notify

UEFI protocol install

Event

axl_loop_add_event

Raw EFI_EVENT — async notification

The raw event source (AXL_SOURCE_EVENT) accepts any EFI_EVENT handle and fires a callback when signaled. The caller owns the event — the loop watches but does not close it. This enables async integration:

  • TCP completion tokens signal when connect/send/recv complete

  • Custom protocol events from UEFI drivers

  • Any firmware event (USB, storage, network state)

Dispatch model: The loop builds an event array from all active non-idle sources and calls WaitForEvent (blocking) or CheckEvent (non-blocking). A 10ms poll timer provides Ctrl-C detection. Idle callbacks fire every iteration before the wait.

Future: Async TCP. The current TCP API blocks with poll+Stall loops. A future async API will use axl_loop_add_event to register completion token events directly, eliminating polling:

axl_tcp_connect_async(host, port, loop, on_connect, data);
axl_tcp_recv_async(sock, loop, on_data, data);
axl_tcp_accept_async(listener, loop, on_accept, data);

The blocking API will remain for simple use cases. The HTTP server will migrate from idle-based polling to event-driven I/O.

M5: Migrate AxlTask

AP worker pool, arena allocator.

Old: AxlTaskPoolInit, AxlTaskSubmit, AxlArenaCreate New: axl_task_pool_init, axl_task_submit, axl_arena_create

Consumer project changes for M5:

  • uefi-devkit: SysInfo uses task pool for parallel CPU/memory probing. Compat macros cover function renames. Callback types (AXL_TASK_PROC, AXL_TASK_COMPLETE) will be renamed.

  • httpfs, uefi-ipmitool: do not use AxlTask. No changes needed.

M6: Migrate AxlNet

TCP, HTTP server/client, URL parser.

Old: AxlTcpConnect, AxlHttpServerNew, AxlUrlParse New: axl_tcp_connect, axl_http_server_new, axl_url_parse

Consumer project changes for M6:

  • httpfs (WebDavFsDxe): uses AxlHttpClientNew, AxlHttpGet, AxlHttpRequest, AxlHttpClientResponseFree, AxlHttpClientFree. Compat macros cover function renames. Type renames (AXL_HTTP_CLIENTAxlHttpClient, AXL_HTTP_CLIENT_RESPONSEAxlHttpResponse) need compat #define.

  • httpfs (HttpFS serve): uses AxlHttpServer* extensively. Same approach.

  • uefi-devkit (Fetch): uses HTTP client. Compat macros cover it.

  • uefi-ipmitool: does not use AxlNet. No changes needed.

C1: Style Guide Compliance

Post-migration cleanup. The M-phases focused on API renames and type migration; this phase enforces the coding style consistently across all source files.

Scope:

  • Spaces before parens: remove func (arg)func(arg) everywhere

  • Doc comments: convert @param blocks to ///< inline style per the updated coding style guide

  • EDK2 qualifiers: remove remaining IN, OUT, OPTIONAL, STATIC (use const, pointer semantics, static)

  • EDK2 types in migrated code: TRUEtrue, FALSEfalse, CONSTconst, BOOLEANbool, VOIDvoid in function signatures (internal UEFI code may keep them)

  • Allocator consistency: replace remaining AllocatePool/FreePool with axl_malloc/axl_free where safe (not in AP-callable code or UEFI protocol buffers)

  • Include cleanup: remove unnecessary EDK2 includes from files that no longer use UEFI APIs directly

Files: all axl-*.c and axl-*.h under src/ and include/. Consumer projects: httpfs, uefi-devkit (if affected).

C2: Dogfooding

Switch internal implementations from EDK2 primitives to AXL APIs. The migration phases renamed the public API but left internals using raw UEFI calls. This phase makes AXL eat its own dog food.

Scope:

  • Memory: replace remaining AllocatePool/AllocateZeroPool/ FreePool with axl_malloc/axl_calloc/axl_free in all migrated modules (Net, Data, Util). Exception: AP-callable code and buffers passed to/from UEFI protocols.

  • String ops: replace AsciiStrLen/AsciiStrCmp/AsciiStrnCmp/ AsciiSPrint/CopyMem with local helpers or AXL equivalents (axl_strlcpy, axl_vformat, etc.).

  • Console output: replace Print(L"...") with axl_print() in all migrated modules. axl-json-print.c is the main target.

  • Logging: ensure every module has AXL_LOG_DOMAIN and uses axl_error/axl_warning/axl_info/axl_debug for diagnostics instead of silent failures or Print. Audit modules that currently have no logging (e.g. axl-string.c, axl-url.c).

  • Include cleanup: remove <Library/UefiLib.h>, <Library/PrintLib.h>, <Library/MemoryAllocationLib.h> from files that no longer need them after switching to AXL APIs.

C3: Test Modernization

Migrate test applications from EDK2 entry points to AXL_APP and standardize the test framework.

Scope:

  • AXL_APP entry points: convert all 9 test files from EFI_STATUS EFIAPI AxlTestFooMain(EFI_HANDLE, EFI_SYSTEM_TABLE*) to int test_foo_main(int argc, char **argv) + AXL_APP(...). Update .inf files: ENTRY_POINT = _AxlEntry.

  • Test output: replace Print(L"PASS: %s\n", Name) with axl_printf("PASS: %s\n", name) — UTF-8 test names instead of wide strings.

  • Test helpers: extract shared Pass/Fail/Check into a common header (axl-test.h) instead of duplicating in every test file.

  • Test .inf cleanup: standardize [LibraryClasses] across all test .inf files (add AxlAppLib, remove UefiApplicationEntryPoint where possible).

  • Consumer test coverage: add build verification for httpfs and uefi-devkit as part of the test-axl.sh runner.


Coding Style

See AXL-Coding-Style.md for the full style guide. The short version: GLib naming, 4-space indent, standard C types in public API, no space before parens.

Design Principles

  1. C is the language. char * not CHAR8. size_t not UINTN. void * not VOID *. bool not BOOLEAN. snake_case, not PascalCase.

  2. %s means char*. AXL’s printf follows C convention, not EDK2. %S (uppercase) for wide strings.

  3. axl.h is self-contained. One include, no EDK2 headers leak through. Apps that need UEFI protocols include <Library/AxlLib.h> explicitly for those specific APIs.

  4. NULL-safe. axl_free(NULL), axl_fclose(NULL), etc. are no-ops.

  5. Allocation failures return NULL. No abort. Caller checks.

  6. UTF-8 everywhere. All strings in the axl.h API are char * (UTF-8). No CHAR16, no char16_t, no wide strings. AXL converts to UCS-2 internally when calling UEFI APIs (file paths, console). Conversion functions (axl_utf8_to_ucs2, axl_ucs2_to_utf8) are exposed for apps that need direct UEFI protocol interop.

  7. EDK2 is invisible. The AXL_APP macro hides the UEFI entry point. _axl_init sets up streams and memory. The app sees int main(int argc, char **argv).

  8. Eat our own dog food. AXL’s own internals use the AXL API. The library allocates with axl_malloc, reports errors with axl_printerr, builds strings with axl_string. If the API isn’t good enough for our own code, it isn’t good enough to ship.

    Exception: very early initialization (before axl_io_init) may use EDK2 primitives directly since streams aren’t available yet.

  9. No legacy EDK2-style API. There is no separate PascalCase layer. All functions follow GLib naming (axl_snake_case). UEFI types are confined to _impl declarations and internal implementation files.

Project

Repository

Name: aximcode/axl-sdk (public repo)

AXL is a standalone library, not embedded in uefi-devkit. Consumer projects (uefi-devkit, httpfs, softbmc, ipmitool) add it to PACKAGES_PATH like they add EDK2.

EDK2 packaging

AxlPkg — a standalone EDK2 package with both .dec (for consumers) and .dsc (for building AXL standalone + tests).

Consumer projects reference it like:

PACKAGES_PATH = /path/to/axl-sdk:/path/to/edk2

[Packages]
  AxlPkg/AxlPkg.dec

[LibraryClasses]
  AxlMemLib|src/mem/AxlMem.inf
  AxlLogLib|src/log/AxlLog.inf
  # ... (see AxlPkg.dsc for full list)

Minimum EDK2 version

edk2-stable202511 (November 2025).

Versioning

Semantic versioning (semver). axl.h is the stable public API — once 1.0 ships, breaking changes require a major version bump. Library/AxlLib.h (EDK2-style internal API) can change in minor releases.

License

BSD-2-Clause-Patent (matching EDK2).

Repository layout

axl-sdk/
  README.md                    Quick start, what AXL is, first app
  LICENSE                      BSD-2-Clause-Patent
  CHANGELOG.md                 Version history
  docs/
    AXL-Design.md              This document (moved from uefi-devkit)
    tutorial.md                Your first AXL app
  include/
    axl.h                      Umbrella header (#include <axl/axl-mem.h> etc.)
    axl/
      axl-mem.h                Memory allocation (Phase S1)
      axl-string.h             String builder (Phase S2)
      axl-io.h                 I/O streams (Phase S3)
    uefi/                      UEFI type headers (native backend)
  src/
    log/                       Logging, domains, handlers
    data/                      Hash, Array, String, JSON, StrBuf
    util/                      File I/O, Path, Args, HexDump, Time
    loop/                      Event loop, timers
    task/                      AP worker pool, arena
    net/                       TCP, HTTP server/client, URL
    mem/                       Allocation wrappers (Phase S1)
    io/                        Streams, printf (Phase S3)
    posix/                     axl.h implementation, AXL_APP entry point (Phase S4)
    backend/                   Backend abstraction + compat headers
    crt0/                      UEFI entry point stub
  test/
    unit/                      Test binaries (.c + .inf)
    integration/               QEMU test runner + HTTP integration tests
      test-axl.sh              QEMU-based test runner
      test-http.sh             HTTP integration tests
      common-test.sh           Shared test helpers
  AxlPkg/
    AxlPkg.dec                 Package declaration
    AxlPkg.dsc                 Standalone build (library + tests)
  scripts/
    build.sh                   Build wrapper

CI (GitHub Actions)

  • Build X64 + AARCH64 on every push

  • Run test-axl.sh (QEMU unit tests)

  • Release: tag -> build -> attach .efi binaries to GitHub release

Dependencies

Phase

Adds

Depends On

R

Rename + repo split

Nothing

S1

src/mem/axl-mem.c

MdePkg

S2

src/data/axl-strbuf.c

S1

S3

src/io/ (new module)

S1, S2, ShellPkg

S4

axl.h, AxlAppEntryPoint

S1-S3

S5

No new modules

S1-S4

Relation to Networking Phases

Phases 8-10 (middleware, client TLS, SoftBMC migration) continue using the EDK2-style API (Library/AxlNet.h). The POSIX-style wrappers for networking (axl_http_get, axl_tcp_connect, etc.) come as part of Phase S4 or S5 when the full axl.h is assembled.

Recommended order: Phase R (rename + repo split) first — it’s mechanical and unblocks everything. Then S1-S3 in sequence. S4-S5 and Phases 8-10 can interleave.