diff --git a/Runner/suites/Multimedia/CDSP/fastrpc_test/fastrpc_test.yaml b/Runner/suites/Multimedia/CDSP/fastrpc_test/fastrpc_test.yaml index 0cae5cf9..ec5dd3ae 100644 --- a/Runner/suites/Multimedia/CDSP/fastrpc_test/fastrpc_test.yaml +++ b/Runner/suites/Multimedia/CDSP/fastrpc_test/fastrpc_test.yaml @@ -5,10 +5,9 @@ metadata: The **fastrpc_test** runner validates FastRPC (Fast Remote Procedure Call) on Qualcomm targets. **Enhanced Test Coverage**: - - Now tests ALL supported DSP domains detected at runtime (ADSP, MDSP, SDSP, CDSP, CDSP1, GPDSP0, GPDSP1) - - Tests BOTH signed (system) and unsigned (user) Protection Domains where hardware supports them - - ADSP/MDSP/SDSP: signed PD only; CDSP/CDSP1/GPDSP: both signed and unsigned PDs - - QCS9075, QCS8275, QCS8300, QCS9100: GPDSP0/GPDSP1 domains are skipped (fastrpc_tests binaries not supported temporarily) + - Uses fastrpc-healthcheck when available to discover online, FastRPC-capable DSP domains + - Derives signed and unsigned Protection Domain support from the live healthcheck report + - Without healthcheck, discovers domains from remoteproc plus FastRPC endpoints and uses a conservative protocol map for PD support - For single-domain testing: set DOMAIN_MODE="single" and specify DOMAIN or DOMAIN_NAME os: - linux @@ -24,7 +23,8 @@ params: PD_MODE: "both" # both|signed-only|unsigned-only (default: both - tests both PDs where supported) UNSIGNED_PD: "" # If set to non-zero, runs only unsigned PD mode (-U 1) REPEAT: 1 # Number of repetitions (default: 1) - TIMEOUT: "" # Timeout for each run (no timeout if omitted) + TIMEOUT: 120 # Required positive timeout for each fastrpc_test invocation + HEALTHCHECK_TIMEOUT: 15 # Required positive timeout for fastrpc-healthcheck run: steps: @@ -32,5 +32,5 @@ run: - cd Runner/suites/Multimedia/CDSP/fastrpc_test - UNSIGNED_PD_PARAM="" - if [ -n "${UNSIGNED_PD}" ] && [ "${UNSIGNED_PD}" != 0 ]; then UNSIGNED_PD_PARAM="--unsigned-pd"; fi - - ./run.sh --arch "${ARCH}" --bin-dir "${BIN_DIR}" --domain-mode "${DOMAIN_MODE}" --domain "${DOMAIN}" --domain-name "${DOMAIN_NAME}" --pd-mode "${PD_MODE}" --repeat "${REPEAT}" --timeout "${TIMEOUT}" $UNSIGNED_PD_PARAM || true + - ./run.sh --arch "${ARCH}" --bin-dir "${BIN_DIR}" --domain-mode "${DOMAIN_MODE}" --domain "${DOMAIN}" --domain-name "${DOMAIN_NAME}" --pd-mode "${PD_MODE}" --repeat "${REPEAT}" --timeout "${TIMEOUT}" --healthcheck-timeout "${HEALTHCHECK_TIMEOUT}" $UNSIGNED_PD_PARAM || true - $REPO_PATH/Runner/utils/send-to-lava.sh fastrpc_test.res || true diff --git a/Runner/suites/Multimedia/CDSP/fastrpc_test/fastrpc_test_README.md b/Runner/suites/Multimedia/CDSP/fastrpc_test/fastrpc_test_README.md index 85f22b00..9f1518ba 100644 --- a/Runner/suites/Multimedia/CDSP/fastrpc_test/fastrpc_test_README.md +++ b/Runner/suites/Multimedia/CDSP/fastrpc_test/fastrpc_test_README.md @@ -1,33 +1,45 @@ -# FastRPC Test Script for Qualcomm Linux-based Platforms (Yocto) +# FastRPC Test Script for Qualcomm Linux-based Platforms ## Overview -The **fastrpc_test** runner validates FastRPC (Fast Remote Procedure Call) on Qualcomm targets, offloading work to DSP domains (e.g., **CDSP**). -It wraps the public [fastrpc test application](https://github.com/quic/fastrpc) with **robust logging, parameter control, and CI-friendly output**. +The **fastrpc_test** runner validates FastRPC (Fast Remote Procedure Call) on Qualcomm targets, +offloading work to all supported DSP domains (ADSP, MDSP, SDSP, CDSP, CDSP1, GDSP0, GDSP1). +It wraps the public [fastrpc test application](https://github.com/quic/fastrpc) with **robust +logging, parameter control, and CI-friendly output**. Supported capabilities: -- Auto-detect architecture from SoC ID. -- Multiple iterations and optional timeouts. -- Precise control over where the binary and assets live via `--bin-dir` and `--assets-dir`. -- Unbuffered output via `stdbuf` or `script` when available (falls back gracefully). +- Uses `fastrpc-healthcheck` when available to discover online DSPs, FastRPC support, signed and + unsigned PD support, firmware information, DSP library paths, and DMA-BUF heap readiness. +- When healthcheck is unavailable, discovers runnable domains from remoteproc state and FastRPC + character endpoints. The fallback cannot discover PD support directly, so it uses the documented + conservative protocol map. Host, test, and DSP skeleton libraries remain runtime-discovered. +- Multiple iterations with a required finite timeout. +- Precise control over binary location via `--bin-dir`. +- Line-buffered output through `stdbuf` when available. ## Features - **Calculator**, **HAP**, and **Multithreading** examples (as provided by `fastrpc_test`) -- CI-ready logs with timestamps and per-iteration results -- Parameterized control (`--arch`, `--repeat`, `--timeout`, `--bin-dir`, `--assets-dir`, `--verbose`) -- Auto-detection fallback for binary and assets -- Silent directory scan (no noisy `ls` dumps) +- CI-ready logs with timestamps and per-iteration, per-domain/PD results +- Parameterized control (`--arch`, `--repeat`, `--timeout`, `--bin-dir`, `--domain-mode`, + `--domain`, `--domain-name`, `--pd-mode`, `--unsigned-pd`, `--verbose`) +- Auto-discovery of system libraries and DSP skeletons for both Yocto and Debian layouts +- Runtime domain and PD discovery without SoC-name filtering ## Prerequisites Have these on the target (or specify paths with the flags below): - `fastrpc_test` binary (from [github.com/quic/fastrpc](https://github.com/quic/fastrpc)) -- A **parent directory** that contains a `linux/` subfolder with the required libraries (often alongside the binary), and architecture folders such as `v68`, `v73`, `v75`. +- Optional `fastrpc-healthcheck`. When installed, this is the primary distro-independent + capability source. An installed healthcheck that fails, times out, or produces an + unrecognized report fails the suite. Runtime fallback is used only when the tool is absent. +- FastRPC system libraries and DSP skeletons auto-discovered from standard locations: + - Yocto: `/usr/local/lib`, `/usr/local/lib/fastrpc_test`, `/usr/local/share/fastrpc_test` + - Debian: `/usr/lib/`, `/usr/lib//fastrpc_test`, `/usr/share/fastrpc_test` + - RPM-based images: `/usr/lib64`, `/usr/lib64/fastrpc_test`, `/usr/share/fastrpc_test` - Optional but recommended: - - `stdbuf` **or** `script` (for unbuffered stdout/stderr) - - `timeout` (GNU coreutils) for wall-clock limiting; the script provides a portable fallback if missing. + - `stdbuf` for line-buffered output. Execution remains bounded without it. ## Directory Structure @@ -38,7 +50,8 @@ Runner/ │ │ ├── CDSP/ │ │ │ ├── fastrpc_test/ │ │ │ │ ├── run.sh -│ │ │ │ ├── fastrpc_test_README.md +│ │ │ │ ├── fastrpc_test_README.md +│ │ │ │ ├── fastrpc_test.yaml ``` ## Usage @@ -49,69 +62,66 @@ Runner/ Usage: run.sh [OPTIONS] Options: - --arch Architecture (only if explicitly provided) - --bin-dir Directory containing 'fastrpc_test' (default: /usr/bin) - --assets-dir Directory that CONTAINS 'linux/' (info only; we run from the binary dir) - --user-pd Use '-U 1' (user/unsigned PD). Default is '-U 0'. - --repeat Number of repetitions (default: 1) - --timeout Timeout for each run (no timeout if omitted) - --verbose Extra logging for CI debugging - --help Show this help + --arch Architecture (only if explicitly provided) + --bin-dir Directory containing 'fastrpc_test' (default: /usr/bin) + --domain <0|1|2|3|4|5|6> DSP domain: 0=ADSP 1=MDSP 2=SDSP 3=CDSP 4=CDSP1 5=GDSP0 6=GDSP1 + --domain-name DSP domain: adsp|mdsp|sdsp|cdsp|cdsp1|gdsp0|gdsp1 + --domain-mode Discover all domains or run only one (default: all-supported) + --pd-mode Select PD mode(s) to run (default: both) + --unsigned-pd Use '-U 1' (user/unsigned PD). Overrides --pd-mode. + --repeat Number of repetitions (default: 1) + --timeout Timeout for each run (default: 120, must be greater than zero) + --healthcheck-timeout Timeout for fastrpc-healthcheck (default: 15) + --verbose Extra logging for CI debugging + --help Show this help Env: - FASTRPC_USER_PD=0|1 Sets PD (-U value). CLI --user-pd overrides to 1. - FASTRPC_EXTRA_FLAGS Extra flags appended to the command. - ALLOW_BIN_FASTRPC=1 Permit using /bin/fastrpc_test (otherwise refused). - -The test executes FROM the assets directory so 'fastrpc_test' can find deps. + FASTRPC_DOMAIN=0|1|2|3|4|5|6 Sets domain; CLI --domain/--domain-name wins. + FASTRPC_DOMAIN_NAME=adsp|... Named domain; CLI wins. + FASTRPC_UNSIGNED_PD=0|1 Sets PD (-U value). CLI --unsigned-pd overrides to 1. + FASTRPC_EXTRA_FLAGS Extra flags appended (space-separated). + FASTRPC_HEALTHCHECK_BIN Optional path to fastrpc-healthcheck. + ALLOW_BIN_FASTRPC=1 Permit using /bin/fastrpc_test when --bin-dir=/bin. ``` ### Quick start ```bash -# If fastrpc_test is already in PATH and assets are discoverable: +# Default: dynamically discover runnable domains and supported PD modes +./run.sh + +# With repeat and timeout: ./run.sh --repeat 3 --timeout 60 ``` ### Common scenarios ```bash -# Default expects /usr/bin/fastrpc_test and /usr/bin/linux -./run.sh +# 1) Use a custom binary directory +./run.sh --bin-dir /tmp/stage/usr/bin -Common scenarios +# 2) Run only unsigned (user) PD across all domains +./run.sh --pd-mode unsigned-only -# 1) Use a custom binary directory (we will cd there and run ./fastrpc_test) -./run.sh --bin-dir /tmp/stage/usr/bin +# 3) Run only signed PD +./run.sh --pd-mode signed-only -# 2) Opt into user/unsigned PD (-U 1) -./run.sh --user-pd -# or via env -FASTRPC_USER_PD=1 ./run.sh +# 4) Force a specific domain (CDSP) +./run.sh --domain 3 +# or by name: +./run.sh --domain-name cdsp -# 3) Add extra flags (kept intact; -U is appended last as '-U 0/1') -FASTRPC_EXTRA_FLAGS="-d 3" ./run.sh +# 5) Force GDSP0 with unsigned PD +./run.sh --domain-name gdsp0 --pd-mode unsigned-only -# 4) Allow /bin explicitly (generally discouraged unless required) -ALLOW_BIN_FASTRPC=1 ./run.sh --bin-dir /bin +# 6) Run SDSP via environment variable with unsigned PD +FASTRPC_DOMAIN=2 FASTRPC_UNSIGNED_PD=1 ./run.sh -# 5) Run multiple iterations with a timeout and verbose logs +# 7) Run multiple iterations with verbose logs ./run.sh --repeat 3 --timeout 120 --verbose -Force CDSP explicitly: - -# 6) ./run.sh --domain 3 -# or -# 6) ./run.sh --domain-name cdsp - -Use ADSP and user PD: - -# 7) ./run.sh --domain-name adsp --user-pd - -From env (CI): - -FASTRPC_DOMAIN=2 FASTRPC_USER_PD=1 ./run.sh -# => SDSP with -U 1 +# 8) Allow /bin explicitly (generally discouraged) +ALLOW_BIN_FASTRPC=1 ./run.sh --bin-dir /bin ``` ### LAVA integration example @@ -125,34 +135,61 @@ FASTRPC_DOMAIN=2 FASTRPC_USER_PD=1 ./run.sh ``` [INFO] 2025-09-02 10:44:46 - -------------------Starting fastrpc_test Testcase---------------------------- -[INFO] 2025-09-02 10:44:46 - Using binary: /usr/bin/fastrpc_test -[INFO] 2025-09-02 10:44:46 - PD setting: -U 0 (use --user-pd to set -U 1) -[INFO] 2025-09-02 10:44:46 - Run dir: /usr/bin (launching ./fastrpc_test) -[INFO] 2025-09-02 10:44:46 - Executing: ./fastrpc_test -d 3 -t linux -U 0 ------ iter1 output begin ----- +[INFO] 2025-09-02 10:44:46 - Domain mode: all-supported +[INFO] 2025-09-02 10:44:46 - Domains to test: 0 3 +[INFO] 2025-09-02 10:44:46 - PD mode: both +[INFO] 2025-09-02 10:44:46 - Running ADSP_signed_iter1 | domain=ADSP | pd=signed +[INFO] 2025-09-02 10:44:46 - Executing: ./fastrpc_test -d 0 -t linux -U 0 +----- ADSP_signed_iter1 output begin ----- ... fastrpc_test output ... ------ iter1 output end ----- -[PASS] 2025-09-02 10:44:50 - iter1: success -[PASS] 2025-09-02 10:44:50 - fastrpc_test : Test Passed (1/1) +----- ADSP_signed_iter1 output end ----- +[PASS] 2025-09-02 10:44:50 - ADSP_signed_iter1: success +... +[INFO] ================================================================================ +[INFO] FastRPC Test Summary +[INFO] ================================================================================ +[INFO] Domain | PD Mode | Total | Pass | Fail | Skip | Status +[INFO] -------------------------------------------------------------------------------- +[INFO] ADSP | Signed | 5 | 5 | 0 | 0 | PASS +[INFO] CDSP | Signed | 5 | 5 | 0 | 0 | PASS +[INFO] CDSP | Unsigned | 5 | 5 | 0 | 0 | PASS +[PASS] 2025-09-02 10:44:50 - fastrpc_test : Test Passed (3/3) ``` ## CI debugging aids -- Binary resolved to /bin/fastrpc_test: By default this is blocked to avoid loader/ramdisk mismatches. Set ALLOW_BIN_FASTRPC=1 and/or --bin-dir /bin if you intentionally need it. -- Error resolving path .../linux: Ensure linux/ is next to the binary (e.g., /usr/bin/linux). The script runs from the binary dir specifically to make this work. -- Session create errors with -U 1: If you opt into user/unsigned PD and see 0x80000416, confirm your image includes unsigned shells/policies (or revert to the default -U 0). -- Per-iteration logs: `logs_fastrpc_test_/iterN.out` (+ `iterN.rc`) -- Summary result file: `fastrpc_test.res` (`PASS` / `FAIL`) -- Verbose mode: adds environment, resolutions, and timing details -- Graceful fallbacks when `stdbuf`, `script`, or `timeout` are missing -- Silent scan (no directory spam) during auto-detection + +- **Capability source**: The startup log reports `capability_source`, `domain_source`, and + `pd_source`. Raw and normalized healthcheck output is retained in the run log directory. +- **Offline automatic domain**: Logged and excluded from automatic selection. Other runnable + domains continue. +- **Offline explicitly requested domain**: Fails with the healthcheck or remoteproc state. +- **Missing runtime artifacts**: Skips before executing `fastrpc_test` and prints the missing + per-domain system library, test library, or skeleton evidence. +- **Binary resolved to /bin/fastrpc_test**: Blocked by default. Set `ALLOW_BIN_FASTRPC=1` or + use `--bin-dir` to a non-`/bin` path. +- **Session create errors with -U 1**: If unsigned PD returns `0x80000416`, confirm your image + includes unsigned shells/policies (or use `--pd-mode signed-only`). +- **Domain not discovered**: Check `dmesg` for remoteproc firmware load errors. The test + requires the DSP remoteproc to be registered and its firmware present in DT. +- **Per-iteration logs**: `logs_fastrpc_test_/__iter.out` (+ `.rc`, `.env`, `.cmd`) +- **Summary result file**: `fastrpc_test.res` (`PASS` / `FAIL` / `SKIP`) +- **Verbose mode**: adds environment, library resolution, and timing details ## Notes -- If `--arch` is omitted, the script maps `/sys/devices/soc0/soc_id` to a known arch (defaulting to `v68` when unknown). -- If `fastrpc_test` isn’t in `PATH`, use `--bin-dir` or add it to `PATH`. -- If you see `Error resolving path .../linux: No such file or directory`, point `--assets-dir` to the **parent** directory that actually contains a `linux/` subfolder. -- The script changes working directory to the resolved **assets** dir before invoking `fastrpc_test`, which is required for the binary to locate its shared libs/skeletons. +- Domain and PD support are derived from `fastrpc-healthcheck` when available. The fallback is + selected only when the tool is absent and uses runtime remoteproc and endpoint evidence, with + a conservative protocol mapping for PD support. +- This suite runs the public `fastrpc_test` character-device path and therefore requires either + `/dev/fastrpc-` or `/dev/fastrpc--secure` for every selected domain. +- DSP skeleton directories are discovered dynamically by locating `.so` artifacts instead of + assuming fixed ABI directory names such as `v68` or `v75`. +- Override library discovery with `FASTRPC_LIB_SYS_DIR`, `FASTRPC_LIB_TEST_DIR`, or + `FASTRPC_SKEL_BASE`. CLI domain selection takes precedence over environment selection, which + takes precedence over runtime discovery. +- If `fastrpc_test` is not in the default path, use `--bin-dir` to specify its location. ## License -SPDX-License-Identifier: BSD-3-ClauseCopyright (c) Qualcomm Technologies, Inc. +SPDX-License-Identifier: BSD-3-Clause +Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. diff --git a/Runner/suites/Multimedia/CDSP/fastrpc_test/run.sh b/Runner/suites/Multimedia/CDSP/fastrpc_test/run.sh index d3978995..901646df 100755 --- a/Runner/suites/Multimedia/CDSP/fastrpc_test/run.sh +++ b/Runner/suites/Multimedia/CDSP/fastrpc_test/run.sh @@ -36,6 +36,9 @@ fi # shellcheck disable=SC1090,SC1091 . "$TOOLS/lib_fastrpc.sh" + +# shellcheck disable=SC1090,SC1091 +. "$TOOLS/lib_diag.sh" # Optional generic package-set recovery. # This must be a clean no-op when no package-set mapping exists for the active OS/provider. @@ -52,7 +55,8 @@ fi # Defaults REPEAT=1 -TIMEOUT="" +TIMEOUT=120 +HEALTHCHECK_TIMEOUT=15 ARCH="" BIN_DIR="" # directory that CONTAINS fastrpc_test ASSETS_DIR="" # kept for compatibility/logging (not used by new layout) @@ -63,13 +67,17 @@ CLI_DOMAIN_NAME="" DOMAIN_MODE="all-supported" # Default: test all supported domains PD_MODE="both" # Default: test both PDs where supported +# usage +# Print the supported FastRPC test CLI, environment overrides, and selection policy. +# Inputs: none. Output: help text on stdout. +# Returns: 0. Side effects: none. usage() { cat < @@ -77,13 +85,14 @@ Options: --arch Architecture (only if explicitly provided) --bin-dir Directory containing 'fastrpc_test' (default: /usr/bin) --assets-dir (compat) previously used when assets lived under 'linux/' - --domain <0|1|2|3|4|5|6> DSP domain: 0=ADSP, 1=MDSP, 2=SDSP, 3=CDSP, 4=CDSP1, 5=GPDSP0, 6=GPDSP1 - --domain-name DSP domain by name: adsp|mdsp|sdsp|cdsp|cdsp1|gpdsp0|gpdsp1 + --domain <0|1|2|3|4|5|6> DSP domain: 0=ADSP, 1=MDSP, 2=SDSP, 3=CDSP, 4=CDSP1, 5=GDSP0, 6=GDSP1 + --domain-name DSP domain by name: adsp|mdsp|sdsp|cdsp|cdsp1|gdsp0|gdsp1 --domain-mode Discover all supported domains or run only one (default: all-supported) --pd-mode Select PD mode(s) to run (default: both) --unsigned-pd Use '-U 1' (user/unsigned PD). Overrides --pd-mode for compatibility --repeat Number of repetitions (default: 1) - --timeout Timeout for each run (no timeout if omitted) + --timeout Timeout for each run (default: 120, must be greater than zero) + --healthcheck-timeout Timeout for fastrpc-healthcheck (default: 15) --verbose Extra logging for CI debugging --help Show this help @@ -99,6 +108,7 @@ Env: FASTRPC_DOMAIN_NAME=adsp|... Named domain; CLI wins. FASTRPC_UNSIGNED_PD=0|1 Sets PD (-U value). CLI --unsigned-pd overrides to 1. FASTRPC_EXTRA_FLAGS Extra flags appended (space-separated). + FASTRPC_HEALTHCHECK_BIN Optional path to fastrpc-healthcheck. ALLOW_BIN_FASTRPC=1 Permit using /bin/fastrpc_test when --bin-dir=/bin. Notes: @@ -113,33 +123,91 @@ Notes: /usr/lib/ /usr/lib//fastrpc_test /usr/share/fastrpc_test + RPM-based: + /usr/lib64 + /usr/lib64/fastrpc_test + /usr/share/fastrpc_test - Optional overrides: FASTRPC_LIB_SYS_DIR FASTRPC_LIB_TEST_DIR FASTRPC_SKEL_BASE -- Domain mapping: ADSP=0 MDSP=1 SDSP=2 CDSP=3 CDSP1=4 GPDSP0=5 GPDSP1=6 -- PD support: ADSP/MDSP/SDSP support signed only; CDSP/CDSP1/GPDSP support both. +- Domain mapping: ADSP=0 MDSP=1 SDSP=2 CDSP=3 CDSP1=4 GDSP0=5 GDSP1=6 +- With healthcheck, domain and PD support come from its live capability report. +- Without healthcheck, domains come from remoteproc plus endpoint discovery, while PD support uses a conservative protocol fallback map. EOF } -# --------------------- Parse arguments ------------------------- -while [ $# -gt 0 ]; do - case "$1" in - --arch) ARCH="$2"; shift 2 ;; - --bin-dir) BIN_DIR="$2"; shift 2 ;; - --assets-dir) ASSETS_DIR="$2"; shift 2 ;; - --domain) CLI_DOMAIN="$2"; shift 2 ;; - --domain-name) CLI_DOMAIN_NAME="$2"; shift 2 ;; - --domain-mode) DOMAIN_MODE="$2"; shift 2 ;; - --pd-mode) PD_MODE="$2"; shift 2 ;; - --unsigned-pd) UNSIGNED_PD_FLAG=1; shift ;; - --repeat) REPEAT="$2"; shift 2 ;; - --timeout) TIMEOUT="$2"; shift 2 ;; - --verbose) VERBOSE=1; shift ;; - --help) usage; exit 0 ;; - *) echo "[ERROR] Unknown argument: $1" >&2; usage; echo "$TESTNAME : FAIL" >"$RESULT_FILE"; exit 0 ;; - esac -done +# parse_args ARG... +# Parse command-line policy and compatibility options into suite configuration globals. +# Inputs: the original command-line argument vector. Output: no stdout contract. +# Returns: 0 for valid input, and exits the suite after help or invalid input. +# Side effects: updates option globals and writes a FAIL result for unknown arguments. +parse_args() { + while [ "$#" -gt 0 ]; do + case "$1" in + --arch) + ARCH="$2" + shift 2 + ;; + --bin-dir) + BIN_DIR="$2" + shift 2 + ;; + --assets-dir) + ASSETS_DIR="$2" + shift 2 + ;; + --domain) + CLI_DOMAIN="$2" + shift 2 + ;; + --domain-name) + CLI_DOMAIN_NAME="$2" + shift 2 + ;; + --domain-mode) + DOMAIN_MODE="$2" + shift 2 + ;; + --pd-mode) + PD_MODE="$2" + shift 2 + ;; + --unsigned-pd) + UNSIGNED_PD_FLAG=1 + shift + ;; + --repeat) + REPEAT="$2" + shift 2 + ;; + --timeout) + TIMEOUT="$2" + shift 2 + ;; + --healthcheck-timeout) + HEALTHCHECK_TIMEOUT="$2" + shift 2 + ;; + --verbose) + VERBOSE=1 + shift + ;; + --help) + usage + exit 0 + ;; + *) + echo "[ERROR] Unknown argument: $1" >&2 + usage + echo "$TESTNAME : FAIL" >"$RESULT_FILE" + exit 0 + ;; + esac + done +} + +parse_args "$@" # ---- Back-compat: accept --assets-dir but ignore in the new auto-discovered layout. # Export so external tooling (or legacy wrappers) can still read it. @@ -157,10 +225,27 @@ export UNSIGNED_PD_FLAG export VERBOSE # ---------- Validation ---------- -case "$REPEAT" in *[!0-9]*|"") log_error "Invalid --repeat: $REPEAT"; echo "$TESTNAME : FAIL" >"$RESULT_FILE"; exit 0 ;; esac -if [ -n "$TIMEOUT" ]; then - case "$TIMEOUT" in *[!0-9]*|"") log_error "Invalid --timeout: $TIMEOUT"; echo "$TESTNAME : FAIL" >"$RESULT_FILE"; exit 0 ;; esac -fi +case "$REPEAT" in + *[!0-9]*|""|0) + log_error "Invalid --repeat: $REPEAT" + echo "$TESTNAME : FAIL" >"$RESULT_FILE" + exit 0 + ;; +esac +case "$TIMEOUT" in + *[!0-9]*|""|0) + log_error "Invalid --timeout: $TIMEOUT" + echo "$TESTNAME : FAIL" >"$RESULT_FILE" + exit 0 + ;; +esac +case "$HEALTHCHECK_TIMEOUT" in + *[!0-9]*|""|0) + log_error "Invalid --healthcheck-timeout: $HEALTHCHECK_TIMEOUT" + echo "$TESTNAME : FAIL" >"$RESULT_FILE" + exit 0 + ;; +esac # Validate enhanced options case "$DOMAIN_MODE" in all-supported|single) : ;; *) log_error "Invalid --domain-mode: $DOMAIN_MODE"; echo "$TESTNAME : FAIL" >"$RESULT_FILE"; exit 0 ;; esac case "$PD_MODE" in both|signed-only|unsigned-only) : ;; *) log_error "Invalid --pd-mode: $PD_MODE"; echo "$TESTNAME : FAIL" >"$RESULT_FILE"; exit 0 ;; esac @@ -185,7 +270,6 @@ log_info "-------------------Starting $TESTNAME Testcase------------------------ log_info "Kernel: $(uname -a 2>/dev/null || echo N/A)" log_info "Date(UTC): $(date -u 2>/dev/null || echo N/A)" log_soc_info -SOC_MACHINE="$(tr -s ' ' < /sys/devices/soc0/machine 2>/dev/null | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')" # -------------------- Binary directory resolution ----------------- if [ -n "$BIN_DIR" ]; then @@ -213,6 +297,60 @@ if [ ! -x "$RUN_BIN" ]; then exit 0 fi +# -------------------- Logging root ----------------------------- +TS="$(date +%Y%m%d-%H%M%S)" +LOG_ROOT="./logs_${TESTNAME}_${TS}" +if ! mkdir -p "$LOG_ROOT"; then + log_error "Cannot create $LOG_ROOT" + echo "$TESTNAME : FAIL" >"$RESULT_FILE" + exit 0 +fi + +log_info "Evidence directory: $test_path/$LOG_ROOT" + +# -------------------- Capability discovery --------------------- +FASTRPC_HEALTHCHECK_LOG="$LOG_ROOT/fastrpc_healthcheck.log" +FASTRPC_HEALTHCHECK_TSV="$LOG_ROOT/fastrpc_healthcheck.tsv" +export FASTRPC_HEALTHCHECK_TSV + +fastrpc_capture_healthcheck \ + "$FASTRPC_HEALTHCHECK_LOG" \ + "$HEALTHCHECK_TIMEOUT" +healthcheck_status=$? + +case "$healthcheck_status" in + 0) + if fastrpc_parse_healthcheck \ + "$FASTRPC_HEALTHCHECK_LOG" \ + "$FASTRPC_HEALTHCHECK_TSV"; then + export FASTRPC_HEALTHCHECK_DSP_LIB_DIR + log_info "[FASTRPC-POLICY] capability_source=fastrpc-healthcheck domain_source=healthcheck pd_source=healthcheck parsed=$FASTRPC_HEALTHCHECK_TSV" + fastrpc_log_healthcheck_records + else + rm -f "$FASTRPC_HEALTHCHECK_TSV" + log_fail "$TESTNAME FAIL - installed fastrpc-healthcheck produced unrecognized output, artifact=$FASTRPC_HEALTHCHECK_LOG" + echo "$TESTNAME : FAIL" >"$RESULT_FILE" + exit 0 + fi + ;; + 1) + rm -f "$FASTRPC_HEALTHCHECK_TSV" + log_fail "$TESTNAME FAIL - installed fastrpc-healthcheck execution failed, artifact=$FASTRPC_HEALTHCHECK_LOG" + echo "$TESTNAME : FAIL" >"$RESULT_FILE" + exit 0 + ;; + 2) + rm -f "$FASTRPC_HEALTHCHECK_TSV" + log_info "[FASTRPC-POLICY] capability_source=runtime-fallback domain_source=remoteproc-endpoint pd_source=protocol-fallback-map reason=fastrpc-healthcheck-not-installed" + ;; + *) + rm -f "$FASTRPC_HEALTHCHECK_TSV" + log_fail "$TESTNAME FAIL - unexpected fastrpc-healthcheck status=$healthcheck_status, artifact=$FASTRPC_HEALTHCHECK_LOG" + echo "$TESTNAME : FAIL" >"$RESULT_FILE" + exit 0 + ;; +esac + # -------------------- Runtime layout discovery -------------------- fastrpc_setup_runtime_layout @@ -228,59 +366,54 @@ ensure_usr_lib_dsp_symlinks log_dsp_remoteproc_status # -------------------- Domain and PD selection ------------------- -# Resolve domains and PDs to test DOMAINS_TO_TEST="$(resolve_domains_to_test)" +SELECTION_SOURCE="auto" +if [ -n "$CLI_DOMAIN_NAME" ] || [ -n "$CLI_DOMAIN" ] || + [ "$DOMAIN_MODE" = "single" ]; then + SELECTION_SOURCE="explicit" +fi + +if [ -z "$DOMAINS_TO_TEST" ] && [ "$SELECTION_SOURCE" = "explicit" ]; then + log_fail "$TESTNAME FAIL - explicitly requested domain is invalid or unavailable" + echo "$TESTNAME : FAIL" >"$RESULT_FILE" + exit 0 +fi + if [ -z "$DOMAINS_TO_TEST" ]; then log_skip "$TESTNAME SKIP - no mapped/supported domains detected" echo "$TESTNAME : SKIP" >"$RESULT_FILE" exit 0 fi -# -------------------- SoC-specific domain blacklist -------------------- -# QRB2210: FastRPC not supported - skip entire test -# QCS9075, QCS8275, QCS8300, QCS9100: GPDSP0 (domain 5) and GPDSP1 (domain 6) not supported currently -# SM8850: libhap_example HAP_mem DMA not supported - treat as known skip per invocation -# -# Do not skip Glymur CRD by SoC name. Newer Glymur/Debian images expose -# ADSP/CDSP remoteproc instances and FastRPC skeletons, so runtime discovery -# should decide whether the test can run. -soc_skip_all=0 -soc_skip_gpdsp=0 - -case "$SOC_MACHINE" in - *QRB2210*|*"Glymur CRD"*) - soc_skip_all=1 - ;; - *QCS9075*|*QCS8275*|*QCS8300*|*QCS9100*) - soc_skip_gpdsp=1 - ;; -esac - -if [ "$soc_skip_all" -eq 1 ]; then - log_skip "$TESTNAME SKIP - SoC $SOC_MACHINE does not support FastRPC" +if ! fastrpc_validate_runtime_artifacts "$DOMAINS_TO_TEST"; then + log_skip "$TESTNAME SKIP - FastRPC test artifacts are incomplete: $FASTRPC_ARTIFACT_ERROR" echo "$TESTNAME : SKIP" >"$RESULT_FILE" exit 0 fi -if [ "$soc_skip_gpdsp" -eq 1 ]; then - filtered="" - for d in $DOMAINS_TO_TEST; do - case "$d" in - 5|6) log_info "SoC $SOC_MACHINE: skipping $(domain_to_name "$d") (not supported)" ;; - *) filtered="${filtered:+$filtered }$d" ;; - esac - done - DOMAINS_TO_TEST="$filtered" -fi +# Validate every selected domain before handing it to fastrpc_test. +for d in $DOMAINS_TO_TEST; do + fastrpc_domain_ready "$d" + domain_ready_status=$? -if [ -z "$DOMAINS_TO_TEST" ]; then - log_skip "$TESTNAME SKIP - no supported domains remain after SoC filter ($SOC_MACHINE)" - echo "$TESTNAME : SKIP" >"$RESULT_FILE" - exit 0 -fi + if [ "$domain_ready_status" -ne 0 ]; then + log_fail "$TESTNAME FAIL - $(domain_to_name "$d") is not ready, selection=$SELECTION_SOURCE" + echo "$TESTNAME : FAIL" >"$RESULT_FILE" + exit 0 + fi + + if ! fastrpc_domain_endpoint_available "$d"; then + label="$(domain_to_endpoint_label "$d")" + log_fail "$TESTNAME FAIL - $(domain_to_name "$d"): /dev/fastrpc-${label}[-secure] not found" + echo "$TESTNAME : FAIL" >"$RESULT_FILE" + exit 0 + fi + +done log_info "Domain mode: $DOMAIN_MODE" +log_info "Domain selection source: $SELECTION_SOURCE" log_info "Domains to test: $DOMAINS_TO_TEST" # Build human-readable domain names @@ -299,23 +432,23 @@ log_info "PD mode: $PD_MODE" # -------------------- Buffering tool availability --------------- HAVE_STDBUF=0; command -v stdbuf >/dev/null 2>&1 && HAVE_STDBUF=1 -HAVE_SCRIPT=0; command -v script >/dev/null 2>&1 && HAVE_SCRIPT=1 -HAVE_TIMEOUT=0; command -v timeout >/dev/null 2>&1 && HAVE_TIMEOUT=1 buf_label="none" if [ $HAVE_STDBUF -eq 1 ]; then buf_label="stdbuf -oL -eL" -elif [ $HAVE_SCRIPT -eq 1 ]; then - buf_label="script -q" fi -# -------------------- Logging root ----------------------------- -TS="$(date +%Y%m%d-%H%M%S)" -LOG_ROOT="./logs_${TESTNAME}_${TS}" -mkdir -p "$LOG_ROOT" || { log_error "Cannot create $LOG_ROOT"; echo "$TESTNAME : FAIL" >"$RESULT_FILE"; exit 0; } +log_info "Repeats: $REPEAT | Timeout: ${TIMEOUT}s | Buffering: $buf_label" -tmo_label="none"; [ -n "$TIMEOUT" ] && tmo_label="${TIMEOUT}s" -log_info "Repeats: $REPEAT | Timeout: $tmo_label | Buffering: $buf_label" +matrix_combinations=0 +for matrix_domain in $DOMAINS_TO_TEST; do + for matrix_pd in $(effective_pds_for_domain "$matrix_domain"); do + [ -n "$matrix_pd" ] && matrix_combinations=$((matrix_combinations + 1)) + done +done +matrix_invocations=$((matrix_combinations * REPEAT)) +matrix_timeout_budget=$((matrix_invocations * TIMEOUT)) +log_info "[FASTRPC-MATRIX] combinations=$matrix_combinations repeats=$REPEAT invocations=$matrix_invocations maximum_timeout_budget=${matrix_timeout_budget}s" # -------------------- Run loop --------------------------------- # Nested loop over domains and PDs @@ -359,7 +492,7 @@ for DOMAIN in $DOMAINS_TO_TEST; do iter_rc="$LOG_ROOT/${iter_tag}.rc" iter_cmd="$LOG_ROOT/${iter_tag}.cmd" iter_env="$LOG_ROOT/${iter_tag}.env" - iter_dmesg="$LOG_ROOT/${iter_tag}.dmesg" + iter_dmesg="$LOG_ROOT/${iter_tag}_kernel" iso_now="$(date -u +%Y-%m-%dT%H:%M:%SZ)" set -- -d "$DOMAIN" -t linux @@ -391,16 +524,13 @@ for DOMAIN in $DOMAINS_TO_TEST; do ( cd "$RUN_DIR" || exit 127 if [ $HAVE_STDBUF -eq 1 ]; then - runWithTimeoutIfSet stdbuf -oL -eL ./fastrpc_test "$@" - elif [ $HAVE_SCRIPT -eq 1 ]; then - cmd_str="./fastrpc_test$(cmd_to_string "$@")" - if [ -n "$TIMEOUT" ] && [ $HAVE_TIMEOUT -eq 1 ]; then - script -q -c "timeout $TIMEOUT $cmd_str" /dev/null - else - script -q -c "$cmd_str" /dev/null - fi + diag_run_with_timeout \ + "$TIMEOUT" \ + stdbuf -oL -eL ./fastrpc_test "$@" else - runWithTimeoutIfSet ./fastrpc_test "$@" + diag_run_with_timeout \ + "$TIMEOUT" \ + ./fastrpc_test "$@" fi ) >"$iter_log" 2>&1 rc=$? @@ -415,7 +545,11 @@ for DOMAIN in $DOMAINS_TO_TEST; do if [ "$rc" -ne 0 ]; then log_fail "$iter_tag: fastrpc_test exited $rc" - dmesg | tail -n 300 > "$iter_dmesg" 2>/dev/null + mkdir -p "$iter_dmesg" + scan_dmesg_errors \ + "$iter_dmesg" \ + "fastrpc|remoteproc|adsprpc|cdsprpc|sdsprpc" \ + "" || true log_dsp_remoteproc_status fi @@ -433,15 +567,10 @@ for DOMAIN in $DOMAINS_TO_TEST; do fi # Track invocation result immediately - # SM8850: libhap_example HAP_mem DMA handle not supported - treat as known skip if [ "$rc" -eq 0 ] && [ -r "$iter_log" ] && grep -F -q -e "All tests completed successfully" -e "All applicable tests PASSED" "$iter_log"; then PASS_COUNT=$((PASS_COUNT+1)) combo_pass=$((combo_pass+1)) log_pass "$iter_tag: success" - elif case "$SOC_MACHINE" in *SM8850*) true ;; *) false ;; esac && only_hap_example_failed "$iter_log"; then - PASS_COUNT=$((PASS_COUNT+1)) - combo_pass=$((combo_pass+1)) - log_pass "$iter_tag: success (libhap_example.so HAP_mem skipped on $SOC_MACHINE - DMA handle not supported)" else combo_fail=$((combo_fail+1)) log_warn "$iter_tag: success pattern not found" @@ -478,8 +607,8 @@ overall_subtests_pass=0 overall_subtests_fail=0 overall_subtests_skip=0 -# shellcheck disable=SC2034 # _pass_cnt/_fail_cnt consumed from tracker but not used in display -while IFS=: read -r domain pd_val _pass_cnt _fail_cnt combo_total_tests combo_pass_tests combo_fail_tests combo_skip_tests; do +# shellcheck disable=SC2034 # pass_cnt/fail_cnt consumed from tracker but not used in display +while IFS=: read -r domain pd_val pass_cnt fail_cnt combo_total_tests combo_pass_tests combo_fail_tests combo_skip_tests; do [ -z "$domain" ] && continue dom_name="$(domain_to_name "$domain")" diff --git a/Runner/utils/lib_fastrpc.sh b/Runner/utils/lib_fastrpc.sh index dc470019..a2e1e118 100755 --- a/Runner/utils/lib_fastrpc.sh +++ b/Runner/utils/lib_fastrpc.sh @@ -9,18 +9,22 @@ # Yocto/current: # libs : /usr/local/lib # test libs : /usr/local/lib/fastrpc_test -# skeletons : /usr/local/share/fastrpc_test/v75, v68 +# skeletons : dynamically discovered below /usr/local/share/fastrpc_test # # Debian: # libs : /usr/lib/ # test libs : /usr/lib//fastrpc_test -# skeletons : /usr/share/fastrpc_test/v75, v68 +# skeletons : dynamically discovered below /usr/share/fastrpc_test # # Optional environment overrides: # FASTRPC_LIB_SYS_DIR # FASTRPC_LIB_TEST_DIR # FASTRPC_SKEL_BASE +# fastrpc_append_word_unique CURRENT NEW +# Append NEW to the space-separated CURRENT list when it is non-empty and absent. +# Inputs: two strings. Output: the resulting list on stdout. +# Returns: 0. Side effects: none. fastrpc_append_word_unique() { current="$1" new="$2" @@ -44,6 +48,10 @@ fastrpc_append_word_unique() { fi } +# fastrpc_append_colon_dir CURRENT_PATH NEW_DIR +# Append an existing NEW_DIR to a colon-separated path without duplicates. +# Inputs: a path list and directory. Output: the resulting path on stdout. +# Returns: 0. Side effects: probes NEW_DIR with test -d only. fastrpc_append_colon_dir() { current_path="$1" new_dir="$2" @@ -72,13 +80,21 @@ fastrpc_append_colon_dir() { esac } -fastrpc_first_existing_word_dir() { +# fastrpc_first_dir_with_file CANDIDATE_DIRS FILE_PATTERN +# Find the first space-separated candidate directory containing a matching file. +# Inputs: directory list and find-compatible basename pattern. Output: directory on stdout. +# Returns: 0 when found, 1 otherwise. Side effects: none. +fastrpc_first_dir_with_file() { candidate_dirs="$1" + file_pattern="$2" for candidate_dir in $candidate_dirs; do [ -n "$candidate_dir" ] || continue - if [ -d "$candidate_dir" ]; then + if [ -d "$candidate_dir" ] && + find "$candidate_dir" -maxdepth 1 \( -type f -o -type l \) \ + -name "$file_pattern" -print -quit 2>/dev/null | + grep -q .; then printf '%s\n' "$candidate_dir" return 0 fi @@ -87,6 +103,82 @@ fastrpc_first_existing_word_dir() { return 1 } +# fastrpc_find_file_in_dirs CANDIDATE_DIRS FILE_PATTERN +# Find the first matching regular file or symlink directly below candidate directories. +# Inputs: space-separated directories and basename pattern. Output: file path on stdout. +# Returns: 0 when found, 1 otherwise. Side effects: none. +fastrpc_find_file_in_dirs() { + candidate_dirs="$1" + file_pattern="$2" + + for candidate_dir in $candidate_dirs; do + [ -d "$candidate_dir" ] || continue + + candidate_file="$( + find "$candidate_dir" -maxdepth 1 \( -type f -o -type l \) \ + -name "$file_pattern" -print -quit 2>/dev/null + )" + if [ -n "$candidate_file" ]; then + printf '%s\n' "$candidate_file" + return 0 + fi + done + + return 1 +} + +# fastrpc_find_file_in_trees CANDIDATE_DIRS FILE_PATTERN +# Recursively find the first matching regular file or symlink in candidate trees. +# Inputs: space-separated tree roots and basename pattern. Output: file path on stdout. +# Returns: 0 when found, 1 otherwise. Side effects: none. +fastrpc_find_file_in_trees() { + candidate_dirs="$1" + file_pattern="$2" + + for candidate_dir in $candidate_dirs; do + [ -d "$candidate_dir" ] || continue + + candidate_file="$( + find "$candidate_dir" \( -type f -o -type l \) \ + -name "$file_pattern" -print -quit 2>/dev/null + )" + if [ -n "$candidate_file" ]; then + printf '%s\n' "$candidate_file" + return 0 + fi + done + + return 1 +} + +# fastrpc_find_skeleton_dirs SKELETON_BASES +# Discover unique directories containing any required FastRPC DSP skeleton. +# Input: space-separated tree roots. Output: colon-separated directories on stdout. +# Returns: 0. Side effects: none. +fastrpc_find_skeleton_dirs() { + skeleton_bases="$1" + skeleton_dirs="" + + for skeleton_base in $skeleton_bases; do + [ -d "$skeleton_base" ] || continue + + while IFS= read -r skeleton_dir; do + [ -n "$skeleton_dir" ] || continue + skeleton_dirs="$(fastrpc_append_colon_dir "$skeleton_dirs" "$skeleton_dir")" + done </dev/null | sort -u) +EOF + done + + printf '%s\n' "$skeleton_dirs" +} + +# fastrpc_detect_multiarch_triplet +# Detect the target multiarch triplet from image tools or the running architecture. +# Inputs: none. Output: triplet or an empty line on stdout. +# Returns: 0. Side effects: executes read-only compiler, package, and uname probes. fastrpc_detect_multiarch_triplet() { triplet="" @@ -115,6 +207,11 @@ fastrpc_detect_multiarch_triplet() { printf '%s\n' "$triplet" } +# fastrpc_discover_runtime_layout +# Discover FastRPC system, test, and DSP skeleton library locations. +# Inputs: optional FASTRPC_* path overrides and healthcheck DSP path globals. +# Outputs: FASTRPC_*_CHECKED and FASTRPC_RESOLVED_* shell globals, no stdout contract. +# Returns: 0. Side effects: read-only filesystem traversal. fastrpc_discover_runtime_layout() { FASTRPC_MULTIARCH_TRIPLET="$(fastrpc_detect_multiarch_triplet)" @@ -134,7 +231,9 @@ fastrpc_discover_runtime_layout() { # Yocto/current layout. FASTRPC_LIB_SYS_DIRS_CHECKED="$(fastrpc_append_word_unique "$FASTRPC_LIB_SYS_DIRS_CHECKED" "/usr/local/lib")" + FASTRPC_LIB_SYS_DIRS_CHECKED="$(fastrpc_append_word_unique "$FASTRPC_LIB_SYS_DIRS_CHECKED" "/usr/local/lib64")" FASTRPC_LIB_TEST_DIRS_CHECKED="$(fastrpc_append_word_unique "$FASTRPC_LIB_TEST_DIRS_CHECKED" "/usr/local/lib/fastrpc_test")" + FASTRPC_LIB_TEST_DIRS_CHECKED="$(fastrpc_append_word_unique "$FASTRPC_LIB_TEST_DIRS_CHECKED" "/usr/local/lib64/fastrpc_test")" FASTRPC_SKEL_BASES_CHECKED="$(fastrpc_append_word_unique "$FASTRPC_SKEL_BASES_CHECKED" "/usr/local/share/fastrpc_test")" # Debian/multiarch layout. @@ -145,25 +244,194 @@ fastrpc_discover_runtime_layout() { # Generic fallbacks. FASTRPC_LIB_SYS_DIRS_CHECKED="$(fastrpc_append_word_unique "$FASTRPC_LIB_SYS_DIRS_CHECKED" "/usr/lib")" + FASTRPC_LIB_SYS_DIRS_CHECKED="$(fastrpc_append_word_unique "$FASTRPC_LIB_SYS_DIRS_CHECKED" "/usr/lib64")" FASTRPC_LIB_TEST_DIRS_CHECKED="$(fastrpc_append_word_unique "$FASTRPC_LIB_TEST_DIRS_CHECKED" "/usr/lib/fastrpc_test")" + FASTRPC_LIB_TEST_DIRS_CHECKED="$(fastrpc_append_word_unique "$FASTRPC_LIB_TEST_DIRS_CHECKED" "/usr/lib64/fastrpc_test")" FASTRPC_SKEL_BASES_CHECKED="$(fastrpc_append_word_unique "$FASTRPC_SKEL_BASES_CHECKED" "/usr/share/fastrpc_test")" - FASTRPC_RESOLVED_LIB_SYS_DIR="$(fastrpc_first_existing_word_dir "$FASTRPC_LIB_SYS_DIRS_CHECKED" || true)" - FASTRPC_RESOLVED_LIB_TEST_DIR="$(fastrpc_first_existing_word_dir "$FASTRPC_LIB_TEST_DIRS_CHECKED" || true)" - FASTRPC_RESOLVED_SKEL_BASE="$(fastrpc_first_existing_word_dir "$FASTRPC_SKEL_BASES_CHECKED" || true)" + FASTRPC_RESOLVED_LIB_SYS_DIR="$( + fastrpc_first_dir_with_file "$FASTRPC_LIB_SYS_DIRS_CHECKED" 'lib*dsprpc.so*' || true + )" + FASTRPC_RESOLVED_LIB_SYS_PATH="" + for library_dir in $FASTRPC_LIB_SYS_DIRS_CHECKED; do + if find "$library_dir" -maxdepth 1 \( -type f -o -type l \) \ + -name 'lib*dsprpc.so*' -print -quit 2>/dev/null | + grep -q .; then + FASTRPC_RESOLVED_LIB_SYS_PATH="$( + fastrpc_append_colon_dir "$FASTRPC_RESOLVED_LIB_SYS_PATH" "$library_dir" + )" + fi + done + + FASTRPC_RESOLVED_LIB_TEST_PATH="" + for test_library_dir in $FASTRPC_LIB_TEST_DIRS_CHECKED; do + if find "$test_library_dir" -maxdepth 1 \( -type f -o -type l \) \ + \( -name 'libcalculator.so*' -o -name 'libhap_example.so*' -o -name 'libmultithreading.so*' \) \ + -print -quit 2>/dev/null | grep -q .; then + FASTRPC_RESOLVED_LIB_TEST_PATH="$( + fastrpc_append_colon_dir "$FASTRPC_RESOLVED_LIB_TEST_PATH" "$test_library_dir" + )" + fi + done + if [ -n "${FASTRPC_HEALTHCHECK_DSP_LIB_DIR:-}" ]; then + FASTRPC_SKEL_BASES_CHECKED="$( + fastrpc_append_word_unique \ + "$FASTRPC_SKEL_BASES_CHECKED" \ + "$FASTRPC_HEALTHCHECK_DSP_LIB_DIR" + )" + fi + + FASTRPC_RESOLVED_SKEL_PATH="$(fastrpc_find_skeleton_dirs "$FASTRPC_SKEL_BASES_CHECKED")" +} + +# fastrpc_missing_test_libraries +# Identify required host test libraries absent from the discovered search directories. +# Inputs: FASTRPC_LIB_TEST_DIRS_CHECKED. Output: space-separated names on stdout. +# Returns: 0. Side effects: read-only filesystem traversal. +fastrpc_missing_test_libraries() { + missing_libraries="" + + for test_library in libcalculator.so libhap_example.so libmultithreading.so; do + found_library=0 + + for test_dir in $FASTRPC_LIB_TEST_DIRS_CHECKED; do + if find "$test_dir" -maxdepth 1 \( -type f -o -type l \) \ + -name "${test_library}*" -print -quit 2>/dev/null | + grep -q .; then + found_library=1 + break + fi + done + + if [ "$found_library" -eq 0 ]; then + missing_libraries="$(fastrpc_append_word_unique "$missing_libraries" "$test_library")" + fi + done + + printf '%s\n' "$missing_libraries" +} + +# fastrpc_missing_skeleton_libraries +# Identify required DSP skeleton libraries absent from the discovered search trees. +# Inputs: FASTRPC_SKEL_BASES_CHECKED. Output: space-separated names on stdout. +# Returns: 0. Side effects: read-only filesystem traversal. +fastrpc_missing_skeleton_libraries() { + missing_skeletons="" + + for skeleton_library in \ + libcalculator_skel.so \ + libhap_example_skel.so \ + libmultithreading_skel.so; do + found_skeleton=0 + + for skeleton_base in $FASTRPC_SKEL_BASES_CHECKED; do + if find "$skeleton_base" \( -type f -o -type l \) \ + -name "${skeleton_library}*" -print -quit 2>/dev/null | + grep -q .; then + found_skeleton=1 + break + fi + done + + if [ "$found_skeleton" -eq 0 ]; then + missing_skeletons="$( + fastrpc_append_word_unique "$missing_skeletons" "$skeleton_library" + )" + fi + done + + printf '%s\n' "$missing_skeletons" +} + +# fastrpc_missing_domain_system_libraries DOMAIN_IDS +# Identify runtime libraries absent for the selected FastRPC domains. +# Input: space-separated domain IDs. Output: space-separated DOMAIN:LIBRARY entries. +# Returns: 0. Side effects: read-only filesystem traversal. +fastrpc_missing_domain_system_libraries() { + selected_domains="$1" + missing_libraries="" + + for selected_domain in $selected_domains; do + required_library="$(fastrpc_domain_field "$selected_domain" 7)" + [ -n "$required_library" ] || continue + + if ! fastrpc_find_file_in_dirs \ + "$FASTRPC_LIB_SYS_DIRS_CHECKED" \ + "${required_library}*" >/dev/null; then + missing_entry="$(domain_to_name "$selected_domain"):${required_library}" + missing_libraries="$( + fastrpc_append_word_unique "$missing_libraries" "$missing_entry" + )" + fi + done + + printf '%s\n' "$missing_libraries" +} + +# fastrpc_validate_runtime_artifacts DOMAIN_IDS +# Validate the FastRPC binary's host dependencies and selected-domain artifacts. +# Inputs: space-separated domain IDs, RUN_BIN, and discovered FASTRPC_* globals. +# Output: no stdout contract. +# Returns: 0 when usable, 1 otherwise, and sets FASTRPC_ARTIFACT_ERROR. +# Side effects: runs read-only find and optional ldd probes. +fastrpc_validate_runtime_artifacts() { + selected_domains="$1" + FASTRPC_ARTIFACT_ERROR="" + missing_domain_libraries="$( + fastrpc_missing_domain_system_libraries "$selected_domains" + )" + missing_test_libraries="$(fastrpc_missing_test_libraries)" + missing_skeleton_libraries="$(fastrpc_missing_skeleton_libraries)" + + if [ -n "$missing_domain_libraries" ]; then + FASTRPC_ARTIFACT_ERROR="missing selected-domain system libraries: $missing_domain_libraries" + elif [ -z "$FASTRPC_RESOLVED_LIB_SYS_DIR" ]; then + FASTRPC_ARTIFACT_ERROR="no FastRPC system library was found" + elif [ -n "$missing_test_libraries" ]; then + FASTRPC_ARTIFACT_ERROR="missing test libraries: $missing_test_libraries" + elif [ -n "$missing_skeleton_libraries" ]; then + FASTRPC_ARTIFACT_ERROR="missing DSP skeleton libraries: $missing_skeleton_libraries" + elif [ -z "$FASTRPC_RESOLVED_SKEL_PATH" ]; then + FASTRPC_ARTIFACT_ERROR="no directory containing required DSP skeleton libraries was found" + elif command -v ldd >/dev/null 2>&1 && + ldd "$RUN_BIN" 2>/dev/null | grep -q 'not found'; then + FASTRPC_ARTIFACT_ERROR="fastrpc_test has unresolved host library dependencies" + fi - FASTRPC_RESOLVED_SKEL_PATH="" - if [ -n "$FASTRPC_RESOLVED_SKEL_BASE" ]; then - FASTRPC_RESOLVED_SKEL_PATH="$(fastrpc_append_colon_dir "$FASTRPC_RESOLVED_SKEL_PATH" "$FASTRPC_RESOLVED_SKEL_BASE/v75")" - FASTRPC_RESOLVED_SKEL_PATH="$(fastrpc_append_colon_dir "$FASTRPC_RESOLVED_SKEL_PATH" "$FASTRPC_RESOLVED_SKEL_BASE/v68")" + if [ -z "$FASTRPC_ARTIFACT_ERROR" ] && command -v ldd >/dev/null 2>&1; then + for test_library in libcalculator.so libhap_example.so libmultithreading.so; do + test_library_path="$( + fastrpc_find_file_in_dirs \ + "$FASTRPC_LIB_TEST_DIRS_CHECKED" \ + "${test_library}*" || true + )" + + if [ -n "$test_library_path" ] && + ldd "$test_library_path" 2>/dev/null | grep -q 'not found'; then + FASTRPC_ARTIFACT_ERROR="$test_library has unresolved host library dependencies" + break + fi + done fi + + [ -z "$FASTRPC_ARTIFACT_ERROR" ] } +# fastrpc_export_runtime_env +# Build and export host and DSP library search paths from discovered directories. +# Inputs: FASTRPC_RESOLVED_* globals and existing library-path environment values. +# Outputs: exported LD_LIBRARY_PATH and DSP-specific *_LIBRARY_PATH variables. +# Returns: 0. Side effects: mutates the current shell environment. fastrpc_export_runtime_env() { new_ld_library_path="" - new_ld_library_path="$(fastrpc_append_colon_dir "$new_ld_library_path" "$FASTRPC_RESOLVED_LIB_SYS_DIR")" - new_ld_library_path="$(fastrpc_append_colon_dir "$new_ld_library_path" "$FASTRPC_RESOLVED_LIB_TEST_DIR")" + for resolved_dir in $(printf '%s' "$FASTRPC_RESOLVED_LIB_SYS_PATH" | tr ':' ' '); do + new_ld_library_path="$(fastrpc_append_colon_dir "$new_ld_library_path" "$resolved_dir")" + done + + for resolved_dir in $(printf '%s' "$FASTRPC_RESOLVED_LIB_TEST_PATH" | tr ':' ' '); do + new_ld_library_path="$(fastrpc_append_colon_dir "$new_ld_library_path" "$resolved_dir")" + done if [ -n "${LD_LIBRARY_PATH:-}" ]; then if [ -n "$new_ld_library_path" ]; then @@ -188,17 +456,21 @@ fastrpc_export_runtime_env() { fi } +# fastrpc_log_runtime_layout +# Log discovered FastRPC paths and the resolved location of every required artifact. +# Inputs: discovered FASTRPC_* globals. Output: no machine-readable stdout contract. +# Returns: 0. Side effects: emits informational and warning log records. fastrpc_log_runtime_layout() { log_info "FastRPC multiarch triplet: ${FASTRPC_MULTIARCH_TRIPLET:-}" - if [ -n "$FASTRPC_RESOLVED_LIB_SYS_DIR" ]; then - log_info "FastRPC system library dir: $FASTRPC_RESOLVED_LIB_SYS_DIR" + if [ -n "$FASTRPC_RESOLVED_LIB_SYS_PATH" ]; then + log_info "FastRPC system library path: $FASTRPC_RESOLVED_LIB_SYS_PATH" else log_warn "No FastRPC system library dir found. Checked: $FASTRPC_LIB_SYS_DIRS_CHECKED" fi - if [ -n "$FASTRPC_RESOLVED_LIB_TEST_DIR" ]; then - log_info "FastRPC test library dir: $FASTRPC_RESOLVED_LIB_TEST_DIR" + if [ -n "$FASTRPC_RESOLVED_LIB_TEST_PATH" ]; then + log_info "FastRPC test library path: $FASTRPC_RESOLVED_LIB_TEST_PATH" else log_warn "No FastRPC test library dir found. Checked: $FASTRPC_LIB_TEST_DIRS_CHECKED" fi @@ -208,8 +480,45 @@ fastrpc_log_runtime_layout() { else log_warn "No DSP skeleton dirs found. Checked bases: $FASTRPC_SKEL_BASES_CHECKED" fi + + runtime_libraries="$( + fastrpc_domain_table | awk -F '|' '!seen[$7]++ {print $7}' + )" + for runtime_library in $runtime_libraries; do + runtime_library_path="$( + fastrpc_find_file_in_dirs \ + "$FASTRPC_LIB_SYS_DIRS_CHECKED" \ + "${runtime_library}*" || true + )" + log_info "[FASTRPC-ARTIFACT] type=runtime-library name=$runtime_library path=${runtime_library_path:-missing}" + done + + for test_library in libcalculator.so libhap_example.so libmultithreading.so; do + test_library_path="$( + fastrpc_find_file_in_dirs \ + "$FASTRPC_LIB_TEST_DIRS_CHECKED" \ + "${test_library}*" || true + )" + log_info "[FASTRPC-ARTIFACT] type=test-library name=$test_library path=${test_library_path:-missing}" + done + + for skeleton_library in \ + libcalculator_skel.so \ + libhap_example_skel.so \ + libmultithreading_skel.so; do + skeleton_library_path="$( + fastrpc_find_file_in_trees \ + "$FASTRPC_SKEL_BASES_CHECKED" \ + "${skeleton_library}*" || true + )" + log_info "[FASTRPC-ARTIFACT] type=dsp-skeleton name=$skeleton_library path=${skeleton_library_path:-missing}" + done } +# fastrpc_setup_runtime_layout +# Discover, report, and export the complete FastRPC runtime library layout. +# Inputs: optional FASTRPC_* path overrides. Output: discovered/exported globals. +# Returns: 0. Side effects: logs discovery and mutates library-path environment values. fastrpc_setup_runtime_layout() { fastrpc_discover_runtime_layout fastrpc_log_runtime_layout @@ -223,6 +532,10 @@ fastrpc_setup_runtime_layout() { # -------------------- FastRPC test orchestration helpers -------------------- +# log_debug MESSAGE... +# Emit a diagnostic message only when VERBOSE is set to 1. +# Inputs: message arguments and VERBOSE. Output: no stdout contract. +# Returns: 0. Side effects: logs to stderr when enabled. # shellcheck disable=SC2317 log_debug() { if [ "${VERBOSE:-0}" -eq 1 ]; then @@ -230,6 +543,10 @@ log_debug() { fi } +# cmd_to_string ARG... +# Render command arguments as a readable shell-like string for diagnostic logging. +# Inputs: arbitrary command arguments. Output: one escaped string on stdout. +# Returns: 0. Side effects: none. The output is descriptive and must not be evaluated. cmd_to_string() { out="" for a in "$@"; do @@ -246,6 +563,10 @@ cmd_to_string() { printf "%s" "$out" } +# extract_test_summary_counts LOG_FILE +# Parse the final FastRPC test totals from a retained command log. +# Input: readable log path. Output: total:passed:failed:skipped on stdout. +# Returns: 0 and substitutes zero for missing or malformed fields. Side effects: none. extract_test_summary_counts() { log_file="$1" @@ -262,18 +583,12 @@ extract_test_summary_counts() { printf '%s:%s:%s:%s\n' "$total" "$passed" "$failed" "$skipped" } -# Returns true if the only failing subtest is libhap_example.so. -# Used to treat HAP_mem DMA failures as known-skip on affected SoCs. -only_hap_example_failed() { - log_file="$1" - - [ -r "$log_file" ] || return 1 - grep -F -q "[FAIL]" "$log_file" || return 1 - ! grep -F "[FAIL]" "$log_file" | grep -q -v "libhap_example.so" -} - +# log_dsp_remoteproc_status +# Log runtime remoteproc state for every FastRPC firmware alias in the domain table. +# Inputs: runtime DT and remoteproc sysfs through shared helpers. Output: no stdout contract. +# Returns: 0. Side effects: emits informational logs only. log_dsp_remoteproc_status() { - fw_list="adsp mdsp sdsp cdsp cdsp0 cdsp1 gdsp0 gdsp1 gpdsp0 gpdsp1" + fw_list="$(fastrpc_domain_table | awk -F '|' '{print $5}')" any=0 for fw in $fw_list; do @@ -297,32 +612,80 @@ __RPROC__ [ "$any" -eq 0 ] && log_info "rproc: no *dsp remoteproc entries detected via DT" } +# fastrpc_domain_table +# Emit the protocol-defined FastRPC domain metadata used by discovery and policy. +# Fields: ID, name, endpoint, URI suffix, firmware aliases, PD modes, runtime library. +# Inputs: none. Output: pipe-separated domain rows on stdout. +# Returns: 0. Side effects: none. +fastrpc_domain_table() { + cat <<'EOF' +0|ADSP|adsp|adsp|adsp|0|libadsprpc.so +1|MDSP|mdsp|mdsp|mdsp|0|libmdsprpc.so +2|SDSP|sdsp|sdsp|sdsp|0|libsdsprpc.so +3|CDSP|cdsp|cdsp|cdsp cdsp0|0 1|libcdsprpc.so +4|CDSP1|cdsp1|cdsp1|cdsp1|0 1|libcdsprpc.so +5|GDSP0|gdsp0|gdsp0|gdsp0 gpdsp0|0 1|libcdsprpc.so +6|GDSP1|gdsp1|gdsp1|gdsp1 gpdsp1|0 1|libcdsprpc.so +EOF +} + +# fastrpc_domain_field DOMAIN_ID FIELD_NUMBER +# Read one field from the FastRPC domain table for a numeric domain identifier. +# Inputs: domain ID and one-based field number. Output: matching field on stdout. +# Returns: awk status, normally 0 even when no row matches. Side effects: none. +fastrpc_domain_field() { + requested_domain="$1" + requested_field="$2" + + fastrpc_domain_table | awk -F '|' -v domain="$requested_domain" -v field="$requested_field" ' + $1 == domain { + print $field + exit + } + ' +} + +# name_to_domain DOMAIN_NAME +# Map a case-insensitive public domain name or supported alias to its numeric ID. +# Input: one domain name. Output: numeric domain ID on stdout when recognized. +# Returns: awk status, normally 0 even when unmapped. Side effects: none. name_to_domain() { - case "$(printf "%s" "$1" | tr '[:upper:]' '[:lower:]')" in - adsp) echo 0 ;; - mdsp) echo 1 ;; - sdsp) echo 2 ;; - cdsp) echo 3 ;; - cdsp1) echo 4 ;; - gpdsp0|gdsp0) echo 5 ;; - gpdsp1|gdsp1) echo 6 ;; - *) echo "" ;; - esac + requested_name="$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]')" + + fastrpc_domain_table | awk -F '|' -v requested="$requested_name" ' + { + alias_count = split($5, aliases, " ") + for (alias_number = 1; alias_number <= alias_count; alias_number++) { + if (requested == aliases[alias_number]) { + print $1 + exit + } + } + } + ' } +# domain_to_name DOMAIN_ID +# Map a numeric FastRPC domain identifier to its public display name. +# Input: numeric domain ID. Output: domain name or UNKNOWN on stdout. +# Returns: 0. Side effects: none. domain_to_name() { - case "$1" in - 0) echo "ADSP" ;; - 1) echo "MDSP" ;; - 2) echo "SDSP" ;; - 3) echo "CDSP" ;; - 4) echo "CDSP1" ;; - 5) echo "GPDSP0" ;; - 6) echo "GPDSP1" ;; - *) echo "UNKNOWN" ;; - esac + domain_name="$(fastrpc_domain_field "$1" 2)" + printf '%s\n' "${domain_name:-UNKNOWN}" } +# domain_to_endpoint_label DOMAIN_ID +# Return the device-node label associated with a FastRPC domain. +# Input: numeric domain ID. Output: endpoint label or an empty line on stdout. +# Returns: the domain-table lookup status. Side effects: none. +domain_to_endpoint_label() { + fastrpc_domain_field "$1" 3 +} + +# append_unique CURRENT NEW +# Append NEW to a space-separated list when it is not already present. +# Inputs: current list and new word. Output: resulting list on stdout. +# Returns: 0. Side effects: none. append_unique() { current="$1" new="$2" @@ -337,21 +700,256 @@ append_unique() { [ -n "$current" ] && printf "%s %s" "$current" "$new" || printf "%s" "$new" } -canonicalize_domain_name() { - norm="$(printf "%s" "$1" | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]')" +# fastrpc_capture_healthcheck LOG_FILE TIMEOUT_SECONDS +# Run the image-provided FastRPC healthcheck under the shared bounded runner. +# Inputs: retained log path, positive timeout, and optional FASTRPC_HEALTHCHECK_BIN. +# Output: no stdout contract. Returns: 0 on success, 1 on execution failure, 2 if absent. +# Side effects: truncates LOG_FILE and emits healthcheck diagnostic logs. +fastrpc_capture_healthcheck() { + healthcheck_log="$1" + healthcheck_timeout="$2" + healthcheck_bin="${FASTRPC_HEALTHCHECK_BIN:-}" + + if [ -z "$healthcheck_bin" ]; then + healthcheck_bin="$(command -v fastrpc-healthcheck 2>/dev/null || true)" + fi + + if [ -z "$healthcheck_bin" ] && [ -x "${BIN_DIR:-/usr/bin}/fastrpc-healthcheck" ]; then + healthcheck_bin="${BIN_DIR:-/usr/bin}/fastrpc-healthcheck" + fi + + [ -n "$healthcheck_bin" ] || return 2 + + : >"$healthcheck_log" + log_info "[FASTRPC-HEALTHCHECK] command=$healthcheck_bin timeout=${healthcheck_timeout}s artifact=$healthcheck_log" + + diag_run_with_timeout "$healthcheck_timeout" "$healthcheck_bin" >"$healthcheck_log" 2>&1 + healthcheck_rc=$? + + if [ "$healthcheck_rc" -eq 0 ]; then + return 0 + fi + + log_warn "[FASTRPC-HEALTHCHECK] command failed rc=$healthcheck_rc artifact=$healthcheck_log" + return 1 +} + +# fastrpc_parse_healthcheck LOG_FILE TSV_FILE +# Parse the healthcheck DSP capability table and advertised DSP library path. +# Inputs: raw healthcheck log and destination TSV path. Output: no stdout contract. +# Returns: 0 when at least one DSP row is parsed, 1 otherwise. +# Side effects: replaces TSV_FILE and sets FASTRPC_HEALTHCHECK_DSP_LIB_DIR. +fastrpc_parse_healthcheck() { + healthcheck_log="$1" + healthcheck_tsv="$2" + + FASTRPC_HEALTHCHECK_DSP_LIB_DIR="$( + sed -n 's/^[[:space:]]*DSP dynamic libs path[[:space:]]*:[[:space:]]*//p' \ + "$healthcheck_log" | tail -n 1 + )" + + awk ' + BEGIN { + OFS = "\t" + in_table = 0 + } + $1 == "DSP" && $2 == "State" && $3 == "SignedPD" { + in_table = 1 + next + } + in_table && $1 ~ /^-+$/ { + next + } + in_table && NF >= 5 { + name = toupper($1) + if (name ~ /^(ADSP|MDSP|SDSP|CDSP|CDSP1|GDSP0|GDSP1|GPDSP0|GPDSP1)$/) { + support = tolower($5) + for (column = 6; column <= NF; column++) { + support = support " " tolower($column) + } + print name, tolower($2), tolower($3), tolower($4), support + } + } + ' "$healthcheck_log" >"$healthcheck_tsv" + + [ -s "$healthcheck_tsv" ] +} - case "$norm" in - cdsp0) echo "cdsp" ;; - gdsp0) echo "gpdsp0" ;; - gdsp1) echo "gpdsp1" ;; - *) printf "%s" "$norm" ;; +# fastrpc_healthcheck_record DOMAIN_ID +# Select the parsed healthcheck row for a domain, accepting public GDSP aliases. +# Input: numeric domain ID and FASTRPC_HEALTHCHECK_TSV. Output: one TSV row on stdout. +# Returns: awk status, normally 0 even when no row matches. Side effects: none. +fastrpc_healthcheck_record() { + domain_id="$1" + healthcheck_name="$(fastrpc_domain_field "$domain_id" 2)" + + case "$healthcheck_name" in + GDSP0) healthcheck_pattern='GDSP0|GPDSP0' ;; + GDSP1) healthcheck_pattern='GDSP1|GPDSP1' ;; + *) healthcheck_pattern="$healthcheck_name" ;; esac + + awk -F '\t' -v names="$healthcheck_pattern" ' + BEGIN { + count = split(names, accepted, "|") + } + { + for (item = 1; item <= count; item++) { + if ($1 == accepted[item]) { + print + exit + } + } + } + ' "${FASTRPC_HEALTHCHECK_TSV:-/dev/null}" +} + +# fastrpc_log_healthcheck_records +# Log every parsed FastRPC domain capability record for live CI evidence. +# Input: FASTRPC_HEALTHCHECK_TSV. Output: no machine-readable stdout contract. +# Returns: 0. Side effects: emits informational logs. +fastrpc_log_healthcheck_records() { + while IFS="$(printf '\t')" read -r hc_name hc_state hc_signed hc_unsigned hc_support; do + [ -n "$hc_name" ] || continue + log_info "[FASTRPC-CAPABILITY] domain=$hc_name state=$hc_state signed_pd=$hc_signed unsigned_pd=$hc_unsigned support=$hc_support source=fastrpc-healthcheck" + done <"$FASTRPC_HEALTHCHECK_TSV" +} + +# fastrpc_healthcheck_supported_domains +# Select online, FastRPC-supported domain IDs from the parsed healthcheck table. +# Input: FASTRPC_HEALTHCHECK_TSV. Output: one numeric domain ID per stdout line. +# Returns: 0. Side effects: logs exclusion and mapping diagnostics to stderr. +fastrpc_healthcheck_supported_domains() { + while IFS="$(printf '\t')" read -r \ + hc_name hc_state hc_signed hc_unsigned hc_support; do + if [ "$hc_state" != "online" ]; then + log_info "[FASTRPC-DISCOVERY] domain=$hc_name eligible=no reason=healthcheck-state-$hc_state" >&2 + continue + fi + + if [ "$hc_support" != "yes" ]; then + log_info "[FASTRPC-DISCOVERY] domain=$hc_name eligible=no reason=healthcheck-support-$hc_support" >&2 + continue + fi + + hc_domain="$(name_to_domain "$hc_name")" + if [ -n "$hc_domain" ]; then + printf '%s\n' "$hc_domain" + else + log_warn "[FASTRPC-DISCOVERY] domain=$hc_name eligible=no reason=unmapped-healthcheck-domain" >&2 + fi + done <"$FASTRPC_HEALTHCHECK_TSV" +} + +# fastrpc_healthcheck_domain_ready DOMAIN_ID +# Enforce that an explicitly selected domain is listed, online, and supported. +# Input: numeric domain ID and FASTRPC_HEALTHCHECK_TSV. Output: no stdout contract. +# Returns: 0 when ready, 1 when unhealthy, 2 when unlisted. +# Side effects: emits failure diagnostics. +fastrpc_healthcheck_domain_ready() { + healthcheck_record="$(fastrpc_healthcheck_record "$1")" + if [ -z "$healthcheck_record" ]; then + log_fail "[FASTRPC-CAPABILITY] domain=$(domain_to_name "$1") expected=healthcheck-record observed=not-listed artifact=$FASTRPC_HEALTHCHECK_TSV" + return 2 + fi + + IFS="$(printf '\t')" read -r hc_name hc_state hc_signed hc_unsigned hc_support </dev/null || true + )" + [ -n "$remoteproc_entries" ] || continue + + while IFS='|' read -r remoteproc_path remoteproc_state remoteproc_firmware remoteproc_name; do + [ -n "$remoteproc_path" ] || continue + remoteproc_record="${remoteproc_state}|${remoteproc_path}|${remoteproc_firmware}|${remoteproc_name}" + + if [ "$remoteproc_state" = "running" ]; then + printf '%s\n' "$remoteproc_record" + return 0 + fi + + if [ -z "$fallback_record" ]; then + fallback_record="$remoteproc_record" + fi + done <&2 - for fw in adsp mdsp sdsp cdsp cdsp0 cdsp1 gpdsp0 gpdsp1 gdsp0 gdsp1; do + if [ -s "${FASTRPC_HEALTHCHECK_TSV:-}" ]; then + fastrpc_healthcheck_supported_domains + return + fi + + for fw in $(fastrpc_domain_table | awk -F '|' '{print $5}'); do entries="$(get_remoteproc_by_firmware "$fw" "" all 2>/dev/null || true)" if [ -n "$entries" ]; then @@ -366,25 +964,37 @@ discover_supported_domains() { [ -n "$nameguess" ] || continue - canon="$(canonicalize_domain_name "$nameguess")" - d="$(name_to_domain "$canon")" + d="$(name_to_domain "$nameguess")" if [ -n "$d" ]; then - printf '%s\n' "$d" - log_debug "discover: fw=$fw rname=$rname rfirm=$rfirm canon=$canon domain=$d state=$rstate" + if [ "$rstate" != "running" ]; then + log_info "[FASTRPC-DISCOVERY] domain=$(domain_to_name "$d") eligible=no reason=remoteproc-state-$rstate" >&2 + else + if fastrpc_domain_endpoint_available "$d"; then + printf '%s\n' "$d" + log_debug "discover: fw=$fw rname=$rname rfirm=$rfirm domain=$d state=$rstate" + else + label="$(domain_to_endpoint_label "$d")" + log_info "[FASTRPC-DISCOVERY] domain=$(domain_to_name "$d") eligible=no reason=endpoint-absent expected=/dev/fastrpc-${label}[-secure]" >&2 + fi + fi else - log_debug "discover: fw=$fw rname=$rname rfirm=$rfirm canon=$canon domain=" + log_debug "discover: fw=$fw rname=$rname rfirm=$rfirm domain=" fi done <&2 + else + printf '%s\n' "$d" + log_debug "discover: fw=$fw dt-only domain=$d" + fi fi else log_debug "discover: fw=$fw not present" @@ -392,6 +1002,11 @@ EOF done } +# resolve_domains_to_test +# Apply CLI, environment, and dynamic-discovery precedence to the domain selection. +# Inputs: CLI_DOMAIN*, DOMAIN_MODE, FASTRPC_DOMAIN*, and runtime discovery. +# Output: unique space-separated valid domain IDs on stdout. Returns: 0. +# Side effects: logs invalid entries and verbose diagnostics. resolve_domains_to_test() { resolved="" @@ -413,38 +1028,59 @@ resolve_domains_to_test() { valid="" for d in $resolved; do - case "$d" in - 0|1|2|3|4|5|6) - case " $valid " in - *" $d "*) - : - ;; - *) - if [ -n "$valid" ]; then - valid="${valid} ${d}" - else - valid="$d" - fi - ;; - esac - ;; - *) - log_warn "Ignoring invalid domain '$d'" - ;; - esac + if [ -n "$(fastrpc_domain_field "$d" 2)" ]; then + case " $valid " in + *" $d "*) + : + ;; + *) + if [ -n "$valid" ]; then + valid="${valid} ${d}" + else + valid="$d" + fi + ;; + esac + else + log_warn "Ignoring invalid domain '$d'" + fi done printf '%s' "$valid" } +# domain_supported_pds DOMAIN_ID +# Return signed and unsigned protection-domain modes supported by one DSP domain. +# Input: numeric domain ID and optional healthcheck table. Output: space-separated 0/1 values. +# Returns: 0. Side effects: none. domain_supported_pds() { - case "$1" in - 0|1|2) printf "%s" "0" ;; - 3|4|5|6) printf "%s" "0 1" ;; - *) printf "%s" "" ;; - esac + domain_id="$1" + + if [ -s "${FASTRPC_HEALTHCHECK_TSV:-}" ]; then + healthcheck_record="$(fastrpc_healthcheck_record "$domain_id")" + + if [ -n "$healthcheck_record" ]; then + IFS="$(printf '\t')" read -r \ + hc_name hc_state hc_signed hc_unsigned hc_support <