Load the trustlet and configure it

On the phone, end to end from the daemon:

    lookupTA('focal64') -> result=23 (nothing to unload)
    trustlet loaded from /lib/firmware/focal64.mbn, distName='fingerprint'
    config /lib/firmware/fingerprintd.json: 349 bytes
      CMD 0x100d -> result=0 rc=0 (Success)
      CMD 0x2005 -> result=0 rc=0 (Success)

The config is the one fp6fpcfg.py --daemon generates, so the reduction of nine
hand-edited ffcfg files to one generator is confirmed against the trustlet
rather than only against the files it replaced.

A stale instance is unloaded before loading, which is what stops a crashed
experiment costing a reboot; result=23 is the clean-slate answer.

The request envelope moves into Fingerprintd:Ta with the rest of the layouts:
command id at +0, declared length at +4, payload at +0x10, and on the way back
the trustlet's own rc at +8 and the capture metric at +0x0c. Both are HEADER
fields ahead of the payload -- the metric has been miscalled "payload+12" in
this project's notes, and every recorded finger number depends on reading it
where it actually is.

ENUMERATE answering rc=0 is correct here and not a regression: no group is
active and no storage listeners are registered yet, so there are no templates
to count.
This commit is contained in:
Jorijn van der Graaf 2026-09-02 18:19:26 +02:00
commit 2648e46d43
3 changed files with 225 additions and 2 deletions

View file

@ -233,6 +233,46 @@ export namespace fingerprintd::ta {
// itself is the caller's to choose.
inline constexpr std::size_t SetActiveGroupGidOff = 0;
// ---- The request/response envelope ------------------------------------
//
// sendRequest carries two buffers in and two back. The request is:
//
// +0x00 u32 command id
// +0x04 u32 declared payload length
// +0x10 the payload
//
// and the returned copy of it carries the trustlet's own return code and
// the capture metric in the header, ahead of the payload:
//
// +0x08 i32 rc the trustlet's result, distinct from QTEE's
// +0x0c i32 metric CAPTURE_IMAGE's finger signal
//
// The metric is a HEADER field. It has been called "payload+12" in this
// project's notes and it is not; it tracks the finger reproducibly and
// every recorded number depends on reading it here.
inline constexpr std::size_t ReqCmdOff = 0x00;
inline constexpr std::size_t ReqLenOff = 0x04;
inline constexpr std::size_t ReqPayloadOff = 0x10;
inline constexpr std::size_t RespRcOff = 0x08;
inline constexpr std::size_t RespMetricOff = 0x0c;
inline void BuildRequest(std::span<std::byte> req, Cmd cmd,
std::span<const std::byte> payload) {
std::ranges::fill(req, std::byte{0});
detail::StoreU32(req, ReqCmdOff, static_cast<std::uint32_t>(cmd));
if (!payload.empty()) {
detail::StoreU32(req, ReqLenOff, static_cast<std::uint32_t>(payload.size()));
std::ranges::copy(payload, req.begin() + static_cast<std::ptrdiff_t>(ReqPayloadOff));
}
}
inline std::int32_t ResultCode(std::span<const std::byte> reqOut) {
return static_cast<std::int32_t>(detail::LoadU32(reqOut, RespRcOff));
}
inline std::int32_t CaptureMetric(std::span<const std::byte> reqOut) {
return static_cast<std::int32_t>(detail::LoadU32(reqOut, RespMetricOff));
}
// ---- Responses --------------------------------------------------------
//
// THE TRAP. The buffer that comes back is the whole REQUEST, and the