Platform Fault Detection Interface (PFDI) ***************************************** This document describes the Trusted Firmware-A (TF-A) support for the Platform Fault Detection Interface (PFDI). PFDI provides a standard EL3 interface for running platform or PE fault-detection tests, reporting their result to the non-secure world, and coordinating out-of-reset (OoR) self-tests during CPU bring-up. PFDI is intended for platforms that integrate a processor or platform self-test library and need a standard firmware interface for diagnostics. Non-secure software can use it to discover the available test library, request online tests, and read the last recorded test result, while TF-A can use it to run OoR tests before a PE is released for normal execution. For the architectural definition of PFDI, refer to the `PFDI Supplement`_. This document focuses on the TF-A implementation and on the platform code that must be provided to make it usable. SMC Interface ============= The following SMC function IDs are implemented: - ``PFDI_VERSION`` - ``PFDI_FEATURES`` - ``PFDI_PE_TEST_ID`` - ``PFDI_PE_TEST_PART_COUNT`` - ``PFDI_PE_TEST_RUN`` - ``PFDI_PE_TEST_RESULT`` - ``PFDI_FW_CHECK`` - ``PFDI_FORCE_ERROR`` Execution Model =============== - PFDI operations are **PE-local**. ``PFDI_PE_TEST_RUN`` and ``PFDI_PE_TEST_RESULT`` operate on the calling PE. - ``PFDI_FORCE_ERROR`` is also PE-local and applies to the next invocation of the targeted PFDI ABI from that same PE, even if that invocation would otherwise fail normal parameter validation. - ``PFDI_PE_TEST_RUN`` is executed in one of two modes: - **OoR mode** (``PFDI_OOR_MODE``): used by TF-A during PE bring-up. - **Online mode** (``PFDI_ONL_MODE``): used by non-secure callers after boot. - For OoR execution, TF-A stores the per-PE result and uses it later to decide whether a PE is allowed to continue boot. - ``start`` and ``end`` may be passed as ``-1`` together to request the full test range. Any other mixed use of ``-1`` is rejected. - Pending injected errors, stored results, and any other PFDI state are not persistent across reset or firmware update. Required Platform Functions =========================== The core PFDI service requires exactly one registered test library descriptor: .. code-block:: c REGISTER_PFDI_FUNC(name, run, count, result); All three callbacks must be implemented. ``run(start, end, mode, ft_id)`` -------------------------------- This callback executes the requested test range on the current PE. - ``start`` and ``end`` are the test-case indices to execute. - ``mode`` is either ``PFDI_OOR_MODE`` or ``PFDI_ONL_MODE``. - ``ft_id`` must be updated with the failing test identifier when returning ``PFDI_RET_FAULT_FOUND``. - Return ``PFDI_SMCC_RET_SUCCESS`` on success, or a ``pfdi_status_t`` error code on failure. ``count(tc_size)`` ------------------ This callback returns the total number of available test cases. - ``tc_size`` must be populated with the number of test parts. - Return ``PFDI_RET_TEST_COUNT_ZERO`` if no tests are available. ``result(cpu_num, ft_id)`` -------------------------- This callback returns the stored result for the requested PE. - ``cpu_num`` is the logical CPU number supplied by TF-A. - ``ft_id`` should be updated with the failing test identifier when the stored result is ``PFDI_RET_FAULT_FOUND``. - Return ``PFDI_RET_NOT_RUN`` until OoR testing has completed for that PE. Optional Platform-Specific Functions ==================================== Platforms may also register an optional descriptor: .. code-block:: c static const struct plat_pfdi_func_desc plat_pfdi_func_desc = { .name = "my-platform", .force_plat_err = force_plat_err, .check_plat_err = check_plat_err, .post_run = post_run, }; pfdi_register_plat_func_desc(&plat_pfdi_func_desc); All callbacks are optional and may be ``NULL``. The platform must register the descriptor during BL31 platform setup, before ``pfdi_init()`` runs. Registrations are merged by callback slot, which allows separate components to install disjoint hooks such as ``check_plat_err()`` and ``post_run()``. ``force_plat_err(fid, error_id)`` --------------------------------- This hook runs when ``PFDI_FORCE_ERROR`` is used to inject a failure for a given SMC function. Use it when error injection must also modify platform state, for example: - programming a hardware fault-status register, - forcing an SBIST/BIST failure indication, - priming a platform monitor so that the next request observes the injected error. If this hook returns non-zero, the PFDI service rejects the injection request. ``check_plat_err(fid, error_id)`` --------------------------------- This hook runs when an injected error is consumed by a later PFDI operation. Use it to validate a generic injected error against platform state. Typical uses are: - checking whether the expected hardware condition was actually latched before returning the error to the caller. If no platform hook is registered, the PFDI service returns the injected ``error_id`` directly. When a hook is present, TF-A still returns the original injected ABI error to the caller, so the hook must not depend on rewriting the reported ``x0`` value. ``post_run(status, start, end, mode, ft_id)`` --------------------------------------------- This hook runs after every ``pfdi_pe_test_run()`` attempt, regardless of whether the test run succeeded or failed. Use it for follow-up actions such as: - clearing temporary hardware state, - recording telemetry, - updating platform result storage, - triggering additional housekeeping after an OoR or online run. Platform Integration Steps ========================== To enable PFDI on a platform: 1. Select the ``PFDI_SUPPORT`` option in the platform build. 2. Define ``PFDI_TEST_LIB_VERSION`` to the implemented test library version, either in ``platform_def.h`` or on the build command line. 3. Compile the PFDI service code and the platform test implementation into BL31. 4. Provide one ``REGISTER_PFDI_FUNC()`` instance with working ``run()``, ``count()`` and ``result()`` callbacks. 5. If OoR tests must run when a secondary PE is powered on through a platform-specific path, implement ``pfdi_enable()`` and ``plat_pfdi_mpidr_by_core_pos()``. The latter maps the linear core position to the MPIDR expected by the platform's PSCI ``pwr_domain_on()`` callback, and returns ``INVALID_MPID`` for an invalid position. 6. Optionally provide ``struct plat_pfdi_func_desc`` when platform-specific error injection, validation, or post-run processing is needed. Configuration ============= ``PFDI_SUPPORT`` ---------------- Enables the EL3 PFDI service. ``PFDI_TEST_LIB_VERSION`` ------------------------- This value is optional. If it is not defined, TF-A uses zero and ``PFDI_PE_TEST_ID`` returns ``PFDI_RET_UNKNOWN``. Platforms can define it in ``platform_def.h`` or pass it on the build command line. PFDI_TEST_LIB_VERSION encoding (uint64_t) As per Platform Fault Detection Interface Specification v1.0BET0, the test library version returned by ``PFDI_PE_TEST_ID`` in the following format: :: Bits [63:32] : Reserved, must be 0 Bits [31:24] : Vendor ID Bits [23:20] : Reserved, must be 0 Bits [19:16] : Implementation ID Bits [15:8] : Major version Bits [7:0] : Minor version # Vendor IDs _____________________________________________________________________________ | Vendor ID | Vendor name | |____________________________________|______________________________________| | 0 | Arm Limited | |____________________________________|______________________________________| | Others | Reserved | |____________________________________|______________________________________| PFDI Test Library Implementation IDs _____________________________________________________________________________ | Implementation ID | Library name | |____________________________________|______________________________________| | 0 | Reserved | |____________________________________|______________________________________| | 1 | Arm STL | |____________________________________|______________________________________| | Others | Reserved | |____________________________________|______________________________________| Notes: - A value of 0 means no test engine metadata is available, and ``PFDI_PE_TEST_ID`` returns ``PFDI_RET_UNKNOWN``. - Currently only Vendor ID 0 is valid. - For Arm vendor, Implementation ID 1 identifies Arm STL. - On error, the encoded value must be zero. Example:: PFDI_TEST_LIB_VERSION := 0x0000000000010100 Vendor ID = 0x00 (Arm Limited) Implementation ID = 0x01 (Arm STL) Major version = 0x01 Minor version = 0x00 Limitations =========== - ``PFDI_FW_CHECK`` currently has no firmware-specific checks behind it and returns success unless an injected error is configured. - ``PFDI_FORCE_ERROR`` is one-shot per PE and per ABI function. The next invocation of the targeted function consumes the pending injected error and returns it in ``x0`` with ``x1``-``x4`` cleared. - The platform must provide result storage semantics that match the TF-A flow, especially for OoR execution on secondary PEs. - The current implementation assumes that PFDI tests are safe to run on the target PE in the requested execution mode. -------------- *Copyright (c) 2026, Arm Limited and Contributors. All rights reserved.* .. _PFDI Supplement: https://support.arm.com/documentation/110468/latest/