Skip to main content

<alp/storage.h> — Block Storage

Generic block storage over flash, eMMC, or SD. Optional inline AES encryption on AEN SecAES targets.

:::danger Breaking change — writes need allow_unsafe_write on Yocto/Linux alp_storage_config_t now carries bool allow_unsafe_write, defaulting to false. On the Yocto/Linux backend, alp_storage_write() and alp_storage_erase() return ALP_ERR_INVAL unless it is set true.

This is a data-destruction guard, not a formality. On this backend /dev/mmcblk<N> is the whole-disk node — not a partition — and on V2N /dev/mtd0 is the FIP/bootloader partition. An unguarded write to either bricks the board. Reads are unaffected. :::

#include <alp/storage.h>

Read / write a block

alp_storage_t *st = alp_storage_open(&(alp_storage_config_t){
.device = ALP_STORAGE_DEVICE_OSPI_FLASH,
});

uint8_t block[256];
alp_storage_read(st, /* offset */ 0x1000, block, sizeof(block));
alp_storage_write(st, 0x1000, block, sizeof(block));

alp_storage_close(st);

allow_unsafe_write — the destructive-write guard

FieldTypeDefaultNotes
allow_unsafe_writeboolfalseYocto/Linux backend: alp_storage_write() and alp_storage_erase() return ALP_ERR_INVAL unless true.
alp_storage_config_t cfg = ALP_STORAGE_CONFIG_DEFAULT(ALP_STORAGE_KIND_SD_MMC);
cfg.allow_unsafe_write = true; // I accept that this node is the whole disk

The device nodes this backend opens are not partitions:

  • ALP_STORAGE_KIND_SD_MMC/dev/mmcblk<N>, the whole-disk node. A write at offset 0 lands on the partition table.
  • On V2N, /dev/mtd0 is the FIP/bootloader partition. Writing or erasing it without knowing exactly what you are doing bricks the board.

There is no undo and no confirmation prompt on an embedded target, so the SDK requires the caller to opt in per handle. Leave it false for read-only workloads.

Yocto / Linux (V2N / V2M) backend

alp_storage_open(), alp_storage_read() and alp_storage_get_info() are now real on this backend; they previously returned ALP_ERR_NOSUPPORT.

KindNodeGeometry source
ALP_STORAGE_KIND_SD_MMC/dev/mmcblk<N>BLKGETSIZE64 / BLKSSZGET
INTERNAL_FLASH / QSPI_FLASH / OSPI_FLASH/dev/mtd<N>MEMGETINFO

Geometry is read from the kernel, not assumed, and I/O is real pread / pwrite.

alp_storage_configure_inline_aes() remains ALP_ERR_NOSUPPORT on this backend.

Inline AES (AEN OSPI / HexSPI)

On AEN's OSPI / HexSPI controllers, inline AES decryption can be enabled at storage open time:

alp_storage_t *st = alp_storage_open(&(alp_storage_config_t){
.device = ALP_STORAGE_DEVICE_OSPI_FLASH,
});

alp_storage_inline_aes_t aes = {
.key_slot = 0,
.iv = { /* 16 bytes */ },
};
alp_storage_configure_inline_aes(st, &aes);

After this, reads return decrypted data transparently. Useful for protected firmware images and credential blobs.

File systems

For higher-level access, declare your partitions in board.yaml's storage: block — the orchestrator emits the fixed-partitions DTS overlay and the per-fs Kconfig (CONFIG_FILE_SYSTEM_LITTLEFS=y / _FAT_FILESYSTEM_ELM=y / _FILE_SYSTEM_EXT2=y) plus an optional static fs_mount_t alp_storage_mounts[] table for boot-time iteration.

Default-initialiser macro

ALP_STORAGE_CONFIG_DEFAULT(id) (v0.10) takes the backing-store kind as its identity argument:

alp_storage_config_t cfg = ALP_STORAGE_CONFIG_DEFAULT(ALP_STORAGE_KIND_INTERNAL_FLASH);

It sets kind from id plus: instance_id = 0, freq_hz = 0 (use the devicetree default), read_only = false, and allow_unsafe_write = false.

The allow_unsafe_write = false default is the point of the macro here: a config that picks up the new field automatically defaults to the non-destructive setting, so code written before the field existed cannot start erasing a bootloader by accident.

See the shared macro contract for the C++ compound-literal caveat that applies to every ALP_*_CONFIG_DEFAULT.

See also

Questions about this page? Discuss in Community Forum