Client API

Header: zbc_client.h

The client API provides functions for guest/embedded code to make semihosting calls to the host system.

Types

type zbc_client_state_t

Client state structure.

Initialize with zbc_client_init() before use.

type zbc_response_t

Response from a semihosting call.

Populated by zbc_call() and zbc_parse_response().

Initialization

void zbc_client_init(zbc_client_state_t *state, volatile void *dev_base)

Initialize client state with device base address.

The function detects the platform’s integer size, pointer size, and endianness automatically using compile-time configuration macros.

Parameters:
  • state – Client state structure to initialize

  • dev_base – Memory-mapped device base address

int zbc_client_check_signature(const zbc_client_state_t *state)

Check if a semihosting device is present by reading the signature.

Call this before making semihosting calls to verify the device exists.

Parameters:
  • state – Initialized client state

Returns:

ZBC_OK if device signature matches “SEMIHOST”, ZBC_ERR_NULL_ARG if state or dev_base is NULL, ZBC_ERR_DEVICE_ERROR if signature mismatch

void zbc_client_reset_cnfg(zbc_client_state_t *state)

Reset the CNFG sent flag, forcing resend on next call.

Normally the CNFG chunk is sent only once. Use this if you need to resend configuration (e.g., after device reset).

Parameters:
  • state – Initialized client state

Making Calls

int zbc_call(zbc_response_t *response, zbc_client_state_t *state, void *buf, size_t buf_size, int opcode, uintptr_t *args)

Execute a semihosting syscall.

This is the main entry point for making semihosting calls. The function: 1. Builds a RIFF request from the opcode table 2. Submits the request to the device (synchronous) 3. Parses the response into the response structure

On success, check response->result for the syscall return value and response->error_code for the host errno.

Parameters:
  • response – Receives parsed response (result, errno, data pointer)

  • state – Initialized client state

  • buf – RIFF buffer (caller-provided)

  • buf_size – Size of buffer in bytes

  • opcode – SH_SYS_* opcode from zbc_protocol.h

  • args – Array of arguments (layout depends on opcode), may be NULL

Returns:

ZBC_OK on success, ZBC_ERR_* on protocol/transport error

Example:

zbc_response_t response;
uintptr_t args[1];
args[0] = (uintptr_t)"Hello\n";

int rc = zbc_call(&response, &client, buf, sizeof(buf),
                  SH_SYS_WRITE0, args);
if (rc != ZBC_OK) {
    /* Protocol error */
}
uintptr_t zbc_semihost(zbc_client_state_t *state, uint8_t *riff_buf, size_t riff_buf_size, uintptr_t op, uintptr_t param)

ARM-compatible semihost entry point.

This is a thin wrapper around zbc_call() that accepts the ARM-style parameter block format (op, pointer-to-args) used by picolibc and newlib.

Use this to implement sys_semihost() for libc integration.

Parameters:
  • state – Initialized client state

  • riff_buf – RIFF buffer

  • riff_buf_size – Size of buffer

  • op – SH_SYS_* opcode

  • param – Pointer to args array (cast from uintptr_t*)

Returns:

Syscall result, or (uintptr_t)-1 on error

Use this to implement sys_semihost() for libc integration:

uintptr_t sys_semihost(uintptr_t op, uintptr_t param)
{
    return zbc_semihost(&client, riff_buf, sizeof(riff_buf), op, param);
}

Low-Level Functions

int zbc_client_submit(zbc_client_state_t *state, void *buf, size_t size)

Submit a RIFF request to the semihosting device.

This writes the buffer address to RIFF_PTR and triggers DOORBELL. The host processes the request synchronously - when this function returns, the response is already in the RIFF buffer. Most users should use zbc_call() instead.

Parameters:
  • state – Initialized client state

  • buf – RIFF buffer containing the request

  • size – Size of request data

Returns:

ZBC_OK on success, error code on failure

int zbc_parse_response(zbc_response_t *response, const uint8_t *buf, size_t capacity, const zbc_client_state_t *state)

Parse response from RIFF buffer.

Extracts the result, errno, and data from a RETN or ERRO chunk. Most users should use zbc_call() instead.

Parameters:
  • response – Receives parsed response

  • buf – RIFF buffer containing the response

  • capacity – Buffer capacity

  • state – Client state (for int_size/endianness)

Returns:

ZBC_OK on success, ZBC_ERR_PARSE_ERROR on failure

Configuration Macros

These macros can be overridden at compile time to configure the client for non-standard platforms:

ZBC_CLIENT_INT_SIZE

Size of int in bytes. Default: sizeof(int)

ZBC_CLIENT_PTR_SIZE

Size of pointers in bytes. Default: sizeof(void *)

ZBC_CLIENT_ENDIANNESS

Endianness (ZBC_ENDIAN_LITTLE or ZBC_ENDIAN_BIG). Default: detected from __BYTE_ORDER__