Adds two sections to the xipfs suite, guarded by CONFIG_FDPIC so a build
without the loader is unaffected. They belong here rather than in their own
test because what they exercise is modules loaded *out of the filesystem* --
the pin, the in-place mapping and the loader are one path.
'fdpic' asserts on the loader properties that otherwise fail *quietly*: a
loader that skips DT_INIT_ARRAY runs a C++ module happily with every global
left zero, one that skips DT_JMPREL loads a module that hard-faults only
once it calls out, and one that mis-sizes the descriptor pool corrupts the
heap. None of those announce themselves. The module exit status is the
channel -- each module checks its own invariants and reports a bitmask. It
also covers shared libraries across concurrent instances, per-instance data,
the leaf-library GOT fallback, the R_ARM_FUNCDESC descriptor pool, and every
firmware entry point that has to resolve a module callback, including
mq_notify and timer_create with SIGEV_THREAD.
'reject' mutates a known-good module byte by byte and asserts the loader
refuses it rather than loading something broken: a missing import, and more
DT_NEEDED entries than the walk will follow.
The modules are embedded as headers, for the same reason as in
examples/fdpicxip, and built for cortex-m3 for the same reason: one set of
blobs then runs on both the v7-M and v8-M targets. Their sources and the
makefile that regenerates these headers live in
apps/examples/fdpicxip/modules, so the copies the two apps carry are built
from the same sources in the same way.
Verified on a Pimoroni Pico Plus 2: fdpic 33/33, reject 7/7, and the whole
suite 130/130 with them included. The same three numbers on mps2-an500 under
QEMU, which is a Cortex-M7 rather than the RP2350's Cortex-M33.
Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
Twelve sections, selected by name on the command line because the power loss
sweeps run for minutes while everything else runs in seconds.
The routine part covers the VFS paths, the write-once rules (reopen for
write, append, seek during write, truncate of a written file are all refused)
and both mmap variants: that a plain mapping lands inside the media window
with no heap growth, that MAP_XIP_STRICT fails with ENXIO rather than
copying, and that N mappings of one file produce N pins on one extent.
The rest is aimed at the two properties that are easy to get wrong and quiet
when they are:
Pin release. A pin taken by one task and a task that dies with a mapping
still live both have to end with the extent movable again -- the second
without the task ever calling munmap, since a module that faults never will.
Both are checked by asking the defragmenter to move the extent afterwards.
Power-loss atomicity. With CONFIG_FS_XIPFS_FAULT_INJECT the suite fails the
Nth flash operation, remounts, and checks the volume is consistent and every
file that had been committed is byte-for-byte intact. It sweeps N across
create, unlink and defragmentation, and repeats the sweep with the failing
write torn -- a partial program rather than a clean refusal -- which is what
a real power loss mid-program leaves behind.
Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>