From 9bdb22b13ef77936d2e8cc72e0435aa4b2237c5b Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Thu, 14 Aug 2025 14:31:47 +0200 Subject: [PATCH 01/69] README: discourage use of ancient GCC Newer compiler versions include various improvements, ranging from codegen and support for newer arch extensions to improved warning messages, which help keep the code less buggy. Discourage the use of the six year old GCC 7.5, in favor of using whatever newest revision the user's distribution decides to ship. Signed-off-by: Konrad Dybcio --- README.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 55888c7..7fb4a88 100644 --- a/README.md +++ b/README.md @@ -55,14 +55,12 @@ cd fastrpc sudo make install ``` -### Steps to Generate ARM Binaries Using Linaro Toolchain on Ubuntu Build Machine +### Steps to cross-compile the project on Ubuntu -1. **Install Linaro tools and add the tools bin location to the path:** +1. **Install the cross compiler and dependencies:** ```bash - wget -c https://releases.linaro.org/components/toolchain/binaries/latest-7/aarch64-linux-gnu/gcc-linaro-7.5.0-2019.12-i686_aarch64-linux-gnu.tar.xz - tar xf gcc-linaro-7.5.0-2019.12-i686_aarch64-linux-gnu.tar.xz - export PATH="$PATH:/toolchain/bin" + sudo apt install g++-aarch64-linux-gnu binutils-aarch64-linux-gnu ``` 2. **Create softlink files for the compiler, linker, and other tools. Create environment variables as below for the auto tools:** @@ -196,4 +194,4 @@ Thanks for your interest in contributing to FastRPC! Please read our [Contributi ## License -FastRPC is licensed under the BSD 3-clause "New" or "Revised" License. Check out the [LICENSE](LICENSE.txt) for more details. \ No newline at end of file +FastRPC is licensed under the BSD 3-clause "New" or "Revised" License. Check out the [LICENSE](LICENSE.txt) for more details. From 97b649d1fbe9a14964a5ad56ea488791b3b4d418 Mon Sep 17 00:00:00 2001 From: Vinayak Katoch Date: Wed, 3 Dec 2025 14:32:50 +0530 Subject: [PATCH 02/69] Add systemd service files for FastRPC daemons Create systemd service files for DSP RPC daemons (aDSP, cDSP, gDSP, sDSP) with device-conditional startup. Each service uses After directives to ensure proper ordering with corresponding device units (dev-fastrpc-*-device and dev-fastrpc-*-secure.device),and ConditionPathExists directives to conditionally start only when at least one of the device paths exists (/dev/fastrpc-* or /dev/fastrpc-*-secure). Includes automatic restart on failure with 5-second delay between attempts. Services are enabled for multi-user.target. Signed-off-by: Vinayak Katoch --- Makefile.am | 2 +- configure.ac | 10 ++++++++++ files/Makefile.am | 13 +++++++++++++ files/adsprpcd.service | 14 ++++++++++++++ files/cdsp1rpcd.service | 14 ++++++++++++++ files/cdsprpcd.service | 14 ++++++++++++++ files/gdsp0rpcd.service | 14 ++++++++++++++ files/gdsp1rpcd.service | 14 ++++++++++++++ files/sdsprpcd.service | 14 ++++++++++++++ 9 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 files/Makefile.am create mode 100644 files/adsprpcd.service create mode 100644 files/cdsp1rpcd.service create mode 100644 files/cdsprpcd.service create mode 100644 files/gdsp0rpcd.service create mode 100644 files/gdsp1rpcd.service create mode 100644 files/sdsprpcd.service diff --git a/Makefile.am b/Makefile.am index f068b7c..111c639 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,3 +1,3 @@ -SUBDIRS = inc src test +SUBDIRS = inc src test files ACLOCAL_AMFLAGS = -I m4 diff --git a/configure.ac b/configure.ac index ca83f2d..7a87f37 100644 --- a/configure.ac +++ b/configure.ac @@ -39,6 +39,15 @@ AM_PROG_CC_C_O # Checks for libraries. +# Configure systemd unit directory option (--with-systemdsystemunitdir) +AC_ARG_WITH([systemdsystemunitdir], + [AS_HELP_STRING([--with-systemdsystemunitdir=DIR], + [Directory for systemd service files (default: /lib/systemd/system)])], + [systemdsystemunitdir="$withval"], + [systemdsystemunitdir="/lib/systemd/system"]) +AC_MSG_NOTICE([systemd unit directory: $systemdsystemunitdir]) +AC_SUBST([systemdsystemunitdir]) + # Checks for typedefs, structures, and compiler characteristics. # Checks for library functions. @@ -68,5 +77,6 @@ Makefile inc/Makefile src/Makefile test/Makefile +files/Makefile ]) AC_OUTPUT diff --git a/files/Makefile.am b/files/Makefile.am new file mode 100644 index 0000000..dac901f --- /dev/null +++ b/files/Makefile.am @@ -0,0 +1,13 @@ +# Systemd service files + +# Define systemd unit directory +systemdsystemunitdir = @systemdsystemunitdir@ + +# List of systemd service files to install +dist_systemdsystemunit_DATA = \ + adsprpcd.service \ + cdsprpcd.service \ + cdsp1rpcd.service \ + gdsp0rpcd.service \ + gdsp1rpcd.service \ + sdsprpcd.service diff --git a/files/adsprpcd.service b/files/adsprpcd.service new file mode 100644 index 0000000..ac9c987 --- /dev/null +++ b/files/adsprpcd.service @@ -0,0 +1,14 @@ +[Unit] +Description=aDSP RPC daemon +After=dev-fastrpc-adsp.device dev-fastrpc-adsp-secure.device +ConditionPathExists=|/dev/fastrpc-adsp +ConditionPathExists=|/dev/fastrpc-adsp-secure + +[Service] +Type=exec +ExecStart=/usr/bin/adsprpcd +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target diff --git a/files/cdsp1rpcd.service b/files/cdsp1rpcd.service new file mode 100644 index 0000000..b0fc1ef --- /dev/null +++ b/files/cdsp1rpcd.service @@ -0,0 +1,14 @@ +[Unit] +Description=cDSP RPC daemon +After=dev-fastrpc-cdsp1.device dev-fastrpc-cdsp1-secure.device +ConditionPathExists=|/dev/fastrpc-cdsp1 +ConditionPathExists=|/dev/fastrpc-cdsp1-secure + +[Service] +Type=exec +ExecStart=/usr/bin/cdsprpcd rootpd cdsp1 +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target diff --git a/files/cdsprpcd.service b/files/cdsprpcd.service new file mode 100644 index 0000000..ae597c8 --- /dev/null +++ b/files/cdsprpcd.service @@ -0,0 +1,14 @@ +[Unit] +Description=cDSP RPC daemon +After=dev-fastrpc-cdsp.device dev-fastrpc-cdsp-secure.device +ConditionPathExists=|/dev/fastrpc-cdsp +ConditionPathExists=|/dev/fastrpc-cdsp-secure + +[Service] +Type=exec +ExecStart=/usr/bin/cdsprpcd +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target diff --git a/files/gdsp0rpcd.service b/files/gdsp0rpcd.service new file mode 100644 index 0000000..259eaf2 --- /dev/null +++ b/files/gdsp0rpcd.service @@ -0,0 +1,14 @@ +[Unit] +Description=gDSP RPC daemon +After=dev-fastrpc-gdsp0.device dev-fastrpc-gdsp0-secure.device +ConditionPathExists=|/dev/fastrpc-gdsp0 +ConditionPathExists=|/dev/fastrpc-gdsp0-secure + +[Service] +Type=exec +ExecStart=/usr/bin/gdsprpcd rootpd gdsp0 +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target diff --git a/files/gdsp1rpcd.service b/files/gdsp1rpcd.service new file mode 100644 index 0000000..e442bab --- /dev/null +++ b/files/gdsp1rpcd.service @@ -0,0 +1,14 @@ +[Unit] +Description=gDSP RPC daemon +After=dev-fastrpc-gdsp1.device dev-fastrpc-gdsp1-secure.device +ConditionPathExists=|/dev/fastrpc-gdsp1 +ConditionPathExists=|/dev/fastrpc-gdsp1-secure + +[Service] +Type=exec +ExecStart=/usr/bin/gdsprpcd rootpd gdsp1 +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target diff --git a/files/sdsprpcd.service b/files/sdsprpcd.service new file mode 100644 index 0000000..1586d75 --- /dev/null +++ b/files/sdsprpcd.service @@ -0,0 +1,14 @@ +[Unit] +Description=sDSP RPC daemon +After=dev-fastrpc-sdsp.device dev-fastrpc-sdsp-secure.device +ConditionPathExists=|/dev/fastrpc-sdsp +ConditionPathExists=|/dev/fastrpc-sdsp-secure + +[Service] +Type=exec +ExecStart=/usr/bin/sdsprpcd +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target From 0bb5d7b14b77a09b93a510df766c1eb4f82f4257 Mon Sep 17 00:00:00 2001 From: Vinayak Katoch Date: Mon, 22 Dec 2025 14:38:52 +0530 Subject: [PATCH 03/69] CI: Fix distcheck permission errors for systemd service installation Configure systemd unit directory through DISTCHECK_CONFIGURE_FLAGS to avoid permission denied errors during distcheck. Signed-off-by: Vinayak Katoch --- .github/workflows/build_linux_gnu.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_linux_gnu.yml b/.github/workflows/build_linux_gnu.yml index 841ce3a..b3fe1ad 100644 --- a/.github/workflows/build_linux_gnu.yml +++ b/.github/workflows/build_linux_gnu.yml @@ -32,4 +32,4 @@ jobs: - name: Compile code for LE platform run: | GITCOMPILE_NO_MAKE=true ./gitcompile - make distcheck + make distcheck DISTCHECK_CONFIGURE_FLAGS="--with-systemdsystemunitdir='lib/systemd/system'" From aaafd3736e85d07fc2680af134b232d1c67d69e7 Mon Sep 17 00:00:00 2001 From: Ekansh Gupta Date: Tue, 4 Nov 2025 15:24:00 +0530 Subject: [PATCH 04/69] .gitignore: ignore gdsprpcd Add generated gdsprpcd file to .gitignore. Signed-off-by: Ekansh Gupta --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 38df5eb..39d4919 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ stamp-h1 src/adsprpcd src/cdsprpcd src/sdsprpcd +src/gdsprpcd test/fastrpc_test # make dist tarballs From 37e11eb9f00a1df3c04d99f4498d9c4a241bf369 Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Tue, 6 Jan 2026 11:01:48 +0530 Subject: [PATCH 05/69] Configure workflow to run Armor on AWS self-hosted runner - Updated `runs-on` to use self-hosted runner group: `GHA-fastrpc-Prd-SelfHosted-RG` - Use AWS runners to support uploading artifacts to the configured S3 location Signed-off-by: Tharun Kumar Merugu --- .github/workflows/run_armor.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/run_armor.yml b/.github/workflows/run_armor.yml index fa28806..0421ca8 100644 --- a/.github/workflows/run_armor.yml +++ b/.github/workflows/run_armor.yml @@ -37,7 +37,9 @@ permissions: jobs: RUN-ARMOR: - runs-on: ubuntu-22.04 + runs-on: + group: GHA-fastrpc-Prd-SelfHosted-RG + labels: [ self-hosted, fastrpc-prd-u2404-x64-large-od-ephem ] steps: - uses: actions/checkout@v4 - name: Set event variables From 045ff886d2d6777ca3c19f43f79be5590d42535a Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Wed, 17 Dec 2025 15:08:32 +0100 Subject: [PATCH 06/69] .github: Add issue template for bug reports To streamline the bug reporting process, ask some questions upfront. Signed-off-by: Konrad Dybcio --- .github/ISSUE_TEMPLATE/bug-report.yaml | 67 ++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug-report.yaml diff --git a/.github/ISSUE_TEMPLATE/bug-report.yaml b/.github/ISSUE_TEMPLATE/bug-report.yaml new file mode 100644 index 0000000..76125ec --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.yaml @@ -0,0 +1,67 @@ +name: Bug Report +description: File a bug report. +labels: ["Bug"] +assignees: + - ekanshibu +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + - type: input + id: fastrpc-ver + attributes: + label: FastRPC version + description: Which release (or git commit) of the library can you + reproduce the issue on? + placeholder: v1.0.1 + validations: + required: true + - type: input + id: dsp-fw-ver + attributes: + label: DSP firmware version + description: "What is the DSP firmware version you're running? (hint: + strings dsp.mbn | grep QC_IMAGE)" + placeholder: ADSP.VT.5.4.1-00123-XYZ-1 + validations: + required: true + - type: input + id: device-info + attributes: + label: SoC and device name + description: What SoC and device can you reproduce this issue on? + placeholder: Qualcomm SC8280XP CRD + validations: + required: true + - type: input + id: kernel-ver + attributes: + label: Kernel version + description: What kernel version are you running? + placeholder: v6.19-rc1 + validations: + required: true + - type: textarea + id: what-happened + attributes: + label: What happened? + description: Also tell us, what did you expect to happen? + placeholder: Tell us what you see! + validations: + required: true + - type: textarea + id: steps-to-repro + attributes: + label: Steps to reproduce + description: Please include all relevant details + placeholder: Run xyz --foo=bar + validations: + required: true + - type: textarea + id: logs + attributes: + label: Relevant log output + description: Please copy and paste any relevant log output. This will be + automatically formatted into code, so no need for backticks. + render: shell From 8d97b02906f913d3d53c22751b23f45f8b21cb83 Mon Sep 17 00:00:00 2001 From: Jianping Li Date: Fri, 5 Sep 2025 14:38:28 +0800 Subject: [PATCH 07/69] cleanup:remove unused/unsupported PM QoS code (#225) Clean up unused PM QoS implementation. PM QoS is not supported by fastrpc driver, so related code is removed. Signed-off-by: Jianping Li --- inc/Makefile.am | 1 - inc/fastrpc_internal.h | 13 +-- inc/fastrpc_latency.h | 56 ----------- src/Makefile.am | 1 - src/dspsignal.c | 1 - src/fastrpc_apps_user.c | 55 ++--------- src/fastrpc_latency.c | 201 ---------------------------------------- 7 files changed, 9 insertions(+), 319 deletions(-) delete mode 100644 inc/fastrpc_latency.h delete mode 100644 src/fastrpc_latency.c diff --git a/inc/Makefile.am b/inc/Makefile.am index dd76127..9b1657b 100644 --- a/inc/Makefile.am +++ b/inc/Makefile.am @@ -45,7 +45,6 @@ noinst_HEADERS = \ fastrpc_hash_table.h \ fastrpc_internal.h \ fastrpc_ioctl.h \ - fastrpc_latency.h \ fastrpc_log.h \ fastrpc_mem.h \ fastrpc_notif.h \ diff --git a/inc/fastrpc_internal.h b/inc/fastrpc_internal.h index 31f1b5d..0f04e3b 100644 --- a/inc/fastrpc_internal.h +++ b/inc/fastrpc_internal.h @@ -15,7 +15,6 @@ #include "AEEstd.h" #include "AEEQList.h" #include "AEEStdErr.h" -#include "fastrpc_latency.h" #include "fastrpc_common.h" // Aligns the memory @@ -308,7 +307,7 @@ struct handle_list { remote_handle64 remotectlhandle; remote_handle64 adspperfhandle; int procattrs; - struct fastrpc_latency qos; + int adaptive_qos; struct fastrpc_thread_params th_params; int unsigned_module; bool pd_dump; @@ -367,16 +366,6 @@ int fastrpc_get_cap(uint32_t domain, uint32_t attributeID, uint32_t *capability) **/ int check_rpc_error(int err); -/** - * @brief Notify the FastRPC QoS logic of activity outside of the invoke code path - * that should still be considered in QoS timeout calculations. - * Note that the function will silently fail on errors such as the domain - * not having a valid QoS mode. - * - * @param[in] domain DSP domain - **/ -void fastrpc_qos_activity(int domain); - /** * @brief Make IOCTL call to exit async thread */ diff --git a/inc/fastrpc_latency.h b/inc/fastrpc_latency.h deleted file mode 100644 index caee084..0000000 --- a/inc/fastrpc_latency.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. -// SPDX-License-Identifier: BSD-3-Clause - -#ifndef __FASTRPC_LATENCY_H__ -#define __FASTRPC_LATENCY_H__ - -#define FASTRPC_LATENCY_START (1) -#define FASTRPC_LATENCY_STOP (0) -#define FASTRPC_LATENCY_EXIT (2) - -#define SEC_TO_NS (1000000000) -#define MS_TO_US (1000) -#define US_TO_NS MS_TO_US - -#define FASTRPC_LATENCY_VOTE_ON (1) -#define FASTRPC_LATENCY_VOTE_OFF (0) -#define FASTRPC_LATENCY_WAIT_TIME_USEC (100000) -#define FASTRPC_QOS_MAX_LATENCY_USEC (10000) - -/* FastRPC latency voting data for QoS handler of a session */ -struct fastrpc_latency { - int adaptive_qos; - int state; //! latency thread handler running state - int exit; - int invoke; //! invoke count in tacking window - int vote; //! current pm_qos vote status - int dev; //! associated device node - int wait_time; //! wait time for review next voting - int latency; //! user requested fastrpc latency in us - pthread_t thread; - pthread_mutex_t mut; - pthread_mutex_t wmut; - pthread_cond_t cond; -}; - -/* Increment RPC invoke count for activity detection in a window of time - * @param qos, pointer to domain latency data - * return, fastrpc error codes - */ -int fastrpc_latency_invoke_incr(struct fastrpc_latency *qos); - -/* Set qos enable and latency parameters for a configured domain - * @param qos, pointer to domain latency data - * @param enable, qos enable/disable - * @param latency, fastrpc latency requirement from user in us - * @return, fastrpc error codes - */ -int fastrpc_set_pm_qos(struct fastrpc_latency *qos, uint32_t enable, - uint32_t latency); - -/* Initialization routine to initialize globals & internal data structures */ -int fastrpc_latency_init(int dev, struct fastrpc_latency *qos); -/* De-init routine to cleanup globals & internal data structures*/ -int fastrpc_latency_deinit(struct fastrpc_latency *qos); - -#endif /*__FASTRPC_LATENCY_H__*/ diff --git a/src/Makefile.am b/src/Makefile.am index 9a3608d..991058b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,7 +16,6 @@ LIBDSPRPC_SOURCES = \ fastrpc_async.c \ fastrpc_mem.c \ fastrpc_notif.c \ - fastrpc_latency.c \ fastrpc_ioctl.c \ fastrpc_log.c \ fastrpc_procbuf.c \ diff --git a/src/dspsignal.c b/src/dspsignal.c index 01c1c1c..7e3fa88 100644 --- a/src/dspsignal.c +++ b/src/dspsignal.c @@ -219,7 +219,6 @@ AEEResult dspsignal_wait(int domain, uint32_t id, uint32_t timeout_usec) { domain = get_domain(domain); VERIFYC(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), AEE_EBADPARM); VERIFYC((ds = (struct dspsignal_domain_signals *)signals->domain_signals[domain]) != NULL, AEE_EBADSTATE); - fastrpc_qos_activity(domain); FARF(MEDIUM, "%s: Wait signal %u timeout %u", __func__, id, timeout_usec); errno = 0; diff --git a/src/fastrpc_apps_user.c b/src/fastrpc_apps_user.c index f111ccf..c19fbef 100644 --- a/src/fastrpc_apps_user.c +++ b/src/fastrpc_apps_user.c @@ -57,7 +57,6 @@ #include "fastrpc_common.h" #include "fastrpc_config.h" #include "fastrpc_internal.h" -#include "fastrpc_latency.h" #include "fastrpc_log.h" #include "fastrpc_mem.h" #include "fastrpc_notif.h" @@ -216,6 +215,7 @@ extern int perf_v2_dsp; #define MIN_PD_INITMEM_SIZE (3 * 1024 * 1024) #define MAX_PD_INITMEM_SIZE (200 * 1024 * 1024) +#define FASTRPC_QOS_MAX_LATENCY_USEC (10000) #define PM_TIMEOUT_MS 5 enum handle_list_id { @@ -1335,7 +1335,6 @@ int remote_handle_invoke_domain(int domain, remote_handle handle, } if (!IS_STATIC_HANDLE(handle)) { - fastrpc_latency_invoke_incr(&hlist[domain].qos); if ((rpc_timeout = fastrpc_config_get_rpctimeout()) > 0) { frpc_timer.domain = domain; frpc_timer.sc = sc; @@ -1978,18 +1977,13 @@ int remote_handle64_close(remote_handle64 handle) { return nErr; } -static int manage_pm_qos(int domain, remote_handle64 h, uint32_t enable, - uint32_t latency) { - return fastrpc_set_pm_qos(&hlist[domain].qos, enable, latency); -} - static int manage_adaptive_qos(int domain, uint32_t enable) { int nErr = AEE_SUCCESS; remote_handle64 handle = INVALID_HANDLE; /* If adaptive QoS is already enabled/disabled, then just return */ - if ((enable && hlist[domain].qos.adaptive_qos) || - (!enable && !hlist[domain].qos.adaptive_qos)) + if ((enable && hlist[domain].adaptive_qos) || + (!enable && !hlist[domain].adaptive_qos)) return nErr; if (hlist[domain].dev != -1) { @@ -2020,11 +2014,11 @@ static int manage_adaptive_qos(int domain, uint32_t enable) { __func__, enable, domain); goto bail; } else { - hlist[domain].qos.adaptive_qos = ((enable == RPC_ADAPTIVE_QOS) ? 1 : 0); + hlist[domain].adaptive_qos = ((enable == RPC_ADAPTIVE_QOS) ? 1 : 0); } } else { /* If session is not created already, then just set process attribute */ - hlist[domain].qos.adaptive_qos = ((enable == RPC_ADAPTIVE_QOS) ? 1 : 0); + hlist[domain].adaptive_qos = ((enable == RPC_ADAPTIVE_QOS) ? 1 : 0); } if (enable) @@ -2089,14 +2083,6 @@ static int manage_poll_qos(int domain, remote_handle64 h, uint32_t enable, return nErr; } -// Notify FastRPC QoS logic of activity outside of the invoke code path. -// This function needs to be in this file to be able to access hlist. -void fastrpc_qos_activity(int domain) { - if (IS_VALID_EFFECTIVE_DOMAIN_ID(domain) && hlist) { - fastrpc_latency_invoke_incr(&hlist[domain].qos); - } -} - static inline int enable_process_state_notif_on_dsp(int domain) { int nErr = AEE_SUCCESS; remote_handle64 notif_handle = 0; @@ -2285,7 +2271,6 @@ static int fastrpc_dsp_process_clean(int domain) { int remote_handle_control_domain(int domain, remote_handle64 h, uint32_t req, void *data, uint32_t len) { int nErr = AEE_SUCCESS; - const unsigned int POLL_MODE_PM_QOS_LATENCY = 100; FARF(RUNTIME_RPC_HIGH, "Entering %s, domain %d, handle %llu, req %d, data %p, size %d\n", __func__, domain, h, req, data, len); @@ -2302,8 +2287,6 @@ int remote_handle_control_domain(int domain, remote_handle64 h, uint32_t req, case RPC_DISABLE_QOS: { VERIFY(AEE_SUCCESS == (nErr = manage_adaptive_qos(domain, RPC_DISABLE_QOS))); - VERIFY(AEE_SUCCESS == - (nErr = manage_pm_qos(domain, h, RPC_DISABLE_QOS, lp->latency))); VERIFY(AEE_SUCCESS == (nErr = manage_poll_qos(domain, h, RPC_DISABLE_QOS, lp->latency))); /* Error ignored, currently meeting qos requirement is optional. Consider @@ -2311,20 +2294,8 @@ int remote_handle_control_domain(int domain, remote_handle64 h, uint32_t req, fastrpc_set_qos_latency(domain, h, FASTRPC_QOS_MAX_LATENCY_USEC); break; } - case RPC_PM_QOS: { - VERIFY(AEE_SUCCESS == - (nErr = manage_adaptive_qos(domain, RPC_DISABLE_QOS))); - VERIFY(AEE_SUCCESS == - (nErr = manage_pm_qos(domain, h, RPC_PM_QOS, lp->latency))); - /* Error ignored, currently meeting qos requirement is optional. Consider - * to error out in later targets */ - fastrpc_set_qos_latency(domain, h, lp->latency); - break; - } case RPC_ADAPTIVE_QOS: { - /* Disable PM QoS if enabled and then enable adaptive QoS */ - VERIFY(AEE_SUCCESS == - (nErr = manage_pm_qos(domain, h, RPC_DISABLE_QOS, lp->latency))); + /* Enable adaptive QoS */ VERIFY(AEE_SUCCESS == (nErr = manage_adaptive_qos(domain, RPC_ADAPTIVE_QOS))); /* Error ignored, currently meeting qos requirement is optional. Consider @@ -2335,13 +2306,6 @@ int remote_handle_control_domain(int domain, remote_handle64 h, uint32_t req, case RPC_POLL_QOS: { VERIFY(AEE_SUCCESS == (nErr = manage_poll_qos(domain, h, RPC_POLL_QOS, lp->latency))); - - /* - * Poll QoS option also enables PM QoS to enable early response from DSP - * and stop the CPU cores from going into deep sleep low power modes. - */ - VERIFY(AEE_SUCCESS == (nErr = manage_pm_qos(domain, h, RPC_PM_QOS, - POLL_MODE_PM_QOS_LATENCY))); break; } default: @@ -3211,7 +3175,6 @@ static void domain_deinit(int domain) { fastrpc_clear_handle_list(NON_DOMAIN_HANDLE_LIST_ID, domain); } fastrpc_perf_deinit(); - fastrpc_latency_deinit(&hlist[domain].qos); trace_marker_deinit(domain); deinitFileWatcher(domain); adspmsgd_stop(domain); @@ -3367,7 +3330,7 @@ static int get_process_attrs(int domain) { attrs = fastrpc_get_property_int(FASTRPC_PROCESS_ATTRS, 0); attrs |= fastrpc_get_property_int(FASTRPC_PROCESS_ATTRS_PERSISTENT, 0); fastrpc_trace = fastrpc_get_property_int(FASTRPC_DEBUG_TRACE, 0); - attrs |= hlist[domain].qos.adaptive_qos ? FASTRPC_MODE_ADAPTIVE_QOS : 0; + attrs |= hlist[domain].adaptive_qos ? FASTRPC_MODE_ADAPTIVE_QOS : 0; attrs |= hlist[domain].unsigned_module ? FASTRPC_MODE_UNSIGNED_MODULE : 0; attrs |= (hlist[domain].pd_dump | fastrpc_config_is_pddump_enabled()) ? FASTRPC_MODE_ENABLE_PDDUMP @@ -3573,7 +3536,7 @@ void print_process_attrs(int domain) { signedMd = true; pd_initmem_size = hlist[domain].pd_initmem_size; } - if (hlist[domain].qos.adaptive_qos) + if (hlist[domain].adaptive_qos) qos = true; if (hlist[domain].pd_dump | fastrpc_config_is_pddump_enabled()) configPDdump = true; @@ -4020,8 +3983,6 @@ static int domain_init(int domain, int *dev) { ret); } fastrpc_perf_init(hlist[domain].dev, domain); - VERIFY(AEE_SUCCESS == - (nErr = fastrpc_latency_init(hlist[domain].dev, &hlist[domain].qos))); get_dsp_dma_reverse_rpc_map_capability(domain); hlist[domain].state = FASTRPC_DOMAIN_STATE_INIT; hlist[domain].ref = 0; diff --git a/src/fastrpc_latency.c b/src/fastrpc_latency.c deleted file mode 100644 index 46fdab8..0000000 --- a/src/fastrpc_latency.c +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. -// SPDX-License-Identifier: BSD-3-Clause - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef FARF_ERROR -#define FARF_ERROR 1 -#endif - -#include "AEEStdErr.h" -#include "AEEstd.h" -#include "HAP_farf.h" -#include "fastrpc_common.h" -#include "fastrpc_internal.h" -#include "fastrpc_latency.h" -#include "verify.h" - -int fastrpc_latency_invoke_incr(struct fastrpc_latency *qp) { - if (qp == NULL || qp->state == FASTRPC_LATENCY_STOP) - goto bail; - qp->invoke++; - if (qp->vote == FASTRPC_LATENCY_VOTE_OFF) { - pthread_mutex_lock(&qp->wmut); - pthread_cond_signal(&qp->cond); - pthread_mutex_unlock(&qp->wmut); - } -bail: - return 0; -} - -int fastrpc_latency_init(int dev, struct fastrpc_latency *qos) { - int nErr = 0; - - VERIFYC(qos && dev != -1, AEE_ERPC); - - qos->dev = dev; - qos->state = FASTRPC_LATENCY_STOP; - qos->thread = 0; - qos->wait_time = FASTRPC_LATENCY_WAIT_TIME_USEC; - pthread_mutex_init(&qos->mut, 0); - pthread_mutex_init(&qos->wmut, 0); - pthread_cond_init(&qos->cond, NULL); -bail: - return nErr; -} - -int fastrpc_latency_deinit(struct fastrpc_latency *qos) { - int nErr = 0; - - VERIFYC(qos, AEE_ERPC); - if (qos->state == FASTRPC_LATENCY_START) { - pthread_mutex_lock(&qos->wmut); - qos->exit = FASTRPC_LATENCY_EXIT; - pthread_cond_signal(&qos->cond); - pthread_mutex_unlock(&qos->wmut); - if (qos->thread) { - pthread_join(qos->thread, 0); - qos->thread = 0; - FARF(ALWAYS, "latency thread joined"); - } - pthread_mutex_destroy(&qos->mut); - pthread_mutex_destroy(&qos->wmut); - } -bail: - return nErr; -} - -/* FastRPC QoS handler votes for pm_qos latency based on - * RPC activity in a window of time. - */ -static void *fastrpc_latency_thread_handler(void *arg) { - int nErr = 0; - long ns = 0; - struct timespec tw; - struct timeval tp; - int invoke = 0; - struct fastrpc_ioctl_control qos = {0}; - struct fastrpc_ctrl_latency lp = {0}; - struct fastrpc_latency *qp = (struct fastrpc_latency *)arg; - - if (qp == NULL) { - nErr = AEE_ERPC; - FARF(ERROR, "Error 0x%x: %s failed \n", nErr, __func__); - return NULL; - } - VERIFYC(qp->dev != -1, AEE_ERPC); - - FARF(ALWAYS, "%s started for QoS with activity window %d ms", __func__, - FASTRPC_LATENCY_WAIT_TIME_USEC / MS_TO_US); - - // Look for RPC activity in 100 ms window - qp->wait_time = FASTRPC_LATENCY_WAIT_TIME_USEC; - qp->invoke++; - while (1) { - nErr = gettimeofday(&tp, NULL); - /* valid values for "tv_nsec" are [0, 999999999] */ - ns = ((tp.tv_usec + qp->wait_time) * US_TO_NS); - tw.tv_sec = tp.tv_sec + (ns / SEC_TO_NS); - tw.tv_nsec = (ns % SEC_TO_NS); - - pthread_mutex_lock(&qp->wmut); - if (qp->wait_time) - pthread_cond_timedwait(&qp->cond, &qp->wmut, &tw); - else - pthread_cond_wait(&qp->cond, &qp->wmut); - pthread_mutex_unlock(&qp->wmut); - - if (qp->exit == FASTRPC_LATENCY_EXIT) { - qp->exit = 0; - break; - } - - pthread_mutex_lock(&qp->mut); - invoke = qp->invoke; - qp->invoke = 0; - pthread_mutex_unlock(&qp->mut); - - if (invoke) { - // found RPC activity in window. vote for pm_qos. - qp->wait_time = FASTRPC_LATENCY_WAIT_TIME_USEC; - if (qp->vote == FASTRPC_LATENCY_VOTE_OFF) { - lp.enable = FASTRPC_LATENCY_VOTE_ON; - lp.latency = qp->latency; - nErr = ioctl_control(qp->dev, DSPRPC_CONTROL_LATENCY, &lp); - if (nErr == AEE_SUCCESS) { - qp->vote = FASTRPC_LATENCY_VOTE_ON; - } else if (nErr == AEE_EUNSUPPORTED) { - goto bail; - } else { - FARF(ERROR, - "Error %d: %s: PM QoS ON request failed with errno %d (%s)", - nErr, __func__, errno, strerror(errno)); - } - } - } else { - // No RPC activity detected in a window. Remove pm_qos vote. - qp->wait_time = 0; - if (qp->vote == FASTRPC_LATENCY_VOTE_ON) { - lp.enable = FASTRPC_LATENCY_VOTE_OFF; - lp.latency = 0; - nErr = ioctl_control(qp->dev, DSPRPC_CONTROL_LATENCY, &lp); - if (nErr == AEE_SUCCESS) { - qp->vote = FASTRPC_LATENCY_VOTE_OFF; - } else if (nErr == AEE_EUNSUPPORTED) { - goto bail; - } else { - FARF(ERROR, - "Error %d: %s: PM QoS OFF request failed with errno %d (%s)", - nErr, __func__, errno, strerror(errno)); - } - } - } - } - FARF(ALWAYS, "FastRPC latency thread for QoS exited"); -bail: - if (nErr != AEE_SUCCESS) { - FARF(ERROR, - "Error 0x%x: %s failed for wait time %d latency control enable %d " - "latency %d\n", - nErr, __func__, qp->wait_time, qos.lp.enable, qos.lp.latency); - } - return NULL; -} - -int fastrpc_set_pm_qos(struct fastrpc_latency *qos, uint32_t enable, - uint32_t latency) { - int nErr = AEE_SUCCESS; - int state = 0; - - VERIFYC(qos != NULL, AEE_EBADPARM); - if (qos->exit == FASTRPC_LATENCY_EXIT) - goto bail; - pthread_mutex_lock(&qos->mut); - state = qos->state; - qos->latency = latency; - pthread_mutex_unlock(&qos->mut); - - if (!enable && state == FASTRPC_LATENCY_START) { - qos->exit = FASTRPC_LATENCY_EXIT; - pthread_mutex_lock(&qos->wmut); - pthread_cond_signal(&qos->cond); - pthread_mutex_unlock(&qos->wmut); - } - - if (enable && state == FASTRPC_LATENCY_STOP) { - qos->state = FASTRPC_LATENCY_START; - VERIFY(AEE_SUCCESS == (nErr = pthread_create(&qos->thread, 0, - fastrpc_latency_thread_handler, - (void *)qos))); - } -bail: - return nErr; -} From a527681d0d955555f8d41a7206d3f186fb1762dc Mon Sep 17 00:00:00 2001 From: Sairamreddy Bojja Date: Mon, 5 Jan 2026 12:46:46 +0530 Subject: [PATCH 08/69] Add systemd unit file for audiopd aDSP RPC daemon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a systemd unit file for the audiopd RPC daemon, allowing the aDSP to load modules dynamically as needed. This supports features such as runtime loading of decoder modules for compress‑offload audio playback. Signed-off-by: Sairamreddy Bojja --- files/Makefile.am | 1 + files/adsprpcd_audiopd.service | 14 ++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 files/adsprpcd_audiopd.service diff --git a/files/Makefile.am b/files/Makefile.am index dac901f..5bf1307 100644 --- a/files/Makefile.am +++ b/files/Makefile.am @@ -6,6 +6,7 @@ systemdsystemunitdir = @systemdsystemunitdir@ # List of systemd service files to install dist_systemdsystemunit_DATA = \ adsprpcd.service \ + adsprpcd_audiopd.service \ cdsprpcd.service \ cdsp1rpcd.service \ gdsp0rpcd.service \ diff --git a/files/adsprpcd_audiopd.service b/files/adsprpcd_audiopd.service new file mode 100644 index 0000000..99bdf1a --- /dev/null +++ b/files/adsprpcd_audiopd.service @@ -0,0 +1,14 @@ +[Unit] +Description=audiopd aDSP RPC daemon +After=dev-fastrpc-adsp.device dev-fastrpc-adsp-secure.device +ConditionPathExists=|/dev/fastrpc-adsp +ConditionPathExists=|/dev/fastrpc-adsp-secure + +[Service] +Type=exec +ExecStart=/usr/bin/adsprpcd audiopd +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target From b0b38f7acf5fa3c0392f3cf91f7c7bfd03405059 Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Tue, 20 Jan 2026 13:02:23 +0530 Subject: [PATCH 09/69] CI: Improve LAVA job health check and result handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Poll job state via lavacli inside Docker Handle cancelled/incomplete states and enforce 2‑hour timeout On completion, fetch results and determine pass/fail Update GitHub summary with job status, job ID, and URL Prevent incorrect reporting when jobs fail early or never finish Signed-off-by: Tharun Kumar Merugu --- .github/workflows/test.yml | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c9de0aa..4e56ec5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -78,19 +78,36 @@ jobs: id: check_job run: | STATE="" + START_TIME=$(date +%s) while [ "$STATE" != "Finished" ]; do state=$(docker run -i --rm --workdir="$PWD" -v "$(dirname $PWD)":"$(dirname $PWD)" ${{ inputs.docker_image }} sh -c "lavacli identities add --token ${{ secrets.LAVA_OSS_TOKEN }} --uri https://lava-oss.qualcomm.com/RPC2 --username ${{ secrets.LAVA_OSS_USER }} production && lavacli -i production jobs show $JOB_ID" | grep state) STATE=$(echo "$state" | cut -d':' -f2 | sed 's/^ *//;s/ *$//') echo "Current status: $STATE" + CURRENT_TIME=$(date +%s) + ELAPSED_TIME=$(((CURRENT_TIME - START_TIME)/3600)) + if [ $ELAPSED_TIME -ge 2 ]; then + echo "Timeout: 2 hours exceeded." + summary=":x: Lava job exceeded time limit." + echo "summary=$summary" >> $GITHUB_OUTPUT + exit 1 + fi sleep 30 done health=$(docker run -i --rm --workdir="$PWD" -v "$(dirname $PWD)":"$(dirname $PWD)" ${{ inputs.docker_image }} sh -c "lavacli identities add --token ${{ secrets.LAVA_OSS_TOKEN }} --uri https://lava-oss.qualcomm.com/RPC2 --username ${{ secrets.LAVA_OSS_USER }} production && lavacli -i production jobs show $JOB_ID" | grep Health) HEALTH=$(echo "$health" | cut -d':' -f2 | sed 's/^ *//;s/ *$//') if [[ "$HEALTH" == "Complete" ]]; then - echo "Lava job passed." - summary=":heavy_check_mark: Lava job passed." - echo "summary=$summary" >> $GITHUB_OUTPUT - exit 0 + TEST_RESULTS=$(docker run -i --rm --workdir="$PWD" -v "$(dirname $PWD)":"$(dirname $PWD)" ${{ inputs.docker_image }} sh -c "lavacli identities add --token ${{ secrets.LAVA_OSS_TOKEN }} --uri https://lava-oss.qualcomm.com/RPC2 --username ${{ secrets.LAVA_OSS_USER }} production && lavacli -i production results $JOB_ID" | grep fail || echo "Pass") + if [[ "$TEST_RESULTS" == "Pass" ]]; then + echo "Lava job passed." + summary=":heavy_check_mark: Lava job passed." + echo "summary=$summary" >> $GITHUB_OUTPUT + exit 0 + else + echo "Lava job failed." + summary=":x: Lava job failed." + echo "summary=$summary" >> $GITHUB_OUTPUT + exit 1 + fi else echo "Lava job failed." summary=":x: Lava job failed." From cf2bae4c064a023559fca09f1970d8959bd9a658 Mon Sep 17 00:00:00 2001 From: Vinayak Katoch Date: Mon, 19 Jan 2026 13:14:42 +0530 Subject: [PATCH 10/69] Non-Android builds lack BSD string functions Standard glibc does not provide BSD-specific string functions like strlcpy and strlcat, which are needed for safe string operations. Android includes these functions natively, but Linux GNU builds require an external library to provide them. Add dependency on libbsd-overlay for non-Android targets to provide the missing BSD functions. Configure the build system to detect and link against libbsd when building for Linux GNU platforms. Signed-off-by: Vinayak Katoch --- configure.ac | 8 ++++++++ src/Makefile.am | 12 ++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index 7a87f37..886ce92 100644 --- a/configure.ac +++ b/configure.ac @@ -63,6 +63,14 @@ AS_IF([test "$compile_for_android" = no], [ AC_SUBST(YAML_LIBS) ]) +# Check for libbsd only if not Android (provides strlcpy, strlcat, etc.) +AS_IF([test "$compile_for_android" = no], [ + PKG_CHECK_MODULES([BSD], [libbsd-overlay], [], + [AC_MSG_ERROR([libbsd (libbsd-overlay) is required but not found.])]) + AC_SUBST(BSD_CFLAGS) + AC_SUBST(BSD_LIBS) +]) + # Configure config base path option (--with-config-base-dir) AC_ARG_WITH([config-base-dir], [AS_HELP_STRING([--with-config-base-dir=PATH], diff --git a/src/Makefile.am b/src/Makefile.am index 991058b..fd0e080 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,7 +5,7 @@ LIBDSPRPC_CFLAGS = -fno-short-enums -U_DEBUG -DARM_ARCH_7A -DLE_ENABLE -DENABLE_ if ANDROID_CC LIBDSPRPC_CFLAGS += -DDEFAULT_DSP_SEARCH_PATHS='";/vendor/lib/rfsa/adsp;/vendor/dsp;"' else -LIBDSPRPC_CFLAGS += -DPARSE_YAML @YAML_CFLAGS@ -DDEFAULT_DSP_SEARCH_PATHS='";/usr/lib/rfsa/adsp;/usr/lib/dsp;"' +LIBDSPRPC_CFLAGS += -DPARSE_YAML @YAML_CFLAGS@ @BSD_CFLAGS@ -DDEFAULT_DSP_SEARCH_PATHS='";/usr/lib/rfsa/adsp;/usr/lib/dsp;"' endif LIBDSPRPC_SOURCES = \ @@ -67,11 +67,11 @@ LIBDEFAULT_LISTENER_SOURCES = \ if ANDROID_CC USE_LOG = -llog else -# Add YAML libs to link flags for non-Android builds -libadsprpc_la_LIBADD = @YAML_LIBS@ -libcdsprpc_la_LIBADD = @YAML_LIBS@ -libsdsprpc_la_LIBADD = @YAML_LIBS@ -libgdsprpc_la_LIBADD = @YAML_LIBS@ +# Add YAML and BSD libs to link flags for non-Android builds +libadsprpc_la_LIBADD = @YAML_LIBS@ @BSD_LIBS@ +libcdsprpc_la_LIBADD = @YAML_LIBS@ @BSD_LIBS@ +libsdsprpc_la_LIBADD = @YAML_LIBS@ @BSD_LIBS@ +libgdsprpc_la_LIBADD = @YAML_LIBS@ @BSD_LIBS@ endif ADSP_CFLAGS = $(LIBDSPRPC_CFLAGS) -DDEFAULT_DOMAIN_ID=0 From e3acb5816d32f0ee571c9a8c6704183d68fad88f Mon Sep 17 00:00:00 2001 From: Vinayak Katoch Date: Mon, 19 Jan 2026 14:06:29 +0530 Subject: [PATCH 11/69] ci: update workflows with libbsd-dev dependency Add libbsd-dev:arm64 to ARM64 workflows (build_linux_arm64.yml, codeql.yml, abi-compat.yml) and ensure libbsd-dev is in build_linux_gnu.yml to resolve configure errors during compilation. Signed-off-by: Vinayak Katoch --- .github/workflows/abi-compat.yml | 3 ++- .github/workflows/build_linux_arm64.yml | 3 ++- .github/workflows/build_linux_gnu.yml | 2 +- .github/workflows/codeql.yml | 3 ++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/abi-compat.yml b/.github/workflows/abi-compat.yml index 281ef33..6771d22 100644 --- a/.github/workflows/abi-compat.yml +++ b/.github/workflows/abi-compat.yml @@ -82,7 +82,8 @@ jobs: automake autoconf libtool pkg-config \ gcc-aarch64-linux-gnu g++-aarch64-linux-gnu binutils-aarch64-linux-gnu \ libyaml-dev \ - libyaml-0-2:arm64 libyaml-dev:arm64 + libyaml-0-2:arm64 libyaml-dev:arm64 \ + libbsd-dev:arm64 # Sanity checks abi-compliance-checker -version diff --git a/.github/workflows/build_linux_arm64.yml b/.github/workflows/build_linux_arm64.yml index cfcb8e0..52636f9 100644 --- a/.github/workflows/build_linux_arm64.yml +++ b/.github/workflows/build_linux_arm64.yml @@ -63,7 +63,8 @@ jobs: automake autoconf libtool pkg-config \ gcc-aarch64-linux-gnu g++-aarch64-linux-gnu binutils-aarch64-linux-gnu\ libyaml-dev \ - libyaml-0-2:arm64 libyaml-dev:arm64 + libyaml-0-2:arm64 libyaml-dev:arm64 \ + libbsd-dev:arm64 - name: Sanity check libyaml (headers + ARM64 pc) run: | diff --git a/.github/workflows/build_linux_gnu.yml b/.github/workflows/build_linux_gnu.yml index b3fe1ad..8f57fbd 100644 --- a/.github/workflows/build_linux_gnu.yml +++ b/.github/workflows/build_linux_gnu.yml @@ -26,7 +26,7 @@ jobs: sudo apt-get install -y \ build-essential \ autoconf automake libtool pkg-config \ - libyaml-dev \ + libyaml-dev libbsd-dev \ tar gzip - name: Compile code for LE platform diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 588a214..596c738 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -77,7 +77,8 @@ jobs: automake autoconf libtool pkg-config \ gcc-aarch64-linux-gnu g++-aarch64-linux-gnu binutils-aarch64-linux-gnu\ libyaml-dev \ - libyaml-0-2:arm64 libyaml-dev:arm64 + libyaml-0-2:arm64 libyaml-dev:arm64 \ + libbsd-dev:arm64 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL From 9c20e57797e9408cdcaf9c755d7e72b5aec8671d Mon Sep 17 00:00:00 2001 From: Vinayak Katoch Date: Wed, 21 Jan 2026 12:37:28 +0530 Subject: [PATCH 12/69] Add cross-compilation dependency installation instructions Document required dependencies (libyaml, libmd, libbsd) for cross-compiling FastRPC on Ubuntu. Include step-by-step build instructions with proper cross-compilation configuration for aarch64-linux-gnu target to resolve dependency missing failures during the build process. Signed-off-by: Vinayak Katoch --- README.md | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7fb4a88..6bbcd65 100644 --- a/README.md +++ b/README.md @@ -57,12 +57,46 @@ sudo make install ### Steps to cross-compile the project on Ubuntu -1. **Install the cross compiler and dependencies:** +1. **Install the cross compiler and required dependencies:** + Install cross-compilation toolchain: ```bash sudo apt install g++-aarch64-linux-gnu binutils-aarch64-linux-gnu ``` + Install and build libyaml: + ```bash + git clone https://github.com/yaml/libyaml.git + cd libyaml + ./bootstrap + ./configure --host=aarch64-linux-gnu + make + sudo make install + cd .. + ``` + + Install and build libmd: + ```bash + git clone https://git.hadrons.org/git/libmd.git + cd libmd + ./autogen + ./configure --host=aarch64-linux-gnu + make + sudo make install + cd .. + ``` + + Install and build libbsd: + ```bash + git clone https://gitlab.freedesktop.org/libbsd/libbsd.git + cd libbsd + ./autogen + ./configure --host=aarch64-linux-gnu + make + sudo make install + cd .. + ``` + 2. **Create softlink files for the compiler, linker, and other tools. Create environment variables as below for the auto tools:** ```bash From db3e697e6fd1d10d38b65ec3a25168ab07e4a4ed Mon Sep 17 00:00:00 2001 From: Jianping Li Date: Mon, 19 Jan 2026 17:32:46 +0800 Subject: [PATCH 13/69] Handle RPC_PM_QOS command for backward compatibility Some may send the RPC_PM_QOS control-domain command. The current driver does not support PM QoS operations, so return a false success to preserve compatibility and avoid triggering unexpected failures. Signed-off-by: Jianping Li --- src/fastrpc_apps_user.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/fastrpc_apps_user.c b/src/fastrpc_apps_user.c index c19fbef..0807bca 100644 --- a/src/fastrpc_apps_user.c +++ b/src/fastrpc_apps_user.c @@ -2294,6 +2294,11 @@ int remote_handle_control_domain(int domain, remote_handle64 h, uint32_t req, fastrpc_set_qos_latency(domain, h, FASTRPC_QOS_MAX_LATENCY_USEC); break; } + case RPC_PM_QOS: { + FARF(ALWAYS, "Warning: PM QoS is not supported; ignoring request and returning " + "success for backward compatibility"); + break; + } case RPC_ADAPTIVE_QOS: { /* Enable adaptive QoS */ VERIFY(AEE_SUCCESS == From eeb9d5b7d7a54873d2ceb6c5362dfd895ce68b35 Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Tue, 20 Jan 2026 16:53:37 +0530 Subject: [PATCH 14/69] CI: Add nightly kernel build workflow with weekly artifact upload - Introduces GitHub Actions workflow to build the Linux kernel using the FastRPC Docker image - Runs weekly every Sunday at midnight UTC - Builds kernel from qcom-next branch of qualcomm-linux/kernel - Uploads compressed artifacts for debugging and validation Signed-off-by: Tharun Kumar Merugu --- .github/nightly-kernel-build.yml | 88 ++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 .github/nightly-kernel-build.yml diff --git a/.github/nightly-kernel-build.yml b/.github/nightly-kernel-build.yml new file mode 100644 index 0000000..9cd2087 --- /dev/null +++ b/.github/nightly-kernel-build.yml @@ -0,0 +1,88 @@ +# Nightly Build kernel and upload artifacts +# This workflow builds the Linux kernel nightly from the `qcom-next` branch +# of the `qualcomm-linux/kernel` repository using a custom Docker image. +# Artifacts are zipped and uploaded for 30 days retention. + +name: Nightly Build kernel and upload artifacts + +on: + schedule: + - cron: '0 0 * * 0' # Runs every Sunday at midnight UTC + workflow_dispatch: # Allows manual trigger + +jobs: + build-and-upload: + runs-on: + group: GHA-fastrpc-Prd-SelfHosted-RG + labels: [ self-hosted, fastrpc-prd-u2404-x64-large-od-ephem ] + steps: + # Checkout fastrpc-image repository to get the Dockerfile + - name: Checkout fastrpc-image repo for Dockerfile + uses: actions/checkout@v4 + with: + fetch-depth: 0 + repository: qualcomm/fastrpc-image + ref: main + + - name: Build fastrpc docker image + run: | + docker build -t fastrpc-image:latest -f Dockerfile . + + - name: Configure git + shell: bash + run: | + git config --global user.name "github-actions" + git config --global user.email "github-actions@github.com" + + - name: Clone kernel repository + shell: bash + run: | + echo "Cloning qualcomm-linux/kernel into ${{ github.workspace }}/kernel..." + git clone https://github.com/qualcomm-linux/kernel.git "${{ github.workspace }}/kernel" + cd "${{ github.workspace }}/kernel" + echo "Fetching all branches and checking out 'qcom-next'..." + git fetch origin + git checkout qcom-next + echo "Successfully checked out qcom-next branch." + + - name: Build kernel + shell: bash + run: | + echo "Creating kobj directory for out-of-tree build output..." + mkdir -p "${{ github.workspace }}/kobj" + echo "Running Docker container to build the kernel..." + docker run -i --rm \ + --user "$(id -u):$(id -g)" \ + --volume "${{ github.workspace }}:/workspace" \ + --workdir="/workspace/kernel" \ + fastrpc-image:latest bash -c " + echo 'Inside container: Current working directory is $(pwd)' + echo 'Inside container: Building kernel with output directory O=/workspace/kobj' + make O=/workspace/kobj defconfig + make O=/workspace/kobj -j\$(nproc) all + make O=/workspace/kobj -j\$(nproc) dir-pkg INSTALL_MOD_STRIP=1 + " + echo "Kernel build completed. Checking for kobj output..." + ls -l "${{ github.workspace }}/kobj" || echo "kobj directory is empty or missing." + + - name: Zip kobj folder + shell: bash + run: | + mkdir -p build_output + if [ -d "${{ github.workspace }}/kobj" ]; then + echo "zipping kobj to build_output/kobj.tar.gz..." + tar -cvf build_output/kobj.tar -C "${{ github.workspace }}" kobj + gzip -9 build_output/kobj.tar + echo "Successfully created build_output/kobj.tar.gz" + else + echo "Error: kobj directory not found." + exit 1 + fi + + - name: Upload zipped kobj as artifact to aws S3 bucket + uses: qualcomm/fastrpc/.github/actions/aws_s3_helper@development + with: + s3_bucket: qli-prd-fastrpc-gh-artifacts + local_file: ${{ github.workspace }}/build_output/kobj.tar.gz + mode: single-upload + deviceTree: false \ No newline at end of file From e9df1a21f884391270735087b391ec89290c48ac Mon Sep 17 00:00:00 2001 From: Simon Beaudoin Date: Sat, 18 Oct 2025 23:43:41 -0700 Subject: [PATCH 15/69] Add workflow to trigger a build of the package repo This workflow is an adapted copy of this workflow : https://github.com/qualcomm-linux/pkg-template/blob/main/.github/workflows/to_paste_in_upstream/pkg-build-pr-check.yml With this workflow in position, a PR in the upstream project repo (this one) triggers a build or the sister package repo. The special repo variable PKG_REPO_GITHUB_NAME will need to be set. See visit https://github.com/qualcomm-linux/pkg-template for more info about this whole CI workflow Signed-off-by: Simon Beaudoin --- .github/workflows/pkg-build-pr-check.yml | 39 ++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/pkg-build-pr-check.yml diff --git a/.github/workflows/pkg-build-pr-check.yml b/.github/workflows/pkg-build-pr-check.yml new file mode 100644 index 0000000..a0af2a3 --- /dev/null +++ b/.github/workflows/pkg-build-pr-check.yml @@ -0,0 +1,39 @@ + +name: Package Build PR Check +description: | + This workflow will execute when a PR is open against the configured branch. + On top of whatever kind of CI/CD logic happens in this upstream repo, this + workflow will make sure that what is attempted to be merged in the main release + branch won't break the debian package. The variable PKG_REPO_GITHUB_NAME needs to + be set in the repo where this file reside. This variable hold the packaging repo + name on github associated to this upstream repo. What will happen is that the PR + triggering this workflow will go knock on the packaging repo's door and trigger + a full build of the package if it were to include these changes. + +on: + pull_request_target: + branches: [ main, development ] + types: + - ready_for_review + - synchronize + paths-ignore: + - '.github/**' + +permissions: + contents: read + +concurrency: + group: pr-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + package-build-pr-check: + uses: qualcomm-linux/qcom-build-utils/.github/workflows/qcom-upstream-pr-pkg-build-reusable-workflow.yml@main + with: + qcom-build-utils-ref: main + upstream-repo: ${{github.repository}} + upstream-repo-ref: ${{github.head_ref}} + pkg-repo: ${{vars.PKG_REPO_GITHUB_NAME}} + pr-number: ${{github.event.pull_request.number}} + secrets: + TOKEN: ${{ secrets.DEB_PKG_BOT_CI_TOKEN }} From 9c9fee148c1f77aa6b562b32e3611359d885be72 Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Sat, 31 Jan 2026 16:42:20 +0530 Subject: [PATCH 16/69] CI: Introduce Precompiled Kernel Image Workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -This change adds support for a precompiled kernel image by implementing a nightly kernel build workflow that compiles the kernel once and uploads the resulting artifacts to S3. PR workflows are updated to download these nightly artifacts when generating the ramdisk, removing the need to rebuild the kernel within every PR. -This eliminates repeated kernel rebuilds across PRs, significantly reducing CI time, compute usage, and kernel‑related failure noise. Signed-off-by: Tharun Kumar Merugu --- .github/actions/aws_s3_helper/action.yml | 158 ++++++++++++++---- .github/actions/build/action.yml | 39 +++-- .github/actions/sync/action.yml | 16 -- .../{ => workflows}/nightly-kernel-build.yml | 7 +- .github/workflows/sync_build.yml | 1 + 5 files changed, 157 insertions(+), 64 deletions(-) rename .github/{ => workflows}/nightly-kernel-build.yml (96%) diff --git a/.github/actions/aws_s3_helper/action.yml b/.github/actions/aws_s3_helper/action.yml index 147f5de..8e43007 100644 --- a/.github/actions/aws_s3_helper/action.yml +++ b/.github/actions/aws_s3_helper/action.yml @@ -10,13 +10,21 @@ inputs: required: false default: ../artifacts/file_list.txt download_file: - description: S3 path of the file to download (e.g., path/to/your/file.txt). Used only in 'download' mode. + description: S3 key of the file to download (e.g., path/to/your/file.txt). Used only in 'download' mode. required: false default: '' download_location: - description: Local directory where the downloaded file should be placed. Used only in 'download' mode. + description: Local directory or file path where the downloaded file should be placed. Used only in 'download' mode. required: false default: . + artifacts: + description: > + Optional S3 key or prefix for upload/download. + - If ends with '/', it is treated as a prefix and the local filename is appended. + - If not ending with '/', it is treated as a full S3 key. + - If empty, a default location is derived. + required: false + default: '' mode: description: Mode of operation (single-upload, multi-upload, download) required: true @@ -39,50 +47,140 @@ runs: shell: bash env: UPLOAD_LOCATION: ${{ github.repository_owner }}/${{ github.event.repository.name }}/${{ github.workflow }}/${{ github.head_ref != '' && github.head_ref || github.run_id }}/${{ inputs.deviceTree }}/ + DEFAULT_UPLOAD_LOCATION: ${{ github.repository_owner }}/${{ github.event.repository.name }}/ run: | + set -euo pipefail echo "::group::$(printf '__________ %-100s' 'Process' | tr ' ' _)" - case "${{ inputs.mode }}" in + + S3_BUCKET="${{ inputs.s3_bucket }}" + MODE="${{ inputs.mode }}" + LOCAL_FILE="${{ inputs.local_file }}" + ARTIFACTS="${{ inputs.artifacts }}" + DOWNLOAD_FILE="${{ inputs.download_file }}" + DOWNLOAD_LOCATION="${{ inputs.download_location }}" + WORKSPACE="${{ github.workspace }}" + DEVICE="${{ inputs.deviceTree }}" + UPLOAD_LOCATION="${{ env.UPLOAD_LOCATION }}" + DEFAULT_UPLOAD_LOCATION="${{ env.DEFAULT_UPLOAD_LOCATION }}" + + # Helpers + _choose_upload_key() { + # $1: local path of file to upload + local local_path="$1" + local base; base="$(basename "$local_path")" + + if [ -n "$ARTIFACTS" ]; then + # user provided a path; decide whether it's a prefix or a full key + if [[ "$ARTIFACTS" == */ ]]; then + # prefix: append filename + echo "${ARTIFACTS}${base}" + else + # full key + echo "${ARTIFACTS}" + fi + else + # default to computed upload location + filename + echo "${UPLOAD_LOCATION}${base}" + fi + } + + case "${MODE}" in multi-upload) - echo "Uploading files to S3 bucket..." + echo "Uploading files to S3 bucket (multi-upload)..." + if [ ! -f "$LOCAL_FILE" ]; then + echo "ERROR: File list not found: $LOCAL_FILE" >&2 + exit 1 + fi + + mkdir -p "${WORKSPACE}/${DEVICE}" + MANIFEST="${WORKSPACE}/${DEVICE}/presigned_urls_${DEVICE}.json" + echo "{" > "$MANIFEST" first_line=true - # Start the JSON object - mkdir -p "${{ github.workspace }}/${{ inputs.deviceTree }}" - echo "{" > ${{ github.workspace }}/${{ inputs.deviceTree }}/presigned_urls_${{ inputs.deviceTree }}.json - while IFS= read -r file; do + + while IFS= read -r file || [ -n "$file" ]; do + # Skip blank and comment lines + [[ -z "${file// }" || "$file" =~ ^[[:space:]]*# ]] && continue + if [ -f "$file" ]; then - echo "Uploading $file..." - aws s3 cp "$file" s3://${{ inputs.s3_bucket }}/${{ env.UPLOAD_LOCATION }} - echo "Uploaded $file to s3://${{ inputs.s3_bucket }}/${{ env.UPLOAD_LOCATION }}" - echo "Creating Pre-signed URL for $file..." - filename=$(basename "$file") - presigned_url=$(aws s3 presign s3://${{ inputs.s3_bucket }}/${{ env.UPLOAD_LOCATION }}$filename --expires-in 259200) + key="$(_choose_upload_key "$file")" + s3_uri="s3://${S3_BUCKET}/${key}" + + echo "Uploading $file to $s3_uri ..." + aws s3 cp "$file" "$s3_uri" --sse AES256 + echo "Uploaded $file to $s3_uri" + + echo "Creating Pre-signed URL for $s3_uri ..." + presigned_url=$(aws s3 presign "$s3_uri" --expires-in 259200) + if [ "$first_line" = true ]; then first_line=false else - echo "," >> ${{ github.workspace }}/${{ inputs.deviceTree }}/presigned_urls_${{ inputs.deviceTree }}.json + echo "," >> "$MANIFEST" fi - # Append the pre-signed URL to the file - echo " \"${file}\": \"${presigned_url}\"" >> ${{ github.workspace }}/${{ inputs.deviceTree }}/presigned_urls_${{ inputs.deviceTree }}.json - echo "Pre-signed URL for $file: $presigned_url" + + printf ' "%s": "%s"' "$file" "$presigned_url" >> "$MANIFEST" + echo "" else - echo "Warning: $file does not exist or is not a regular file." + echo "Warning: $file does not exist or is not a regular file." >&2 fi - done < "${{ inputs.local_file }}" - # Close the JSON object - echo "}" >> ${{ github.workspace }}/${{ inputs.deviceTree }}/presigned_urls_${{ inputs.deviceTree }}.json + done < "$LOCAL_FILE" + + + echo "}" >> "$MANIFEST" ;; + single-upload) echo "Uploading single file to S3 bucket..." - aws s3 cp "${{ inputs.local_file }}" s3://${{ inputs.s3_bucket }}/${{ env.UPLOAD_LOCATION }} - echo "Uploaded ${{ inputs.local_file }} to s3://${{ inputs.s3_bucket }}/${{ env.UPLOAD_LOCATION }}" - echo "Creating Pre-signed URL for ${{ inputs.local_file }}..." - presigned_url=$(aws s3 presign s3://${{ inputs.s3_bucket }}/${{ env.UPLOAD_LOCATION }}${{ inputs.local_file }} --expires-in 259200) + if [ ! -f "$LOCAL_FILE" ]; then + echo "ERROR: Local file not found: $LOCAL_FILE" >&2 + exit 1 + fi + + key="$(_choose_upload_key "$LOCAL_FILE")" + s3_uri="s3://${S3_BUCKET}/${key}" + + echo "Uploading $LOCAL_FILE to $s3_uri ..." + aws s3 cp "$LOCAL_FILE" "$s3_uri" --sse AES256 + echo "Uploaded $LOCAL_FILE to $s3_uri" + + echo "Creating Pre-signed URL for $s3_uri ..." + presigned_url=$(aws s3 presign "$s3_uri" --expires-in 259200) echo "presigned_url=${presigned_url}" >> "$GITHUB_OUTPUT" ;; + download) - #Download The required file from s3 - echo "Downloading files from S3 bucket..." - aws s3 cp s3://${{ inputs.s3_bucket }}/${{ inputs.download_file }} ${{ inputs.download_location }} + + echo "Downloading file from S3 bucket..." + # Priority: + # - If ARTIFACTS is provided and not ending with '/', treat it as key + # - Else if ARTIFACTS ends with '/', error (need a concrete key) + # - Else use DOWNLOAD_FILE (must be set) + if [ -n "$ARTIFACTS" ]; then + if [[ "$ARTIFACTS" == */ ]]; then + echo "ERROR: 'artifacts' ends with '/'. Please provide a full S3 key (not a prefix) for download mode, or use 'download_file'." >&2 + exit 1 + fi + key="$ARTIFACTS" + else + if [ -z "$DOWNLOAD_FILE" ]; then + echo "ERROR: 'download_file' must be provided when 'artifacts' is empty in download mode." >&2 + exit 1 + fi + key="$DOWNLOAD_FILE" + fi + s3_uri="s3://${S3_BUCKET}/${key}" + + # Ensure download location exists if it is a directory + if [ -d "$DOWNLOAD_LOCATION" ]; then + echo "Downloading $s3_uri -> ${DOWNLOAD_LOCATION}/" + aws s3 cp "$s3_uri" "${DOWNLOAD_LOCATION}/" + else + mkdir -p "$(dirname "$DOWNLOAD_LOCATION")" + echo "Downloading $s3_uri -> ${DOWNLOAD_LOCATION}" + aws s3 cp "$s3_uri" "${DOWNLOAD_LOCATION}" + fi + + echo "Downloaded ${s3_uri} to ${DOWNLOAD_LOCATION}" ;; *) echo "Invalid mode. Use 'upload' or 'download'." @@ -90,6 +188,8 @@ runs: ;; esac + echo "::endgroup::" + - name: Upload artifacts if: ${{ inputs.mode == 'multi-upload' }} uses: actions/upload-artifact@v4 diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index cae6e2f..87926af 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -16,6 +16,10 @@ inputs: workspace_path: description: Workspace path required: true + deviceTree: + description: Target device Tree name or identifier, used to organize uploads in S3. + type: string + required: true runs: using: "composite" @@ -35,26 +39,29 @@ runs: " echo "::endgroup::" - - name: Build kernel using Docker Image - shell: bash - run: | - cd ${{ inputs.workspace_path }}/kernel - - echo "::group::$(printf '__________ %-100s' 'Compile kernel' | tr ' ' _)" - docker run -i --rm \ - --user $(id -u):$(id -g) \ - --workdir="$PWD" \ - -v "$(dirname $PWD)":"$(dirname $PWD)" \ - ${{ inputs.docker_image }} bash -c " - make O=../kobj defconfig - make O=../kobj -j$(nproc) - make O=../kobj -j$(nproc) dir-pkg INSTALL_MOD_STRIP=1 - " - echo "::endgroup::" + - name: Download Kernel artifact + uses: qualcomm-linux-stg/fastrpc/.github/actions/aws_s3_helper@development + with: + s3_bucket: qli-stg-fastrpc-gh-artifacts + artifacts: kernel-artifact/kobj.tar.gz + deviceTree: false + download_location: ${{ inputs.workspace_path }} + mode: download - name: Package Files into ramdisk shell: bash run: | + echo "Extracting kobj.tar.gz" + ls -la ${{ inputs.workspace_path }}/ + mkdir -p extracted_kobj + tar -xzf "${{ inputs.workspace_path }}/kobj.tar.gz" -C extracted_kobj + echo "Contents of extracted_kobj:" + find extracted_kobj -type d + # Move extracted folder to kobj + rm -rf kobj + mv extracted_kobj/kobj kobj + ls -la kobj + echo "Package FastRPC firmware files" cp -r ${{ inputs.workspace_path }}/firmware_dir/* ${{ inputs.workspace_path }}/artifacts/ramdisk_fastrpc/ diff --git a/.github/actions/sync/action.yml b/.github/actions/sync/action.yml index 6eb3ce1..677ed74 100644 --- a/.github/actions/sync/action.yml +++ b/.github/actions/sync/action.yml @@ -6,7 +6,6 @@ description: | It clones and copies FastRPC hexagon DSP binaries and Linux firmware (specifically QCOM firmware) based on the provided `hexDSPBinary` and `linuxFirmware` input. - It also clones the `qualcomm-linux/kernel` repository. The action sets an output `workspace_path` to the GitHub workspace directory. @@ -107,21 +106,6 @@ runs: find firmware_dir -type d -print find firmware_dir -type f -print - - name: Configure git - shell: bash - run: | - git config --global user.name "github-actions" - git config --global user.email "github-actions@github.com" - - - name: Clone kernel repositories - shell: bash - run: | - cd ${{ github.workspace }} - git clone https://github.com/qualcomm-linux/kernel.git - cd kernel - git fetch origin - git checkout qcom-next - - name: Set workspace path id: set-workspace shell: bash diff --git a/.github/nightly-kernel-build.yml b/.github/workflows/nightly-kernel-build.yml similarity index 96% rename from .github/nightly-kernel-build.yml rename to .github/workflows/nightly-kernel-build.yml index 9cd2087..b70466a 100644 --- a/.github/nightly-kernel-build.yml +++ b/.github/workflows/nightly-kernel-build.yml @@ -7,14 +7,14 @@ name: Nightly Build kernel and upload artifacts on: schedule: - - cron: '0 0 * * 0' # Runs every Sunday at midnight UTC + - cron: '0 0 * * 0' # Runs at 00:00, only on Sunday UTC workflow_dispatch: # Allows manual trigger jobs: build-and-upload: - runs-on: + runs-on: group: GHA-fastrpc-Prd-SelfHosted-RG - labels: [ self-hosted, fastrpc-prd-u2404-x64-large-od-ephem ] + labels: [ self-hosted, fastrpc-prd-u2404-x64-large-od-ephem ] steps: # Checkout fastrpc-image repository to get the Dockerfile - name: Checkout fastrpc-image repo for Dockerfile @@ -85,4 +85,5 @@ jobs: s3_bucket: qli-prd-fastrpc-gh-artifacts local_file: ${{ github.workspace }}/build_output/kobj.tar.gz mode: single-upload + artifacts: kernel-artifact/kobj.tar.gz deviceTree: false \ No newline at end of file diff --git a/.github/workflows/sync_build.yml b/.github/workflows/sync_build.yml index f886c00..e7cafa3 100644 --- a/.github/workflows/sync_build.yml +++ b/.github/workflows/sync_build.yml @@ -57,6 +57,7 @@ jobs: with: docker_image: ${{ inputs.docker_image }} workspace_path: ${{ steps.sync.outputs.workspace_path }} + deviceTree: ${{ inputs.deviceTree }} - name: Create file list for artifacts upload run: | From afbf652dc172a0bcf633865e9ae9bd64ca84c3ec Mon Sep 17 00:00:00 2001 From: Abhinav Parihar Date: Mon, 2 Feb 2026 14:05:41 +0530 Subject: [PATCH 17/69] Move -ldl -lm and $(USE_LOG) from LDFLAGS to *_LIBADD Autotools expects library dependencies to be specified via *_LIBADD, not LDFLAGS. Placing -ldl -lm and $(USE_LOG) in *_LIBADD ensures libtool orders them after objects and before dependent libs, and prevents it from treating dependent libs as linker flags. This fixes a non-Android link failure on aarch64 where libtool tried to load a .la for BSD and errored with: libtool: error: '/usr/aarch64-linux-gnu/lib/libbsd.la' is not a valid libtool archive By moving these flags into lib{adsp,cdsp,sdsp,gdsp}rpc_la_LIBADD and keeping LDFLAGS limited to versioning, the link completes cleanly across targets. Signed-off-by: Abhinav Parihar --- src/Makefile.am | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index fd0e080..0191bf0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -68,17 +68,17 @@ if ANDROID_CC USE_LOG = -llog else # Add YAML and BSD libs to link flags for non-Android builds -libadsprpc_la_LIBADD = @YAML_LIBS@ @BSD_LIBS@ -libcdsprpc_la_LIBADD = @YAML_LIBS@ @BSD_LIBS@ -libsdsprpc_la_LIBADD = @YAML_LIBS@ @BSD_LIBS@ -libgdsprpc_la_LIBADD = @YAML_LIBS@ @BSD_LIBS@ +libadsprpc_la_LIBADD = -ldl -lm $(USE_LOG) @YAML_LIBS@ @BSD_LIBS@ +libcdsprpc_la_LIBADD = -ldl -lm $(USE_LOG) @YAML_LIBS@ @BSD_LIBS@ +libsdsprpc_la_LIBADD = -ldl -lm $(USE_LOG) @YAML_LIBS@ @BSD_LIBS@ +libgdsprpc_la_LIBADD = -ldl -lm $(USE_LOG) @YAML_LIBS@ @BSD_LIBS@ endif ADSP_CFLAGS = $(LIBDSPRPC_CFLAGS) -DDEFAULT_DOMAIN_ID=0 lib_LTLIBRARIES += libadsprpc.la libadsprpc_la_SOURCES = $(LIBDSPRPC_SOURCES) -libadsprpc_la_LDFLAGS = -ldl -lm $(USE_LOG) -version-number @LT_VERSION_NUMBER@ +libadsprpc_la_LDFLAGS = -version-number @LT_VERSION_NUMBER@ libadsprpc_la_CFLAGS = $(ADSP_CFLAGS) lib_LTLIBRARIES += libadsp_default_listener.la @@ -91,7 +91,7 @@ CDSP_CFLAGS = $(LIBDSPRPC_CFLAGS) -DDEFAULT_DOMAIN_ID=3 lib_LTLIBRARIES += libcdsprpc.la libcdsprpc_la_SOURCES = $(LIBDSPRPC_SOURCES) -libcdsprpc_la_LDFLAGS = -ldl -lm $(USE_LOG) -version-number @LT_VERSION_NUMBER@ +libcdsprpc_la_LDFLAGS = -version-number @LT_VERSION_NUMBER@ libcdsprpc_la_CFLAGS = $(CDSP_CFLAGS) lib_LTLIBRARIES += libcdsp_default_listener.la @@ -104,7 +104,7 @@ SDSP_CFLAGS = $(LIBDSPRPC_CFLAGS) -DDEFAULT_DOMAIN_ID=2 lib_LTLIBRARIES += libsdsprpc.la libsdsprpc_la_SOURCES = $(LIBDSPRPC_SOURCES) -libsdsprpc_la_LDFLAGS = -ldl -lm $(USE_LOG) -version-number @LT_VERSION_NUMBER@ +libsdsprpc_la_LDFLAGS = -version-number @LT_VERSION_NUMBER@ libsdsprpc_la_CFLAGS = $(SDSP_CFLAGS) lib_LTLIBRARIES += libsdsp_default_listener.la @@ -116,7 +116,7 @@ libsdsp_default_listener_la_CFLAGS = $(SDSP_CFLAGS) -DUSE_SYSLOG GDSP_CFLAGS = $(LIBDSPRPC_CFLAGS) -DDEFAULT_DOMAIN_ID=5 libgdsprpc_la_SOURCES = $(LIBDSPRPC_SOURCES) -libgdsprpc_la_LDFLAGS = -ldl -lm $(USE_LOG) -version-number @LT_VERSION_NUMBER@ +libgdsprpc_la_LDFLAGS = -version-number @LT_VERSION_NUMBER@ libgdsprpc_la_CFLAGS = $(GDSP_CFLAGS) libgdsp_default_listener_la_SOURCES = $(LIBDEFAULT_LISTENER_SOURCES) From a4955f1404c79ea5e1b4392b3e66c9d87c077310 Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Tue, 3 Feb 2026 17:10:40 +0530 Subject: [PATCH 18/69] CI: Use Generic overlay without kselftest and env-based test method - Switch to Generic overlay that excludes kselftest - Removes unnecessary kselftest dependency for our use cases Signed-off-by: Tharun Kumar Merugu --- .github/actions/lava_job_render/action.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/lava_job_render/action.yml b/.github/actions/lava_job_render/action.yml index 98ad026..8b18d2e 100644 --- a/.github/actions/lava_job_render/action.yml +++ b/.github/actions/lava_job_render/action.yml @@ -178,6 +178,7 @@ runs: -e TARGET_DTB="${{ env.DEVICE_TREE }}" \ ${{ inputs.docker_image }} \ sh -c 'export BOOT_METHOD=fastboot && \ + export TEST_METHOD=generic && \ export TARGET=${TARGET} && \ export TARGET_DTB=${TARGET_DTB} && \ python3 lava_Job_definition_generator.py --localjson ./data/cloudData.json --fastrpc-premerge' From 4d44250444172c9e4aaf355fc6ee3da9e624d824 Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Tue, 6 Jan 2026 15:56:56 +0530 Subject: [PATCH 19/69] feat(talos): add support for qcs615-ride target - Added new Talos target configuration - Enables Talos to build and test for the qcs615-ride platform with correct device tree, firmware, LAVA integration, and DSP binary mapping. Signed-off-by: Tharun Kumar Merugu --- ci/MACHINES.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ci/MACHINES.json b/ci/MACHINES.json index 44d8ecd..df35c5a 100644 --- a/ci/MACHINES.json +++ b/ci/MACHINES.json @@ -16,5 +16,11 @@ "linuxFirmware": "qcs8300", "lavaDeviceName": "qcs8300-ride", "hexDSPBinary": "qcs8300" + }, + "qcs615-ride": { + "deviceTree": "qcs615-ride", + "linuxFirmware": "qcs615", + "lavaDeviceName": "qcs615-ride", + "hexDSPBinary": "qcs615" } } \ No newline at end of file From 51ebeab8d21e2f397040dcf69ec3463733f4b287 Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Thu, 5 Feb 2026 12:39:24 +0530 Subject: [PATCH 20/69] fix(prod): update S3 bucket to qli-prd-fastrpc-gh-artifacts Bug - Production was still referencing the staging artifacts bucket (qli-stg-fastrpc-gh-artifacts) causing 403/NotFound when fetching runtime asset. Fix - Replace STG bucket with PRD bucket in prod config Signed-off-by: Tharun Kumar Merugu --- .github/actions/build/action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index 87926af..f64628c 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -40,9 +40,9 @@ runs: echo "::endgroup::" - name: Download Kernel artifact - uses: qualcomm-linux-stg/fastrpc/.github/actions/aws_s3_helper@development + uses: qualcomm/fastrpc/.github/actions/aws_s3_helper@development with: - s3_bucket: qli-stg-fastrpc-gh-artifacts + s3_bucket: qli-prd-fastrpc-gh-artifacts artifacts: kernel-artifact/kobj.tar.gz deviceTree: false download_location: ${{ inputs.workspace_path }} From d1e70ea2a5cd5302147014b1829ea4f2b870d79b Mon Sep 17 00:00:00 2001 From: Vinayak Katoch Date: Wed, 21 Jan 2026 17:20:32 +0530 Subject: [PATCH 21/69] dsprpcd: Add help functionality Add -h/--help support to display daemon usage, functionality, and command-line options with appropriate examples for each DSP subsystem. Signed-off-by: Vinayak Katoch --- src/dsprpcd.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/src/dsprpcd.c b/src/dsprpcd.c index 348049a..2e203b5 100644 --- a/src/dsprpcd.c +++ b/src/dsprpcd.c @@ -14,6 +14,7 @@ #include #include #include +#include #ifndef ADSP_LISTENER_VERSIONED #define ADSP_LISTENER_VERSIONED "libadsp_default_listener.so.1" @@ -34,6 +35,64 @@ typedef int (*dsp_default_listener_start_t)(int argc, char *argv[]); +/** + * Prints help information about the daemon. + * @param program_name The name of the program + * @param dsp_name The DSP name (ADSP, CDSP, etc.) + */ +static void print_help(const char *program_name, const char *dsp_name) { + printf("Usage: %s [OPTION]...\n", program_name); + printf("Daemon that establishes a connection to %s.\n", dsp_name); +#ifdef USE_ADSP + printf("If audiopd is passed as an argument to this daemon, it will connect to audio PD on %s.\n", dsp_name); +#endif + printf("If no argument is provided or rootpd is passed, it will connect to root PD on %s.\n\n", dsp_name); + + printf("Functionality:\n"); +#ifdef USE_ADSP + printf(" rootpd:\n"); + printf(" - Exception logging: Facilitates transfer of %s process exception logs\n", dsp_name); + printf(" to the HLOS (High-Level Operating System) logging infrastructure for\n"); + printf(" effective monitoring and debugging\n"); + printf(" - Remote file system access\n"); + printf(" audiopd:\n"); + printf(" - Memory requirements for audio PD dynamic loading\n"); + printf(" - Remote file system access\n\n"); +#elif defined(USE_SDSP) + printf(" rootpd:\n"); + printf(" - Remote file system access\n\n"); +#else + printf(" rootpd:\n"); + printf(" - Exception logging: Facilitates transfer of %s process exception logs\n", dsp_name); + printf(" to the HLOS (High-Level Operating System) logging infrastructure for\n"); + printf(" effective monitoring and debugging\n"); + printf(" - Remote file system access\n\n"); +#endif + + printf("Options:\n"); + printf(" -h, --help display this help and exit\n"); + printf(" start daemon for specific PD and domain\n"); +#ifdef USE_ADSP + printf(" example: %s rootpd adsp\n", program_name); +#elif defined(USE_SDSP) + printf(" example: %s rootpd sdsp\n", program_name); +#elif defined(USE_CDSP) + printf(" example: %s rootpd cdsp (or cdsp1)\n", program_name); +#elif defined(USE_GDSP) + printf(" example: %s rootpd gdsp0 (or gdsp1)\n", program_name); +#endif +#ifndef USE_GDSP + printf(" start daemon for specific PD\n"); + printf(" example: %s rootpd\n", program_name); + printf(" (no arguments) start daemon for root PD (default domain)\n\n"); +#else + printf("\n"); +#endif + + printf("Note that this daemon runs continuously and automatically restarts on errors.\n"); + printf("It exits only when the fastRPC device node is not accessible.\n"); +} + // Result struct for dlopen. struct dlopen_result { void *handle; @@ -93,6 +152,25 @@ int main(int argc, char *argv[]) { #else goto bail; #endif + + // Parse command-line options + static struct option long_options[] = { + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} + }; + + int opt; + while ((opt = getopt_long(argc, argv, "h", long_options, NULL)) != -1) { + switch (opt) { + case 'h': + print_help(argv[0], dsp_name); + return 0; + default: + fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]); + return 1; + } + } + VERIFY_EPRINTF("%s daemon starting", dsp_name); while (1) { From e5e0cf9945e80b477099795f71b2cab7d30abb70 Mon Sep 17 00:00:00 2001 From: Sandhya Adavikolanu Date: Fri, 6 Feb 2026 14:25:11 -0800 Subject: [PATCH 22/69] Update stale-issues.yaml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit github-actions: align stale workflow with OSSOps recommendations This update brings the stale-issues GitHub workflow into alignment with OSSOps-recommended settings. The changes improve the handling of stale issues and pull requests, ensure maintainers are notified when items become stale, and prevent premature closure of open work. These updates help maintain consistent triage behavior across Qualcomm-hosted open-source projects. Changes included: - Set a 30-day threshold for marking issues and PRs as stale. - Notify the appropriate team when an item becomes stale. - Prevent automatic closure of stale issues and PRs. - Preserve existing exemption labels and behavior. - Improve consistency with Qualcomm open-source automation templates. These changes enhance project hygiene and ensure the workflow follows Qualcomm’s open-source best practices. Signed-off-by: Sandhya Adavikolanu --- .github/workflows/stale-issues.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/stale-issues.yaml b/.github/workflows/stale-issues.yaml index 4fe8631..76f3db2 100644 --- a/.github/workflows/stale-issues.yaml +++ b/.github/workflows/stale-issues.yaml @@ -11,13 +11,13 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v9 + - uses: actions/stale@v10 with: - stale-issue-message: 'This issue has been marked as stale due to 60 days of inactivity.' - stale-pr-message: 'This pull request has been marked as stale due to 60 days of inactivity.' + stale-issue-message: 'qualcomm/fastrpc.triage This issue has been marked as stale due to 30 days of inactivity.' + stale-pr-message: 'qualcomm/fastrpc.triage This pull request has been marked as stale due to 30 days of inactivity.' exempt-issue-labels: bug,enhancement exempt-pr-labels: bug,enhancement - days-before-stale: 60 + days-before-stale: 30 days-before-close: -1 remove-stale-when-updated: true remove-issue-stale-when-updated: true From 0815543cfad50d1d0fc70eb4099ea977ce13a4f8 Mon Sep 17 00:00:00 2001 From: Simon Beaudoin Date: Tue, 10 Feb 2026 10:18:20 -0800 Subject: [PATCH 23/69] pkg-build-pr-check: Fix repo/ref when fork PR When the PR is from a fork of the upstream project, the pr-build-pr-check workflows did not handle that correctly. Now, the proper repo and ref are forwarded to the reusable workflow_ Signed-off-by: Simon Beaudoin --- .github/workflows/pkg-build-pr-check.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pkg-build-pr-check.yml b/.github/workflows/pkg-build-pr-check.yml index a0af2a3..3963281 100644 --- a/.github/workflows/pkg-build-pr-check.yml +++ b/.github/workflows/pkg-build-pr-check.yml @@ -31,8 +31,8 @@ jobs: uses: qualcomm-linux/qcom-build-utils/.github/workflows/qcom-upstream-pr-pkg-build-reusable-workflow.yml@main with: qcom-build-utils-ref: main - upstream-repo: ${{github.repository}} - upstream-repo-ref: ${{github.head_ref}} + upstream-repo: ${{ github.event.pull_request.head.repo.full_name }} + upstream-repo-ref: ${{ github.event.pull_request.head.ref }} pkg-repo: ${{vars.PKG_REPO_GITHUB_NAME}} pr-number: ${{github.event.pull_request.number}} secrets: From be0565fd4f6a045424449f24e1f108432e58779b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Minier?= Date: Sun, 15 Feb 2026 13:52:37 +0100 Subject: [PATCH 24/69] gitignore: Add .dirstamp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit automake will create .dirstamp as a target for build subdirectories, add these to build time artifacts. Also drop generated src/dspqueue/.dirstamp. Signed-off-by: Loïc Minier --- .gitignore | 1 + src/dspqueue/.dirstamp | 0 2 files changed, 1 insertion(+) delete mode 100644 src/dspqueue/.dirstamp diff --git a/.gitignore b/.gitignore index 39d4919..fb105e1 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ libtool stamp-h1 .deps/ +.dirstamp .libs/ # Compiled objects diff --git a/src/dspqueue/.dirstamp b/src/dspqueue/.dirstamp deleted file mode 100644 index e69de29..0000000 From d5c7039995ee526c342f72f0eb467800e942e463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Minier?= Date: Mon, 16 Feb 2026 18:45:35 +0100 Subject: [PATCH 25/69] README: Use Markdown to define Terms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop image which breaks the overall style and makes reading harder. Signed-off-by: Loïc Minier --- Docs/images/Term_definitions.png | Bin 55966 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Docs/images/Term_definitions.png diff --git a/Docs/images/Term_definitions.png b/Docs/images/Term_definitions.png deleted file mode 100644 index 9875fdb9e26e43326cfd35c0a875f54953437483..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55966 zcmdSBWmJ@18}|(&B`p$4Nk|AvDGV(zfGDjZNJ$Pz4&6w1qkxnQC}7ai-R02IJv0p6 z_3rVy?&n_5TJOjA!~K46c`}PNoaf&AJoa(?{{Lf#s;MZD+_-ZC3k!=x@hMaT3+vhz z_{U3t2R>=Be7p$$!*@b{RHii`o{7M>3Fo!({#A&kpWAe+EmkXS{urHk)zW4 zC;7}Em0X5^Ie;9|R-%T^`S&`Aby*Mdp-f1`-T$qtkauqfvK4LWFAg1O^j$MkL>$b} z=J5TknHlTagFiOM+jEtynCH>z;~H~oFVeF9HGISS^l&q!S|el)M}p|UCR*aq?r6#- z<7^>X%Kmka4j77swLd@Csr6mwCSzUCAvfBIj)dP0aULaNMx({YE28r1-jT-#S}E@u z4|L`7#!+WHhfZmsaeI`_-f!V@W6OftvI(;k>kSv?Z$zonmid)!n`IL=Hp8!8J8jjS z<G`I9F+kXl#Vn_gT>I968yCGrqq1yqqf;? zVVg;aL!s97n#a4juRW zAv`DD{hP-|QTybK&(-FeGAj!Td*ns^)zQ`DYEA|kU3;W|G^i?7=`^A@@}Rhbg-X=( za11uFT+%C9@>E1LVqq#@Pi*9~G>!}S!U=?7AeE+FFr#}eorHU--J5fn3-{!Ab|1!!dl^z;j2gd=Dv>lI1w4EL>SocY5FD7x|S; zmtu}enpI=_HM_Qm+e_#Ao;$5elZar*=J`bnrE10MV2%#z^5SU5g+|XYc73|GT4a7@ z^oMpy4~2X%je#fJWxrpcy2!Y_O25`U83$cCAI7aTvOxRDJjU|RkL2~fO#juR2j!FV zLgVJFI%-eKZKftK&$eudqGQ0YPw6?2nWED@&_%8MQKARchvSyqi$jAS!HcaKkt~L; zXudd{u&pe?JamWXFuG;|5~Jx~;@do30#gmQB4rRAioEmqzRL%}V0sRsV3W{$9}A74 zY92@EO(bN2c%;h7GTiaBgL8y(nC+AkD*5S=#r#JDZ@2K=h1vO1sjKt7uTm?_ry=oY zODVRWjIY2_)e1;2<#qOdioHJYC4BLBiMdH4J_ntb3A18p$`rF|G^2!-VHmQwq6fcM z;%L%=J3SJ)kXsUig+M_EwLJqOZVR@pd5;dnA-u4fi?mkOr7f=bvaJMHj_9G*eI=DeY?%i`t zW2SgC$NKl?8pZeCmrptCgnt7QbwR~sKOdO;&@K!f6>7FHb zVMyu(6>n2edsti=zh>v%`Ri)0SIWVM5EFm1v&Pe0G-y8RIcq=HoBbk&NTIW>DUyRK zT96||8|J)Mza;Y9j}%lfNuzmxk!gr&>CrFsRs{sgF7!0(W54 z_!-`0_6NmzoWh=T6rw@KUf>nd(T7yd6b@_ZRBo2fOxO7? z)$Ac1UhBJk@#4OjCjdEO^4#`aM36CxkJe$EH3blU{93#}@O;9nCfoh;WO*VyZ!#PQ zDa=TPbF@ReJFPfoG59s|ff2k1-ell?Vmgr-<}D>*Q28wCT+e07ls8|)rw+a(b#)T$ zl@)=B(bUA>rrbD=oO9Bg1#$vCo$C7i3%VER?w=gqX6_=KDf5e(JKwdpIA+*_%&kmG zo^2RM395+kX3wweeTc3>DMpD|JoZ#xh!R7apX{KD;tvA{mG-?F-eZ5XMV1ecQ}E)| zDF>Z9QQtmC66K=4?g?yQ)ccXV+>&kD?v8^>Vkn0>N2;!3d8)>Ez z&Q(7Jkar&YG_^GOZGEQs`{|9-E^5rw5-mm!FyK>d$j ztwk_NdE21>eFiAWSLEbX+}S^g1A)4~`uN|;2_U~MjjYBz@Bi2pvmnxArp{{<2eVI{ zo$vKdO;$Q=ZrN+3nG&hrXbvWGSx$3F|C?ci5P-ckRctjoeo|HHB0)?;pIs%@JmV4D zSnQ{Fuowmb=tm;ah!XWIc~hGjs;nHD5GxJM<%?*kOFLL9Jg6G%9p9Za+_!3vCL@KX zSH7xdq>E`dHOXNolvwd^fq<{}#d{xm_Iij>tB2lwCDYX5PkfgL*fOVZ$i!#=#;w>U z=;l){XFP?|7+KOh>fkET?tH=o1gq5fwtw~cZntHrm6lfF=k`mtu>Kd!P$91Gdr`5N z{S=dZqzITk18aK~gk`X?uTO&T_DM`b@>_`&Gt^mREjMd28J51fHvBzNOe2X+j799l zp2c)cW%bdt$5hpNeu`Ke$-m#4vZs=LG37Gjbhc3vtz-J(mDO`dK<*%T?a@e)W%}|) zJh}>S&wXWV5{k>RAp!xbIAE(Nsow44o?=h2nlGDnw;U-js1I{EuQ@|k>wyh)1+V)}XzJ^1``2}yy zwjU-Xm~ff#+FO%PwZR@a-Fffr1#*f?!K;Q}a~GJ@Fy*nOCVHd3FjsOefRg8qLT&EM zZ{Zo;emtK`%zkShqB($0H1MuOpd~yGf0R=7x-yA6=B62dWb=o2hWDuj+Ny>pPuPC< zV9ABaS7nWr?4k$^Wi`l7nt$0$jjs`lFMzb5+#N1u>XEE*INRty#ptnNXe|m-m#O2O zg-zYeU73m?GS}qVB)v1E`=B2Pcrn~Mp2uG4Lwv8_A#dV#WiatTtB zclV}lEIzVFJuS)HCz0xJUa>LHEH>O2EyA^aqdOCX8vI`2zC8HCyXsshtDQXEoYR6Y zVI!Y})N&fHhF_e{WOV1y4OxQSytH1n`qmoP-I>DLXz|^ra%1{Sf%{qn>VjM;dr`i} zAf=qt)Uh_jTlzJkf5xORpXM^n-y9e}^ULz}NRBGg#HW3>v|jwSwQ+0bwS6HJgj67aUDN)>(Kdr<(jD zAB^5evFUSRt5LpnV@EuNK7T>vd_u0KKOTv_!WHf^76)$5N5UPD`SR<%Wmz0^TL1I2 zFOqEvp~6G`QO8E)yJdlX?IcK743DmjOoFWUFg`S~YJRfBG(DP-lD$IIX>GLSV$?WV zyZW3Kn;pJe$mD%&SUwj-S5-daJ%Na-^*9o0&$6B0k70wu7$y6(y$DRBh>zVafaK{ZHM9* zD(A4`Jlo9O`4Eqfu+DplN~MC}O{x9@vjU~XM-~6cSZrsz5j__t-rD`RRVt|yxA zTMBU=e++!Q9I6U~({=0SE`q}@qqz0I1mvZldIo4OeZ6;$e0hS znG4t>-X~T#0gq9#zOetuAcI=xiW3CBiuKW=tjL|(!}0FZ^h-;yp`RTuL_dhRzK>0M ze#i3197vgs9d1*=PqRSEiEbj|bS)Ht zC!WKU2h z-VJxrd+fi56%ia%HD2$5b~?m45~Z2-D<&i@Kd3+7wE<~lx5O&b)H!$;?(e6=Hj29+ zYR-68wcCu6ifzo^5w@{9Xd-OF-lnkCxE|8COHX|r%3AHTzJ#gm;_)|UUC?vqn5wVc z&QB|$(0ti8HH%Gqp5C5`$b8%jywWMUq26r=>UYfX59H0jFBVU@E=2w|yhhKHsztp` z^q@3GB%ViTSMG3-{OE^KLy#_}$`NOMe)|4pdEw8R-$D~Thz5%nj`LP;KEZF^90oy1HaDjSSDY>-(#nEzfv7!AGK&%J{wdmM zoe7t2w!OlDc-HfU?f630C8XK%=dX{y6?h`dITkW5-}*M{w!`Vo^B48kTHH+9{D|CW zzSF5|LHOE=SjBNFnLt5Wb~ZYg+AB26lEi517 z&>(mmpjH}OB@gUV+d_JDE2=xJ`saIH8;>@`oe4#+%81}i@Zfde|s%JxxuZS z@nv8Ij0$J7jrpEjNGa}`Jliid?R_$Vul2Q_{W$bsZv4wYd05RT;XaBcpwOqj-yh<` zy!)$r{S{_XK7M#<8xqBQ8MT(rp{Tm2Zgr6bwZ^i~L__N6tV?4bT%&yfozv#gcvy|K zuQ2*>tp`r;IQ||-xv;Cb>1~R28P^+OM4x_}Nrjz``|6jUybDW(rHe$&OJt_-X?}7m z)>HcDsjyui?J2>|Wt^;KhG0*&G*uk=54Ub3(yS;?Grl~jwc~^yzV$PCekUiEF!pJA zFH>MMsaOxotCi5J!UM?yPR;VsG?r^Le}rfLxJlYIgr|KDA5#vCzZXSm-yUiVBdL~t zc9ZQuohwEI`iYe5-o`ufla|=znc13HqrhhQ7Fz9CBT9TEwS{V?XXra)pH&}}%Y=1# zGV61XUa&51z<$1bcAEo!@Q_B){f*v2D#NudQ+}C8lDd=fiekv`2s%YR^nvmt8IzP^ z$QFud{wW``yYW+$uQ?=$hl!S#g$xu>zZvqB2HePE$;;HnY>r}#J2lx%Jt9CL4hc=?lU(cP(g zpZrxt@9c)h-&-tXRT#Pzi~{jbP$7Qu-RZ;p=x2fE8<+}*^g+Msnr!Wo@O6k?#aJb@ zO!0ul)SuzD$s*xa<5Dc6%s7#SfA)=7_7J^?A2iw&HEP4}VOB-jLaMpw!uwQv`<^^H zYxZH>oM|cljBG-9>Yi?}O`PAtoNe3dqAChpz4nJe7KqVXZM92$%*D?;kz)P)?D}O= z%|De>-<44)=Ip58Q_v6-a{H8>^K)j8xW*xu{U1mZ-1$Lw0;&=ZxvYdsGhx}krQl>{fvgax$-)xhiE zH(gKbpqlv^8PzwUG_Mq)6jqbtn;&D;TDvdIg)hmXYx6h4;)m~*2A5&*Qf2j3WyVgR zw9eR2WjtB-o$?8G(j^00Uk?ASw$SPjyH zNoHH&EbfZMY}ZsIL=?R2tSZvIL)No6A%6SZ#$vx8G7ypK+nK-{g7qrxc3xV!wUWbN z=1iniylTbo8_f{yjB9dTWCtwYdJvXir3ib?F3NN*$SLT*Te>sef(UkDvD;sOrK0U3i*e&kqehY@seBx9>8;0~f0ibDdt>+{WLfdHF}<1# za-kxAS>@U5IGfq?lDpCwT&!!O@%hcPupW5&x@&)00=)@qKnMFhu`NgowBNP=-i@FL zf*K!YV*K#(vrfy_qIpZ|P*KeE;4H|aNM$49og1+6M=zig$=jW0CIZdsb3Z*&N!huj zMD}h{SV+|r_4blS@bZ#kixJfj%XvZCMARJ`#=iK#Z@9us^{Sl@BMCj_?huKyE9!fr z?g{AsfsP!r6J4<|MKP#cS0Ozbn1PmaeHVQ?@PInKrb97+wAO5$zP-8Gtqq^oc~^jL zT2LjlWtS(Fjy^+X``Z1j;8gduJfZXuZ&oHmV8bZ;@O$HqxFLM|;LyXi z&N%nICi*Dq-kfQOTEq)v>w)?$dLs=xbB8<2;fW-b!7F0L#ykG!H4iw;YK%fk1ougV zh;zbhy$xZ0qO(?WJ+Gv|&XFP{%jXpfQ6+)i1PejCS{?jVJ+ z`~UGPr?zM&DdD4ki2(xd1q|)ed4YLO3?*;mw3f$^g#SHd;@`VcV@*2(C17Wog zWCa|^5h0&idXfdF+?LapgUFabUQ+nMG(l`jLJGkghy8ZZF!o{s$!MJeZZiSSqgjTlxNG5rakNAa*52M+ zFq3nM+3(^#$8F|ddPEfUFlm+R@5dt*;kRcd=bE2Me@)`Ie4zGD22^%$6fHr_fo^}9;JWB^;sd}~U2a`9rf6N|ExfmRwtGBA~ znLPV6)&CaPEuApjTT}LP5bp1G&nY+}>_fUzfo?#>&BJ^{dfz5qSqKgiiL_PIr;Z+! z5+-uUuG9sOt=e*rg-BstP$h2CDkTfFM&Ot_uMV_I>~^pg5ou&xdyh#=)S2YUN!8e?0nuWJ!RLHOle*dv129s=T=F}a zMcL;td)fr@ce>I&&h@+B&ex$7=~A87d;3$+e&2h_2|EEFtq z997yf^^tB1y@D?4m+_tu#`;r#NfRdNfDOIWm zH?FzwMH~0kx^@4#c{KvMDbV-@GSgnZ*-B%;lWS`+k!%9Xqf-$e2Fo0pfn_A}0=Nzwk4FO_Umwh(kO0 zv@QZzp|^-9L4h_e>bzl&JPV;yaZ!1N*fWS*fxv-@lqD7rVcYe)3Y>PAmE!b zjHrZd{u&WFS@Kt00UYPo)BE<#qsFMv1gwcH=v`3dTgS^ylvz(zE~i^k()9&bl7gwO_OBfgU8v{3-nv=8B-%pMy)&OMk<3dRj z2!bV@^=fYEGNJ(+!c&efzH@Jy-DE4IkTIb2nom|jN74zG)gknhs-T&6r-z#dSm(X zgV-(^&!IN`VhJIF7%3(LTdV<+jLv=<6fXw)FPwV&nM9m&%v<7M1)tgn&Xj%I}3BsB6ms<4xHM z+yTTy&mNX$jW6&})CFxd;q^Vg>f3D4UhDZ z4{vFoOqpptK*u^MyT1MbKWMv4Kb+->E$-_(RG(bhx!r_Q^Y?W(H$K3%WB+G3cA#Wm_2w?$|r&@Y$pAa(cqSZD5J?Rv;D?h?$td`wwURw*w(PDCT zh%=X}*yf{>FG>L*dZqq~BqSH%Kha?97qo9pF4Ts?Nlz#O7p6HO*E$HNGD%A_%x}B5 zI`q9}Ke+c%t0^@c1hPqLOK!BzOmvpMv1>{|3#mjG~dBsyKUB)dq#E>VC`i@rK zGrfo)T3c}{di7oN>+5~>qD{k`V*utJ>*?53E-I<;xPmwWtET?;+~D8EWxps&{TnKJ z(mDU_zE`TFMDg26`*aUGvk@IziFJe1fEljfld4hvl%-Rnv%YwFYQ>8t`h~^tnph9| zOuaUPXDli+17(!A+s3rXoQ%)=VAtvFs+#Xw(f_l0Di~M7$uGa!B&3mb!C=1YS}i>0 z3HO#6I9B%uRm)#Zf@<1WogjgIhFa+jUqB`z>n>->mN~NwU)PUI{+4M@%3n=tCn3*@ zX5Sle0#&?!lH&E8mSOhjQoHLOvrN+gEk(o|NyrsIrDN1t_0g^9jj@tVai^#|d}X)Y z^apAi*tQzqdV>gy1`2zrhaK&h%>yU>YL(IvTX^v9vv03M z>ObPj=L+vjv=5H&+CAK^B2Qxyr|14E@!tQvLkk+q__|lS;qC~uAlQE8d7XV;7Sk5I zjE!l|6)L5r+ke#B#rFF^{lq~c!_!M+BT3o8>!q`z*GgWP_mfhCrXr{tJiu9m6BbV3#BoktC+ zFAk4(n5S4sS|`tjUmJ`$vxl3PIfd30KW4!1XJctHJn^QhuHrINM+QjWP|;FlaoTsw zi(%gf;67RK_a9M;dC&fhQa)dO5M7pdN@B9}m7Xv|t3xX40l_-#As@Keb{p7UkFqglI`G_Neki0CvzJ1R}@ zhYM~)*E*Q*v8?SZ3NDSNv;S(7;>{OFh-8x#wytMdonnts+#@uQX)k z#+WXr_r9udkmk_BweF>zx8haS7U9!`H$w4b;Y{{}W7EB_8Bb~;v*Ip5&0gwpcwlej zcVltGC&y=O%tSbjfaT=3mGbh$W;Xpe)so?!Fc+3mM29Uhokn+!CYnVY32SqhLd=Wb-gDv}nvqG+F%VZQV8?c8(aIDbaKO^cgK9zFM)TO>n*+rNsmL1VE;>= zC}yIi^l>O)M(TLGldfZt=1j4Q36=oMP*rLZL(6Dt`DKbibP!Np7^*iAjn(ueK#Pt9+U!2@9nv}@{7XkD z8RD%91nQ18X{jem6Zt3WeS8F~P^Byih-2N}tqn(%KRo(}n{=o>XLMp>2e({0O8Vxe zkzqjXXZ=yq-QZQJ^u=CQ1&z3Kwif3D;LWk6fa#-*WU^F10rKsUx+}u#({<-in%Wgh zN$6@57F5HnA22FhCXvljTnPqoS3C4tSIkKG!@-;c-xn%uiH>~Zq2kB#`0RpR^J#c% z&#w5mN?tL1z3=uk8Nn1IxHxMU7aVOZXVA|*z3>^i!Xv6ikRSd1H35=m#Gb*c!_C_-eDpMBCZRI)lPyNYZFdY4(oS4Rs|k5o#DL{GO-*n|hC@+{~W$ zt(lKdA7dQtyZlFdGy!>1@R*ZEhsx+PuHaqQ#1PLjqrt>?q5wm23dFjUO?IxMA`SJ~ zq}@ix=Qz5$T86R|$Q-;OZ8|$B?#!o38<1zrld}8i*3@;i*sZG|DU(nQA&-z$Z}FVT z=phoN6^)=iZFw$+g2XNP?cJP~t>Y7MPi^jqSw~jW*K~AVqqyK0 zM1td+P;`Frvgy2(j6}R9DqSSf#N&!K90DeWEy4BLchwa(xOkn6xU;sK_)fm^==Li( z-f_#!QaWA1G7j(von`gdu+D5%(XBm|yttv-LHSbXnfR(xiyF=?L8E|-j=-N;k}B!nzBJp=d&(XyVviKsoBpTw`P z#Po5ztk7Uv?b*ju^!^3Q1I>h}aETKkA+~ch^5i=cUVjVaV4HPh>;`$zc zu%Tr?%@S!>rg)dKdmbcwC|T#j1syX~->yT(SXPq7t=D32JdpfaSkXP`W5wXNhMWPp z7YUnzub8PFM>T3@{fKy~x>~wjwBuRSKUhCwZt)AZ3MFSD1<)&ju*^}Bf;sK|1LXmn z(L-)ComT|RCeH)N;r~TOpF92+jVS+b_Lxj0umLPDdH?kck;@FdUF*5vt(^G>;*me5 z{qp-SZ~7m03Bh9iZw&S!89=KukR?vp)?a)SV|j=3e_3pviuT3Jl8R)@7+|b5OtZ9A z0V=~#;M`ruBe|1s_PyqAJFwSKJ?M2Kbjs>oJ>yh#{(LJ&q`1JMN7XBGJ={%M`CE4l z`}e&GKt)z0ug)EWUC@)06wKdLv{PM(FW!Csc_@{k5m_&+Hiu&H`UA3=O?TjR1k$gV z*w$94zQg~4SKB~suEyx{46d`j&dR`|G6@_n)<>|kzqU)CivtX^>Sf5gxMeQ{(WFd^ zIq3vd@H(UGEcOw|%@?DFh<788G@b%7&E#zdoFZ<&AobeD-jS3hOb>Z1xrv^M4Qhmm z7Yo$OwGRPWv}{weBQNZAy8rif$5^(`w(9GD2HlRhbZ8>vKp{WUT>bbzNDEV!VZ5qm zi-`vIuOTh~^Jy`hKPKX>DXa$Ku+?lcaNcfWEDbJec{x@6Sqjy_+cEl$7C-%i*GFxm z(0h{@Pbr`RDd5jtE`r+D9@t^O0=KU|y2DQqWA+7jZ2b=?@xd=Zl{voe=_EeX!`K>@ zssEh zJCE$Re-!$O0SC#{dOuzA*YQ|$%_m(_o%rBHWU14=; zp-|9DxJojPDw4xJ{<#He&|W;3I?l{Qibeb1l&a!$e|7uBt;<3i;KRriv78eUG%c#g z)Lrvh|5>g%lwxo8`;+O2I(0aUbRMFid$e%I^)nQp~*pw#HY7=PbcR5BMm>l9@u}lhacP2T!Cui zYk@eKb`*f8QL>p;*+opcl=4?`ZH4X8B0fxabGB~}^>3~1P)ckI@#fD|;MHdGLNE?C z_OJNlz7cD*2cIQz@JW007AFC}SRxf&xqAdq%W~AYWqS-SllRd=sz5H?!S?CKL_;rz ztqwRe7v0i$n%@y2=>cr+n;bqlvDT?|^3pVTWQ4P(3)O+l(vWFK4D+F|DBZZ{`8C^aEInzMInHwb zJs(CdwowJTij0$hqUCiOh8LxRLkks`M*=WX1aD1G^9d`mEo593c!V)V7Vu`l0T0a( zVX}H5$O*=jNbIVO&UW-JdZxafgfn#oV0k*Tl~51)){H4Y zVK*ULkOSaG&_s7g@e$DGLe5&7KEvSKf9*yyz}_lNr&LPC8r*-ks`pw@?iFaS*wl9> z=1YYHr-`|g88a8u?1p*qsfp(R!wLIq)ya#}Py)-9&wXUp?6h;4 zvcaElJOGawl?m?*gpK^v8M(wWL6)qF6$mN?0VF&WdZ`P5!H;}Qu1PD{@L16+k=oIp zzY!Ht0y3IYR~d%SBoTAU!c#+KzM;CTgMjV|yBtU@W?qp=ofpcrYw9_@;-*ZhIA*v2 zcIY|=oc+>1R{*8k_1dEtl=FFpwkj4#9dxw{X}&$zbqfrkYi?~AHPOjXOq3&%Qk=;0 zi9d~`_oTl@9|nR~=TG1Z65^t{c5wm_=lxY$B969m&_QA5+$ct5+!g@`JrrM86YzD~ z_q1lW=Ui;B`T{|?n_hzhPoz%eG{#~hrs-l5z5&9mR|))5n>i3w1ss4{V-dH#fl82H zDK@V-FcO3D`Ab6J5vq=h7$Uh7C7zT*VAH3{qXIy>j1KCFh5_4{6WL~1S^Q-*-Ie;^ zWy{$w!up#&kktc2d>Sz;k+TBw~jieyLGj*5_wJW;l$?j|~ z5K07|6+vJns{Ep3o*8KM-5n5qA!8iqFz5s^q`VQ&t#XMJ+p=07cu!%*@|HWyey=e= z<`x#r*LN-JPv#!h`P8>p-|vfT5kI1r!h5KK?pI*4wl=#ve{KazKj-v7ydYxyNd=Z; z2IFdgs?VeSrKfH;U}TNXJorMJO)!IVp``@;C|)CAA#lfV+gLpIc3U_@kgDWK3roUe zIoO8A1G?CjOag zz??S6hf!hYcJy}QuB64w$wSy)a}KCjg>inQVL&o%64Z@RWyq#_^P@-H^I;bY!p>TLFblot5l5n2hR6ucIw%>+D4`SPz{q3#`@5rB@ zIw_X|MTjFsC$1nF_BIY5kM-Y)&eObUj#&ktqV*2DWbyo>^~G?EbY#lt^EBq@Ym&W+LJNe0iWUASk;y814GK8npU(|RD zSnkdyr>-;}R=UUS5BtXhf>DsHl*@5218--rrk}5vgJ{@Ze$6QC7TYY1XUMUEd-*<4 zE?$STMP8Aoe|VW#QD!Ik3<6Wr*U*W1To&OjfGl(ZJ5;(}`^7oZYlY!dx`p=QZBYjt zy?A67%cSv5g4=}kJauKFQ6?I+uY6VhjW4ZGSfuM8Re0A>fe@BqDS}LWuT*3S=^VmO zMuQEj?5;HX${*0dVH3{d$Q}CVBKo`&Z`(LUB(MiNoe5^#;wSxUvF2=;9VgLx9BiHa z>{#rt>wl3DLo}nH#E>WrqtEl~Np_hHT^Y+K(kR2$b());Lfn=tUx~-p-YZ5?LGmD0 zKlxYkSgWyVAC+}`dc`yY(NdG&t^beAW*Wb7kaE&r1lJ*z_au{*!A0ur%aG!?FJm4% zJt0*pqt#~DFc6NwJ=n#|aDGew4hLQpRHBs8C#+AsuU(PiziitNAtR}Qp)a&IBIjhhv*`~XnO@Ay(G_Nd^^}Eh2viialvjL5fS3?xY_>D@TKDBOOmCf zg@%6HeLznuwielFI1$^yYC+9dM(5>qjxWo{+YnM5iA04_?6nbfEU>cB{NYv(lcrW2 z_=RzGrFN@P4<8ITN%l$6SCsZd*BQ&OG7wDN3u_b9=4@{~HYqmjDGtPhR=Z@~SAU^}y2L!pzgSV5aN@}$Mh^C8l_*hO zPP21qkxloa1*y=Jv5%f89caMIk&3&nftP|;6p^rzN^%~o!Jez0+u0pz3IkT>y&9Zf zui~vDaxY$1??nj|$?Q+K{kT(G(xS@lsCfbH3k?y_8e?JGjlKTe08c#j9yOi?v#6W| zf|rKBsPGG2T_4r_>socK>$3^u@P^Se=Wz?6!j2bNkvu$FPmY~sk3HzE($r@_-6Q0J znjz476Cz2z%Hl&F+|FwhB1u6ZcbP6@{bTjB4lS%qT4JB*H26H;F>?RmKIbFvVJ;#T zHml!3ym#Hwmg$*@D|?3n)L>m>F8yaAefAN0C7e7q$&fP8Y@|c}wO@{2qHLsdBs)4R z^s-I;L)9%78{*{@wFQ&kTBc_y@a{jNmAM=4{Eh7gbkevQH%EnzO!owln$Yz|;8l9T z^!dq19+^nv;+se6Lh3SY@xh{~c&{S+K**TPz9+NSm!F=Ht-0h4nfYvH%T!SVYAMCD zImpGW5t;KMW`gR8` z6|qEDXZUTaXlxxgwC5Q8B7t_X-PcH_?ekklyKl68v{Rn(IBlWWkL+d}URIhtNk;v_ zD8XhOw?k-;FE7q?9vW0kEgOE`)41V}gC8qI-g-Do>mY@bRyAOjYDSDb@eal44rBCh zOj!t|CS>mL6D|67gyiD=9T3D%0#QZn8rF>7xjx?c(Wu`0Lg{jd4&>qA?x0U_S9wu~ z#SfzQWTdtccP2thB@{dug$>%}K4EI@ z)EtS@O~A0bru3%kWOLkvdJVagXZl4@6u55utJ@m9RUP3&9pZ%Jt*D-smg8=PPdkip zFB6TrxgP~xJp6#4A|J*`B$Y4c4b7C;$0w4tcXea;Qkba3WdGEad)}mt1S}uUG1wln zeXR)Umo{6#<~kFx)g+xMk|q@^v!YP+G=7#^qgmmKr?Ph%F-Y<> zF&Xnys@F8g_Fwl5-aUU>WUc52S4^+SDAD5NHz+3Ry>@fAGplNeW#6w<6!rW~6jSeY zs(y<7_+>*5SBsCOv}+16z6(QXqO%oyQ6$EZ0-T8=AA~-~4@t1uC{YbworIL||I?F} z5L?4zKj7wzcW+Vd7Q0Tw4PLA5YlJiNzBobt8wNGA;_8p_M!-G`YZGOnHOIS+_kbj! zo9L0%j6S@TN+^Vj2|tR)`eK$e(`HgupN_YK|Gn3B3j8!0Jw6TEpJi8|+bgD&u03Xj zX5vh#Sm`rrx@5LN`Z zVjKRFv>VrEM{uyrebC37N>TR#hi=}mCf+8{+Auub_TsaZm7zvGoL7jToiI2|PBcn^ zxliXbeEApXAD~B|r>bACU^yu))of9~1V?XwVa#UR6(rQRVcU!-GaMYPgL%qj1u5Ep zxlCxC**A`}%B1yL#C;`MGZenb`mQSphAmUMkE{NC{0Sd^<=OJR137+YiE(814%5B7 zhl>CgsCqsHN8EPlkr=(x#uN?>p?lGK=yPjaqXQEcL>;<|c<%*} z^OL6;`5F2l6KNiN!|xHRR_2+82Vi`08SkP&3mvuY=zwW?WCAr}>s2Hwbe?%LAeW`G z2j1@id}L!Xpf?RMe)m=2PX~?HPhS{&==RVZ3lR^5J;mumC=xKgBYT!Y@z+tu!pgb( zj|~kfAG7!W#Z_)BQtawaHSp!+gKm5qpkYk*-l9CJXEmU9{i2>=U0K{ja{&o8tqmY#r`u_5G zxvj0rc?Eo7GKt@K;}bBpj?=sT?J#71#|j+Uq0Yc+(rq*2b>u{6Rp`6^k1xmwXrlc# z^gEysYqKuyWOttGh-GzvaSIx?5FCM0tO}D0{w!>|kuU9!=d3!CuQvs{n0{AAYZT~9 zRGR@!+z~XJR-FN6V-Ne+yC(sZMUHVV&;?gDUF(tZV!F&)#|0Qxt3W^fa=smUr=7`# zLCm>yKM~V4G6mjUGiT4!4gSMNiP-OX zG(nqy0n81QzQW~8pDe2aY4k@CsPju;=vvCRUn(pItrje+KXuB>Y7T)%Z4r6dy}vp* z1uPZwp#47u*dYLsDmq&qDaa7p#g7so4LF7ab5O1kHNvz-&2v|55x5 z9U_QdtzBaFK?4RFF;dSqnV$Xvm{SE^Fz*HoU{(|j-QU1~SFQJF1y2|TGw{gp{v8Xb zb@sTu8lX_UleVqC@v4ucfHSxKvYWU5rDuxLant<_Op&|^>IXO0y?^H#@0s&7osiYa zCn4)K3f7Mlf-iHf z6-VHxfa22|f2Th7G5EGl)h*DWA~FK$1|X)4-qpTuqSPY3`o09F_W3e92@H#eP28ly zGf(ya=coiNTVv^ocwNblEaJRmNqF1hjIVkGdq;_iYSg&@d8|L2&&PW}pV#8yw1@3k zzLWm_#q~QL2WyLNUs>n3x{`lvyn7hLN z+fw`g!z-DzorU(^-~V;H4uJzY?Cbw&2xflA_uo*|;r7qUXJP%{y6WY`^vwOYaW=`| z95|8Cz~AWNu#Ei8kbLx+4A|9vU;LUCfFbFRfRnRo#{2An3mY9@lmh7dGicib%EuIc zJN*J!NRNd*kGCiLPr7RcmH~OF1PVcmx7jO~clY<1E-LQw!{?!Aw-C3I&w;Lh#U0#!_VvB>L~;a-;7ScH%|e^x-|`m_+;!S!ZQBS=>PQVE}yiV z19(*lsLF_SVIy9d>nQjN2iVdBb+;a}t~{|{UJ>%zed9VI0N4JJ0LO<2Ql{QyJP!f$I&04|9_f#@+9Qc zFVOSa8lUU-+wyisk5Q*{Phjes0uf}xbG+)eWf!#@hTAKLIM!UH+BFeYmMpePt%HE% z2%t_jKvu1jz@NAVdMpzssgQaOzaMMj`}_vTf8$~GhJaw-Hkg2F%-)g)toSzjEB!XW za6m25>U(s9svWp{4THS1B8BY5wrWar%$co?dTcTK5>BKyP*cG3gM&Q+(SX8s>ZwaO z0;ep{9-M6YSXA|`<)^z%;63^sbDz?zgD3oUo&yrez-kZEEmvR9Z51u1%j34MqX z5M&Q^ufbUrqJE%=*oUpX`BcSK=&d!M{z%Xot^saADlR;NWneHX?+`}*`HvnVGY(kd zCdS@tbPX0q2#)NCvK+_`od74v^l%;ZACdbg1K%@`29lazJzs&*tp#)5%V7^t!YZgV zwHg^f6XKsnN_M4=sWhfFj1PhC^W*}DIQ=Q6V_GxN6Wn55*f3pJ<28TPBlMK@<7e5S zayVUb5*Ul~i#w{iZY+${j!+7WTW;Oq$+EuJ!K-+|Dp#OgB;}tt08imB2U=d|mrYb& z8Z(FtOnYNBMv0KisJpuKZ~;)R3S=AOGfZClv10QftoPF!=LcjZn&C1gELFwPbTsGL z`a{vUauDSFIHR9_@#E(r33C&Eb0$0C>GtA3=-e@lQ98*9zXjzZXbpRp-=GcQ{=~jj zpO^JX&!G<+_6l+Ty078aD0Q2%;0d4^FXI_hD)=^qAg!iKTQOqb*F6J#?Qk8n-x9`u)cIs_Jk zk1%jP(yuI2W6DmhmN5@cq_l2z`@EqR+^iRBF0o)Dt;gBjeT$Qur$E&DrckW+1846& z(Ga9-iho33USV1$GMKHC=UV|(W6UjV7et*;7l#XR3E#lk6G(7=krRafy2|t=?^Lj56Xa^LpS=?&9=74>*p0T3soz z%j{cx`JgF~w(JIx+}M4)@7e}L8tWa!S`0f8T%vs&u?zy0)uL-(zs!Q4`CqT6JbI&~ z*BOjh^eR`&FNqs?;e=_NY_T`kwb#Z#wiWI?3G^6E%_RLNClD-JakSw`BtdI~FV0VW zo&egJ2DsI=D8b@3X_H_S(1#r`XDSV6bf#vUlYplCXUvs%pA#2lBw27=JiB$LP_|<} zFDJd2Obk-WATe7xqVMrD(g)Q3&vaa=-;RW=Oae(vlRf_KA_eDX1GxS1w#U%4n)hUh zuY(f(3U{y3Jc}3Ez}n5;FVX$?5JrZ2h_WyON->-jI#a|lwDJF8?k%IL{`z)b1qJEu zZcrM9Mb`oZX%s<1I+X5~lx~!65Kuu%LXqw+rKMR5B!oqmXa2nZ&vQTb8T-{f`;4*Q z`2ui^^_y${=Dfbw^|{zJa_pw$1;mz?y~EbDc>UiooI>Zj4OJ)*{=;)D44%@kj~#Z- z=n%7kJ}3Y6&)%Qw5pWEDS$EN1RhuFx{C_fcZc z$>jWZWMI(Y69mR%V34&JM4FujFMB%1UIi!!kC7gc0)%jexBzf+YWPB zvz#vXQhLo(eM_>J<_$2WLNs65-=E%T3nQ}Ma43cc4fZH$LU~@H6lgXgs$)k0=5GB~ zlR-~xqRDyY!8^n{J2F{=TICrs6bgBWrMRGih*)00m8xJerhzT;r~}=YwpnICA~WJ_yXV1ug;;vue;4>eLq+fE@T|;Dw}G3ziikYcbhWbaFUxiD>I? z2z;Rwatmyk32Gx`($QT;a!ytHgPZ>|+;)h6@M?mg>#z$l$&xT6^5Nb~=D$)&xe*>= zeSk}z1(TuW2#$0v7>0mi*#_Vp%QIUAOxXw(_19toTzQY+@KI~_!iKsUA;K`RWli(R zhPQoDf=<1qb5O#3B>#%OfHTIo8y=2Nw@qC@1sB(gSk=_T7c>=IIfH5SQj0oC1Ffcb z`do>Nm13*gVu{0yR_ok1_Q8)zsgmYtmaL~za66FNW7bfeHRj+yfQKf~`S+m(&Z}+> z=vlWfrH2)CFe#5<$S^8l)cLjI>3riq>dRUrr zhDUYko5&M@=7U&QW2pYEi1CDJ@@c{3Wv47|zQgH*fVSYp;KB$yXR|9Wc3ARTIYDLl ztYLw=q-{6Sg0-L4tMY_s-=+bl%-%U}$8^xH`D~+3NH+7)cbt9>SZDhUapfCq*i(Ms zZdW(g-q8AbT$p)JD?!q~b6OdFhiP=+lp`Vz9#lBN-QFG%SAMF%aQp2@{+vNzsug3it8EK+i46-m z;S1n5<90*C6{~e_;CLptG>yIh->u3!)KjEFT=1jlFIpakb5}6j{GH{~RpTvX|EsH7 zmibNW+-TV~#{k8Bm)74Gs7s6dR%dDFa8iJA2wOu_RZ(SCRhee$?^YZ|fcc6=aWBp* z9dZQ!eXx%}6bXJS6^ zyR(<$7ZuZ<$9&t6AMKXU!z>BAz6T%wyBMNh;Sb9{v3Sxyokk&C2G&40Pc0Eru9Tpd z_^pCLy3l2X${ifXHRbFXx=zvVeRgb(rEq7$*&tT1o!~i(rFN?;MQ${aET2?wbQx@u zuk#z1nsfOqQ(#XkYsWt%v0z%mLO51zf=l>qLOs1F9MeC5MP|VRey6$0px-Rb==R9v zdjs0*-VLbGqvY|Mb3`&dgtT|002O~3L%WxLe5H_27M zcqdON#{c_9A$_pfN@rE|Am*4J^DeG&fpXD#=ur{N%sCFG{9Y)}1gzi4*q+0$>{hm! z00lK^481rP(P6;9IcYnSGP98$@9pRdDOnTki!vc~9`Wy5H1ZOdy*O4|KN-fe%h zGtK2e78R+d$h9%^z5G#*A5OWqg8Qa?irngFcCGi^8>wpVl~FXS_qGVUDi=?0O-qwM zf}QogZQ19!GfY}dh01W5w)LadwrH3VKe;@7{DjX>AJ*O*?=6yI0DFaMvpS$X%=|SP z?f2DkTEVZUHrnbueMzMu!mOO9-Vy9){Uj4cNqx$ z&dJv~PELTqR4%8$<>`$>4R@o|vr9+E5!RhXW@73y>tu=0Uj2@BcT2XHJFK5>HaSu! z4Yhx8n6aam(}qT3&cJ(mxhH`co~yt#hJU~(;IO>a@*cd<@!*_P=96POPmGFq*93&x zPA|^-gzxuUwTl%^p7#Vb&2)9luy1WpoNiMe$h~OD-mxbJE8i|X+yk2~Kkkr=gleu5 zzFtYyH7T+=qnu)p3Nrbg{{8s;H^&2l`A`{Vhc{_jIs9bb^yMtPZKzEz+JDA-=_TWN z>D8;0zyDT|JZv{RSJ>8g(6K8eTwOEOhLEuIUK||`vmKMT2&^2IU-X{8`z6|X^#u3h z=_e+LnYm0&X_fCdt%NnU3jGvXdssDsY5j^o1H&V=!cweu+Ajhmcp2<`(EvwQ~ z+rN*6QqM!#D;@L7v=RbzTJa-YEh3nZfGV}gHs^_CpDW1f;73(pe9^Ldo|oM8s!c@3 zWG(16!|OOQaZ6W*G2>>Qz%J(3!HBcHxGn*+o2{KhY(ouqB47I2AaSZ7s7pRObI`Iy zR{jaMdem(ta#2R~Eg2)d8_B){&cmxQgjD$saL-5OuZY*q#-CEUGSHQb=!aI}srk+% z((s!E(yh{NK31JwvmeJq-sX$0S}Odck2{`vNW{QSQL)b-be4)%D3)@#%^EdUeBUH~ z#-7#X^>8&_Jf5|6U(39~UFU-c?HH-bUgo`2K4r$PAO%dV7uSkY*opUzlOy7^4!wRa zwf$LL(!|`L)&AH-qJ}SVlbgV&8^;}fi8Qd-L!~8K1fjap)&sU$#bHRXL58B)j!U*Fsk#hBd9vas7*jC*Lfhh(4QlX>VVF1yGynGD?yYi@V98kz}mt z=qJ8ARG%4iIjXE90E* zoO~Q4{}<$9*T*t2UChEkYy1d0=N-0IP z18`WdyVK)3Z@dd~@!k*n6wYiNoqe-k>CCxT>*xK-%+{JSt2;Rw_>|ddKPj<;%z-pJs@&rjWMw{UGP133=&{pT~?&P(2t6kmh1!nC(?Z~4QYk6AZMpY`eTj~Z{^))I|# z#t(n{Sejk=FsLtZ$Mu}Viz`++8!2vItTDzQoo*^V%2a23MwRrhHBg%%_;C2{qNA#~ zGw&D{`TKQ7b^0?-MFu3gRFkGE1Bsn!T-$yui$fDT5nbVS5n(BF0aX}+e@{~ig%!lx zg2db=5(~Vn5^WL>YW7*NXbb;zxJvmoaavA#*d$=4Xe(zi$pXW$L!>%y1fUd;`Y60H zEfl{-@}pm4HRCY^j3`No>*99(e9kMbwv=LBU0N^%|FLO6PCWgI^;_$1qG$X(4i9aD zkZ_V?W&cTztdvvj*QczS3W4JUGOp>y%gll~u;CkLM*{8u_7kBJKA2eU*c zfE4ZhFV^p$M{ke#)Gp+JG_nR^elPCPq}06n2Mrfc53bai^9j!z{}bQG+&=`S84JMv z@(YaWIg(GBZe@dz{o~I_b<*w+Q#x)Cyw)9TVFtT)M?t#<9jIq@`YdG{QJ+WTNFPCV z;vrxs*4-C{puSLa8=Jo8KMlZl1oleH&k-E>-Ii~$E-^^Qf;a!M5uZtT+5wTy(-UZB zUx7(k+OxLK=rGN6dVqc{tv_-b7zzM z`O_LM>pu{A?=J!uBqJ*iK;Ac5oTa)QI3A4_zPK*{i{$p!)F;Q5kw+OKj(@4X^?wui zgEVgeE6a0$r@q0yZid|xKIk~fVHTisTua5?{g%hz3v|4~1AtjtA4Y6QhnOt^>EAly z6zPbi9?E#_W*AHSucH~_MILMXpC z^5QlGBd?2&y-PGc)g?++u*+7WP3&1$q1wxY@~ zca}T$u0@#)TYxs4sp`~pc~!dyuEjOSjPXFuD=Ls)IVW3S%7Dz<(;P9|SKy(M$KGQt ziI+O>ogKknhve^OFqWH7?;mx@3aKRELV!7bxecGc=*u76UvqpWq}DoIM}ThgXH(ik zz=i_>^s)`?Z+V{{D(xSwa2y@79=)2cF$K!#o3+6TZkH(H5`xJfI-_9}t%VCjY;9=< zu!jl&vLo{+J!$fD!Bb8$rz}368mExJG!g}OwvY5k^i2+l%z$I_s4w1WG`1`V8&?>; zd{gt;@z`rHXiVGHQaTU4M*YUkQD~F^ChNV5N^hpHZn79U@j8=l6UQY}nMlgJ_c1Py z@^cET7yVFb3cdyQ>y5z5UQLJa8_AKpr@fP)Q*}-hW}WXTRcO)~LG(juOlny#$zNUk zIP9T3u%3MaGe!rn-XTPU^KJytO;57$C}VikktW=8@Y`dOU@GPSNfG8|ZNY|**|}l_@mGN*&;GTrMZgxr z+()}c9d=8?HuG^muykCX!cG8l?U_;OpBd|1`{bWR%E{Y?8OJwC(A_OLV$P3u7v>{lyX_0YGh_-(cF8#=M9 zE8wXerM;8YKROczr0(xqgGId>*BDv$YuEqnC~o`X9N3W4y#F=iQtefxUc34jKD$Ad zP6g_OVrzo1^+X*xI2eTLFzfP|!mIr>XSL-PCiJ22PTfG_72 zdmD33*_=O4qLnxHUVjrsXSJrH-`j-(!-NJf@mPRx1G>CEMGHumQQ1l znPSrG5%9UGJos#9k+L%aoSP zhZq&)I<b_1MNqgnt&@v$I{fAKKpt+`|oY9@A~?U&6@GPsZTC>Zi?cgv=;&0VCx*hW`iM z@JE1um^=CC*!fw&q)-R9|TIw)$Tkh&^)u9>pkltHyA7jnw2gAdoAZs z#sgO{Zmz_l5hY%qwW}FY&8bBXPq1bw5w@S5w&)ewBw+X4B2lzoZS6B5hVbL|0v-VC z@D&6+s!d3FZiT<$luYK_DaHpQpN~6IkWlWS_GDXyNp#GEJihmh*lNtGO&&#?_9Fe znNs*pIwI>q2>|4lA$%gJ?(W2_FiMt6C0s8aWPrRh>VFJQ1rk57my{d z=rI)JqROPF_EpDsC@H1|vK+}3nUs$k@0vf4V0}O24X~q?nmH?wC>MtoLLAmzSy4N# zvT?^Gfu9}MN{Uh<21|>x6>FJ=Ts7@+M6Jo`mBrvlX~mGn)oP=vm|X|SRS9ju{Mx=x z!BGctHR7H9bKVP)Z#KBHXoqD%&;c5 z?b1h$s0J&imd^BX1{HU>aFHFl|QjA|{4T&x_6;YBaJsA?jZ zu#Ii1g3wp<)nRuJqg!&XSB$q}bV7vG4znKP(-P2PJ*S}U9Mv)c{&TzhD3tm)WU^-c z=mYSGI45}{e1%=!#nyhGqM=%w$ksl(IWEDM@-hWHo69uQs%H^?f~YG611c6U@+|mH z_HEtUc8=N}ecgr6NAAyAcHVo!r+a4SB<_GlA35Kc z_#Y<2&rx+2lDP9U&wGy7!5sw3**ylX$tmLXFzjFX$?F`?cHH)2>Za>yZ3> z^yNl0Idj%pM@@ohq8pfJb&G}6)+BV?p5CoxmAn9mh#DIwJx6Wof|U0JIkh7LN>wf& z?@m*VYe!JmRI;%})>d$9M)~EZ2qa*%EOEnU&xI;R(YFSIZ+w%0EUM%uUD^vf)-Tx|p}X9WEFQlahu+PcQ*O?T3ebYP+4azQ)}sFTj6UPRHj~k71ywGs0l85`Z=izOw4?1s!X%@1V#Jbn!ka1d^ElV0 z4>FUKB{}7O<1z=b`iJP^1W58>)l!3PIcM612$s#6qHw}Kd^-B)dz{6{kdicn0+(W3 zFTN6ksP65p9@u`F$|PSoZ)cmHe7O8KUXJ44`bh!8uv(J-4ql&1ob8-(ku%PB*W0v7 zR`Mp+;Eh_J!n+nVL6>BaJFwuul(#)BPDEEA-}Jka+)?29hp@uqW#t8)()R7TFBul6C8G4usyzp3MU9DEsqY!9tt76!Bl&0pl|!KIO!h zLjw*)K1KP{#{%j6%FCfkz2iC1huBN8(P-z15+BAAr)qkv^elK$on0fFVz`up!8i}E zzWc95&RM$^F6!TeY&&MdK{Hk~y@;fUe9t1s zUX7I~*!%@2BqE;`JD8qKUi6T_8ox&(BS7|=HPMt7&hB5(-P9B%6egfikOrO%;c}0F zN-Gwxm!U`00PNT7_@F_9>t`%49SS}W)H7O|fE2kgk8kS17Bc&DJicph%4X5yK zOTo&-%A#mZix6dSuRREw=%1Pq6mWF}6YibcLI>r^w7LXZIxaTKo=eumhfHNUeg+tV z8wU41=IlkH?{modCK4UUI+hBJta)bfoxdpm{G*yeOP_O}hi-Ym9m(*O6i(<}Mu5O* zyeXVn9m%cD*DQHka@C8t_bxaA(L~E+(XTz)A~+AKAt|Qx|Lr6h?XVVzt~-b-VExR7 zZ5~7LoI!aZ(Q(#b6BZE1TN}SBEWiN)&)pTzigrrPh}^C)ytCcZV{7FmwdBBruj1Yqg|p0mygz&x$T zS%jD!r3$QB>gpf{&&tfdTUw6`g8Qx~C|hX&$J-%11}O>8$1*?=5u;dEl(xlFX0jU2 z+62+FCY64Y|E-KQ0=)}sU>*#y=D`f_M0!dm9?;LhA6T0odB zE8bz9v*C*4vi7sosHa?~IX z3|0IrK#3j8Yv7FVpf4PeGXvMzzeZcArOR#?DQ5kndjTJwlfY5!7z!q`e zv*=idOcaahJ%KcPhxbjIMi6jatKj5=(w&m#z{zGc=lDMyQ6)}4pl#C=H1A9w1>#AA z%hV9Nd1g2sjn$MU0(dprEA$EV{v%ADI6D#yv;JZ6yF*X2)^?)%!Hdb>@4$`gsn`mo z#r254ncP-@AA;*>X@uLTEclRH6q+L+1JmxALw^dFl_B^)G{pZ_HpKn_-i)3H0PPR) z%QjBWk-iZv?+of4>Udt0T!E&chX1uGYQs$ZOWerMV-jQ-*_~1e7 zK~AcwscOt)Q0K;?7*qLD?%+F5oZN_lF6~!DjxYDKPK&-Rs`M+6v)%>m0u{9x*Wi&Z zBr4I{s`L7ROVw@!OI)Q5slj9JyMZ?3bMEj;0lNo0+L{q^E@(Wk)u-&-F(eF3X| zsv8SOs{1A>HH#MKE1+k1I5zFSehGv)g&CRW6ZOs8P9+@b>`cZZ5NF_P+^_U)Aomp;&!8016Jjv3tmrjk$}r^MuJ; z#*i-gFdw+rJYrmXC+4~u0&v^n)|17j3RAN%*V=2Kgl*IpS@&O$h!1bKB~||EK&&P6 zAgDxc$()kTJ}3p%U~d{H)WsX2qO2qbugVcv3FNuB{cH*N1YN*h;{n0rW;R~q(ab(5 zfA-l02segoXX~o~rSSPSS`cGIGTA|o>@jK%+|h@Ax~Mf;?)79$eTIydS3s6*tU3F& zvNHkx2r^D=t5n719rv0>qq2{>Ni1Y(LmfZKdPOLr&RAxoRp4O?v|-TSA#tyk$l2qD z_g@0!D!~=2*fv+u-1Mkl0NxH21k^KkOiqXnM^xjqd-r$jzLqW1-qFwZxhZwaf5NKAfRr{i%lyDq``gyp=%0a1LeWSAWk9F<>d>(76}Vr&STUCto**mb{FZllBwfR z|A6>7rO>GhvoQ)tfYDN+YpoKczF2ZGhm|()||8n^_>u=7le{+3@AU$+s!=4i8Cum_y>cDqqtKfMujUonkJK0$pDzbMW> zj#BO`j)$15{kgE=z^57w=T_nSf@HoI9T}{QpJYKCcKfb*co*MD!A}S!L8Z3~Bs2d( zW!9&{%IwZNa)9_JMC7fM^caI2n|rc~CDY+cSzlE7lm0emv{_#eUj70V1#I=O5{kWZ z7SotHY=c;h$)s__$-jXqD+>@GR<_a<86viML0DmfKL;=>>rUSd%3V>0Rm(Nj%!S%_ z#F>%+pW@4}aeb-6EPUs~LVSm8aiBXSgJ%UavVefZeJaKpxoS3;+$(-j)ba_;cPJ}J zEl%v-nMo$Sf9u$t!cVu*)51q18(f-MxDuI7xK zt+O$bK$1k~^FIvYB_RT|XX~*L)iQBm(NM9@GfYjJESU@s?*txqB#1W8U~i+j%1ez; z-*h7nPp|$0n2$TZaW>?>d;_`a>8jG_AtQmS$}NR^hv@D{>rB2`XHaq52K$BuxK)Nr z7RIB#ob)Dh5Owtze^QcAhc8|hatP=aCj_;#@;+N zZZykGiY!)$CI^s!w?dYtgnLkn1uq_D66BML;aT56$Bg(+je&*P_GwTa{r06=C|fxS zALd1Q8&?`94oZVS()ka3(#*(tC9DIYa)W2>2s9VVqxi&*(bpdVI8Hbr@`W}9?ro9> zukky+EO^Y#gtmr`m@G9sA36{xB8gGY@6u6YPa)aV>djQRV-JMgCqta3Ca^f7ZYsIA zhdod{ZK~*I$uZ!qRv~Y@JOg0L1>in5v+Pj_4zy10?!w1a%(>Vk=_dHfS{z4oo?yhb z73xrv$3!jvZN(yq;4mrU5Nb4#A>?6>BW;;WbeQhbG7=PVQ(RrShSM?ykn2|V+ zMeZAtf!&x^Y&MRb=v(J&mVO8M&CGI}>m zl1Hn`>t_3}6^8>2M|sZC&P*Jg54?37xAmDuaU88F2PPwJyfd1u^VjwiQa3qf*N-v- z(T)R~RfAtnKajz%4LQ~%Z@Fm2BOPCzRfMACZ-~*@(L!|wT03s6APXyHdJ01A2As3- z!uLYNRoSb;kSUK@7g%3YkTrq}jmC_vC zWfj7}PA0%03Xkl&(J0i)-)YBpc0Q^EIzIJ^vqKu1dx^P=Y-sEccZzqmrS7+$${MO8+ZZG8+Uup6d#F7wx>;z)rVaH(I=~zfXMwY)D?4>gGfUAPU6!ivL(Ic)~0}I z*ds@+uRwvlp7IUzBDjWTtCHa>(-}DreU=8fJS;axKW7Ng9wiBs4+!!`Vajv7@%1<{ zWE%NC#Z~Cb-wfkXstMf6^@U3&BqnkUlE@o-&rWZ9N`1>)9Ize1CIa@kVjkObDY55_ zsd9oE!Pkn-%PY9)g!l1utXB>jgtdeb-w2!T_v#XUVAI`&ox;xP*=b$g^-5dIbtfod zI+C_%nixc3W%U|O?pq3;kYE_V;T;0V*1LoSwwRnoltb$1$!yWD`Kv>!Oy4Mfogp@J z->Pq5tZ=aHJDHbr!aFj}jJ%dv?r0n6T>Z5w9agthqxe`I*f7(0%-ZX!v!CKeG!ypW z4B*!@tmbJ<)8p?Q#i>8(ekd@=m)`j~8bzxlA~0N}nFVsV!lovzGXV-pkqw&cI4fqH zMJQG7=~QrW=q1NcZ7s43O%CCxh|`RcN{PxntV%w#zi;`Dv_GHkP{8)q{6Jm9pH1Z? zdnP}9_$8G%yhPrbiQ1yQk0~iOxy@aIB9kaAj7@ASJBjcxk**MG8S>ETc-b#m_ulnm zcTh(t9$Q|kSM85L@ZQpc30`uLGHGLIyvaCHWo#VqAkGEu)gYo6xrGpPu;PWS%L|&ZJ3rMEJnyD`|QQt>Bffo@&xotKM%Xx~Wt##iWR2<+9E` zaM%RFo$_KVe%+a1cDA5WhGg`s{xumm8QpR9K_zFNgVQVYP3ZaE^>GR`*4}tzLHxV$ok*|;-cjclS*l&~ zD!IA9_%yqbb)Ku(82-n(_n?jU=9v0;v!2t1ck#UWhxhBIa|tYhM@||rt0WT%LNbor z^sXoZ;WzIQwZ#dq65v%k?ainH-&#kMRt((@H(V+cgCsX`Y@Z%4Jk(`l&i%~FPbiQ{ z)#XODcZZEG*1n0sAZRA%%9y^q9Sg$eM6g6O_808yp!BxC?pdG>Xpw3*ctd-a6o0j| zGe&!5(xg%oA492GR=N3Jhy`F(dZYRdWYgDd_v>H=LAb&g?qJ@=qx3;@I4j(TSb*_7 zd_p0BI^kvaF)yDKadEyOvkaJp>nhM&aFO~rP$!Tyy7(1h-E(Ty6U_4_ity2vN+kPv zL*r{;StM!F1XRSU7=uK|p!GM^wvr7Q9y@_QbPDFjZVHtbrN_NB%yu4uE((U!LdJo^ z2^p;-lX(Nkdt#C5S`6&?|w4sTz%Qc-+?@&-nA@YNHk`!y=I|gs(Xyr5oZ0}DJ;(q#cAP6xw=XVr-R?K&Z zzHSolCF~#iQNp?Uc9v__!<<}=oLe50I)@BpXtt)Z5jz{j%H8x=igbxWdt{wE#-j*s zO0OxbnG|2UC!d=}>+*jgVSJLW)itTp787olaY%iud@LD{B1qz_Gb$?f`Wkq7=ZCXD zbo{cz9%1tj6PsYT)dwE^)>NJjlFq*8m5jqQdrof3ZB39!?q0;^`n(q%c5Rh9cv7D# z?ppiG+ea4iFQ%k7DS)VX8+u6ZBRozrl}EL~Hkgi>BwX!n`+V%)#a5MxEfHEnn0z&P zFgtz7DK!>E(cFt}zOHdbsbpMhDYF*R)}~9!_b?0iP2ScFFz$=G!RtBW$xu)ukGf#v zAHT&)&$JJ6e2AN;A5D^Qq&nWo_jB3P$6dCwie(igT4-hJ#@}u#^S4!eHqMzo@5p50l((bdx0W zx`+b4+fdFZN73UY*2IxWbA|Nj8|-+qooVLzVZ*5M+bMgI6W&snL(y@ns(zWb_}W0Y zT*~vLrSrRhGDFhCiTFb@5-P1n%|t68C075i2(u(xKt}!UmyCF@3b;qpDAEoSc|aW& zy-yo6vwEFOW+DgIO%Q$868kA?mKai)i;<=6p<&Cg`X)f0w^npec^Ff$JF(yz=FwZ6 zW&VM5#&^yGI8M`58EfrrO@6jo3A}5dz{fi8ssc7mX!QgPN9tW2k9e>jPuI z>K4gdubphNn1YyLKF`4{hQXAd0&`#JZWT6@5RFp8k={12gx2vR~LUX8ud`&(L0_%{>(;x?4|gqVcj%=~K}s`>olwz={X z>P0ZYoK?;$V!>A3cw9Cw}eFuH+U8Mqp6`5bR= zR(v~tb^?BR4J7nGrj#qXFSj(-WYxr50F{s(j%j4gEFWvME|EM1|R_3FjNa&;K7VAnxqzU zLoPwB=+yUZOw=#IoXJjfEeEuMckO`rWrcDw`z}b|dlV|gdq5I}0TAo9|MIk|ph`** zG|sH~29&QaP*{uS^Q87JNY{BnJ_V>rCae|6e+ba*zDaKEWjY0t`r;xWZ0mYi)&bh z#rHJxrJu@>-~hKdejTQ@ABY+YbNGTDnYTaXp5f-=2~W35g6+z~0UW^HpdbyDz5g{= z{|OYq> z2COwjKYNsxn}b2SXSUn8Q#Z$5&URS~nq0G-XS_4`1rk zE_LRM*oBRKD1=S_wN zgY7}L+g0wBTe$b9-h)U35wnq5o?0)xz#1MB=#C5kAJ+Ez5KrASvuB+k02o9WSZBL) zf4|+6A#n&CUDE=?pKZq43pR@CmmaUKq2%uJMJ9F2Rh$8^l!dwofLC7wV_ub^PsPr{ z*ZK?Kj^fT3!TAWASu5^<{Ez1+dyb3L@-x7ESe13`XDj5KuzC%JD!DO$dz)t<1j?+# zcNB)dmOl6hifc9o4}xu=l5!Ay+k%{2^E3TRoG2dt)~7sRVSF#xqy<+d|F*Ub%Sm*6 zSgY~t1u)6qra#!^0|7J$ZuteWc|a*&5B%_4SHG@RvZsd2KlIG;Jb_E_3m7B(Ajg1R zU#kD~K@4Y?+mREj^-O(uI?}I>Ga?EG%zvv$_*Sa#EX}$7YY~n~+Y*09YgSBj^l7s- z)-*vLFvVhe^&JP}@H#kLi+c%&Pb9Sox77LNY8i4e5tZXX7=9& zUQsM}Y5L1v=<5g8F@5sO>j5{)(j!m%LPK*bl`#=5cko?SIsq%>YojY-BknQ7dKSlf zInkrf?Aqjr?4Snlrn?#`nQZHW_k>bV_akfmHf4YHbOgqU#ToBc8iyI6Go>FYnyd%{ zV34_QpqXd46`i2=C1@93gIIpl;*I1Tz@xfb(Q@r`0;U&;xXA!)H4NGbR?x#&*4D_C zT9fnm=l{#8td*W&#-d`xs4G$&!#1<*mSTWe-~!Db{zp~0Z`n>=%Rk=Yf^VGJ{~JRt zSG(o^Rcn`>LKM2jn%Dq$RVVQ-AX+-l+104+MiAn#E77^9K&%j`p36lkl<>b z{#W!q$#b9)yqTdFrNgIh$ATsEAoF$k01RAecnZPm@he~hw?UO%yI`ZMvlg})ZH0h0 zyMS2g0kLiV_Lc3vid6I{1bEZS{ct?&0zg%eG+cnHmHv*4IR5}6uX!}~Z-YmW85!@R zQ)=6)CA`rP1wJzG zvku{ZwZ-KdeG-;IJbnip9GnI(xMu|b!blv^!&P^WA%!aLNk2Y|Rq-JmV#QAR&Q-sw4UUhR^jSb`(qmpR zHAxuaXlib=);|lL@8Oyy2o8bPBL#R*jlGLwm4-ParPW(-j=qEW){wdx&e8{}9a{H6Tufp@pE^Q|iBeKm&6!>AC`SG>I4BW8LvkBj&OyE@o;^noEJv%#C$HYc9}cutR1R-?{HzU4KUZD8CvdgF1j zIZ=|=Y?%n80}ize3pp@Lzp_L73hdl!fxvMdmTkSFpnq|)xAz*C%1r$bsL|UQ4_OLkEy-s(y%Y-i(g)VZLMspst@|9WNO z-}GUcTa>12L!xz=5`PWW)LW0>(gUR95B4NR|2p~swzv^YZTi-T-q8z8pUhY@7!1`c zMF%@~^P8v&%%&Q;L{jnN-WjPdsIR!f>&>#B@HDoD4#~c}h*FZPMv%SMHv%M}CjwT1 zFO$xPL#iw<0aS#17ra9G(PIUC!S`cFV$&S>Tx zl3-TVY=%Y;2I)r+#DczYzSh3r9ex{1SlOE607CHWp67&D$5+&BWriM{5VQSc{1IOx z*evI=@E1pHFJN&E9?(HQm_yDN|VO{=W(X!JJ<(q8UH`< zJq97Gm^1lXla&J8)x3af3?5G|*<=vRK&#g(@vip6-JJX9PhtXChe(uBxT6f*Hk4ma z1*g3%y3w%wWf#W>@y;S9>bap5J=qjsC%+tKW@s5Vuu8Wath5K?Acy=gau)zy@r2sJ z-S1q25qSle6bX+lXRWUNGbeH*B_W)XNy#L@U`CHtz7an33FAyWw8h}_izlERimhiK zx*-hNfHgk$!wTajhWpo@x*8Psea&a2bDzY{vSphf(C`Ra*cTzMG|mJa2wVaB%}u6! zR(3gx@0br4b+?-5G1ffzq1WL-DRs6+GPk_c4B3=-K(1orjyKi5$cQ}q;q$kV6A!dY z5*}cLNIe4+q`!1(a(WLhq>e@Z3ZDwN=c&GO+ID93(gk=awTfN>4jl7g*96ItB77uH zE=#<`I0%WcsD#G#e**> z=ov+?vN&$XUVuVa1z-Fx!_xr#3ss7h5}Zt^cmIa2W+X(Fy=(qt{U8B%!#U|a@llxE zh*_54{-{ScmkW6Lmv8UMCCf6Y?0l80>r}##jJW_4*=cs~tpV4{HdTwWhj&xO@=!>= zMDA^-YF;G#_dY=p;q|mX{s@{nIe_4eFyg^2-%N{( z)rZwYXPiHbbtuTyekz*QM;O0LG@5TvlXw3`v(#CgrdXdK?Ga1&^!(nCs|}0)&~$%l zfb3iq(IK87>$AaA5Iz1KkQ2Y!E0l&a`sC2GB-^8UHGqhYSj4LGQStQ0`{!?Tr4ua2 zC5S{uyb^9-vqXDu=xi(lX2;l?s!VDZ*-?lY;R0%M?@O%z2Em#@RsG$ zBTJ4F0wO1k&1B-j4cd+0Y|qwygVwMosu{JPHGQoI(@e4Jz-W9u?lKvhlzOA#!W3Xi z>LbHAZ&km;@4d;=6=;Tb;%=U&&FA>g22(L#n6Ts}% z28P{Dv>TVM zfa=LAbm)({hg=Un3$WInwK8KUP5hGcYMH_$C%&c+F!L47acmOPF{>FzK5afm zOb}S4-`D6I63WqJXvl4mKYL9oE(vef_>EJ4Wl>Ph9RgC4Kv3 zt7TJzp{br%<94W2bPQZA^cdoM9=acmBm1tHwF!TG@KlY`e)|tg*dtUO3+^;@Rh?O3DbMWAag; zy2XQ?SU2yN@*zIijeIV8wIdA|5x6y3#ku~Y(Pj49%pR`G_4Jj{$TFV z#G1vJA~`uXV|yRxr6hh`c`4r*r$*I1Mdq9EX-yAyzm^E5yKTqx2PdR2%+)X#%$$i8 zTaXlo1ZNzZ)SE`g#CVvDdw;MIm$4o8^Xq-F5m6~htv?4Op<+6!i(>)oADr&JY3b`x zXn`>}bg+oj(d%!sZZhDQ7Ch+vq4P1ITUK&Lm`$$3i_dz7iQ8eOF?!=&JoSV3N$R1b z)E&i#Mp-hEt+r?vJWim#okx!%olu5YcfW-BPJ^$R{t`1z3j0U{}fp=2>f&i_sP zeKCr+J+6%$Uxbu$Q_L=s?cmR%Y<<=8?w;$G#>N;O=7=Wra-VG!nK^wFv!fX42pXw> zG=O@T%Oun38kk#zbjm_$t#qqCvD1Cnc!-m<5n1H@?(X1+#{75MU{IF*x>`_16IWNo z4*jOVU3kptPc70rT^)c945rFfS$9cOvDlyY|P;L*Y=S6(tE=c&5%dex-65o6Hs zWkWTc2OrzZ=?Jjf2S`8qI1}2UYuORR37nYsmff@OHmR)cv8lX!I4q&g?)aGE8EYsb z&Q>Q5-%n9XZ5&Kl>fZ9zavyeu7O~=N8vEMBZzds^Wg;#`boxT4MJ>M%ur_bNzi(n1 zTP-Uv&gK-ogb40O6p2(|zUD>5X>U=jmv9B8PYjR}I7%@R&%q1G-#oF)dscofg5Eo7 zQ=Hr(OUYU^e2nF329M&bMn&ZmUxA`wPaKu_edTkd{#M8t;cm{YC52;aJU%EA#IHY2 zk=5bF(YDqZtv-E2s>y;>UAXJ*(>vs^U~SVJZm&J~jlG|9EUMFz;NwVd!58yARjV~$ zERt2T1=J79FY=!q1V6ZvyS{hC37>T-B%SLC0~?R)EnB>`Az~hX;K}1|O**`UUA=B- zMyor=dclw1D6NbLq}X%15lNdgrS3gOL7n(gppL`wULx%5U1Zc*Bh^5NFrR128>WMD&eSlL7)H+Q_muSQg={StBLrVcoc_ zGaq4%sq!rn$|(4_gbvww%*3oJ08??w#nVf2b7ZFyX%Ze#ZyKh&No70zL1C=kezQY% zW5~}~W?iDcugDd&R?WcE2wX(9UL53(%QQA|x77)FJ8k1?O5xM;&2D54meQQ?SN#sA zBtcKcSjuAnoe%F4I5~%zLxMb3DTy~NeJ_BowU*+3?>FnVHr8AWi&jKl2!3@cdr<2A zs31d$tpOa4X8*}dLz(e78RZ*U?}LfDBWhnx4gYjqn!DZm=h65B+?$Ft zg(H9jY_bIE?q!LXO0Vq6dLzRJKY!Pgk`>X3B8bM1bT=ObTR2$SegEkhBQ znl<|J8gX;)Ha`(F4tY0_CYk~ju!$El0t1rSWzNnDL{!;}95qMovigIE6!i(344ZMgiEDp|l`coY*pawd#@;N#5B zg>FEZUFvN$>w?l!WuRcLSlGV9erq)|;OeCAxNef4KjB^~?{`={3XvKi1PbA9X`tvA{;f$TcxM+>$ect15R{M`y zpjfc5<8Kj=Z)EVpbBm(j@y_}40v;#-7&B?xFKH+$*;n-N9;D%&RGGpJzHKUauKk9^6EfH<0SaE4E1k#=KpDqFQ5UxAcNX7p)&5jRpUx3 z=0K8$7>Euai{8kB%7N&WkPG_?jKCUM{w*85;5}Rbo$Y4QhzH}Dug<`yw*XA5yVZx% zSpP3GcB*%A^pnpxlfOpg3EV+<)(G8MDzZ^C^?rBfWkEM6^GE=m?DCZwko9YT(zvg( zN+8^2HZV{_J>^v+RMuI`pk&?=(QpigB_AFS13T(Y1sFxR?!tH0fN$IhG$|*~fw9d( zK{W4+*AkOKkem)xk2_43YLO*-9cF+c?ommgr3gE>1EC-BHwO-GjE`wQIHdW#9}rLz zYEBp$&6igrH-u1{283$4QVYW`{hkmQS0F8(DP+-_q zDQgbs={!DR^d@ee|5%=(s`|Bx(-Z2rWr@FcNwC9;Sbqa*kps98xC8QH<;xf7%BwFy zVp(`U2OuwZ!9@`ab}lPL--76Q+1lDmzsQfH{}`}m3Z(84-fvh3jqYG*k_@`f(DWzS zv@STKQP)t{7`ScDK)Mb20*Ky2t?Uqe`Gb=-LE3g?lIy?7%Q!mq4n|W=-madY6089l zn?VAg2dz@n6F&S4K;qgU*S8>YeF#Q2wsA_Nw3Q$t+~BbAW#;WuPJOLsR_m>)IQ-f<@0!QlG0eaC@7gWWOHjKd5H1!exB7Cr(i9r< zRDkN@ih!$gVULJWp?45f;VV1q&}sW-3s|K*Q5siJj6I4|(%#}%Ivv4Q9G)o?z2ZLC zM6P)%Pc7g7)7)D|RTYKn!b&ShO39{?ZjkOSX%M7a1Sv`Bl9W#APH8udbSfoCcS?7o z-&~&Wob$yP_t(95-2FrL5ZJ7}*IIMF@AE#P7IO=XrN5Bho$pONY<@gV#>V7BC5Ywi z1-hHhUfxD+V2*A1s>K_9cXL++SpSEgLO9L<7rD@15bE+plb|UuY7ZoiAApX`ttj0o zoP{b@H)l7`7=jw?FF|Y805W0bRxt((cnw*-n%oZU_M^(urmleB!De5fc#dE@N30Pu+m`Fiw2Sy}-p$@dw8CkgI>xo}AMaWYoX9B@Z`y~Fm-5Ee zBx;mDz>7xjRe{IBPt11As;iD)SEtrlII_ixV$HzBpi$w&!Q4jQL&5rq#J0%V;IZAY z=b6FY$Jna;+u4Eh;6}(0q#}?STy5d{y#&U$1W&B|>fg=%$^gHb#J1=0pP@~}mq29g z23TeJ!yD8H0F2RVfb^*->j3!Jha%F_REhcg;>D%#1L+Bb*v+?l!E7l(P~Ama#{{_^ z%;uWGn!)GR-3T?pu&L3UGi+VYhs~ z6t5I|U^l9E33lNIFy*OMXN)uQTDe;FqpF9Ls;jVllZWSE*=x#+7Mb07jpnL+HHxK_ zwAWqL)gCl>@YvgBLQOW6>m&6CFdCW-+Fl_Ob>xhNVurN|Vdgu%xqVYlipe7af&TJG z0MT?IxMH>HSc2fxh%ge@fKjd+Ob>^21Bzi2MO|BhrbR(avYoKDYXf|kJAKjOa`v*V z!xMpcP2K=z<~^N$b>0e5fI+>B^~b9RlxiJv4lIf?C}qt28WQ-U%4Tsl0I*c(uz_Cs z5dAmFDcULF{_(z;y$2cmxjb;h#NTkrB)K!A37UuWG1JTrHI zI{5idLBLW>;BFeioCcFNdy8~HjppffXC1|2u4whTzVARKFRxNl?MEr_;Cb3aK3EW8 zJ=<{zMj&+qsll%S%%TX756(6?W8=ZR{wcGwu_EMRjuFGs?&1h%Zy}re3St6N%UeXo z3BSwcJBK4D$7Q%Z4M#&!<9!mQDDxF!axt)l$_B-e1(bIrnvR+tVSe_bMI@jQ% zPXc(@y)TR=@XQpF;uV!(||XEQS9-oHFPzT#cI@g`g_3o!`0~N%?e=nzK7EI&Jjmup~xoObzQy}{o&t! zTbWDi!Y(fYFFf_6g`vo=6UBsWO6u}J4~dCg}y;+*S>&gA!f)kwX(=cXJ%Ub;vcgyavHq-L$?)c!3ru2_!S zP^3Nj1^#WMsaSnj&`(w`JRd8Q?ZEiDw9613&Et6*JtD&qJ9c!-07T|aBDZM*SDD6F z%nb>9Eh8x$T^OVvX9Lx9x>vH>{X*DBPoxXS#kfN{2A9oUq8+Uq#gO{#Up?F+((%%1 ztr?^{ku7klIJBSP#m^bxZfS#5|bF!|^zY=5=k zP!CpiBs9W!CWKar3d5s4+13_;$HAAmKQx;3IXpX^=`^hzk>x)}X+3h1)2J_oT?;ZY zVXc`1LcX&i%U8{V(AsYvh2)Zy1v}p9Z7ZX<^tWJO^!A-;&PtZ9oUcQh19LSOS!Ty{ zhsbh6wWQo~Sd(dTm5TKZ=kFOqw=NNc*|iOS4V5~`e*|8~Sy6!L*!09YD?_T$nWKc1 zx!hwcc>(>KhRz;WIA!V2X|gDfTQYdsZm|^yJO)j$#xkcX09Q8iA{;sGt*6P0eLrP% zJd+82vr$|QlZZH$5y;WolmydZlephY&YwcvX!4z}TCF(Y2~JzpAgb8{FmK?h2yTzT zJ!iIv4OwALAU7h7sacuZ78P-!dUD-MxK9_?H`E+i4N`Sp*>*_I9tR7}5Nry-1MWvY z2SjHlqu(s3%&Vm&%)GvITI-?;lNTcIF*IT>*na6U^~8#{#9m?Y){7k_<&_-inuXmg zadK3$wl95zqtsby9oru6Mak3fF@tn10(9mEITFeyMP)B7hRX)|xn%i$3P0KI4AO=- z%APLUiX56f1i8Lav+^6J;sdK<3|zV9AoH7!_S(TFzMqgu3hq1ja12A8blTEvaPHTAi|{gNHUgC?qU=TV!rbZQ6oLfUqzrhBa`^La|MtW6bz& zMJNQP<>->86Bq@hUWL|ph7!aowAbDdcyWxf0h7URQY^{-kv$h(a#WpycxdQ@2*n?VJ!>j*in3*-FD!C00K1ZNi&CG84VE zif9S)ahc&@|4&{Cxx6tGNv7hJ4k7FlV;BE1LxR|YrD_o=S)oocsU?I z!qE6jxTKtUl)N8{iw~{1CJJi0{ekiK7&m3}kWd$qxL!iG++)KBOMg1tSAzv<1x}<- zzluI05blpJW@PK6GE0ZS5^3o0LM=Jr)l5i8SMcx#H-f51UYMeH4vM}MxP!b(qarsc z$qv^c>UCKO6tly}rJd$Vq#k7V!%Hph#4fZCLJ($Z#MZBE*WRzWc8+e8Tn@;EqGhyCL`;*xRhmGWRa;; z`!t{d+hz0Pt+0eSQEs)Ao+JGUzp_>^8rIUvaD8Y{3AY5caF<6P;%OnJM~jqeAPe+RYypGkvaS4qDFaYv19-nW~76h{b=kX=JlZ^I2aZLtb(ki`69z`F~gWOTwWlRPxoUe-x zNzE#RG^98^YlL4%G&pw<{&2>w_b*lo z1Wr)8X;09Ab`ol7EXzU4$r>=FUi%kX?zArF21fU3T+h2(OabHtC8I-DZPowSF~xv_ zsLuEQHXnRT0!5&l+wcDRVgOozXITbLeDAWo&ebj z=;`i#Yz5c^oFyCv5wsvx@a^xsAc!c`3~VVE0QmMU3%sjJ)60O{hO8~81JKzz19&7Y zW2g^6B6}4rCkkauQ@~KBQUYZHkaUcANW>QaNmHi)>s~uMO~8Q7#Ez z&i|Yxj_Q(_l5D#{@K$K{-suFP>5Rfl@rCakZwS7=agBDZ^HV;sF$E=v%b zsKo#z@oZACFS;(cyn=`-sW=;SzGga5koc`U2}9Z~P=KVA>RhmE!I{l7T&tpa)+#r^~jGJR|i z8AffEb=jHV;6JjRRsPF4Fn)PfZzPvfd3IWuX7|=fyqAw2NlmEk9?)FsYIx=yB+C$| zplO`BUxlaafRPctt~8MRKb;M$Ra|HW;^`(OO>BocN1w5W71RR#0Z0qT=1RhjP6BQR z={hPER%7o0Jezuerzrp^;4drt|4Q?g)K7Ity#Ix($ZX;=3+|bhykm!e@lN9y74a*1 zOCMt7Q+QaNfB=OWWa$L%cTD;A>3L+N0?zFGW|bmW%ZP%>A0?Wq0ePz#SO-qJiu(JA zlaDFdN{nA!I*>b|60~1Eb2JnEGJi578XB+l>^3c_p*m)hKPST;P(u&4MQP5h_5WRh zhOCqY{qzGB5v%kw9#*E5vyjYR?<`}IB0SYzS}p|qu|UXlw08IR72xF$!&n5o08|C{ zS1KBgAT*QOUj-%Yi@<`3b1Xx7*J6$_~{t-x13dB0I z?E%ok4p_T7N3g(C68#Z>EJ2)no5hw!J)qP0^76V}UP?RCVs`L;BICq^6(!BF2`r{_ zLI0JNeNchnV%d3SQSC>ED|_p}8P@B(`|Ag!lm11J&gElOb3D??|86Wdc)$_L(fETj zjQ3#K=O*x^gitL9vRJKW;b&{a13mYHIFN9o#&h_A{WrjJr_zhT!Z(#Jfc1`!YJlHW9@^mIPoeOS8uRLU zaIbGwux6FVW#U;tJeG^qJ)D9yx+u2yC~N3eSXRU#m>yLP=En&AIl#1*RuJTHtIU4H zR3~%lIMxL#ku9r4?_E^psy>0BRY9Z3Ya{3Mt(y3kqPQ6C$40=~a{neKAFk#~>D^^$ z!q(~)%j=|~NVy5lm!L{edCZ9A{5j>YcIGbRn|3<{CZ{+3^D6bba`bY~*78cFGH>G_bYuJE6$HMw~JRGJ*-`U)i&-fi(cb~2@Y#7!5iN%}1HsK{r{Eeno2-v^O*2yR7vKMl` zUkeHmNcb-I*FG76zu3Ue!Em9u@q#hJSWi;Nux_5weK(4)Y}1O>8h@V~)D%p%a+S+# zcqsRL)kBCd#Lw!6pZfJy{s);2`D+lL)iBM^^y7T&W;Lazwns5AUmj9&ZzilUOUu92 ztFv8hTr4!MbT|>pnUC*(1)q9y_W<^m04LH0_Oh3IjTfA-=}Bsr$9)88=<;UYh#EJj z<+bJi<9rbbj(F!7j&0_PuzV%eN>q!3P8iR?7!Li9ho~^)kLS>wc%M6qa46|9&Lv=N z?fW{-&Qx?aVu@)rj4c73+6g) zLU51ilHnZ5{q+4IWCEm@#+*CDW8s;$f5#X43;Xxup-a8LlTVbDU#AGkbv)XYmx>Z$ z!ygX<(3eRt#7cBDAA&w*-|x%BIyxStA@SIpz!B0Y;kE>b!DT+dHB zT^!fKw`t>P)Fh(Wvc9|-ed7ak&<@KTgQu-EJAr5K;3e)Qe+SL0PW zWu#)RgPl# z!Q7n55_okRkyRSSl8}5wbj%A;U4ttoA{B+w zQ>DjJTW=~uZfZA_^>l5kKK)SK^kTw5x0@XzI#~MljacWzFP2)(t76N|Rp6wfLH1Wm zxfFjwUxd>7b7~bQs<0%^U)6*Y=yT$KSnvC4?>yG!9*1S^g)P1V#mWK5%dR0@uOglR zqf5g?+9xV?D)Gj$!Gt^8HX>3UU4+N+gIy0zs5TALe|H3;z6ytF)AdL7JU=9$3$d_VjP)M>zMz=>Y2OG ze0p$T7+%-=QE%9e=@#G4N69`x`bc3{%&{D=-|huJqv7*X?8sv5GN ztal@NlkxtMEGALr^A~p(u-+r2t}nh<%q6-V%8j#0v7t|UN^yn{q*V;>kwAS=veAe0 zif2Efb~o1@mqkpswjx-I$jp+bb;>;4fy= zmUgbQNj*!cb5{##IiTNuDib&0zd&IaMJ1b5hvanB>Dk|B*0};h3DI|3+%V=e_MdI_ zbn}#tzf-5(pjXNVg7#8=d#Q}83$)DND?)fr@E&ilTZX!uO~lb(7{W-ML}xy120w?% z8;bS3LD&Fg%`*ZTsqSkOdV;yStc$p={=-PeUWPST5uz1R-jMQZk-OBRe^Zwl9o;MB~>t+xU2rG<#l}*&_KPp##d# zVM02i6nKZlbcrGFJ0wE0w$VS}`mAZY1VqLN-Vg9v9}VN2cZYS$he|BOknp70SBkxI zMwTrfU1feJ{1cbgYD{}4 z@YEUbfplL>RlkQ##lLMA?e8F#9Pv=g^j9?qxd1xU?!UROyo2fSY&%Y{q(j|TyW@9( zdVl%v3?{)p9T_74aKLwy_~vr*Q)1q#4}W!Pj~yDv8e}O^fE}wK)zuJAdr^NgCJLX0jwf#l|37Clm-poeVyE^{eQ&6 zvbyz%{tJ|ZI)YOu5&Ji7g#Nd7nGi2xuZB$!X6puIxu5ML94JAI0#GvILz*P2;t1BJ zHwU3|Lw5-fiR1s9pP*A!4pb%^s~2Xz9c%(M`{V5&%koEPM9H=|rE`TFX)*Hl?NYy)HKMs(JO z_D{rIv~I!Jxo}7#{5Vt!XVQH2bZ#EBk}hpqxX zvE7v8JwSursFh3nm)l+O6eM55w1bd@+p0Bh$s_EcsVD#9zV+K7phfV;7?YuUmZL>;&sZi9h6os7#uI+ zzV=zalxUWOVcn)Lwd#8do8@jn;Cr2r&gp) zI+ZVvR}ad)M##_D7UjbYz{Z*(VHq?w_aOKRx#EF-HNz7SLK)ZbfaoUz%G2nDG#BtR z;PkoxB&1*C0E4L~y%3@$q?6KKLYmgxa^QsQ0(!)XU9h31aa*e&U~WN{ZSVWRhhP8* zM9hFo7cxKNODXY@+MimX;tG<*RkYo_<%O~VjP`0h4j`-{3I~U~BG2ove-#PGq!|Pl zd|xqHX-8@W!`LP$fjk}G=Y)3|sVXH~X^^(m3&24-3Xl6jr;nN8yQycAK0t?TbNQI5 z+<1hdAeaZ6;Y=BE-xJ_A3s4ZJGG!VU2LT_ItQFgj{8fEa%L0fFynUElvD zitmtrQOUV@$iM@V-?=?j?6-iil&Q00~>% zaR$|Unyt5y2*4yS#O?TeAWu1IwZ=AB4O>1sC7&1HN?pW1s>zO_oIL^1T?K3eXA@3r zK_Wxoj5kdBiLOF~S>K&JFo9O&4(f&fM4u`cftK>eg_kc�K<&rYrHzq*vVc|BfK|uG^WDXG`lyiHaS zll&pRc`dciv*h)DPP(06DS*X|fP`7D7~REmrDOPkM}wFi;QAQX15x>Bym~v4~&ScOtW6v5fxP-hodtb-z!?@?@Ie%Xsjkz_Vh3|0dcFaR1ZuGUDF7Zsjsgy& zQ^|F=^p{RA8yE@T}}*XHg2wx3#4yO?+QVYCXxzH7VD!iW7-eMO&q5*Bwt>2x3-)$a>B z=K)d%B`pghIl>dQ;)8;nC+lT;xWPM!eC<+IU{-IgD7`uh5RLlr^X0tB|Kt}mw&`TB zNX_4$k*tvmF1ujfsw#bx%E`$8bGP*OKI`{WH8)q?JJg>Sx^i4ugmgE2Sq(C3% zNCG&fKIKfXYU561R<)ZU%oR8*)O7ghsH*FQ<=Ct~={p#G>>NKDWQ}Da1vP1^; zhfD(7Cu}Ss5$XgCBz6rst=|Xj$i@BHC+WOQ60y+Ha{ubnfkp030(vYetq;{6q-_Qg zM_QdIZ?MI09=UfeMff{E%nefN%w)gOVdnb)*(Z3P28}4P7TQVmgx!Rc;O5&_wf84) z!B9(3`Ui_xA1FU&vxxhnMp|ViVdtEJsihQzAKtpSmRGwn^(RMm-M>gajiG2SqCm5i zK}yRaEb}M|shO8K+|f9!J>H(oWw32cn8%P7Vq3$O93;ECtt8zH8%KU`XxJ4`cf zPShFMdgFN3J4%*797njqIgZ4H;d%>tY~VI;JoT8eI-5i8FI}q)u=G+qlX?A+ZF)s+ zdD#JLN#q#NTem6{usqJaes)9Yj>=>k-hhKt0rfHI{u0Yq@m51$m3Ahgz22PU^UFw8 z7=80;Ec>g=yli{rb-PXFU-_j=Z5dhRo8JnuYTH176+U9D9hJY7gJh!**qb4yWnWFXB9TnD7n^w*+0WKUB z%%Ep2{!6MdR&xFzEyPWyn2w{@8>XA3>O>!A>abQRjKhmZspadTg@Aj z$dPvX%SH!bqw|28w!dS@*GmJ5O@cG^FW#Zjax(()(N z9MFQsC|`uso!qZkUrxj%&oz7l*%F)E)m-g|d=*}1C`*PlP%n-cNgaSUu*4?=`Q&*^ zDxzKg0(L4*t!D%1@D{)63IjpUFixXkA6&h6UlTW!vjA(C_ElSTVDKZhlS0bbHW~+? z?Rvn`9X7nkd$LY*>N)Xy2$gdyYhe_1{m1DS9==KI6=W@ub^23v>LsP_dfaNcw5b}p z%T##0VaEtx+!;zZ1C~PU^ZWjxCcX;h2eGKi94?VQbRzc(`OoB1R}0?svh>h;Bk1#xUqby0rb21 zG$}0+(2oGiy8oFkGMWc&kb5TIf3Gb^SSb7Vui7=R6$FnacGfiLSpN4N%>VFXA(rp} zM&fHlTn&IT+XdCY*Ol+D!FtdId{v%)Yku~(P#=X5bUMn@AQ8P2pxPQU>V{DK7o;2w zf>>5?3?-{`BjU4suKO@^(sga*9@ zI)SjIFu?VBp%118D}diyZ2LRY3smwe#d%TBwrBo6K`ByEno|DrE{cB>4HWiP?x5ad zlD$Lxa{vw&1B@X*2t^%&VubS!j7c3un?4Q~>>la9Eh*?kCe+9F0WamQ^kN@gU144e zZEk#^(dh(}bj_J@e&^@JPYVRE<7MEpsnJfGfGZ7$e==npsHg;>`GrY}$;T3K;7S6&^H;z)5tHjXyQGEU z(f$DR+;h;(v~OQCASIx6Jx(!~nuT*5QoMA5!z0@SeEuUaeb$6yKG@;}Bj;e? zVMHx-vz^D0lYD>`)(1SbpD~4L(qi!~`yBz|u;#_bBX9wQP)G4m9Y{{4q+Wwr4rC#mMtnLR_h&6?zd}ErYgksh#`!%Puqw|v3b3-6>_RA_MH^yc56MoZUc>j8HtBo zrf6C1Igv$zT4$UhD={1>rrq}ePlELhe5}<~(0neWr0_H2O~)hJ6bi#Mq%5=2YbXdc zdIsoO)|58ExqCgsm8}pByEeB98yx`H7o(xzxzYH3ev#(=PiBUjIJZ{jGji$VeDv?R z<2=h(ua9#x+n_BPQVt)EK5++RvfSZu!{Lz&E$Y_c+7THJ>=W}*R^b6bo|#1uNqOz- zJte2D>l;_`9z>S)T&#YJ>4Ii(j!WQQZ;I;|H3d69TLQp;TS@4nS=l+pvkm++l^vA| z#lIUfj1zN9+t)P{aabc+>!|XCafen$INy3)-d=lNf$McQGkU(}IMhdu%SktGujYg5 zJ34*BW~l?OpDHEfrw3hJn?1S};=?j?8d;X7^(`rn&+Ny^hrPkw#^m`Yrx>FNAtR|} zjagUJ9VEE*VEKZka-*87_`ukiUT_!PaR&@wy{-Taf3*<_KQczS;PV74ngZ7kZVmV2 z9zrI)d_hU7NXgxWW;fWx*k8!Sh+8?5Aj3@c5*V3uGp+%WJ}F)dlDH|*21ZR506k7c zjmrZ*T@13V09McihN;!#0nY+G=g;#Y3S^fu_3$>G1!5@*76Z(G_<17z#p?i zTZRZPJ;F&WIW;}c{qA2RH2(&!d(T8*O_88y$1I_5t9XhAmxG9P^!QXrW zCZjrgWkB`7l@3-w(y765)<*0%Z%Ar=kw(CZ%S=E_ap;v9e99NnP2w9|S&sSkJjEhO zH+PXelmrZNy3FHW5>%$5@UVlZC>dR_kftQE^bnava;*A=i4BE(n?XTx4PbP7UbXg3 zgA!R#N(ETXO%MsmvsWS8mM)%`t`N%&j#dH@1jhx=P+qox;ree#wMAH%Vj3Pr$3HK{n&wS3UrFFcr!2BB~X&-N7_pt#1mQ(BgHKL zw9-#o+t#qnvf1p>Ton>|m?kTWDX^XGzxqBF?($rK#X~lm@2i?D>5E8E%8nhY5zDI5 zywD7r76meF*#dHtARGaiFLy6TX^zZ46_Z8!;Rt+;GAr#F^ULc)=MPFC|2HOHfJwc$J zDR8969Ad6j!sykkZlHVDPIjgG+=3*`2DmZG^{fD^C3FA`iYw{MPZU?->XemvPGZ+N zoJ>>nnGsGe13Uz~zGyw*;=O2Q^dR!3+#?MF7?tbG7m?Y@Rco&w1+cuMN*Twha|5HH zh{<+9=ing={6bw8EAxyYQxxD2!NAXqZZP4N+A07OUvd^QLF^F=gIN>ysegLzScdGK zdc*i6vgQ#>ogV9XG5FjeKraMzh`fVnx?=>4Mj-c5cVo}1;TPCeh&MhBt8>5rT`bQ| zb;gukkEvrQ0OL^*aBO!ZvMH}-)H^jP!QJoGrcE`Eo3=;NO96MF8T(dh@m_qxQH!+Y zQ{1zMAN+lu3sZ{+?zqPm+1tw2hY}*Wc_GQ;H>tg(ZnayN-05l8OtqI1Jj?H|KEH`d z{hV8aP$4;)Xbx*s+t_USsl@d%0V|O84=s)gcTIuqw>A4%jwU6&F_l%}d%t%C157Du z&j9Z;Pi1o^Mc3qGscwu-?AB0RqRLo-jP#v0+4(TtW(!#2$3(O7`h(iU+|m+JYnE@m zAFOZz6zqV{FV|RWUF3X~S-=@!R8o!OMf#o~xg_%MDNJ9GtuU@%W4Qy%;obW1$&Qqu z#VE1!>ys#P&NwK(axH{Z?C{+b ztf4hg`Te9qQM&j&?q#-*DkL7z?7Q#;A))Ynyy0Pg6WG^5%h%__t@+-7L1xsVL&JJy|L zN&YY)_!rRQ!fL2G^v4}V^BGoeiEi~{yCGd>z6w7|!YsFe$4aRJWn3hS{Fjl_tE z^9Hzri~@3ypAl9<5>myR7xIHo5;1?(;s}+@ayCfP#h(Iuu^*<1tYv{pLzs-)+FZ*t z&oX`<@NACR-s<_U8>{*j1pG1kK&s1*oY96#n8838fH(B8=KkeILc2N=iZjj7jGtVM zB<>*d6U593zy zY}dR`Aeii8ncl@wo;Q@4b?@oWA)s3L%du45j!0ZXc#suG{Lq02aN)a`quyfRJC+_2 zJ+~oC{qvk7hcOF=QOCKu=>uu)7W^r-(2_#Ui-fFE^IudC$#LH*O=fRR zy9n#qI+I<1u*aTa^RqWoya25+G86H}nOzduGG+b`NL zC$<12ir+#hzs%W#fBaNNxtK8$GFC{us1bc`*h1gUCN(x}xnkIle0}PL^vEZDC^LDBmVI4({Krr)y%G)L*m zPb=*4rx@hb3 zYa$pf?~xHkA%E7)CvnP=rKy0Fu87^Mm$tE1oov~alQ(^0$RveF!K^=Ycnx6Ej@7|?3D#;+WiqA$?f6M(QiQIys$mXd=EZgqUOtf#l!L)d8BK)4D?zu-% zoCk36>oe{cdekB&W)%yo{e#xCiA?$Q88V$8h5j$8SUyLQpEY-nAF#O}C2?qR2Q4U% zH@TE@=$0Ld$p~BfXl|ok-h%O$p`+aJ4h;mP!}+GiI-IAX8P0$39TJu zkl4?X-lvL~(F}hLmpHOyVdD|g1FX)eD+w)@QU1kF)Pvw3s*NUk;~@qQvC86>Jl?wmT6p{TC+;7@#Ts2_EW5?J zP5o}v?vzg!WM0LxJdF33+$p1)>hih9f3#?35;N?wqqP{ZO@c^L+JE;O z5t5$vx1STO!D?8ptfe8P{dIXm!jzRWe<_Cg#FW6sVN}6ztY6z^-~Rl1)Oz*7RQuK` zS${SG0m=34+ffx;G{N=7ZMqMAOOw|)J^@B|9p8*m?`9Q$kyE)Pg_8nGxMO=nX3j0m z*pK-lf^FE8OhtdhhGEN;SmHM|rH#cFnqdr@OKINFnK13SUo&UhOIlk!Z_gn0@S&o(f|Me From 2c3dbc711e9d350b318e363acedd7c995916ec69 Mon Sep 17 00:00:00 2001 From: Vinayak Katoch Date: Sun, 22 Feb 2026 21:22:56 +0530 Subject: [PATCH 26/69] Remove unused rpcmem_set_dmabuf_name dummy function Remove rpcmem_set_dmabuf_name() which was a no-op dummy function. Cleaned up declaration, implementation, and all call sites. Signed-off-by: Vinayak Katoch --- inc/rpcmem_internal.h | 16 ---------------- src/apps_mem_imp.c | 2 -- src/rpcmem_linux.c | 6 ------ 3 files changed, 24 deletions(-) diff --git a/inc/rpcmem_internal.h b/inc/rpcmem_internal.h index 4fe415e..34aa3eb 100644 --- a/inc/rpcmem_internal.h +++ b/inc/rpcmem_internal.h @@ -6,22 +6,6 @@ #include "rpcmem.h" -/* - * rpcmem_set_dmabuf_name() - API to set name for DMA allocated buffer. - * Name string updates as follows. - * Heap : dsp___ - * Non-heap : apps___ - * - * @name : Pointer to string, "dsp" for heap buffers, "apps" for - * non-heap buffers - * @fd : File descriptor of buffer - * @heapid : Heap ID used for memory allocation - * @buf : Pointer to buffer start address - * @rpcflags: Memory flags describing attributes of allocation - * Return : 0 on success, valid non-zero error code on failure - */ -int rpcmem_set_dmabuf_name(const char *name, int fd, int heapid, - void *buf, uint32_t rpc_flags); /* * returns an file descriptor associated with the address */ diff --git a/src/apps_mem_imp.c b/src/apps_mem_imp.c index f288d0a..ffa2a52 100644 --- a/src/apps_mem_imp.c +++ b/src/apps_mem_imp.c @@ -149,7 +149,6 @@ __QAIC_IMPL(apps_mem_request_map64)(int heapid, uint32_t lflags, uint32_t rflags VERIFYC(NULL != (buf = rpcmem_alloc_internal(heapid, lflags, len)), AEE_ENORPCMEMORY); VERIFYC(0 < (fd = rpcmem_to_fd_internal(buf)), AEE_EBADFD); - rpcmem_set_dmabuf_name("dsp", fd, heapid, buf, lflags); /* Using FASTRPC_MAP_FD_DELAYED as only HLOS mapping is reqd at this point */ VERIFY(AEE_SUCCESS == (nErr = fastrpc_mmap(domain, fd, buf, 0, len, @@ -177,7 +176,6 @@ __QAIC_IMPL(apps_mem_request_map64)(int heapid, uint32_t lflags, uint32_t rflags AEE_ENORPCMEMORY); fd = rpcmem_to_fd_internal(buf); VERIFYC(fd > 0, AEE_EBADPARM); - rpcmem_set_dmabuf_name("dsp", fd, heapid, buf, lflags); } VERIFY(AEE_SUCCESS == (nErr = remote_mmap64_internal(fd, rflags, (uint64_t)buf, len, diff --git a/src/rpcmem_linux.c b/src/rpcmem_linux.c index a0814b9..2fc7cb9 100644 --- a/src/rpcmem_linux.c +++ b/src/rpcmem_linux.c @@ -118,12 +118,6 @@ void rpcmem_deinit() { pthread_mutex_destroy(&rpcmt); } -int rpcmem_set_dmabuf_name(const char *name, int fd, int heapid, - void *buf, uint32_t rpcflags) { - // Dummy call where DMABUF is not used - return 0; -} - int rpcmem_to_fd_internal(void *po) { struct rpc_info *rinfo, *rfree = 0; QNode *pn, *pnn; From a9a36d9dca7387364bd40a72b5ea179543026fcd Mon Sep 17 00:00:00 2001 From: Abhinav Parihar Date: Tue, 24 Feb 2026 10:50:35 +0530 Subject: [PATCH 27/69] Drop ADSP_AVS_* env support from path resolver Remove unused ADSP_AVS_CFG_PATH default and ADSP_AVS_PATH handling from get_dirlist_from_env(). Signed-off-by: Abhinav Parihar --- inc/apps_std_internal.h | 6 ------ src/apps_std_imp.c | 18 ------------------ 2 files changed, 24 deletions(-) diff --git a/inc/apps_std_internal.h b/inc/apps_std_internal.h index 37be0c2..d4ce4fe 100644 --- a/inc/apps_std_internal.h +++ b/inc/apps_std_internal.h @@ -18,7 +18,6 @@ // Environment variable name, that can be used to override the search paths #define ADSP_LIBRARY_PATH "ADSP_LIBRARY_PATH" #define DSP_LIBRARY_PATH "DSP_LIBRARY_PATH" -#define ADSP_AVS_PATH "ADSP_AVS_CFG_PATH" #define MAX_NON_PRELOAD_LIBS_LEN 2048 #define FILE_EXT ".so" @@ -29,11 +28,6 @@ #define VENDOR_DOM_LOCATION "/vendor/dsp/xdsp/" #endif -// Search path used by fastRPC for acdb path -#ifndef ADSP_AVS_CFG_PATH -#define ADSP_AVS_CFG_PATH ";/etc/acdbdata/;" -#endif - int fopen_from_dirlist(const char *dirList, const char *delim, const char *mode, const char *name, apps_std_FILE *psout); diff --git a/src/apps_std_imp.c b/src/apps_std_imp.c index 3a69345..209eaac 100644 --- a/src/apps_std_imp.c +++ b/src/apps_std_imp.c @@ -970,20 +970,6 @@ static int get_dirlist_from_env(const char *envvarname, char **ppDirList) { // Append default DSP_SEARCH_PATH to user defined env strlcat(envList, dsp_search_path, envListPrependLen); envListLen = envListPrependLen; - } else if (strncmp(envvarname, ADSP_AVS_PATH, - strlen(ADSP_AVS_PATH)) == 0) { - envListPrependLen = envListLen + strlen(ADSP_AVS_CFG_PATH); - if (envLenGuess < envListPrependLen) { - FREEIF(envListBuf); - VERIFYC(envListBuf = - realloc(envListBuf, sizeof(char) * envListPrependLen), - AEE_ENOMEMORY); - envList = envListBuf; - VERIFY(0 == (nErr = apps_std_getenv(envvarname, envList, - envListPrependLen, &listLen))); - } - strlcat(envList, ADSP_AVS_CFG_PATH, envListPrependLen); - envListLen = envListPrependLen; } } else if (strncmp(envvarname, ADSP_LIBRARY_PATH, strlen(ADSP_LIBRARY_PATH)) == 0 || @@ -991,10 +977,6 @@ static int get_dirlist_from_env(const char *envvarname, char **ppDirList) { strlen(DSP_LIBRARY_PATH)) == 0) { envListLen = listLen = 1 + strlcpy(envListBuf, dsp_search_path, envLenGuess); - } else if (strncmp(envvarname, ADSP_AVS_PATH, - strlen(ADSP_AVS_PATH)) == 0) { - envListLen = listLen = - 1 + strlcpy(envListBuf, ADSP_AVS_CFG_PATH, envLenGuess); } /* From 578edec0b6f1fea61b2ed45219854a58926d1678 Mon Sep 17 00:00:00 2001 From: Ansa Ahmed Date: Fri, 20 Feb 2026 16:01:35 +0530 Subject: [PATCH 28/69] Convert PNG images to mermaid diagrams for README Signed-off-by: Ansa Ahmed --- README.md | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6bbcd65..0e5206c 100644 --- a/README.md +++ b/README.md @@ -12,19 +12,95 @@ FastRPC interfaces are defined in an IDL file, and they are compiled using the Q The following diagram depicts the major FastRPC software components on the CPU and DSP. -![FastRPC Architecture](Docs/images/FastRPC_architecture.png) +```mermaid +flowchart TD +subgraph SMD[Shared Memory Driver] +direction TB +subgraph CPU[CPU] +direction TB +subgraph Application[Application] +direction TB +Stub[Stub] +FRPC_UD[FastRPC user driver] +Stub --> FRPC_UD +end +end +subgraph DSP[DSP] +direction TB +subgraph User_PD[User PD] +direction TB +Skel[Skel] +FRPC_DD[FastRPC DSP user driver] +Skel --> FRPC_DD +end +end +subgraph Kernel_Space[Kernel Space] +direction TB +FRPC_KD[FastRPC Kernel driver] +end +FRPC_UD --> FRPC_KD +FRPC_DD --> FRPC_KD +end +classDef generated fill:#E6E6FA,stroke:#9370DB,color:#000 +classDef fastrpc fill:#4169E1,stroke:#000,color:#000 +classDef shared fill:#FAFAFA,stroke:#666,color:#000 +classDef userpdbox fill:#ABDBE3,stroke:#666,color:#000 +classDef mainbox fill:#7FB3CD,stroke:#666,color:#000 +class Stub,Skel generated +class FRPC_UD,FRPC_DD,FRPC_KD fastrpc +class SMD shared +class Application,User_PD userpdbox +class CPU,DSP,Kernel_Space mainbox +linkStyle default stroke:#000 +``` **Stub and skel** are generated by the IDL compiler. Other modules are part of the software stack on the device. **Definition of the terms in the diagram:** -![Term Definitions](Docs/images/Term_definitions.png) - +| Term | Description | +|------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------| +| Application | User mode process that initiates the remote invocation | +| Stub | Auto-generated code that takes care of marshaling parameters and runs on the CPU | +| FastRPC user driver on CPU | User mode library that is used by the stub code to do remote invocations | +| FastRPC Kernel Driver | Receives the remote invocations from the client, queues them up with the FastRPC DSP driver, and then waits for the response after signaling the remote side | +| FastRPC DSP Driver | Dequeues the messages sent by the FastRPC kernel driver and dispatches them for processing | +| FastRPC user driver on DSP | User mode code that includes a shell executable to run in the user protection domain (PD) on the DSP and complete the remote invocations to the skel library | +| Skel | Auto-generated code that un-marshals parameters and invokes the user-defined implementation of the function that runs on the DSP | +| User PD | User protection domain on the DSP that provides the environment to run the user code | + ### FastRPC Workflow The FastRPC framework consists of the following components. -![FastRPC Workflow](Docs/images/FastRPC_workflow.png) +```mermaid +flowchart LR +subgraph CPU +UC[User Code] +Stub[Stub] +FF[FastRPC Framework] +end +subgraph DSP +FD[FastRPC DSP Framework] +Skel[Skel] +MI[Method Implementation] +end +UC --> |" 1 "| Stub +Stub --> |" 10 "| UC +Stub --> |" 2 "| FF +FF --> |" 9 "| Stub +FF --> |" 3 "| FD +FD --> |" 8 "| FF +FD --> |" 4 "| Skel +Skel --> |" 7 "| FD +Skel --> |" 5 "| MI +MI --> |" 6 "| Skel +classDef generated fill:#E6E6FA,stroke:#9370DB,color:#2A0066 +classDef fastrpc fill:#4169E1,stroke:#000,color:#FFFFFF +classDef shared fill:#F5F5F5,stroke:#666 +class UC,Stub,Skel,MI generated +class FF,FD fastrpc +``` **Workflow:** From 6ad405cd98861453bf194cf522c45c188e1db0bc Mon Sep 17 00:00:00 2001 From: Vinayak Katoch Date: Wed, 18 Feb 2026 16:31:38 +0530 Subject: [PATCH 29/69] Add internal mmap/munmap functions with DSP address tracking Introduce fastrpc_mmap_internal() and fastrpc_munmap_internal() to handle buffer mapping with DSP virtual address management. These functions maintain mappings in the static map list and enable lookup by DSP virtual address. Extract common mmap logic into fastrpc_mmap_helper() to eliminate code duplication between fastrpc_mmap() and fastrpc_mmap_internal(). Simplify apps_mem_request_map64() by removing conditional allocation logic and always allocating in userspace, then using fastrpc_mmap_internal() for mapping. Update apps_mem_request_unmap64() to route to appropriate unmap function based on mapping type: - FASTRPC_ALLOC_HLOS_FD: use fastrpc_munmap() - ADSP_MMAP_HEAP_ADDR/ADSP_MMAP_REMOTE_HEAP_ADDR: use remote_munmap64() - Other allocations: use fastrpc_munmap_internal() Signed-off-by: Vinayak Katoch --- inc/fastrpc_mem.h | 29 +++++++ src/apps_mem_imp.c | 36 ++++----- src/fastrpc_mem.c | 198 ++++++++++++++++++++++++++++++++++++--------- 3 files changed, 206 insertions(+), 57 deletions(-) diff --git a/inc/fastrpc_mem.h b/inc/fastrpc_mem.h index e4b8667..6508ca8 100644 --- a/inc/fastrpc_mem.h +++ b/inc/fastrpc_mem.h @@ -73,4 +73,33 @@ int fastrpc_buffer_ref(int domain, int fd, int ref, void **va, size_t *size); */ void remote_register_buf(void *buf, int size, int fd); +/* + * Internal function to map a buffer and return the DSP virtual address. + * Creates a mapping on the DSP and stores the mapping information in the static map list. + * + * @param domain The DSP domain ID (-1 for current domain) + * @param fd File descriptor of the buffer + * @param vaddr Virtual address of the buffer on CPU side + * @param offset Offset from the beginning of the buffer (must be 0) + * @param length Size of buffer in bytes + * @param flags Mapping flags + * @param raddr Output: DSP virtual address of the mapped buffer + * + * @return 0 on success, error code on failure + */ +int fastrpc_mmap_internal(int domain, int fd, void *vaddr, int offset, size_t length, uint32_t flags, uint64_t *raddr); + +/* + * Internal function to unmap a buffer using the DSP virtual address. + * Looks up the mapping in the static map list using the DSP virtual address, + * then performs the unmap operation and removes the mapping from the list. + * + * @param domain The DSP domain ID (-1 for current domain) + * @param raddr DSP virtual address of the mapped buffer + * @param length Size of buffer in bytes to unmap + * + * @return 0 on success, error code on failure + */ +int fastrpc_munmap_internal(int domain, uint64_t raddr, size_t length); + #endif //FASTRPC_MEM_H diff --git a/src/apps_mem_imp.c b/src/apps_mem_imp.c index ffa2a52..7813bb3 100644 --- a/src/apps_mem_imp.c +++ b/src/apps_mem_imp.c @@ -163,23 +163,13 @@ __QAIC_IMPL(apps_mem_request_map64)(int heapid, uint32_t lflags, uint32_t rflags */ *vadsp = (uint64_t)fd; } else { - /* Memory for unsignedPD's user-heap will be allocated in userspace for - * security reasons. Memory for signedPD's user-heap will be allocated in - * kernel. - */ - if (((rflags != ADSP_MMAP_ADD_PAGES) && - (rflags != ADSP_MMAP_ADD_PAGES_LLC)) || - (((rflags == ADSP_MMAP_ADD_PAGES) || - (rflags == ADSP_MMAP_ADD_PAGES_LLC)) && - (unsigned_module && ualloc_support))) { - VERIFYC(NULL != (buf = rpcmem_alloc_internal(heapid, lflags, len)), - AEE_ENORPCMEMORY); - fd = rpcmem_to_fd_internal(buf); - VERIFYC(fd > 0, AEE_EBADPARM); - } + VERIFYC(NULL != (buf = rpcmem_alloc_internal(heapid, lflags, len)), + AEE_ENORPCMEMORY); + fd = rpcmem_to_fd_internal(buf); + VERIFYC(fd > 0, AEE_EBADPARM); VERIFY(AEE_SUCCESS == - (nErr = remote_mmap64_internal(fd, rflags, (uint64_t)buf, len, - (uint64_t *)vadsp))); + (nErr = fastrpc_mmap_internal(domain, fd, buf, 0, len, + rflags, vadsp))); pbuf = (uint64_t)buf; *vapps = pbuf; minfo->vapps = *vapps; @@ -250,17 +240,27 @@ __QAIC_IMPL(apps_mem_request_unmap64)(uint64_t vadsp, pthread_mutex_unlock(&me->mem_mut); /* If apps_mem_request_map64 was called with flag FASTRPC_ALLOC_HLOS_FD, - * use fastrpc_munmap else use remote_munmap64 to unmap. + * use fastrpc_munmap. For ADSP_MMAP_HEAP_ADDR and ADSP_MMAP_REMOTE_HEAP_ADDR, + * use remote_munmap64. For other cases, use fastrpc_munmap_internal. */ if(mfree && mfree->rflags == FASTRPC_ALLOC_HLOS_FD) { fd = (int)vadsp; VERIFY(AEE_SUCCESS == (nErr = fastrpc_munmap(domain, fd, 0, len))); + } else if (mfree && (mfree->rflags == ADSP_MMAP_HEAP_ADDR || + mfree->rflags == ADSP_MMAP_REMOTE_HEAP_ADDR)) { + /* These cases use remote_mmap64_internal, so use remote_munmap64 */ + VERIFY(AEE_SUCCESS == (nErr = remote_munmap64((uint64_t)vadsp, len))); } else if (mfree || fastrpc_get_pd_type(domain) == AUDIO_STATICPD){ /* * Map info not available for Audio static PD after daemon reconnect, * So continue to unmap to avoid driver global maps leak. + * For other cases, use fastrpc_munmap_internal as they were mapped with fastrpc_mmap_internal. */ - VERIFY(AEE_SUCCESS == (nErr = remote_munmap64((uint64_t)vadsp, len))); + if (mfree) { + VERIFY(AEE_SUCCESS == (nErr = fastrpc_munmap_internal(domain, (uint64_t)vadsp, len))); + } else { + VERIFY(AEE_SUCCESS == (nErr = remote_munmap64((uint64_t)vadsp, len))); + } if (!mfree) goto bail; } diff --git a/src/fastrpc_mem.c b/src/fastrpc_mem.c index 8f62fc2..ab0616a 100644 --- a/src/fastrpc_mem.c +++ b/src/fastrpc_mem.c @@ -440,51 +440,37 @@ int fdlist_fd_from_buf(void *buf, int bufLen, int *nova, void **base, int *attr, return 0; } -int fastrpc_mmap(int domain, int fd, void *vaddr, int offset, size_t length, - enum fastrpc_map_flags flags) { +/** + * Helper function to perform complete mmap operation including error handling + * Returns 0 on success, error code on failure + * On success, vaddrout contains the DSP virtual address + */ +static int fastrpc_mmap_helper(int *domain, int fd, void *vaddr, int offset, + size_t length, uint32_t flags, int attrs, + uint64_t *vaddrout) { struct fastrpc_map map = {0}; - int nErr = 0, dev = -1, iocErr = 0, attrs = 0, ref = 0; - uint64_t vaddrout = 0; + int nErr = 0, dev = -1, iocErr = 0, ref = 0; struct static_map *mNode = NULL, *tNode = NULL; QNode *pn, *pnn; - VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); - - FARF(RUNTIME_RPC_HIGH, - "%s: domain %d fd %d addr %p length 0x%zx flags 0x%x offset 0x%x", - __func__, domain, fd, vaddr, length, flags, offset); - - /** - * Mask is applied on "flags" parameter to extract map control flags - * and SMMU mapping control attributes. Currently no attributes are - * suppported. It allows future extension of the fastrpc_mmap API - * for SMMU mapping control attributes. - */ - attrs = flags & (~FASTRPC_MAP_FLAGS_MASK); - flags = flags & FASTRPC_MAP_FLAGS_MASK; - VERIFYC(fd >= 0 && offset == 0 && attrs == 0, AEE_EBADPARM); - VERIFYC(flags >= 0 && flags < FASTRPC_MAP_MAX && - flags != FASTRPC_MAP_RESERVED, - AEE_EBADPARM); - // Get domain and open session if not already open - if (domain == -1) { - domain = get_current_domain(); + if (*domain == -1) { + *domain = get_current_domain(); } - VERIFYC(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), AEE_EBADPARM); - FASTRPC_GET_REF(domain); - VERIFY(AEE_SUCCESS == (nErr = fastrpc_session_dev(domain, &dev))); + VERIFYC(IS_VALID_EFFECTIVE_DOMAIN_ID(*domain), AEE_EBADPARM); + FASTRPC_GET_REF(*domain); + VERIFY(AEE_SUCCESS == (nErr = fastrpc_session_dev(*domain, &dev))); VERIFYC(-1 != dev, AEE_ERPC); /* Search for mapping in current session static map list */ - pthread_mutex_lock(&smaplst[domain].mut); - QLIST_NEXTSAFE_FOR_ALL(&smaplst[domain].ql, pn, pnn) { + pthread_mutex_lock(&smaplst[*domain].mut); + QLIST_NEXTSAFE_FOR_ALL(&smaplst[*domain].ql, pn, pnn) { tNode = STD_RECOVER_REC(struct static_map, qn, pn); if (tNode->map.fd == fd) { break; } } - pthread_mutex_unlock(&smaplst[domain].mut); + pthread_mutex_unlock(&smaplst[*domain].mut); // Raise error if map found already if (tNode) { @@ -505,13 +491,13 @@ int fastrpc_mmap(int domain, int fd, void *vaddr, int offset, size_t length, map.m.vaddrout = 0; mNode->map = map.m; iocErr = ioctl_mmap(dev, MEM_MAP, flags, attrs, fd, offset, length, - (uint64_t)vaddr, &vaddrout); + (uint64_t)vaddr, vaddrout); if (!iocErr) { - mNode->map.vaddrout = vaddrout; + mNode->map.vaddrout = *vaddrout; mNode->refs = 1; - pthread_mutex_lock(&smaplst[domain].mut); - QList_AppendNode(&smaplst[domain].ql, &mNode->qn); - pthread_mutex_unlock(&smaplst[domain].mut); + pthread_mutex_lock(&smaplst[*domain].mut); + QList_AppendNode(&smaplst[*domain].ql, &mNode->qn); + pthread_mutex_unlock(&smaplst[*domain].mut); mNode = NULL; } else if (errno == ENOTTY || iocErr == (int)(DSP_AEE_EOFFSET | AEE_EUNSUPPORTED)) { @@ -521,16 +507,17 @@ int fastrpc_mmap(int domain, int fd, void *vaddr, int offset, size_t length, nErr = AEE_EFAILED; goto bail; } + bail: - FASTRPC_PUT_REF(domain); + FASTRPC_PUT_REF(*domain); if (nErr) { if (iocErr == 0) { errno = 0; } FARF(ERROR, - "Error 0x%x: %s failed to map buffer fd %d, addr %p, length 0x%zx, " + "Error 0x%x: %s failed for fd %d, addr %p, length 0x%zx, " "domain %d, flags 0x%x, ioctl ret 0x%x, errno %s", - nErr, __func__, fd, vaddr, length, domain, flags, iocErr, + nErr, __func__, fd, vaddr, length, *domain, flags, iocErr, strerror(errno)); } if (mNode) { @@ -540,6 +527,41 @@ int fastrpc_mmap(int domain, int fd, void *vaddr, int offset, size_t length, return nErr; } +int fastrpc_mmap(int domain, int fd, void *vaddr, int offset, size_t length, + enum fastrpc_map_flags flags) { + int nErr = 0, attrs = 0; + uint64_t vaddrout = 0; + + VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); + + FARF(RUNTIME_RPC_HIGH, + "%s: domain %d fd %d addr %p length 0x%zx flags 0x%x offset 0x%x", + __func__, domain, fd, vaddr, length, flags, offset); + + /** + * Mask is applied on "flags" parameter to extract map control flags + * and SMMU mapping control attributes. Currently no attributes are + * suppported. It allows future extension of the fastrpc_mmap API + * for SMMU mapping control attributes. + */ + attrs = flags & (~FASTRPC_MAP_FLAGS_MASK); + flags = flags & FASTRPC_MAP_FLAGS_MASK; + VERIFYC(fd >= 0 && offset == 0 && attrs == 0, AEE_EBADPARM); + VERIFYC(flags >= 0 && flags < FASTRPC_MAP_MAX && + flags != FASTRPC_MAP_RESERVED, + AEE_EBADPARM); + + nErr = fastrpc_mmap_helper(&domain, fd, vaddr, offset, length, flags, attrs, + &vaddrout); + +bail: + if (nErr) { + FARF(ERROR, "Error 0x%x: %s failed for fd %d, addr %p, length 0x%zx, domain %d, flags 0x%x", + nErr, __func__, fd, vaddr, length, domain, flags); + } + return nErr; +} + int fastrpc_munmap(int domain, int fd, void *vaddr, size_t length) { int nErr = 0, dev = -1, iocErr = 0, locked = 0, ref = 0; struct static_map *mNode = NULL; @@ -614,6 +636,104 @@ int fastrpc_munmap(int domain, int fd, void *vaddr, size_t length) { return nErr; } +int fastrpc_mmap_internal(int domain, int fd, void *vaddr, int offset, + size_t length, uint32_t flags, uint64_t *raddr) { + int nErr = 0, attrs = 0; + + VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); + + VERIFYC(raddr != NULL, AEE_EBADPARM); + + FARF(RUNTIME_RPC_HIGH, + "%s: domain %d fd %d addr %p length 0x%zx flags 0x%x offset 0x%x", + __func__, domain, fd, vaddr, length, flags, offset); + + attrs = flags & (~FASTRPC_MAP_FLAGS_MASK); + flags = flags & FASTRPC_MAP_FLAGS_MASK; + VERIFYC(fd >= 0 && offset == 0 && attrs == 0, AEE_EBADPARM); + + nErr = fastrpc_mmap_helper(&domain, fd, vaddr, offset, length, flags, attrs, + raddr); + +bail: + if (nErr) { + FARF(ERROR, "Error 0x%x: %s failed for fd %d, addr %p, length 0x%zx, domain %d, flags 0x%x", + nErr, __func__, fd, vaddr, length, domain, flags); + } + return nErr; +} + +int fastrpc_munmap_internal(int domain, uint64_t raddr, size_t length) { + int nErr = 0, dev = -1, iocErr = 0, locked = 0, ref = 0; + struct static_map *mNode = NULL; + QNode *pn, *pnn; + + VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); + + FARF(RUNTIME_RPC_HIGH, "%s: domain %d raddr 0x%llx length 0x%zx", __func__, + domain, raddr, length); + if (domain == -1) { + domain = get_current_domain(); + } + VERIFYC(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), AEE_EBADPARM); + FASTRPC_GET_REF(domain); + VERIFY(AEE_SUCCESS == (nErr = fastrpc_session_dev(domain, &dev))); + /** + * Search for mapping in current static map list using DSP virtual address (raddr). + */ + pthread_mutex_lock(&smaplst[domain].mut); + locked = 1; + QLIST_NEXTSAFE_FOR_ALL(&smaplst[domain].ql, pn, pnn) { + mNode = STD_RECOVER_REC(struct static_map, qn, pn); + if (mNode->map.vaddrout == raddr) { + FARF(RUNTIME_RPC_HIGH, "%s: unmap found for raddr 0x%llx domain %d", __func__, + raddr, domain); + break; + } + } + VERIFYC(mNode && mNode->map.vaddrout == raddr, AEE_ENOSUCHMAP); + if (mNode->refs > 1) { + FARF(ERROR, "%s: Attempt to unmap raddr 0x%llx with %d outstanding references", + __func__, raddr, mNode->refs - 1); + nErr = AEE_EBADPARM; + goto bail; + } + mNode->refs = 0; + locked = 0; + pthread_mutex_unlock(&smaplst[domain].mut); + + iocErr = ioctl_munmap(dev, MEM_UNMAP, 0, 0, mNode->map.fd, mNode->map.length, + mNode->map.vaddrout); + pthread_mutex_lock(&smaplst[domain].mut); + locked = 1; + if (iocErr == 0) { + QNode_DequeueZ(&mNode->qn); + free(mNode); + mNode = NULL; + } else if (errno == ENOTTY || errno == EINVAL) { + nErr = AEE_EUNSUPPORTED; + } else { + mNode->refs = 1; + nErr = AEE_EFAILED; + } +bail: + if (locked == 1) { + locked = 0; + pthread_mutex_unlock(&smaplst[domain].mut); + } + FASTRPC_PUT_REF(domain); + if (nErr) { + if (iocErr == 0) { + errno = 0; + } + FARF(ERROR, + "Error 0x%x: %s failed raddr 0x%llx, length 0x%zx, domain %d, " + "ioctl ret 0x%x, errno %s", + nErr, __func__, raddr, length, domain, iocErr, strerror(errno)); + } + return nErr; +} + int remote_mem_map(int domain, int fd, int flags, uint64_t vaddr, size_t size, uint64_t *raddr) { int nErr = 0; From 121787f5c52c5bfd49e563a0583de8a196093391 Mon Sep 17 00:00:00 2001 From: Anand Kulkarni Date: Wed, 25 Feb 2026 15:26:37 +0530 Subject: [PATCH 30/69] CI : enable ABI compatibility checker - Switch preflight to reusable orchestrator v2 with ARMOR enabled - Remove standalone run_armor.yml - Add ci/build.sh (autotools build to src/.libs) - Configure abi_checks for libadsprpc, libcdsprpc, libsdsprpc with public headers Signed-off-by: Anand Kulkarni --- .github/workflows/qcom-preflight-checks.yml | 14 ++-- .github/workflows/run_armor.yml | 74 --------------------- ci/build.sh | 66 ++++++++++++++++++ public_headers/config.yml | 9 +++ 4 files changed, 83 insertions(+), 80 deletions(-) delete mode 100644 .github/workflows/run_armor.yml create mode 100755 ci/build.sh diff --git a/.github/workflows/qcom-preflight-checks.yml b/.github/workflows/qcom-preflight-checks.yml index a0c1c8d..9fe04ca 100644 --- a/.github/workflows/qcom-preflight-checks.yml +++ b/.github/workflows/qcom-preflight-checks.yml @@ -12,13 +12,15 @@ permissions: jobs: qcom-preflight-checks: - uses: qualcomm/qcom-reusable-workflows/.github/workflows/qcom-preflight-checks-reusable-workflow.yml@v1.1.4 + uses: qualcomm/qcom-reusable-workflows/.github/workflows/reusable-qcom-preflight-checks-orchestrator.yml@v2 with: # ✅ Preflight Checkers - repolinter: true # default: true - semgrep: true # default: true - copyright-license-detector: true # default: true - pr-check-emails: true # default: true - dependency-review: true # default: true + enable-repolinter-check: true # default: true + enable-semgrep-scan: true # default: true + enable-copyright-license-check: true # default: true + enable-commit-email-check: true # default: true + enable-dependency-review: true # default: true + enable-armor-checkers: true + armor-checker-options: '{"build-script":"ci/build.sh","runs-on":{"group":"GHA-fastrpc-Prd-SelfHosted-RG","labels":["self-hosted","fastrpc-prd-u2404-x64-large-od-ephem"]}}' secrets: SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} diff --git a/.github/workflows/run_armor.yml b/.github/workflows/run_armor.yml deleted file mode 100644 index 0421ca8..0000000 --- a/.github/workflows/run_armor.yml +++ /dev/null @@ -1,74 +0,0 @@ -# This GitHub Actions workflow runs the ARMOR security scanning tool under the following conditions: -# - On push events to 'main' and 'development' branches -# - On pull_request_target events for 'main' and 'development' branches (to handle forked PRs) -# - Manually via workflow_dispatch with required inputs (branch-name, head-sha, base-sha) -# -# The workflow: -# 1. Sets appropriate permissions for repository access and status reporting -# 2. Checks out the repository code -# 3. Dynamically determines event context (head/base SHAs, branch name) across all trigger types -# 4. Executes the ARMOR tool with the collected parameters to perform API compatibility checks and header validation - -name: Run ARMOR via action -on: - push: - branches: [ main, development ] - pull_request_target: - branches: [ main, development ] - workflow_dispatch: - inputs: - branch-name: - description: 'Branch name to scan' - required: true - type: string - head-sha: - description: 'Head commit SHA' - required: true - type: string - base-sha: - description: 'The commit SHA that serves for comparison or analysis' - required: true - type: string - -permissions: - contents: read - pull-requests: write - statuses: write - -jobs: - RUN-ARMOR: - runs-on: - group: GHA-fastrpc-Prd-SelfHosted-RG - labels: [ self-hosted, fastrpc-prd-u2404-x64-large-od-ephem ] - steps: - - uses: actions/checkout@v4 - - name: Set event variables - id: ev - run: | - echo "event_name=${{ github.event_name }}" >> "$GITHUB_OUTPUT" - if [[ "${{ github.event_name }}" == "pull_request_target" ]]; then - echo "head_sha=${{ github.event.pull_request.head.sha }}" >> "$GITHUB_OUTPUT" - echo "base_sha=${{ github.event.pull_request.base.sha }}" >> "$GITHUB_OUTPUT" - echo "branch_name=${{ github.event.pull_request.base.ref }}" >> "$GITHUB_OUTPUT" - elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - echo "head_sha=${{ inputs.head-sha }}" >> "$GITHUB_OUTPUT" - echo "base_sha=${{ inputs.base-sha }}" >> "$GITHUB_OUTPUT" - echo "branch_name=${{ inputs.branch-name }}" >> "$GITHUB_OUTPUT" - else - # push - echo "head_sha=${{ github.event.after }}" >> "$GITHUB_OUTPUT" - echo "base_sha=${{ github.event.before }}" >> "$GITHUB_OUTPUT" - echo "branch_name=${{ github.ref_name }}" >> "$GITHUB_OUTPUT" - fi - echo "ref=${{ github.ref }}" >> "$GITHUB_OUTPUT" - echo "repo=${{ github.repository }}" >> "$GITHUB_OUTPUT" - - - name: Run ARMOR Tool - uses: qualcomm/armor@main - with: - event-name: ${{ steps.ev.outputs.event_name }} - head-sha: ${{ steps.ev.outputs.head_sha }} - base-sha: ${{ steps.ev.outputs.base_sha }} - ref: ${{ steps.ev.outputs.ref }} - repo: ${{ steps.ev.outputs.repo }} - branch-name: ${{ steps.ev.outputs.branch_name }} \ No newline at end of file diff --git a/ci/build.sh b/ci/build.sh new file mode 100755 index 0000000..d4f890d --- /dev/null +++ b/ci/build.sh @@ -0,0 +1,66 @@ +#!/usr/bin/bash +# Copyright (c) Qualcomm Technologies, Inc. +# SPDX-License-Identifier: BSD-3-Clause-Clear + +set -euo pipefail + +echo "Configuring APT for amd64 + arm64 (ports)..." +# Detect Ubuntu codename +CODENAME="$(. /etc/os-release; echo "${VERSION_CODENAME}")" +: "${CODENAME:?Failed to read VERSION_CODENAME from /etc/os-release}" +echo "Detected Ubuntu codename: ${CODENAME}" + +# 1) Enable ARM64 multiarch +sudo dpkg --add-architecture arm64 + +# 2) Overwrite main sources to be amd64-only (archive + security) +sudo tee /etc/apt/sources.list > /dev/null < /dev/null < Date: Wed, 27 Aug 2025 10:40:39 +0800 Subject: [PATCH 31/69] cleanup: remove stale async fastrpc code (#218) Removed async-related fastrpc code. It is stale code that is no longer used or maintained. Signed-off-by: Jianping Li --- inc/Makefile.am | 1 - inc/fastrpc_async.h | 73 ------ inc/fastrpc_internal.h | 15 +- src/Makefile.am | 1 - src/fastrpc_apps_user.c | 211 +---------------- src/fastrpc_async.c | 489 ---------------------------------------- src/fastrpc_cap.c | 6 - src/fastrpc_ioctl.c | 24 +- src/symbols.lst | 2 - 9 files changed, 21 insertions(+), 801 deletions(-) delete mode 100644 inc/fastrpc_async.h delete mode 100644 src/fastrpc_async.c diff --git a/inc/Makefile.am b/inc/Makefile.am index 9b1657b..a22db62 100644 --- a/inc/Makefile.am +++ b/inc/Makefile.am @@ -36,7 +36,6 @@ noinst_HEADERS = \ dspqueue_shared.h \ dspsignal.h \ fastrpc_apps_user.h \ - fastrpc_async.h \ fastrpc_cap.h \ fastrpc_common.h \ fastrpc_config.h \ diff --git a/inc/fastrpc_async.h b/inc/fastrpc_async.h deleted file mode 100644 index 76c244d..0000000 --- a/inc/fastrpc_async.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. -// SPDX-License-Identifier: BSD-3-Clause - -#ifndef FASTRPC_ASYNC_H -#define FASTRPC_ASYNC_H - -#include "remote64.h" -#include "fastrpc_internal.h" - -#define POS_TO_MASK(pos) ((1UL << pos) - 1) - -#define FASTRPC_ASYNC_JOB_POS 4 // Position in jobid where job starts - -// Store jobs in Queue. Index of queue calculated based on hash value of job. Always needs to be 2^value -#define FASTRPC_ASYNC_QUEUE_LIST_LEN 16 - -// Position where hash ends in jobid -#define FASTRPC_ASYNC_HASH_IDX_POS (FASTRPC_ASYNC_JOB_POS + (FASTRPC_ASYNC_QUEUE_LIST_LEN >> 2)) - -// Position in jobid where timespec starts -#define FASTRPC_ASYNC_TIME_SPEC_POS 48 - -#define SECONDS_PER_HOUR (3600) - -#define FASTRPC_ASYNC_DOMAIN_MASK (POS_TO_MASK(FASTRPC_ASYNC_JOB_POS)) -#define FASTRPC_ASYNC_JOB_CNT_MASK (POS_TO_MASK(FASTRPC_ASYNC_TIME_SPEC_POS) & ~FASTRPC_ASYNC_DOMAIN_MASK) -#define FASTRPC_ASYNC_HASH_MASK (POS_TO_MASK(FASTRPC_ASYNC_HASH_IDX_POS) & ~FASTRPC_ASYNC_DOMAIN_MASK) - -// Async job structure -struct fastrpc_async_job { - uint32_t isasyncjob; // set if async job - /* - * Fastrpc async job ID bit-map: - * - * bits 0-3 : domain ID - * bits 4-47 : job counter - * bits 48-63 : timespec - */ - fastrpc_async_jobid jobid; - uint32_t reserved; // reserved -}; - -/* - * Internal function to save async job information before submitting to DSP - * @ domain: domain to which Async job is submitted - * @ asyncjob: Async job structure - * @ desc: Async desc passed by user - * returns 0 on success - * - */ -int fastrpc_save_async_job(int domain, struct fastrpc_async_job *asyncjob, fastrpc_async_descriptor_t *desc); - -/* - * Internal function to remove async job, if async invocation to DSP fails - * @ jobid: domain to which Async job is submitted - * @ asyncjob: Async job id - * @ dsp_invoke_done: DSP invocation is successful - * returns 0 on success - * - */ -int fastrpc_remove_async_job(fastrpc_async_jobid jobid, bool dsp_invoke_done); - -/* - * API to initialize async module data strcutures and globals - */ -int fastrpc_async_domain_init(int domain); - -/* - * API to de-initialize async module data strcutures and globals - */ -void fastrpc_async_domain_deinit(int domain); - -#endif // FASTRPC_ASYNC_H diff --git a/inc/fastrpc_internal.h b/inc/fastrpc_internal.h index 0f04e3b..2005b8f 100644 --- a/inc/fastrpc_internal.h +++ b/inc/fastrpc_internal.h @@ -42,8 +42,6 @@ * Update these values for any additions to * the corresponding enums. **/ -/* Max value of fastrpc_async_notify_type, used to validate the user input */ -#define FASTRPC_ASYNC_TYPE_MAX FASTRPC_ASYNC_POLL + 1 /* Max value of remote_dsp_attributes, used to validate the attribute ID*/ #define FASTRPC_MAX_DSP_ATTRIBUTES MCID_MULTICAST + 1 @@ -189,7 +187,6 @@ enum fastrpc_control_type { FASTRPC_CONTROL_WAKELOCK = 4, FASTRPC_CONTROL_PM = 5, FASTRPC_CONTROL_RPC_POLL = 7, - FASTRPC_CONTROL_ASYNC_WAKE = 8, FASTRPC_CONTROL_NOTIF_WAKE = 9, }; @@ -315,11 +312,8 @@ struct handle_list { int disable_exit_logs; struct fastrpc_dsp_capabilities cap_info; int trace_marker_fd; - uint64_t jobid; /* Capability flag to check if mapping DMA handle through reverse RPC is supported */ int dma_handle_reverse_rpc_map_capability; - /* Mutex to synchronize ASync init and deinit */ - pthread_mutex_t async_init_deinit_mut; uint32_t pd_initmem_size; /** Initial memory allocated for remote userPD */ uint32_t refs; // Number of multi-domain handles + contexts on session bool is_session_reserved; /** Set if session is reserved or used */ @@ -366,11 +360,6 @@ int fastrpc_get_cap(uint32_t domain, uint32_t attributeID, uint32_t *capability) **/ int check_rpc_error(int err); -/** - * @brief Make IOCTL call to exit async thread - */ -int fastrpc_exit_async_thread(int domain); - /** * @brief Make IOCTL call to exit notif thread */ @@ -491,8 +480,7 @@ int fastrpc_update_module_list(uint32_t req, int domain, remote_handle64 handle, * @brief functions to wrap ioctl syscalls for downstream and upstream kernel **/ int ioctl_init(int dev, uint32_t flags, int attr, unsigned char* shell, int shelllen, int shellfd, char* initmem, int initmemlen, int initmemfd, int tessiglen); -int ioctl_invoke(int dev, int req, remote_handle handle, uint32_t sc, void* pra, int* fds, unsigned int* attrs, void *job, unsigned int* crc, uint64_t* perf_kernel, uint64_t* perf_dsp); -int ioctl_invoke2_response(int dev, fastrpc_async_jobid *jobid, remote_handle *handle, uint32_t *sc, int* result, uint64_t *perf_kernel, uint64_t *perf_dsp); +int ioctl_invoke(int dev, int req, remote_handle handle, uint32_t sc, void* pra, int* fds, unsigned int* attrs, unsigned int* crc, uint64_t* perf_kernel, uint64_t* perf_dsp); int ioctl_invoke2_notif(int dev, int *domain, int *session, int *status); int ioctl_mmap(int dev, int req, uint32_t flags, int attr, int fd, int offset, size_t len, uintptr_t vaddrin, uint64_t* vaddr_out); int ioctl_munmap(int dev, int req, int attr, void* buf, int fd, int len, uint64_t vaddr); @@ -528,7 +516,6 @@ int ioctl_mdctx_manage(int dev, int req, void *user_ctx, unsigned int *domain_ids, unsigned int num_domain_ids, uint64_t *ctx); const char* get_secure_domain_name(int domain_id); -int is_async_fastrpc_supported(void); #include "fastrpc_ioctl.h" diff --git a/src/Makefile.am b/src/Makefile.am index 0191bf0..8470bf3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -13,7 +13,6 @@ LIBDSPRPC_SOURCES = \ fastrpc_perf.c \ fastrpc_pm.c \ fastrpc_config.c \ - fastrpc_async.c \ fastrpc_mem.c \ fastrpc_notif.c \ fastrpc_ioctl.c \ diff --git a/src/fastrpc_apps_user.c b/src/fastrpc_apps_user.c index 0807bca..fad04d5 100644 --- a/src/fastrpc_apps_user.c +++ b/src/fastrpc_apps_user.c @@ -52,7 +52,6 @@ #include "apps_std_internal.h" #include "dspsignal.h" #include "fastrpc_apps_user.h" -#include "fastrpc_async.h" #include "fastrpc_cap.h" #include "fastrpc_common.h" #include "fastrpc_config.h" @@ -1154,8 +1153,7 @@ static void fastrpc_delete_timer(timer_t *timer) { } int remote_handle_invoke_domain(int domain, remote_handle handle, - fastrpc_async_descriptor_t *desc, uint32_t sc, - remote_arg *pra) { + uint32_t sc, remote_arg *pra) { int dev, total, bufs, handles, i, nErr = 0, wake_lock = 0, rpc_timeout = 0; unsigned req; uint32_t len; @@ -1164,7 +1162,6 @@ int remote_handle_invoke_domain(int domain, remote_handle handle, uint32_t *crc_local = NULL; uint64_t *perf_kernel = NULL; uint64_t *perf_dsp = NULL; - struct fastrpc_async_job asyncjob = {0}, *job = NULL; fastrpc_timer frpc_timer; int trace_marker_fd = hlist[domain].trace_marker_fd; bool trace_enabled = false; @@ -1208,31 +1205,6 @@ int remote_handle_invoke_domain(int domain, remote_handle handle, INITIALIZE_REMOTE_ARGS(total); - if (desc) { - struct timespec time_spec; - // Check for valid user async descriptor - VERIFYC(desc->type >= FASTRPC_ASYNC_NO_SYNC && - desc->type < FASTRPC_ASYNC_TYPE_MAX, - AEE_EBADPARM); - VERIFYC(!(desc->type == FASTRPC_ASYNC_CALLBACK && desc->cb.fn == NULL), - AEE_EBADPARM); - pthread_mutex_lock(&hlist[domain].async_init_deinit_mut); - if (AEE_SUCCESS != (nErr = fastrpc_async_domain_init(domain))) { - pthread_mutex_unlock(&hlist[domain].async_init_deinit_mut); - goto bail; - } - asyncjob.jobid = ++list->jobid; - pthread_mutex_unlock(&hlist[domain].async_init_deinit_mut); - clock_gettime(CLOCK_MONOTONIC, &time_spec); - asyncjob.jobid = ((((time_spec.tv_sec) / SECONDS_PER_HOUR) - << (FASTRPC_ASYNC_TIME_SPEC_POS / 2)) - << ((FASTRPC_ASYNC_TIME_SPEC_POS + 1) / 2) | - (asyncjob.jobid << FASTRPC_ASYNC_JOB_POS) | domain); - asyncjob.isasyncjob = 1; - fastrpc_save_async_job(domain, &asyncjob, desc); - job = &asyncjob; - } - req = INVOKE; VERIFYC(!(NULL == pra && total > 0), AEE_EBADPARM); for (i = 0; i < bufs; i++) { @@ -1247,11 +1219,6 @@ int remote_handle_invoke_domain(int domain, remote_handle handle, set_args_fd(i, fd); req = INVOKE_FD; } - // AsyncRPC doesn't support Non-ion output buffers - if (asyncjob.isasyncjob && i >= (int)REMOTE_SCALARS_INBUFS(sc)) { - VERIFYM(fd != -1, AEE_EBADPARM, - "AsyncRPC doesn't support Non-ion output buffers"); - } if (nova) { req = INVOKE_ATTRS; append_args_attr(i, FASTRPC_ATTR_NOVA); @@ -1309,7 +1276,7 @@ int remote_handle_invoke_domain(int domain, remote_handle handle, } if (IS_CRC_CHECK_ENABLED(hlist[domain].procattrs) && - (!IS_STATIC_HANDLE(handle)) && !asyncjob.isasyncjob) { + (!IS_STATIC_HANDLE(handle))) { int nInBufs = REMOTE_SCALARS_INBUFS(sc); crc_local = (uint32_t *)calloc(M_CRCLIST, sizeof(uint32_t)); crc_remote = (uint32_t *)calloc(M_CRCLIST, sizeof(uint32_t)); @@ -1352,7 +1319,7 @@ int remote_handle_invoke_domain(int domain, remote_handle handle, wake_lock = 0; } // Macros are initializing and destroying pfds and pattrs. - nErr = ioctl_invoke(dev, req, handle, sc, get_args(), pfds, pattrs, job, + nErr = ioctl_invoke(dev, req, handle, sc, get_args(), pfds, pattrs, crc_remote, perf_kernel, perf_dsp); if (nErr) { nErr = convert_kernel_to_user_error(nErr, errno); @@ -1368,7 +1335,7 @@ int remote_handle_invoke_domain(int domain, remote_handle handle, } if (IS_CRC_CHECK_ENABLED(hlist[domain].procattrs) && - (!IS_STATIC_HANDLE(handle)) && !asyncjob.isasyncjob) { + (!IS_STATIC_HANDLE(handle))) { int nInBufs = REMOTE_SCALARS_INBUFS(sc); VERIFYC(crc_local != NULL && crc_remote != NULL, AEE_ENOMEMORY); for (i = nInBufs; i < bufs; i++) @@ -1384,7 +1351,7 @@ int remote_handle_invoke_domain(int domain, remote_handle handle, } if (IS_KERNEL_PERF_ENABLED(hlist[domain].procattrs) && - (!IS_STATIC_HANDLE(handle)) && !asyncjob.isasyncjob) { + (!IS_STATIC_HANDLE(handle))) { VERIFYC(perf_kernel != NULL, AEE_ENOMEMORY); FARF(ALWAYS, "RPCPERF-K H:0x%x SC:0x%x C:%" PRIu64 " F:%" PRIu64 " ns M:%" PRIu64 @@ -1395,7 +1362,7 @@ int remote_handle_invoke_domain(int domain, remote_handle handle, perf_kernel[7], perf_kernel[8]); } if (IS_DSP_PERF_ENABLED(hlist[domain].procattrs) && - (!IS_STATIC_HANDLE(handle)) && !asyncjob.isasyncjob) { + (!IS_STATIC_HANDLE(handle))) { VERIFYC(perf_dsp != NULL, AEE_ENOMEMORY); FARF(ALWAYS, "RPCPERF-D H:0x%x SC:0x%x C:%" PRIu64 " M_H:%" PRIu64 " us M:%" PRIu64 @@ -1412,16 +1379,6 @@ int remote_handle_invoke_domain(int domain, remote_handle handle, fastrpc_perf_update(dev, handle, sc); } bail: - if (asyncjob.isasyncjob) { - if (!nErr) { - FARF(RUNTIME_RPC_HIGH, "adsprpc : %s Async job Queued, job 0x%" PRIx64 "", - __func__, asyncjob.jobid); - desc->jobid = asyncjob.jobid; - } else { - fastrpc_remove_async_job(asyncjob.jobid, false); - desc->jobid = -1; - } - } DESTROY_REMOTE_ARGS(); if (crc_local) { free(crc_local); @@ -1431,11 +1388,11 @@ int remote_handle_invoke_domain(int domain, remote_handle handle, free(crc_remote); crc_remote = NULL; } - if (perf_kernel && !asyncjob.isasyncjob) { + if (perf_kernel) { free(perf_kernel); perf_kernel = NULL; } - if (perf_dsp && !asyncjob.isasyncjob) { + if (perf_dsp) { free(perf_dsp); perf_dsp = NULL; } @@ -1474,7 +1431,7 @@ int remote_handle_invoke(remote_handle handle, uint32_t sc, remote_arg *pra) { domain = get_current_domain(); FASTRPC_GET_REF(domain); VERIFY(AEE_SUCCESS == - (nErr = remote_handle_invoke_domain(domain, handle, NULL, sc, pra))); + (nErr = remote_handle_invoke_domain(domain, handle, sc, pra))); bail: FASTRPC_PUT_REF(domain); if (nErr != AEE_SUCCESS) { @@ -1522,7 +1479,7 @@ int remote_handle64_invoke(remote_handle64 local, uint32_t sc, FASTRPC_GET_REF(domain); VERIFY(AEE_SUCCESS == (nErr = get_handle_remote(local, &remote))); VERIFY(AEE_SUCCESS == - (nErr = remote_handle_invoke_domain(domain, remote, NULL, sc, pra))); + (nErr = remote_handle_invoke_domain(domain, remote, sc, pra))); bail: FASTRPC_PUT_REF(domain); if (nErr != AEE_SUCCESS) { @@ -1543,72 +1500,6 @@ int remote_handle64_invoke(remote_handle64 local, uint32_t sc, return nErr; } -int remote_handle_invoke_async(remote_handle handle, - fastrpc_async_descriptor_t *desc, uint32_t sc, - remote_arg *pra) { - int domain = -1, nErr = AEE_SUCCESS, ref = 0; - - VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); - - FARF(RUNTIME_RPC_HIGH, "Entering %s, handle %u desc %p sc %X remote_arg %p\n", - __func__, handle, desc, sc, pra); - FASTRPC_ATRACE_BEGIN_L("%s called with handle 0x%x , scalar 0x%x", __func__, - (int)handle, sc); - VERIFYC(handle != (remote_handle)-1, AEE_EINVHANDLE); - - domain = get_current_domain(); - FASTRPC_GET_REF(domain); - VERIFY(AEE_SUCCESS == - (nErr = remote_handle_invoke_domain(domain, handle, desc, sc, pra))); -bail: - FASTRPC_PUT_REF(domain); - if (nErr != AEE_SUCCESS) { - if (0 == check_rpc_error(nErr)) { - FARF(ERROR, - "Error 0x%x: %s failed for handle 0x%x, method %d async type %d on " - "domain %d (sc 0x%x) (errno %s)\n", - nErr, __func__, (int)handle, REMOTE_SCALARS_METHOD(sc), desc->type, - domain, sc, strerror(errno)); - } - } - FASTRPC_ATRACE_END(); - return nErr; -} - -int remote_handle64_invoke_async(remote_handle64 local, - fastrpc_async_descriptor_t *desc, uint32_t sc, - remote_arg *pra) { - remote_handle64 remote = 0; - int nErr = AEE_SUCCESS, domain = -1, ref = 0; - - VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); - - FARF(RUNTIME_RPC_HIGH, "Entering %s, handle %llu desc %p sc %X remote_arg %p\n", __func__, - local, desc, sc, pra); - FASTRPC_ATRACE_BEGIN_L("%s called with handle 0x%x , scalar 0x%x", __func__, - (int)local, sc); - VERIFYC(local != (remote_handle64)-1, AEE_EINVHANDLE); - - VERIFY(AEE_SUCCESS == (nErr = get_domain_from_handle(local, &domain))); - FASTRPC_GET_REF(domain); - VERIFY(AEE_SUCCESS == (nErr = get_handle_remote(local, &remote))); - VERIFY(AEE_SUCCESS == - (nErr = remote_handle_invoke_domain(domain, remote, desc, sc, pra))); -bail: - FASTRPC_PUT_REF(domain); - if (nErr != AEE_SUCCESS) { - if (0 == check_rpc_error(nErr)) { - FARF(ERROR, - "Error 0x%x: %s failed for handle 0x%" PRIx64 - ", method %d on domain %d (sc 0x%x) (errno %s)\n", - nErr, __func__, local, REMOTE_SCALARS_METHOD(sc), domain, sc, - strerror(errno)); - } - } - FASTRPC_ATRACE_END(); - return nErr; -} - int listener_android_geteventfd(int domain, int *fd); int remote_handle_open_domain(int domain, const char *name, remote_handle *ph, uint64_t *t_spawn, uint64_t *t_load) { @@ -2099,81 +1990,6 @@ static inline int enable_process_state_notif_on_dsp(int domain) { return nErr; } -/* - * Internal function to get async response from kernel. Waits in kernel until - * response is received from DSP - * @ domain: domain to which Async job is submitted - * @ async_data: IOCTL structure that is sent to kernel to get async response - * job information returns 0 on success - * - */ -int get_remote_async_response(int domain, fastrpc_async_jobid *jobid, - int *result) { - int nErr = AEE_SUCCESS, dev = -1; - uint64_t *perf_kernel = NULL, *perf_dsp = NULL; - fastrpc_async_jobid job = -1; - int res = -1; - remote_handle handle = -1; - uint32_t sc = 0; - - VERIFYC(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), AEE_EBADPARM); - VERIFY(AEE_SUCCESS == (nErr = domain_init(domain, &dev))); - VERIFYM(-1 != dev, AEE_ERPC, "open dev failed\n"); - if (IS_KERNEL_PERF_ENABLED(hlist[domain].procattrs)) { - perf_kernel = (uint64_t *)calloc(PERF_KERNEL_KEY_MAX, sizeof(uint64_t)); - VERIFYC(perf_kernel != NULL, AEE_ENOMEMORY); - } - if (IS_DSP_PERF_ENABLED(hlist[domain].procattrs)) { - perf_dsp = (uint64_t *)calloc(PERF_DSP_KEY_MAX, sizeof(uint64_t)); - VERIFYC(perf_dsp != NULL, AEE_ENOMEMORY); - } - nErr = ioctl_invoke2_response(dev, &job, &handle, &sc, &res, perf_kernel, - perf_dsp); - if (IS_KERNEL_PERF_ENABLED(hlist[domain].procattrs) && - (!IS_STATIC_HANDLE(handle))) { - VERIFYC(perf_kernel != NULL, AEE_ENOMEMORY); - FARF(ALWAYS, - "RPCPERF-K H:0x%x SC:0x%x C:%" PRIu64 " F:%" PRIu64 " ns M:%" PRIu64 - " ns CP:%" PRIu64 " ns L:%" PRIu64 " ns G:%" PRIu64 " ns P:%" PRIu64 - " ns INV:%" PRIu64 " ns INVOKE:%" PRIu64 " ns\n", - handle, sc, perf_kernel[0], perf_kernel[1], perf_kernel[2], - perf_kernel[3], perf_kernel[4], perf_kernel[5], perf_kernel[6], - perf_kernel[7], perf_kernel[8]); - } - if (IS_DSP_PERF_ENABLED(hlist[domain].procattrs) && - (!IS_STATIC_HANDLE(handle))) { - VERIFYC(perf_dsp != NULL, AEE_ENOMEMORY); - FARF(ALWAYS, - "RPCPERF-D H:0x%x SC:0x%x C:%" PRIu64 " M_H:%" PRIu64 " us M:%" PRIu64 - " us G:%" PRIu64 " us INVOKE:%" PRIu64 " us P:%" PRIu64 - " us CACHE:%" PRIu64 " us UM:%" PRIu64 " us " - "UM_H:%" PRIu64 " us R:%" PRIu64 " us E_R:%" PRIu64 - " us J_S_T:%" PRIu64 " us\n", - handle, sc, perf_dsp[0], perf_dsp[1], perf_dsp[2], perf_dsp[3], - perf_dsp[4], perf_dsp[5], perf_dsp[6], perf_dsp[7], perf_dsp[8], - perf_dsp[9], perf_dsp[10], perf_dsp[11]); - } - *jobid = job; - *result = res; - -bail: - if (perf_kernel) { - free(perf_kernel); - perf_kernel = NULL; - } - if (perf_dsp) { - free(perf_dsp); - perf_dsp = NULL; - } - if (nErr) { - FARF(ERROR, - "Error 0x%x: %s failed to get async response data for domain %d errno " - "%s", - nErr, __func__, domain, strerror(errno)); - } - return nErr; -} - /* fastrpc_set_qos_latency: Send user QoS latency requirement to DSP. DSP will use required features to meet the requirement. @@ -3119,7 +2935,6 @@ PL_DEP(gpls); PL_DEP(apps_std); PL_DEP(rpcmem); PL_DEP(listener_android); -PL_DEP(fastrpc_async); static int attach_guestos(int domain) { int attach; @@ -3170,9 +2985,6 @@ static void domain_deinit(int domain) { dspsignal_domain_deinit(domain); listener_android_domain_deinit(domain); hlist[domain].first_revrpc_done = 0; - pthread_mutex_lock(&hlist[domain].async_init_deinit_mut); - fastrpc_async_domain_deinit(domain); - pthread_mutex_unlock(&hlist[domain].async_init_deinit_mut); fastrpc_notif_domain_deinit(domain); fastrpc_clear_handle_list(MULTI_DOMAIN_HANDLE_LIST_ID, domain); fastrpc_clear_handle_list(REVERSE_HANDLE_LIST_ID, domain); @@ -4043,7 +3855,6 @@ static void fastrpc_apps_user_deinit(void) { pthread_mutex_destroy(&hlist[i].mut); pthread_mutex_destroy(&hlist[i].lmut); pthread_mutex_destroy(&hlist[i].init); - pthread_mutex_destroy(&hlist[i].async_init_deinit_mut); } listener_android_deinit(); free(hlist); @@ -4132,7 +3943,6 @@ static int fastrpc_apps_user_init(void) { FOR_EACH_EFFECTIVE_DOMAIN_ID(i) { hlist[i].dev = -1; hlist[i].th_params.thread_priority = DEFAULT_UTHREAD_PRIORITY; - hlist[i].jobid = 1; hlist[i].info = -1; hlist[i].th_params.stack_size = DEFAULT_UTHREAD_STACK_SIZE; sem_init(&hlist[i].th_params.r_sem, 0, @@ -4149,7 +3959,6 @@ static int fastrpc_apps_user_init(void) { pthread_mutex_init(&hlist[i].mut, &attr); pthread_mutex_init(&hlist[i].lmut, 0); pthread_mutex_init(&hlist[i].init, 0); - pthread_mutex_init(&hlist[i].async_init_deinit_mut, 0); } listener_android_init(); VERIFY(AEE_SUCCESS == (nErr = PL_INIT(apps_std))); diff --git a/src/fastrpc_async.c b/src/fastrpc_async.c deleted file mode 100644 index c3b69e5..0000000 --- a/src/fastrpc_async.c +++ /dev/null @@ -1,489 +0,0 @@ -// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. -// SPDX-License-Identifier: BSD-3-Clause - -#ifndef VERIFY_PRINT_ERROR -#define VERIFY_PRINT_ERROR -#endif /* VERIFY_PRINT_ERROR */ - -#define FARF_ERROR 1 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "AEEQList.h" -#include "AEEStdErr.h" -#include "AEEstd.h" -#include "HAP_farf.h" -#include "fastrpc_perf.h" -#include "fastrpc_common.h" -#include "fastrpc_async.h" -#include "platform_libs.h" -#include "verify.h" - -#define GET_DOMAIN_FROM_JOBID(jobid) (jobid & FASTRPC_ASYNC_DOMAIN_MASK) -#define GET_HASH_FROM_JOBID(jobid) \ - ((jobid & FASTRPC_ASYNC_HASH_MASK) >> FASTRPC_ASYNC_JOB_POS) -#define EVENT_COMPLETE 0xff - -struct fastrpc_async { - QList ql[FASTRPC_ASYNC_QUEUE_LIST_LEN]; - pthread_mutex_t mut; - pthread_t thread; - int init_done; - int deinit_started; -}; - -struct fastrpc_async_job_node { - QNode qn; - fastrpc_async_descriptor_t async_desc; - bool isjobdone; - struct pollfd pfd; - int result; -}; - -pthread_mutex_t async_mut = PTHREAD_MUTEX_INITIALIZER; -static struct fastrpc_async lasyncinfo[NUM_DOMAINS_EXTEND]; - -extern void set_thread_context(int domain); -static int get_remote_async_response(int domain, fastrpc_async_jobid *jobid, - int *result); - -int fastrpc_search_async_job(fastrpc_async_jobid jobid, - struct fastrpc_async_job_node **async_node) { - int nErr = AEE_SUCCESS; - int domain, hash; - struct fastrpc_async *me = NULL; - QNode *pn, *pnn; - bool jobfound = false; - struct fastrpc_async_job_node *lasync_node; - - domain = GET_DOMAIN_FROM_JOBID(jobid); - hash = GET_HASH_FROM_JOBID(jobid); - VERIFYC(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), AEE_EBADPARM); - me = &lasyncinfo[domain]; - VERIFYC(me->init_done == 1, AEE_EBADPARM); - pthread_mutex_lock(&me->mut); - QLIST_NEXTSAFE_FOR_ALL(&me->ql[hash], pn, pnn) { - lasync_node = STD_RECOVER_REC(struct fastrpc_async_job_node, qn, pn); - if (lasync_node->async_desc.jobid == jobid) { - jobfound = true; - break; - } - } - pthread_mutex_unlock(&me->mut); - VERIFYC(jobfound, AEE_EBADPARM); - *async_node = lasync_node; -bail: - return nErr; -} - -int fastrpc_async_get_status(fastrpc_async_jobid jobid, int timeout_us, - int *result) { - int nErr = AEE_SUCCESS; - int domain; - struct fastrpc_async *me = NULL; - struct fastrpc_async_job_node *lasync_node = NULL; - eventfd_t event = 0; - - VERIFYC(result != NULL, AEE_EBADPARM); - VERIFY(AEE_SUCCESS == (nErr = fastrpc_search_async_job(jobid, &lasync_node))); - domain = GET_DOMAIN_FROM_JOBID(jobid); - me = &lasyncinfo[domain]; - pthread_mutex_lock(&me->mut); - if (lasync_node->isjobdone) { // If job is done, return result - *result = lasync_node->result; - goto unlock_bail; - } else if (timeout_us == 0) { // If timeout 0, then return PENDING - nErr = AEE_EBUSY; - goto unlock_bail; - } - // If valid timeout(+ve/-ve), create poll event and wait on poll - if (-1 == (lasync_node->pfd.fd = eventfd(0, 0))) { - nErr = AEE_EFAILED; - FARF(ERROR, - "Error 0x%x: %s failed to create poll event for jobid 0x%" PRIx64 - " (%s)\n", - nErr, __func__, jobid, strerror(errno)); - goto unlock_bail; - } - lasync_node->pfd.events = POLLIN; - lasync_node->pfd.revents = 0; - pthread_mutex_unlock(&me->mut); - while (1) { - VERIFYC(0 < poll(&lasync_node->pfd, 1, timeout_us), AEE_EFAILED); - VERIFYC(0 == eventfd_read(lasync_node->pfd.fd, &event), AEE_EFAILED); - if (event) { - break; - } - } - VERIFYC(lasync_node->isjobdone, AEE_EBUSY); - *result = lasync_node->result; - goto bail; -unlock_bail: - pthread_mutex_unlock(&me->mut); -bail: - if (nErr) { - FARF(ERROR, "Error 0x%x: %s failed for jobid 0x%" PRIx64 " (%s)\n", nErr, - __func__, jobid, strerror(errno)); - } - return nErr; -} - -int fastrpc_remove_async_job(fastrpc_async_jobid jobid, - bool dsp_invoke_done) { - int nErr = AEE_SUCCESS; - struct fastrpc_async *me = NULL; - struct fastrpc_async_job_node *lasync_node = NULL; - int domain = -1; - - VERIFY(AEE_SUCCESS == (nErr = fastrpc_search_async_job(jobid, &lasync_node))); - domain = GET_DOMAIN_FROM_JOBID(jobid); - me = &lasyncinfo[domain]; - pthread_mutex_lock(&me->mut); - if (dsp_invoke_done && !lasync_node->isjobdone) { - pthread_mutex_unlock(&me->mut); - nErr = AEE_EBUSY; - goto bail; - } - QNode_DequeueZ(&lasync_node->qn); - pthread_mutex_unlock(&me->mut); - if (lasync_node->async_desc.type == FASTRPC_ASYNC_POLL && - lasync_node->pfd.fd != -1) { - close(lasync_node->pfd.fd); - lasync_node->pfd.fd = -1; - } - free(lasync_node); - lasync_node = NULL; -bail: - if (nErr) { - FARF(ERROR, - "Error 0x%x: %s failed for domain %d and jobid 0x%" PRIx64 " (%s)\n", - nErr, __func__, domain, jobid, strerror(errno)); - } - return nErr; -} - -int fastrpc_release_async_job(fastrpc_async_jobid jobid) { - return fastrpc_remove_async_job(jobid, true); -} - -int fastrpc_save_async_job(int domain, struct fastrpc_async_job *async_job, - fastrpc_async_descriptor_t *desc) { - int nErr = AEE_SUCCESS; - struct fastrpc_async *me = &lasyncinfo[domain]; - struct fastrpc_async_job_node *lasync_job = 0; - int hash = -1; - - VERIFYC(me->init_done == 1, AEE_EINVALIDJOB); - VERIFYC(NULL != (lasync_job = calloc(1, sizeof(*lasync_job))), AEE_ENOMEMORY); - QNode_CtorZ(&lasync_job->qn); - lasync_job->async_desc.jobid = async_job->jobid; - lasync_job->async_desc.type = desc->type; - lasync_job->async_desc.cb.fn = desc->cb.fn; - lasync_job->async_desc.cb.context = desc->cb.context; - lasync_job->isjobdone = false; - lasync_job->result = -1; - lasync_job->pfd.fd = -1; - hash = GET_HASH_FROM_JOBID(lasync_job->async_desc.jobid); - pthread_mutex_lock(&me->mut); - QList_AppendNode(&me->ql[hash], &lasync_job->qn); - pthread_mutex_unlock(&me->mut); - FARF(RUNTIME_RPC_HIGH, "adsprpc: %s : Saving job with jobid 0x%" PRIx64 "", - __func__, lasync_job->async_desc.jobid); -bail: - if (nErr) { - FARF(ERROR, "Error 0x%x: %s failed for domain %d (%s)\n", nErr, __func__, - domain, strerror(errno)); - } - return nErr; -} - -void fastrpc_async_respond_all_pending_jobs(int domain) { - int i = 0; - struct fastrpc_async *me = &lasyncinfo[domain]; - struct fastrpc_async_job_node *lasync_node = NULL; - QNode *pn; - - for (i = 0; i < FASTRPC_ASYNC_QUEUE_LIST_LEN; i++) { - pthread_mutex_lock(&me->mut); - while (!QList_IsEmpty(&me->ql[i])) { - pn = QList_GetFirst(&me->ql[i]); - lasync_node = STD_RECOVER_REC(struct fastrpc_async_job_node, qn, pn); - if (!lasync_node) { - continue; - } - QNode_DequeueZ(&lasync_node->qn); - lasync_node->result = -ECONNRESET; - pthread_mutex_unlock(&me->mut); - if (lasync_node->async_desc.type == FASTRPC_ASYNC_CALLBACK) { - FARF(RUNTIME_RPC_HIGH, - "adsprpc: %s callback jobid 0x%" PRIx64 " and result 0x%x", - __func__, lasync_node->async_desc.jobid, lasync_node->result); - lasync_node->async_desc.cb.fn(lasync_node->async_desc.jobid, - lasync_node->async_desc.cb.context, - lasync_node->result); - } else if (lasync_node->async_desc.type == FASTRPC_ASYNC_POLL) { - FARF(RUNTIME_RPC_HIGH, - "adsprpc: %s poll jobid 0x%" PRIx64 " and result 0x%x", __func__, - lasync_node->async_desc.jobid, lasync_node->result); - if (lasync_node->pfd.fd != -1) { - eventfd_write(lasync_node->pfd.fd, (eventfd_t)EVENT_COMPLETE); - } - } - free(lasync_node); - lasync_node = NULL; - pthread_mutex_lock(&me->mut); - } - pthread_mutex_unlock(&me->mut); - } -} - -static void *async_fastrpc_thread(void *arg) { - int nErr = AEE_SUCCESS; - struct fastrpc_async *me = (struct fastrpc_async *)arg; - int domain = (int)(me - &lasyncinfo[0]); - struct fastrpc_async_job_node *lasync_node = NULL; - int result = -1; - fastrpc_async_jobid jobid = -1; - QNode *pn, *pnn; - - int hash = -1; - bool isjobfound = false; - - /// TODO: Do we really need this line? - set_thread_context(domain); - do { - nErr = get_remote_async_response(domain, &jobid, &result); - VERIFY(nErr == AEE_SUCCESS); - FARF(RUNTIME_RPC_HIGH, - "adsprpc: %s received async response for jobid 0x%" PRIx64 - " and result 0x%x", - __func__, jobid, result); - isjobfound = false; - hash = GET_HASH_FROM_JOBID(jobid); - pthread_mutex_lock(&me->mut); - QLIST_NEXTSAFE_FOR_ALL(&me->ql[hash], pn, pnn) { - lasync_node = STD_RECOVER_REC(struct fastrpc_async_job_node, qn, pn); - if (lasync_node->async_desc.jobid == jobid) { - lasync_node->isjobdone = true; - lasync_node->result = result; - isjobfound = true; - switch (lasync_node->async_desc.type) { - case FASTRPC_ASYNC_NO_SYNC: - FARF(RUNTIME_RPC_HIGH, - "adsprpc: %s nosync jobid 0x%" PRIx64 " and result 0x%x", - __func__, lasync_node->async_desc.jobid, result); - QNode_DequeueZ(&lasync_node->qn); - pthread_mutex_unlock(&me->mut); - free(lasync_node); - lasync_node = NULL; - break; - case FASTRPC_ASYNC_POLL: - FARF(RUNTIME_RPC_HIGH, - "adsprpc: %s poll jobid 0x%" PRIx64 " and result 0x%x", __func__, - lasync_node->async_desc.jobid, result); - if (lasync_node->pfd.fd != -1) { - eventfd_write(lasync_node->pfd.fd, (eventfd_t)EVENT_COMPLETE); - } - pthread_mutex_unlock(&me->mut); - break; - case FASTRPC_ASYNC_CALLBACK: - pthread_mutex_unlock(&me->mut); - FARF(RUNTIME_RPC_HIGH, - "adsprpc: %s callback jobid 0x%" PRIx64 " and result 0x%x", - __func__, lasync_node->async_desc.jobid, result); - lasync_node->async_desc.cb.fn(lasync_node->async_desc.jobid, - lasync_node->async_desc.cb.context, - result); - break; - default: - pthread_mutex_unlock(&me->mut); - FARF(RUNTIME_RPC_HIGH, - "adsprpc: %s Invalid job type for jobid 0x%" PRIx64 "", __func__, - lasync_node->async_desc.jobid); - break; - } - break; - } - } - if (!isjobfound) - pthread_mutex_unlock(&me->mut); - } while (1); -bail: - if (nErr != AEE_SUCCESS) { - VERIFY_EPRINTF("Error 0x%x: %s AsyncFastRPC worker thread exited for " - "domain %d (errno %s), async_domain_deinit started %d", - nErr, __func__, domain, strerror(errno), me->deinit_started); - } - dlerror(); - return (void *)(uintptr_t)nErr; -} - -void async_thread_exit_handler(int sig) { - FARF(ALWAYS, "Async FastRPC worker thread exiting with signal %d\n", sig); - pthread_exit(0); -} - -void fastrpc_async_domain_deinit(int domain) { - struct fastrpc_async *me = &lasyncinfo[domain]; - int err = 0; - - pthread_mutex_lock(&async_mut); - if (!me->init_done) { - goto fasync_deinit_done; - } - FARF(ALWAYS, "%s: Waiting for AsyncRPC worker thread to join for domain %d\n", - __func__, domain); - if (me->thread) { - me->deinit_started = 1; - err = fastrpc_exit_async_thread(domain); - if (err) { - pthread_kill(me->thread, SIGUSR1); - } - pthread_join(me->thread, 0); - me->thread = 0; - } - FARF(ALWAYS, "fastrpc async thread joined for domain %d", domain); - fastrpc_async_respond_all_pending_jobs(domain); - pthread_mutex_destroy(&me->mut); - me->init_done = 0; -fasync_deinit_done: - pthread_mutex_unlock(&async_mut); - return; -} - -int fastrpc_async_domain_init(int domain) { - struct fastrpc_async *me = &lasyncinfo[domain]; - int nErr = AEE_EUNKNOWN, i = 0; - struct sigaction siga; - uint32_t capability = 0; - - pthread_mutex_lock(&async_mut); - if (me->init_done) { - nErr = AEE_SUCCESS; - goto bail; - } - VERIFY(AEE_SUCCESS == - (nErr = fastrpc_get_cap(domain, ASYNC_FASTRPC_SUPPORT, &capability))); - VERIFYC(capability == 1, AEE_EUNSUPPORTED); - me->thread = 0; - pthread_mutex_init(&me->mut, 0); - for (i = 0; i < FASTRPC_ASYNC_QUEUE_LIST_LEN; i++) { - QList_Ctor(&me->ql[i]); - } - VERIFY(AEE_SUCCESS == - (nErr = pthread_create(&me->thread, 0, async_fastrpc_thread, - (void *)me))); - memset(&siga, 0, sizeof(siga)); - siga.sa_flags = 0; - siga.sa_handler = async_thread_exit_handler; - VERIFY(AEE_SUCCESS == (nErr = sigaction(SIGUSR1, &siga, NULL))); - me->init_done = 1; - me->deinit_started = 0; - FARF(ALWAYS, "%s: AsyncRPC worker thread launched for domain %d\n", __func__, - domain); -bail: - pthread_mutex_unlock(&async_mut); - if (nErr != AEE_SUCCESS) { - VERIFY_EPRINTF("Error 0x%x: %s failed for domain %d (%s)\n", nErr, __func__, - domain, strerror(errno)); - fastrpc_async_domain_deinit(domain); - } - return nErr; -} - -/* - * Internal function to get async response from kernel. Waits in kernel until - * response is received from DSP - * @ domain: domain to which Async job is submitted - * @ async_data: IOCTL structure that is sent to kernel to get async response - * job information returns 0 on success - * - */ -static int get_remote_async_response(int domain, fastrpc_async_jobid *jobid, - int *result) { - int nErr = AEE_SUCCESS, dev = -1; - uint64_t *perf_kernel = NULL, *perf_dsp = NULL; - fastrpc_async_jobid job = -1; - int res = -1; - remote_handle handle = -1; - uint32_t sc = 0; - - VERIFYC(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), AEE_EBADPARM); - VERIFY(AEE_SUCCESS == (nErr = fastrpc_session_dev(domain, &dev))); - VERIFYM(-1 != dev, AEE_ERPC, "open dev failed\n"); - if (is_kernel_perf_enabled()) { - perf_kernel = (uint64_t *)calloc(PERF_KERNEL_KEY_MAX, sizeof(uint64_t)); - VERIFYC(perf_kernel != NULL, AEE_ENOMEMORY); - } - if (is_dsp_perf_enabled(domain)) { - perf_dsp = (uint64_t *)calloc(PERF_DSP_KEY_MAX, sizeof(uint64_t)); - VERIFYC(perf_dsp != NULL, AEE_ENOMEMORY); - } - nErr = ioctl_invoke2_response(dev, &job, &handle, &sc, &res, perf_kernel, - perf_dsp); - if (perf_kernel) { - FARF(ALWAYS, - "RPCPERF-K H:0x%x SC:0x%x C:%" PRIu64 " F:%" PRIu64 " ns M:%" PRIu64 - " ns CP:%" PRIu64 " ns L:%" PRIu64 " ns G:%" PRIu64 " ns P:%" PRIu64 - " ns INV:%" PRIu64 " ns INVOKE:%" PRIu64 " ns\n", - handle, sc, perf_kernel[0], perf_kernel[1], perf_kernel[2], - perf_kernel[3], perf_kernel[4], perf_kernel[5], perf_kernel[6], - perf_kernel[7], perf_kernel[8]); - } - if (perf_dsp) { - FARF(ALWAYS, - "RPCPERF-D H:0x%x SC:0x%x C:%" PRIu64 " M_H:%" PRIu64 " us M:%" PRIu64 - " us G:%" PRIu64 " us INVOKE:%" PRIu64 " us P:%" PRIu64 - " us CACHE:%" PRIu64 " us UM:%" PRIu64 " us " - "UM_H:%" PRIu64 " us R:%" PRIu64 " us E_R:%" PRIu64 - " us J_S_T:%" PRIu64 " us\n", - handle, sc, perf_dsp[0], perf_dsp[1], perf_dsp[2], perf_dsp[3], - perf_dsp[4], perf_dsp[5], perf_dsp[6], perf_dsp[7], perf_dsp[8], - perf_dsp[9], perf_dsp[10], perf_dsp[11]); - } - *jobid = job; - *result = res; - -bail: - if (perf_kernel) { - free(perf_kernel); - perf_kernel = NULL; - } - if (perf_dsp) { - free(perf_dsp); - perf_dsp = NULL; - } - if (nErr) { - FARF(ERROR, - "Error 0x%x: %s failed to get async response data for domain %d errno " - "%s", - nErr, __func__, domain, strerror(errno)); - } - return nErr; -} - -// Make IOCTL call to exit async thread -int fastrpc_exit_async_thread(int domain) { - int nErr = AEE_SUCCESS, dev; - - VERIFY(AEE_SUCCESS == (nErr = fastrpc_session_dev(domain, &dev))); - nErr = ioctl_control(dev, DSPRPC_ASYNC_WAKE, NULL); -bail: - if (nErr) - FARF(ERROR, - "Error 0x%x: %s failed for domain %d (errno: %s), ignore if ioctl not " - "supported, try pthread kill ", - nErr, __func__, domain, strerror(errno)); - return nErr; -} diff --git a/src/fastrpc_cap.c b/src/fastrpc_cap.c index 0ad169e..c088a74 100644 --- a/src/fastrpc_cap.c +++ b/src/fastrpc_cap.c @@ -108,12 +108,6 @@ int fastrpc_get_cap(uint32_t domain, uint32_t attributeID, uint32_t *capability) } goto bail; } - if(attributeID == ASYNC_FASTRPC_SUPPORT) { - if(!is_async_fastrpc_supported() ) { - *capability = 0; - goto bail; - } - } VERIFY(AEE_SUCCESS == (nErr = fastrpc_session_open(dom, &dev))); errno = 0; diff --git a/src/fastrpc_ioctl.c b/src/fastrpc_ioctl.c index e0329e1..d0ead7c 100644 --- a/src/fastrpc_ioctl.c +++ b/src/fastrpc_ioctl.c @@ -5,18 +5,11 @@ #include "AEEStdErr.h" #include "HAP_farf.h" -#include "fastrpc_async.h" #include "fastrpc_internal.h" #include "fastrpc_notif.h" #include "remote.h" #include -/* check async support */ -int is_async_fastrpc_supported(void) { - /* async not supported by upstream driver */ - return 0; -} - /* Returns the name of the domain based on the following ADSP/SLPI/MDSP/CDSP - Return Secure node */ @@ -91,7 +84,7 @@ int ioctl_init(int dev, uint32_t flags, int attr, unsigned char *shell, int shel } int ioctl_invoke(int dev, int req, remote_handle handle, uint32_t sc, void *pra, - int *fds, unsigned int *attrs, void *job, unsigned int *crc, + int *fds, unsigned int *attrs, unsigned int *crc, uint64_t *perf_kernel, uint64_t *perf_dsp) { int ioErr = AEE_SUCCESS; struct fastrpc_ioctl_invoke invoke = {0}; @@ -107,12 +100,6 @@ int ioctl_invoke(int dev, int req, remote_handle handle, uint32_t sc, void *pra, return ioErr; } -int ioctl_invoke2_response(int dev, fastrpc_async_jobid *jobid, - remote_handle *handle, uint32_t *sc, int *result, - uint64_t *perf_kernel, uint64_t *perf_dsp) { - return AEE_EUNSUPPORTED; -} - int ioctl_invoke2_notif(int dev, int *domain, int *session, int *status) { return AEE_EUNSUPPORTED; } @@ -256,4 +243,13 @@ int ioctl_mdctx_manage(int dev, int req, void *user_ctx, { // TODO: Implement this for opensource return AEE_EUNSUPPORTED; +} + +int fastrpc_async_get_status(fastrpc_async_jobid jobid, int timeout_us, + int *result) { + return AEE_EUNSUPPORTED; +} + +int fastrpc_release_async_job(fastrpc_async_jobid jobid) { + return AEE_EUNSUPPORTED; } \ No newline at end of file diff --git a/src/symbols.lst b/src/symbols.lst index 05f6adb..66ecb7d 100644 --- a/src/symbols.lst +++ b/src/symbols.lst @@ -34,8 +34,6 @@ rpcmem_alloc2; rpcmem_free; rpcmem_to_fd; - remote_handle_invoke_async; - remote_handle64_invoke_async; fastrpc_async_get_status; fastrpc_release_async_job; dspqueue_create; From 3d4aa43df8c09bab134256301d50b580b8b4496a Mon Sep 17 00:00:00 2001 From: Anand Kulkarni Date: Mon, 9 Mar 2026 12:46:55 +0530 Subject: [PATCH 32/69] CI : workflow_fix to align preflight checks with reusable workflow v2 spec Remove SEMGREP_APP_TOKEN secret that is not defined in the referenced reusable workflow, fixing workflow validation error. Signed-off-by: Anand Kulkarni --- .github/workflows/qcom-preflight-checks.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/qcom-preflight-checks.yml b/.github/workflows/qcom-preflight-checks.yml index 9fe04ca..f7f1d77 100644 --- a/.github/workflows/qcom-preflight-checks.yml +++ b/.github/workflows/qcom-preflight-checks.yml @@ -22,5 +22,3 @@ jobs: enable-dependency-review: true # default: true enable-armor-checkers: true armor-checker-options: '{"build-script":"ci/build.sh","runs-on":{"group":"GHA-fastrpc-Prd-SelfHosted-RG","labels":["self-hosted","fastrpc-prd-u2404-x64-large-od-ephem"]}}' - secrets: - SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} From 0508db3ce318fe356ea0897ccac69c893b853b5b Mon Sep 17 00:00:00 2001 From: Sandhya Adavikolanu Date: Thu, 26 Feb 2026 15:42:24 -0800 Subject: [PATCH 33/69] Rename dependabots.yaml to dependabot.yaml Renamed `.github/dependabots.yaml` to `.github/dependabot.yml` to follow the required GitHub naming convention. This ensures Dependabot can detect and apply security and version updates correctly. Signed-off-by: Sandhya Adavikolanu --- .github/{dependabots.yaml => dependabot.yaml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{dependabots.yaml => dependabot.yaml} (100%) diff --git a/.github/dependabots.yaml b/.github/dependabot.yaml similarity index 100% rename from .github/dependabots.yaml rename to .github/dependabot.yaml From 4d9435e0fa96987e5a8f4e7601aab08937d73ce7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Mar 2026 08:24:31 +0000 Subject: [PATCH 34/69] Bump actions/download-artifact from 4 to 8 Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 8. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v4...v8) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: '8' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4e56ec5..8abaab3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -44,7 +44,7 @@ jobs: image: ${{ inputs.docker_image }} - name: Download URLs list - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: presigned_urls_${{ matrix.build_matrix.deviceTree }}.json merge-multiple: true From 44277337cd71194cc3287872ba3cc97a331f3b70 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Mar 2026 08:24:42 +0000 Subject: [PATCH 35/69] Bump actions/checkout from 4 to 6 Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/abi-compat.yml | 2 +- .github/workflows/build_linux_android.yml | 2 +- .github/workflows/build_linux_arm64.yml | 2 +- .github/workflows/build_linux_gnu.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/loading.yml | 2 +- .github/workflows/nightly-kernel-build.yml | 2 +- .github/workflows/sync_build.yml | 2 +- .github/workflows/test.yml | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/abi-compat.yml b/.github/workflows/abi-compat.yml index 6771d22..9dcecd4 100644 --- a/.github/workflows/abi-compat.yml +++ b/.github/workflows/abi-compat.yml @@ -31,7 +31,7 @@ jobs: # Setup Phase: Prepare environment and install dependencies # ------------------------------------------------------------------------- - name: Checkout PR (new) - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: # fetch-depth: 0 required for git worktree to access development branch # without full history, worktree creation will fail diff --git a/.github/workflows/build_linux_android.yml b/.github/workflows/build_linux_android.yml index aca37ae..884d9a4 100644 --- a/.github/workflows/build_linux_android.yml +++ b/.github/workflows/build_linux_android.yml @@ -18,7 +18,7 @@ jobs: steps: - name: Git checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install auto tools run: | diff --git a/.github/workflows/build_linux_arm64.yml b/.github/workflows/build_linux_arm64.yml index 52636f9..f080a62 100644 --- a/.github/workflows/build_linux_arm64.yml +++ b/.github/workflows/build_linux_arm64.yml @@ -18,7 +18,7 @@ jobs: steps: - name: Git checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Configure APT for amd64 + arm64 (ports) and update shell: bash diff --git a/.github/workflows/build_linux_gnu.yml b/.github/workflows/build_linux_gnu.yml index 8f57fbd..9be28cf 100644 --- a/.github/workflows/build_linux_gnu.yml +++ b/.github/workflows/build_linux_gnu.yml @@ -18,7 +18,7 @@ jobs: steps: - name: Git checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install Autotools + dependencies run: | diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 596c738..439722c 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -32,7 +32,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Configure APT for amd64 + arm64 (ports) and update shell: bash diff --git a/.github/workflows/loading.yml b/.github/workflows/loading.yml index c945c48..d4b04b3 100644 --- a/.github/workflows/loading.yml +++ b/.github/workflows/loading.yml @@ -16,7 +16,7 @@ jobs: steps: - name: Checkout Code - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Load Parameters id: loading diff --git a/.github/workflows/nightly-kernel-build.yml b/.github/workflows/nightly-kernel-build.yml index b70466a..7eed74f 100644 --- a/.github/workflows/nightly-kernel-build.yml +++ b/.github/workflows/nightly-kernel-build.yml @@ -18,7 +18,7 @@ jobs: steps: # Checkout fastrpc-image repository to get the Dockerfile - name: Checkout fastrpc-image repo for Dockerfile - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 0 repository: qualcomm/fastrpc-image diff --git a/.github/workflows/sync_build.yml b/.github/workflows/sync_build.yml index e7cafa3..a483d88 100644 --- a/.github/workflows/sync_build.yml +++ b/.github/workflows/sync_build.yml @@ -33,7 +33,7 @@ jobs: labels: [ self-hosted, fastrpc-prd-u2404-x64-large-od-ephem ] steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: # fetch-depth: 1 is generally sufficient for builds and is faster than 0 (full history). # Change to 0 if your build process strictly requires the full Git history. diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4e56ec5..f5e5c7c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -33,7 +33,7 @@ jobs: build_matrix: ${{ fromJson(inputs.build_matrix) }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: ref: ${{ github.ref }} fetch-depth: 0 From 29e273ece8a2dac2320f0a4717243aea8060423d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Mar 2026 08:24:50 +0000 Subject: [PATCH 36/69] Bump github/codeql-action from 3 to 4 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3 to 4. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/v3...v4) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 596c738..5baf48a 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -82,7 +82,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} build-mode: ${{ matrix.build-mode }} @@ -105,6 +105,6 @@ jobs: ./gitcompile --host=aarch64-linux-gnu - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@v4 with: category: "/language:${{matrix.language}}" From 6c5d7cb3de44c3b2275b55c30a06393a2c10d2d8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Mar 2026 08:24:54 +0000 Subject: [PATCH 37/69] Bump actions/upload-artifact from 4 to 7 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 7. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v4...v7) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/abi-compat.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/abi-compat.yml b/.github/workflows/abi-compat.yml index 6771d22..c37ac42 100644 --- a/.github/workflows/abi-compat.yml +++ b/.github/workflows/abi-compat.yml @@ -169,7 +169,7 @@ jobs: # if: always() ensures reports are uploaded even when ABI check fails # - critical for debugging what specific ABI changes caused the failure if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: abi-compat-reports path: abi/reports From 33096b9069249c52081f33e74a579ba146c5c936 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 26 Mar 2026 10:48:15 +0000 Subject: [PATCH 38/69] fastrpc: config_parser: convert to unix format For some reason it looks like have commited fiels with CRLF fix this by converting them into Unix format. Signed-off-by: Srinivas Kandagatla --- src/fastrpc_config_parser.c | 362 ++++++++++++++++++------------------ 1 file changed, 181 insertions(+), 181 deletions(-) diff --git a/src/fastrpc_config_parser.c b/src/fastrpc_config_parser.c index 786aebe..c1920e5 100644 --- a/src/fastrpc_config_parser.c +++ b/src/fastrpc_config_parser.c @@ -1,181 +1,181 @@ -// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -// SPDX-License-Identifier: BSD-3-Clause-Clear - -#define _GNU_SOURCE -#ifndef VERIFY_PRINT_WARN -#define VERIFY_PRINT_WARN -#endif // VERIFY_PRINT_WARN -#ifndef VERIFY_PRINT_ERROR_ALWAYS -#define VERIFY_PRINT_ERROR_ALWAYS -#endif // VERIFY_PRINT_ERROR_ALWAYS -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define FARF_ERROR 1 -#define FARF_HIGH 1 -#define FARF_MED 1 -#define FARF_LOW 1 -#define FARF_CRITICAL 1 // Push log's to all hooks and persistent buffer. - -#define CONFIG_DIR CONFIG_BASE_DIR "/conf.d/" - -#include "AEEQList.h" -#include "AEEStdErr.h" -#include "AEEstd.h" -#include "HAP_farf.h" -#include "apps_std_internal.h" -#include "fastrpc_config_parser.h" - -static int compare_strings(const void *a, const void *b) { - return strcmp(*(const char **)a, *(const char **)b); -} - -static void get_dsp_lib_path(const char *machine_name, const char *filepath, char *dsp_lib_paths) { - yaml_parser_t parser; - yaml_event_t event; - int done = 0; - int in_machines = 0; - int in_target_machine = 0; - int found_dsp_path = 0; - char current_machine[PATH_MAX] = {0}; - - FILE *file = fopen(filepath, "r"); - if (!file) - return; - - if (!yaml_parser_initialize(&parser)) { - FARF(ALWAYS, "Warning: Failed to initialize YAML parser for file %s\n", filepath); - fclose(file); - return; - } - - yaml_parser_set_input_file(&parser, file); - - while (!done) { - if (!yaml_parser_parse(&parser, &event)) { - FARF(ALWAYS, "Warning: YAML parser error in file %s\n", filepath); - break; - } - - switch (event.type) { - case YAML_SCALAR_EVENT: { - const char *value = (const char *)event.data.scalar.value; - - if (!in_machines && strcmp(value, "machines") == 0) { - in_machines = 1; - } else if (in_machines && !in_target_machine) { - // This is a machine name key - strlcpy(current_machine, value, sizeof(current_machine)); - if (strcmp(current_machine, machine_name) == 0) { - in_target_machine = 1; - } - } else if (in_target_machine && strcmp(value, DSP_LIB_KEY) == 0) { - // Next scalar will be the DSP_LIBRARY_PATH value - yaml_event_delete(&event); - if (yaml_parser_parse(&parser, &event) && event.type == YAML_SCALAR_EVENT) { - strlcpy(dsp_lib_paths, (const char *)event.data.scalar.value, PATH_MAX); - FARF(ALWAYS, "dsp_lib_paths is %s", dsp_lib_paths); - found_dsp_path = 1; - done = 1; - } - } - break; - } - case YAML_MAPPING_END_EVENT: - if (in_target_machine) { - // Exiting the target machine mapping - in_target_machine = 0; - if (found_dsp_path) { - done = 1; - } - } - break; - case YAML_STREAM_END_EVENT: - done = 1; - break; - default: - break; - } - - yaml_event_delete(&event); - } - - yaml_parser_delete(&parser); - fclose(file); - - if (!found_dsp_path) { - FARF(ALWAYS, "Warning: DSP_LIBRARY_PATH not found for machine [%s] in configuration file %s\n", - machine_name, filepath); - } -} - -static void parse_config_dir(char *machine_name) { - DIR *dir = opendir(CONFIG_DIR); - struct dirent *entry; - char *file_list[1024]; - int file_count = 0; - char dsp_lib_paths[PATH_MAX] = {0}; - - if (!dir) - return; - - while ((entry = readdir(dir)) != NULL) { - if (entry->d_type == DT_REG && - (strstr(entry->d_name, ".yaml") || strstr(entry->d_name, ".yml"))) { - file_list[file_count] = strdup(entry->d_name); - file_count++; - } - } - closedir(dir); - - qsort(file_list, file_count, sizeof(char *), compare_strings); - - for (int i = 0; i < file_count; i++) { - char filepath[PATH_MAX]; - snprintf(filepath, sizeof(filepath), "%s%s", CONFIG_DIR, file_list[i]); - get_dsp_lib_path(machine_name, filepath, dsp_lib_paths); - free(file_list[i]); - } - - if (dsp_lib_paths[0] != '\0') { - strlcpy(DSP_LIBS_LOCATION, CONFIG_BASE_DIR, sizeof(DSP_LIBS_LOCATION)); - //append slash in case user passed config base dir doesn't end with slash '/' - strlcat(DSP_LIBS_LOCATION, "/", sizeof(DSP_LIBS_LOCATION)); - strlcat(DSP_LIBS_LOCATION, dsp_lib_paths, sizeof(DSP_LIBS_LOCATION)); - strlcat(DSP_LIBS_LOCATION, DEFAULT_DSP_SEARCH_PATHS, sizeof(DSP_LIBS_LOCATION)); - } else { - FARF(ALWAYS, "Warning: No DSP library path found for machine [%s] in any configuration file\n", - machine_name); - } -} - -void configure_dsp_paths() { - char machine_name[PATH_MAX] = {0}; - FILE *file = fopen(MACHINE_NAME_PATH, "r"); - - if (file == NULL) - return; - - if (fgets(machine_name, sizeof(machine_name), file) != NULL) - // Remove trailing newline if present - machine_name[strcspn(machine_name, "\n")] = '\0'; - - fclose(file); - parse_config_dir(machine_name); -} +// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +// SPDX-License-Identifier: BSD-3-Clause-Clear + +#define _GNU_SOURCE +#ifndef VERIFY_PRINT_WARN +#define VERIFY_PRINT_WARN +#endif // VERIFY_PRINT_WARN +#ifndef VERIFY_PRINT_ERROR_ALWAYS +#define VERIFY_PRINT_ERROR_ALWAYS +#endif // VERIFY_PRINT_ERROR_ALWAYS +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FARF_ERROR 1 +#define FARF_HIGH 1 +#define FARF_MED 1 +#define FARF_LOW 1 +#define FARF_CRITICAL 1 // Push log's to all hooks and persistent buffer. + +#define CONFIG_DIR CONFIG_BASE_DIR "/conf.d/" + +#include "AEEQList.h" +#include "AEEStdErr.h" +#include "AEEstd.h" +#include "HAP_farf.h" +#include "apps_std_internal.h" +#include "fastrpc_config_parser.h" + +static int compare_strings(const void *a, const void *b) { + return strcmp(*(const char **)a, *(const char **)b); +} + +static void get_dsp_lib_path(const char *machine_name, const char *filepath, char *dsp_lib_paths) { + yaml_parser_t parser; + yaml_event_t event; + int done = 0; + int in_machines = 0; + int in_target_machine = 0; + int found_dsp_path = 0; + char current_machine[PATH_MAX] = {0}; + + FILE *file = fopen(filepath, "r"); + if (!file) + return; + + if (!yaml_parser_initialize(&parser)) { + FARF(ALWAYS, "Warning: Failed to initialize YAML parser for file %s\n", filepath); + fclose(file); + return; + } + + yaml_parser_set_input_file(&parser, file); + + while (!done) { + if (!yaml_parser_parse(&parser, &event)) { + FARF(ALWAYS, "Warning: YAML parser error in file %s\n", filepath); + break; + } + + switch (event.type) { + case YAML_SCALAR_EVENT: { + const char *value = (const char *)event.data.scalar.value; + + if (!in_machines && strcmp(value, "machines") == 0) { + in_machines = 1; + } else if (in_machines && !in_target_machine) { + // This is a machine name key + strlcpy(current_machine, value, sizeof(current_machine)); + if (strcmp(current_machine, machine_name) == 0) { + in_target_machine = 1; + } + } else if (in_target_machine && strcmp(value, DSP_LIB_KEY) == 0) { + // Next scalar will be the DSP_LIBRARY_PATH value + yaml_event_delete(&event); + if (yaml_parser_parse(&parser, &event) && event.type == YAML_SCALAR_EVENT) { + strlcpy(dsp_lib_paths, (const char *)event.data.scalar.value, PATH_MAX); + FARF(ALWAYS, "dsp_lib_paths is %s", dsp_lib_paths); + found_dsp_path = 1; + done = 1; + } + } + break; + } + case YAML_MAPPING_END_EVENT: + if (in_target_machine) { + // Exiting the target machine mapping + in_target_machine = 0; + if (found_dsp_path) { + done = 1; + } + } + break; + case YAML_STREAM_END_EVENT: + done = 1; + break; + default: + break; + } + + yaml_event_delete(&event); + } + + yaml_parser_delete(&parser); + fclose(file); + + if (!found_dsp_path) { + FARF(ALWAYS, "Warning: DSP_LIBRARY_PATH not found for machine [%s] in configuration file %s\n", + machine_name, filepath); + } +} + +static void parse_config_dir(char *machine_name) { + DIR *dir = opendir(CONFIG_DIR); + struct dirent *entry; + char *file_list[1024]; + int file_count = 0; + char dsp_lib_paths[PATH_MAX] = {0}; + + if (!dir) + return; + + while ((entry = readdir(dir)) != NULL) { + if (entry->d_type == DT_REG && + (strstr(entry->d_name, ".yaml") || strstr(entry->d_name, ".yml"))) { + file_list[file_count] = strdup(entry->d_name); + file_count++; + } + } + closedir(dir); + + qsort(file_list, file_count, sizeof(char *), compare_strings); + + for (int i = 0; i < file_count; i++) { + char filepath[PATH_MAX]; + snprintf(filepath, sizeof(filepath), "%s%s", CONFIG_DIR, file_list[i]); + get_dsp_lib_path(machine_name, filepath, dsp_lib_paths); + free(file_list[i]); + } + + if (dsp_lib_paths[0] != '\0') { + strlcpy(DSP_LIBS_LOCATION, CONFIG_BASE_DIR, sizeof(DSP_LIBS_LOCATION)); + //append slash in case user passed config base dir doesn't end with slash '/' + strlcat(DSP_LIBS_LOCATION, "/", sizeof(DSP_LIBS_LOCATION)); + strlcat(DSP_LIBS_LOCATION, dsp_lib_paths, sizeof(DSP_LIBS_LOCATION)); + strlcat(DSP_LIBS_LOCATION, DEFAULT_DSP_SEARCH_PATHS, sizeof(DSP_LIBS_LOCATION)); + } else { + FARF(ALWAYS, "Warning: No DSP library path found for machine [%s] in any configuration file\n", + machine_name); + } +} + +void configure_dsp_paths() { + char machine_name[PATH_MAX] = {0}; + FILE *file = fopen(MACHINE_NAME_PATH, "r"); + + if (file == NULL) + return; + + if (fgets(machine_name, sizeof(machine_name), file) != NULL) + // Remove trailing newline if present + machine_name[strcspn(machine_name, "\n")] = '\0'; + + fclose(file); + parse_config_dir(machine_name); +} From d3e718400b64ca98ccebd10e2e05ff693b3b26ef Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 26 Mar 2026 10:51:26 +0000 Subject: [PATCH 39/69] fastrpc: config_parser: add fallback MACHINE_NAME enviroment variable Add MACHINE_NAME enviroment variable as fallback mechanism to detect machine name, this should allow setups which will not have access to /sys/firmware/ entries, example containers itself to be able to use fastrpc libraries and dynamically get hold of hexagon binary paths. Signed-off-by: Srinivas Kandagatla --- src/fastrpc_config_parser.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/fastrpc_config_parser.c b/src/fastrpc_config_parser.c index c1920e5..d832a7b 100644 --- a/src/fastrpc_config_parser.c +++ b/src/fastrpc_config_parser.c @@ -169,13 +169,20 @@ void configure_dsp_paths() { char machine_name[PATH_MAX] = {0}; FILE *file = fopen(MACHINE_NAME_PATH, "r"); - if (file == NULL) - return; - - if (fgets(machine_name, sizeof(machine_name), file) != NULL) - // Remove trailing newline if present - machine_name[strcspn(machine_name, "\n")] = '\0'; + if (file) { + if (fgets(machine_name, sizeof(machine_name), file) != NULL) + // Remove trailing newline if present + machine_name[strcspn(machine_name, "\n")] = '\0'; - fclose(file); - parse_config_dir(machine_name); + fclose(file); + parse_config_dir(machine_name); + } else { + char *env_value = getenv("MACHINE_NAME"); + // fallback to look for MACHINE_NAME in environment variable + if (env_value) { + snprintf(machine_name, sizeof(machine_name), "%s", env_value); + machine_name[strcspn(machine_name, "\n")] = '\0'; + parse_config_dir(machine_name); + } + } } From 9b0e77c97217442eba4c9db2373ae60831b28a73 Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Tue, 31 Mar 2026 09:56:44 +0530 Subject: [PATCH 40/69] ci: replace pull_request_target with pull_request in preflight checks Switch Qualcomm preflight checks workflow from pull_request_target to pull_request to address reported GitHub Actions security vulnerability. This aligns with guidance from IT Security and avoids executing untrusted forked PR code with elevated permissions. Also fixes ABI checks being skipped for fork-based PRs due to pull_request_target behavior. Signed-off-by: Tharun Kumar Merugu --- .github/workflows/qcom-preflight-checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/qcom-preflight-checks.yml b/.github/workflows/qcom-preflight-checks.yml index f7f1d77..ac31b3d 100644 --- a/.github/workflows/qcom-preflight-checks.yml +++ b/.github/workflows/qcom-preflight-checks.yml @@ -1,6 +1,6 @@ name: Qualcomm Preflight Checks on: - pull_request_target: + pull_request: branches: [ development ] push: branches: [ development ] From 6516196e7a064bcbd1bc44cdef6eed4d6e3e3346 Mon Sep 17 00:00:00 2001 From: Anandu Krishnan E Date: Tue, 7 Apr 2026 16:48:52 +0530 Subject: [PATCH 41/69] Introduce rpcmem_alloc2 for large allocations Add rpcmem_alloc2 to handle shared memory requests >= 2GB. The existing rpcmem_alloc API uses an int-sized length parameter, which can overflow or fail when the allocation size crosses the 2GB boundary. Introduce a new allocation API to safely support large buffer requests and avoid failures caused by signed size limitations. Signed-off-by: Anandu Krishnan E --- src/rpcmem_linux.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/rpcmem_linux.c b/src/rpcmem_linux.c index 2fc7cb9..8a9ce40 100644 --- a/src/rpcmem_linux.c +++ b/src/rpcmem_linux.c @@ -240,6 +240,10 @@ void *rpcmem_alloc(int heapid, uint32_t flags, int size) { return rpcmem_alloc_internal(heapid, flags, size); } +void *rpcmem_alloc2(int heapid, uint32_t flags, size_t size) { + return rpcmem_alloc_internal(heapid, flags, (size_t)size); +} + void rpcmem_deinit_internal() { rpcmem_deinit(); } void rpcmem_init_internal() { rpcmem_init(); } From 1c063a7f3852f1c76255cba31eb0a88ac3ea6793 Mon Sep 17 00:00:00 2001 From: Vinayak Katoch Date: Tue, 7 Apr 2026 14:38:07 +0530 Subject: [PATCH 42/69] Enhance logging for expected DSP module-unavailable errors Handle AEE_ENOSUCHMOD as an expected module-availability condition by logging it at FARF(ALWAYS) with a "Warning:" prefix instead of FARF(ERROR) in fastrpc_apps_user.c and listener_android.c. This reduces unnecessary error-noise while preserving ERROR logs for unexpected failures. Signed-off-by: Vinayak Katoch --- src/fastrpc_apps_user.c | 18 +++++++++++++----- src/listener_android.c | 5 +++-- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/fastrpc_apps_user.c b/src/fastrpc_apps_user.c index fad04d5..5b8638c 100644 --- a/src/fastrpc_apps_user.c +++ b/src/fastrpc_apps_user.c @@ -1488,11 +1488,19 @@ int remote_handle64_invoke(remote_handle64 local, uint32_t sc, } if (0 == check_rpc_error(nErr)) { if (get_logger_state(domain)) { - FARF(ERROR, - "Error 0x%x: %s failed for module %s, handle 0x%" PRIx64 - ", method %d on domain %d (sc 0x%x) (errno %s)\n", - nErr, __func__, h->name, local, REMOTE_SCALARS_METHOD(sc), domain, sc, - strerror(errno)); + if (nErr == DSP_AEE_EOFFSET + AEE_ENOSUCHMOD) { + FARF(ALWAYS, + "Warning: %s module %s is not supported on DSP domain %d, handle 0x%" PRIx64 + ", method %d (sc 0x%x) (errno %s)\n", + __func__, h->name, domain, local, REMOTE_SCALARS_METHOD(sc), sc, + strerror(errno)); + } else { + FARF(ERROR, + "Error 0x%x: %s failed for module %s, handle 0x%" PRIx64 + ", method %d on domain %d (sc 0x%x) (errno %s)\n", + nErr, __func__, h->name, local, REMOTE_SCALARS_METHOD(sc), domain, sc, + strerror(errno)); + } } } } diff --git a/src/listener_android.c b/src/listener_android.c index 712945c..831d931 100644 --- a/src/listener_android.c +++ b/src/listener_android.c @@ -349,8 +349,9 @@ static void *listener_start_thread(void *arg) { nErr = __QAIC_HEADER(adsp_listener1_init2)(adsp_listener1_handle); if ((nErr == DSP_AEE_EOFFSET + AEE_ERPC) || nErr == DSP_AEE_EOFFSET + AEE_ENOSUCHMOD) { - FARF(ERROR, "Error 0x%x: %s domains support not available in listener", - nErr, __func__); + FARF(ALWAYS, + "Warning: %s domain support is unavailable on DSP in listener", + __func__); fastrpc_update_module_list(DOMAIN_LIST_DEQUEUE, domain, _const_adsp_listener1_handle, NULL, NULL); adsp_listener1_handle = INVALID_HANDLE; VERIFY(AEE_SUCCESS == (nErr = __QAIC_HEADER(adsp_listener_init2)())); From 5499d1a09c27a01b21f782e5f15cfc812b262b37 Mon Sep 17 00:00:00 2001 From: Vinayak Katoch Date: Wed, 8 Apr 2026 12:18:53 +0530 Subject: [PATCH 43/69] Update FastRPC Architecture diagram layout and components Add missing FastRPC DSP driver node in Kernel Space alongside FastRPC Kernel driver, matching the actual software stack. Signed-off-by: Vinayak Katoch --- README.md | 57 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 0e5206c..167a962 100644 --- a/README.md +++ b/README.md @@ -13,48 +13,60 @@ FastRPC interfaces are defined in an IDL file, and they are compiled using the Q The following diagram depicts the major FastRPC software components on the CPU and DSP. ```mermaid -flowchart TD -subgraph SMD[Shared Memory Driver] +flowchart TB +subgraph SMD["FastRPC Architecture"] direction TB -subgraph CPU[CPU] + +subgraph TOP[" "] +direction LR + +subgraph CPU["CPU"] direction TB -subgraph Application[Application] +subgraph Application["Application"] direction TB -Stub[Stub] -FRPC_UD[FastRPC user driver] -Stub --> FRPC_UD +Stub["Stub"] +FRPC_UD["FastRPC
user
driver"] end +FRPC_KD["FastRPC Kernel
driver"] end -subgraph DSP[DSP] + +subgraph DSP["DSP"] direction TB -subgraph User_PD[User PD] +subgraph User_PD["User PD"] direction TB -Skel[Skel] -FRPC_DD[FastRPC DSP user driver] -Skel --> FRPC_DD +Skel["Skel"] +FRPC_DD["FastRPC
DSP user
driver"] end +FRPC_DSP_KD["FastRPC DSP
driver"] end -subgraph Kernel_Space[Kernel Space] -direction TB -FRPC_KD[FastRPC Kernel driver] + end -FRPC_UD --> FRPC_KD -FRPC_DD --> FRPC_KD end + classDef generated fill:#E6E6FA,stroke:#9370DB,color:#000 classDef fastrpc fill:#4169E1,stroke:#000,color:#000 classDef shared fill:#FAFAFA,stroke:#666,color:#000 classDef userpdbox fill:#ABDBE3,stroke:#666,color:#000 classDef mainbox fill:#7FB3CD,stroke:#666,color:#000 +classDef topbox fill:none,stroke:none,color:none + class Stub,Skel generated -class FRPC_UD,FRPC_DD,FRPC_KD fastrpc +class FRPC_UD,FRPC_KD,FRPC_DD,FRPC_DSP_KD fastrpc class SMD shared class Application,User_PD userpdbox -class CPU,DSP,Kernel_Space mainbox +class CPU,DSP mainbox +class TOP topbox + +Stub <--> FRPC_UD +FRPC_UD <--> FRPC_KD +FRPC_KD <--> |rpmsg| FRPC_DSP_KD +FRPC_DSP_KD <--> FRPC_DD +FRPC_DD <--> Skel + linkStyle default stroke:#000 ``` -**Stub and skel** are generated by the IDL compiler. Other modules are part of the software stack on the device. +**Stub** and **Skel** are generated by the IDL compiler. The modules shown in blue blocks in the diagram are part of the FastRPC software stack on the device. **Definition of the terms in the diagram:** @@ -63,8 +75,9 @@ linkStyle default stroke:#000 | Application | User mode process that initiates the remote invocation | | Stub | Auto-generated code that takes care of marshaling parameters and runs on the CPU | | FastRPC user driver on CPU | User mode library that is used by the stub code to do remote invocations | -| FastRPC Kernel Driver | Receives the remote invocations from the client, queues them up with the FastRPC DSP driver, and then waits for the response after signaling the remote side | -| FastRPC DSP Driver | Dequeues the messages sent by the FastRPC kernel driver and dispatches them for processing | +| FastRPC Kernel Driver | Receives the remote invocations from the client, queues them up for transport to the DSP side over rpmsg, and then waits for the response after signaling the remote side | +| rpmsg | Remote Processor Messaging is the transport mechanism used between the CPU-side FastRPC kernel driver and the DSP-side FastRPC driver to exchange FastRPC requests and responses | +| FastRPC DSP Driver | Dequeues the messages received over rpmsg from the FastRPC kernel driver and dispatches them for processing | | FastRPC user driver on DSP | User mode code that includes a shell executable to run in the user protection domain (PD) on the DSP and complete the remote invocations to the skel library | | Skel | Auto-generated code that un-marshals parameters and invokes the user-defined implementation of the function that runs on the DSP | | User PD | User protection domain on the DSP that provides the environment to run the user code | From 2fcd9a17e93dfdf781c2400bd7eb5922730bbdc3 Mon Sep 17 00:00:00 2001 From: Vinayak Katoch Date: Tue, 24 Feb 2026 14:44:37 +0530 Subject: [PATCH 44/69] Remove DEFAULT_DEVICE fallback to prevent cross-domain routing Remove legacy DEFAULT_DEVICE fallback that could cause incorrect domain routing. Previously, if a requested domain's device nodes were unavailable, the code would fall back to the DEFAULT_DEVICE of the linked library (e.g., ADSP for libadsprpc.so), ignoring the user's domain request. Now each domain only attempts: secure node -> non-secure node, and fails cleanly if both are unavailable. This ensures device opening respects the user's requested domain. Additionally, replace verbose switch-case statement with IS_VALID_DOMAIN_ID check for cleaner, more maintainable code. This consolidates all domain cases (ADSP/MDSP/SDSP/CDSP/CDSP1/GDSP0/GDSP1) into unified logic and improves error handling. Signed-off-by: Vinayak Katoch --- inc/fastrpc_ioctl.h | 18 ------------- src/adsp_default_listener.c | 20 +++++++-------- src/fastrpc_apps_user.c | 50 ++++--------------------------------- src/fastrpc_ioctl.c | 6 ++--- 4 files changed, 18 insertions(+), 76 deletions(-) diff --git a/inc/fastrpc_ioctl.h b/inc/fastrpc_ioctl.h index 779d034..b9cee80 100644 --- a/inc/fastrpc_ioctl.h +++ b/inc/fastrpc_ioctl.h @@ -43,24 +43,6 @@ #define FASTRPC_ATTR_NOVA (256) -/* Secure and default device nodes */ -#if DEFAULT_DOMAIN_ID==ADSP_DOMAIN_ID - #define SECURE_DEVICE "/dev/fastrpc-adsp-secure" - #define DEFAULT_DEVICE "/dev/fastrpc-adsp" -#elif DEFAULT_DOMAIN_ID==MDSP_DOMAIN_ID - #define SECURE_DEVICE "/dev/fastrpc-mdsp-secure" - #define DEFAULT_DEVICE "/dev/fastrpc-mdsp" -#elif DEFAULT_DOMAIN_ID==SDSP_DOMAIN_ID - #define SECURE_DEVICE "/dev/fastrpc-sdsp-secure" - #define DEFAULT_DEVICE "/dev/fastrpc-sdsp" -#elif DEFAULT_DOMAIN_ID==CDSP_DOMAIN_ID - #define SECURE_DEVICE "/dev/fastrpc-cdsp-secure" - #define DEFAULT_DEVICE "/dev/fastrpc-cdsp" -#else - #define SECURE_DEVICE "" - #define DEFAULT_DEVICE "" -#endif - #define INITIALIZE_REMOTE_ARGS(total) int *pfds = NULL; \ unsigned *pattrs = NULL; \ args = (struct fastrpc_invoke_args*) calloc(sizeof(*args), total); \ diff --git a/src/adsp_default_listener.c b/src/adsp_default_listener.c index e37648a..22651bc 100644 --- a/src/adsp_default_listener.c +++ b/src/adsp_default_listener.c @@ -71,7 +71,7 @@ static domain_t *get_domain_uri(int domain_id) { } static const char *get_secure_device_name(int domain_id) { - const char *name; + const char *name = NULL; int domain = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain_id); switch (domain) { @@ -97,15 +97,15 @@ static const char *get_secure_device_name(int domain_id) { name = GDSP1_SECURE_DEVICE_NAME; break; default: - name = DEFAULT_DEVICE; + FARF(ERROR, "ERROR: %s Invalid domain %d", __func__, domain); break; } return name; } -static const char *get_default_device_name(int domain_id) { - const char *name; +static const char *get_non_secure_device_name(int domain_id) { + const char *name = NULL; int domain = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain_id); switch (domain) { @@ -131,7 +131,7 @@ static const char *get_default_device_name(int domain_id) { name = GDSP1_DEVICE_NAME; break; default: - name = DEFAULT_DEVICE; + FARF(ERROR, "ERROR: %s Invalid domain %d", __func__, domain); break; } @@ -172,13 +172,13 @@ static bool fastrpc_dev_exists(const char* dev_name) static int fastrpc_wait_for_device(int domain) { int inotify_fd = -1, watch_fd = -1, err = 0; - const char *sec_dev_name = NULL, *def_dev_name = NULL; + const char *sec_dev_name = NULL, *non_sec_dev_name = NULL; struct pollfd pfd[1]; sec_dev_name = get_secure_device_name(domain); - def_dev_name = get_default_device_name(domain); + non_sec_dev_name = get_non_secure_device_name(domain); - if (fastrpc_dev_exists(sec_dev_name) || fastrpc_dev_exists(def_dev_name)) + if (fastrpc_dev_exists(sec_dev_name) || fastrpc_dev_exists(non_sec_dev_name)) return 0; inotify_fd = inotify_init(); @@ -194,7 +194,7 @@ static int fastrpc_wait_for_device(int domain) return AEE_EINVALIDFD; } - if (fastrpc_dev_exists(sec_dev_name) || fastrpc_dev_exists(def_dev_name)) + if (fastrpc_dev_exists(sec_dev_name) || fastrpc_dev_exists(non_sec_dev_name)) goto bail; memset(pfd, 0 , sizeof(pfd)); @@ -231,7 +231,7 @@ static int fastrpc_wait_for_device(int domain) /* Check if the event corresponds to the creation of the device node. */ if (event->wd == watch_fd && (event->mask & IN_CREATE) && ((strcmp(sec_dev_name, event->name) == 0) || - (strcmp(def_dev_name, event->name) == 0))) { + (strcmp(non_sec_dev_name, event->name) == 0))) { /* Device node created, process proceed to open and use it. */ VERIFY_IPRINTF("Device node %s created!\n", event->name); goto bail; /* Exit the loop after device creation is detected. */ diff --git a/src/fastrpc_apps_user.c b/src/fastrpc_apps_user.c index 5b8638c..a7f916a 100644 --- a/src/fastrpc_apps_user.c +++ b/src/fastrpc_apps_user.c @@ -3038,7 +3038,7 @@ static void domain_deinit(int domain) { } static const char *get_domain_name(int domain_id) { - const char *name; + const char *name = NULL; int domain = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain_id); switch (domain) { @@ -3064,7 +3064,7 @@ static const char *get_domain_name(int domain_id) { name = GDSP1RPC_DEVICE; break; default: - name = DEFAULT_DEVICE; + FARF(ERROR, "ERROR: %s Invalid domain %d", __func__, domain); break; } return name; @@ -3075,40 +3075,7 @@ int open_device_node(int domain_id) { int domain = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain_id); int sess_id = GET_SESSION_ID_FROM_DOMAIN_ID(domain_id); - switch (domain) { - case ADSP_DOMAIN_ID: - case SDSP_DOMAIN_ID: - case MDSP_DOMAIN_ID: - dev = open(get_secure_domain_name(domain), O_NONBLOCK); - if ((dev < 0) && (errno == ENOENT)) { - FARF(RUNTIME_RPC_HIGH, - "Device node %s open failed for domain %d (errno %s)," - "falling back to node %s \n", - get_secure_domain_name(domain), domain, strerror(errno), - get_domain_name(domain)); - dev = open(get_domain_name(domain), O_NONBLOCK); - if ((dev < 0) && (errno == ENOENT)) { - FARF(RUNTIME_RPC_HIGH, - "Device node %s open failed for domain %d (errno %s)," - "falling back to node %s \n", - get_domain_name(domain), domain, strerror(errno), DEFAULT_DEVICE); - dev = open(DEFAULT_DEVICE, O_NONBLOCK); - } - } else if ((dev < 0) && (errno == EACCES)) { - // Open the default device node if unable to open the - // secure device node due to permissions - FARF(RUNTIME_RPC_HIGH, - "Device node %s open failed for domain %d (errno %s)," - "falling back to node %s \n", - get_secure_domain_name(domain), domain, strerror(errno), - DEFAULT_DEVICE); - dev = open(DEFAULT_DEVICE, O_NONBLOCK); - } - break; - case CDSP_DOMAIN_ID: - case CDSP1_DOMAIN_ID: - case GDSP0_DOMAIN_ID: - case GDSP1_DOMAIN_ID: + if (IS_VALID_DOMAIN_ID(domain)) { dev = open(get_secure_domain_name(domain), O_NONBLOCK); if ((dev < 0) && ((errno == ENOENT) || (errno == EACCES))) { FARF(RUNTIME_RPC_HIGH, @@ -3118,18 +3085,11 @@ int open_device_node(int domain_id) { get_domain_name(domain)); dev = open(get_domain_name(domain), O_NONBLOCK); if ((dev < 0) && ((errno == ENOENT) || (errno == EACCES))) { - // Open the default device node if actual device node - // is not present FARF(RUNTIME_RPC_HIGH, - "Device node %s open failed for domain %d (errno %s)," - "falling back to node %s \n", - get_domain_name(domain), domain, strerror(errno), DEFAULT_DEVICE); - dev = open(DEFAULT_DEVICE, O_NONBLOCK); + "Device node %s open failed for domain %d (errno %s)\n", + get_domain_name(domain), domain, strerror(errno)); } } - break; - default: - break; } if (dev < 0) FARF(ERROR, diff --git a/src/fastrpc_ioctl.c b/src/fastrpc_ioctl.c index d0ead7c..c717be9 100644 --- a/src/fastrpc_ioctl.c +++ b/src/fastrpc_ioctl.c @@ -14,7 +14,7 @@ ADSP/SLPI/MDSP/CDSP - Return Secure node */ const char *get_secure_domain_name(int domain_id) { - const char *name; + const char *name = NULL; int domain = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain_id); switch (domain) { @@ -40,7 +40,7 @@ const char *get_secure_domain_name(int domain_id) { name = GDSP1RPC_SECURE_DEVICE; break; default: - name = DEFAULT_DEVICE; + FARF(ERROR, "ERROR: %s Invalid domain %d", __func__, domain); break; } return name; @@ -252,4 +252,4 @@ int fastrpc_async_get_status(fastrpc_async_jobid jobid, int timeout_us, int fastrpc_release_async_job(fastrpc_async_jobid jobid) { return AEE_EUNSUPPORTED; -} \ No newline at end of file +} From 68ef1a370706202e6228bb153e0c2ef4fab9a080 Mon Sep 17 00:00:00 2001 From: Vinayak Katoch Date: Mon, 2 Mar 2026 13:03:36 +0530 Subject: [PATCH 45/69] Merge domain device name functions into unified API Replace duplicate get_secure_domain_name() and get_non_secure_domain_name() implementations with a single get_domain_device_names() function. - Add get_domain_device_names() in fastrpc_apps_user.c - Remove duplicate implementations from fastrpc_ioctl.c and adsp_default_listener.c - Remove unused device name macros from adsp_default_listener.c - Update callers to use unified function - Fix fastrpc_dev_exists() to accept full paths - Fix fastrpc_wait_for_device() basename extraction for inotify - Expose via fastrpc_internal.h Signed-off-by: Vinayak Katoch --- inc/fastrpc_internal.h | 13 +++-- src/adsp_default_listener.c | 111 ++++++------------------------------ src/fastrpc_apps_user.c | 45 ++++++++------- src/fastrpc_ioctl.c | 36 ------------ 4 files changed, 50 insertions(+), 155 deletions(-) diff --git a/inc/fastrpc_internal.h b/inc/fastrpc_internal.h index 2005b8f..920cff9 100644 --- a/inc/fastrpc_internal.h +++ b/inc/fastrpc_internal.h @@ -16,6 +16,7 @@ #include "AEEQList.h" #include "AEEStdErr.h" #include "fastrpc_common.h" +#include "fastrpc_ioctl.h" // Aligns the memory #define ALIGN_B(p, a) (((p) + ((a) - 1)) & ~((a) - 1)) @@ -449,6 +450,14 @@ static __inline int convert_kernel_to_user_error(int nErr, int err_no) { return nErr; } +/** + * @brief Get both secure and non-secure device names for a domain + * @param domain_id: Domain ID + * @param secure_name: Output pointer for secure device name + * @param non_secure_name: Output pointer for non-secure device name + **/ +void get_domain_device_names(int domain_id, const char **secure_name, const char **non_secure_name); + /** * @brief utility APIs used in fastRPC library to get name, handle from domain **/ @@ -515,8 +524,4 @@ int ioctl_optimization(int dev, uint32_t max_concurrency); int ioctl_mdctx_manage(int dev, int req, void *user_ctx, unsigned int *domain_ids, unsigned int num_domain_ids, uint64_t *ctx); -const char* get_secure_domain_name(int domain_id); - -#include "fastrpc_ioctl.h" - #endif // FASTRPC_INTERNAL_H diff --git a/src/adsp_default_listener.c b/src/adsp_default_listener.c index 22651bc..ee3d3fd 100644 --- a/src/adsp_default_listener.c +++ b/src/adsp_default_listener.c @@ -33,20 +33,6 @@ #define POLL_TIMEOUT 10 * 1000 #define EVENT_SIZE ( sizeof (struct inotify_event) ) #define EVENT_BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) ) -#define ADSP_SECURE_DEVICE_NAME "fastrpc-adsp-secure" -#define SDSP_SECURE_DEVICE_NAME "fastrpc-sdsp-secure" -#define MDSP_SECURE_DEVICE_NAME "fastrpc-mdsp-secure" -#define CDSP_SECURE_DEVICE_NAME "fastrpc-cdsp-secure" -#define CDSP1_SECURE_DEVICE_NAME "fastrpc-cdsp1-secure" -#define GDSP0_SECURE_DEVICE_NAME "fastrpc-gdsp0-secure" -#define GDSP1_SECURE_DEVICE_NAME "fastrpc-gdsp1-secure" -#define ADSP_DEVICE_NAME "fastrpc-adsp" -#define SDSP_DEVICE_NAME "fastrpc-sdsp" -#define MDSP_DEVICE_NAME "fastrpc-mdsp" -#define CDSP_DEVICE_NAME "fastrpc-cdsp" -#define CDSP1_DEVICE_NAME "fastrpc-cdsp1" -#define GDSP0_DEVICE_NAME "fastrpc-gdsp0" -#define GDSP1_DEVICE_NAME "fastrpc-gdsp1" // Array of supported domain names and its corresponding ID's. static domain_t supported_domains[] = {{ADSP_DOMAIN_ID, ADSP_DOMAIN}, @@ -70,95 +56,23 @@ static domain_t *get_domain_uri(int domain_id) { return NULL; } -static const char *get_secure_device_name(int domain_id) { - const char *name = NULL; - int domain = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain_id); - - switch (domain) { - case ADSP_DOMAIN_ID: - name = ADSP_SECURE_DEVICE_NAME; - break; - case SDSP_DOMAIN_ID: - name = SDSP_SECURE_DEVICE_NAME; - break; - case MDSP_DOMAIN_ID: - name = MDSP_SECURE_DEVICE_NAME; - break; - case CDSP_DOMAIN_ID: - name = CDSP_SECURE_DEVICE_NAME; - break; - case CDSP1_DOMAIN_ID: - name = CDSP1_SECURE_DEVICE_NAME; - break; - case GDSP0_DOMAIN_ID: - name = GDSP0_SECURE_DEVICE_NAME; - break; - case GDSP1_DOMAIN_ID: - name = GDSP1_SECURE_DEVICE_NAME; - break; - default: - FARF(ERROR, "ERROR: %s Invalid domain %d", __func__, domain); - break; - } - - return name; -} - -static const char *get_non_secure_device_name(int domain_id) { - const char *name = NULL; - int domain = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain_id); - - switch (domain) { - case ADSP_DOMAIN_ID: - name = ADSP_DEVICE_NAME; - break; - case SDSP_DOMAIN_ID: - name = SDSP_DEVICE_NAME; - break; - case MDSP_DOMAIN_ID: - name = MDSP_DEVICE_NAME; - break; - case CDSP_DOMAIN_ID: - name = CDSP_DEVICE_NAME; - break; - case CDSP1_DOMAIN_ID: - name = CDSP1_DEVICE_NAME; - break; - case GDSP0_DOMAIN_ID: - name = GDSP0_DEVICE_NAME; - break; - case GDSP1_DOMAIN_ID: - name = GDSP1_DEVICE_NAME; - break; - default: - FARF(ERROR, "ERROR: %s Invalid domain %d", __func__, domain); - break; - } - - return name; -} /** * fastrpc_dev_exists() - Check if device exists - * @dev_name: Device name + * @dev_path: Full device path (e.g., "/dev/fastrpc-adsp") * * Return: * True: Device node exists * False: Device node does not exist */ -static bool fastrpc_dev_exists(const char* dev_name) +static bool fastrpc_dev_exists(const char* dev_path) { struct stat buffer; - char *path = NULL; - uint64_t len; - len = snprintf(0, 0, "/dev/%s", dev_name) + 1; - if(NULL == (path = (char *)malloc(len * sizeof(char)))) + if (!dev_path) return false; - snprintf(path, (int)len, "/dev/%s", dev_name); - - return (stat(path, &buffer) == 0); + return (stat(dev_path, &buffer) == 0); } /** @@ -175,8 +89,7 @@ static int fastrpc_wait_for_device(int domain) const char *sec_dev_name = NULL, *non_sec_dev_name = NULL; struct pollfd pfd[1]; - sec_dev_name = get_secure_device_name(domain); - non_sec_dev_name = get_non_secure_device_name(domain); + get_domain_device_names(domain, &sec_dev_name, &non_sec_dev_name); if (fastrpc_dev_exists(sec_dev_name) || fastrpc_dev_exists(non_sec_dev_name)) return 0; @@ -227,11 +140,21 @@ static int fastrpc_wait_for_device(int domain) /* Loop over all events in the buffer. */ for (char *ptr = buffer; ptr < buffer + len; ptr += sizeof(struct inotify_event) + event->len) { + const char *sec_dev_basename = NULL, *non_sec_dev_basename = NULL; event = (struct inotify_event *) ptr; + + /* Extract just the device name from full path for comparison */ + sec_dev_basename = strrchr(sec_dev_name, '/'); + non_sec_dev_basename = strrchr(non_sec_dev_name, '/'); + + /* Skip the '/' character if found */ + sec_dev_basename++; + non_sec_dev_basename++; + /* Check if the event corresponds to the creation of the device node. */ if (event->wd == watch_fd && (event->mask & IN_CREATE) && - ((strcmp(sec_dev_name, event->name) == 0) || - (strcmp(non_sec_dev_name, event->name) == 0))) { + ((sec_dev_basename && strcmp(sec_dev_basename, event->name) == 0) || + (non_sec_dev_basename && strcmp(non_sec_dev_basename, event->name) == 0))) { /* Device node created, process proceed to open and use it. */ VERIFY_IPRINTF("Device node %s created!\n", event->name); goto bail; /* Exit the loop after device creation is detected. */ diff --git a/src/fastrpc_apps_user.c b/src/fastrpc_apps_user.c index a7f916a..28bcb10 100644 --- a/src/fastrpc_apps_user.c +++ b/src/fastrpc_apps_user.c @@ -3037,58 +3037,61 @@ static void domain_deinit(int domain) { pthread_mutex_unlock(&hlist[domain].mut); } -static const char *get_domain_name(int domain_id) { - const char *name = NULL; +void get_domain_device_names(int domain_id, const char **secure_name, const char **non_secure_name) { int domain = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain_id); switch (domain) { case ADSP_DOMAIN_ID: - name = ADSPRPC_DEVICE; + *secure_name = ADSPRPC_SECURE_DEVICE; + *non_secure_name = ADSPRPC_DEVICE; break; case SDSP_DOMAIN_ID: - name = SDSPRPC_DEVICE; + *secure_name = SDSPRPC_SECURE_DEVICE; + *non_secure_name = SDSPRPC_DEVICE; break; case MDSP_DOMAIN_ID: - name = MDSPRPC_DEVICE; + *secure_name = MDSPRPC_SECURE_DEVICE; + *non_secure_name = MDSPRPC_DEVICE; break; case CDSP_DOMAIN_ID: - name = CDSPRPC_DEVICE; + *secure_name = CDSPRPC_SECURE_DEVICE; + *non_secure_name = CDSPRPC_DEVICE; break; case CDSP1_DOMAIN_ID: - name = CDSP1RPC_DEVICE; + *secure_name = CDSP1RPC_SECURE_DEVICE; + *non_secure_name = CDSP1RPC_DEVICE; break; case GDSP0_DOMAIN_ID: - name = GDSP0RPC_DEVICE; + *secure_name = GDSP0RPC_SECURE_DEVICE; + *non_secure_name = GDSP0RPC_DEVICE; break; case GDSP1_DOMAIN_ID: - name = GDSP1RPC_DEVICE; + *secure_name = GDSP1RPC_SECURE_DEVICE; + *non_secure_name = GDSP1RPC_DEVICE; break; default: FARF(ERROR, "ERROR: %s Invalid domain %d", __func__, domain); + *secure_name = NULL; + *non_secure_name = NULL; break; } - return name; } int open_device_node(int domain_id) { int dev = -1, nErr = 0; int domain = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain_id); int sess_id = GET_SESSION_ID_FROM_DOMAIN_ID(domain_id); + const char *secure_dev = NULL, *non_secure_dev = NULL; if (IS_VALID_DOMAIN_ID(domain)) { - dev = open(get_secure_domain_name(domain), O_NONBLOCK); + get_domain_device_names(domain, &secure_dev, &non_secure_dev); + dev = open(secure_dev, O_NONBLOCK); if ((dev < 0) && ((errno == ENOENT) || (errno == EACCES))) { FARF(RUNTIME_RPC_HIGH, "Device node %s open failed for domain %d (errno %s)," "falling back to node %s \n", - get_secure_domain_name(domain), domain, strerror(errno), - get_domain_name(domain)); - dev = open(get_domain_name(domain), O_NONBLOCK); - if ((dev < 0) && ((errno == ENOENT) || (errno == EACCES))) { - FARF(RUNTIME_RPC_HIGH, - "Device node %s open failed for domain %d (errno %s)\n", - get_domain_name(domain), domain, strerror(errno)); - } + secure_dev, domain, strerror(errno), non_secure_dev); + dev = open(non_secure_dev, O_NONBLOCK); } } if (dev < 0) @@ -3097,8 +3100,8 @@ int open_device_node(int domain_id) { "dev : %s. (errno %d, %s) (Either the remote processor is down, or " "application does not have permission to access the remote " "processor\n", - nErr, __func__, domain_id, sess_id, get_secure_domain_name(domain), - get_domain_name(domain), errno, strerror(errno)); + nErr, __func__, domain_id, sess_id, secure_dev, + non_secure_dev, errno, strerror(errno)); return dev; } diff --git a/src/fastrpc_ioctl.c b/src/fastrpc_ioctl.c index c717be9..15c778d 100644 --- a/src/fastrpc_ioctl.c +++ b/src/fastrpc_ioctl.c @@ -10,42 +10,6 @@ #include "remote.h" #include -/* Returns the name of the domain based on the following - ADSP/SLPI/MDSP/CDSP - Return Secure node - */ -const char *get_secure_domain_name(int domain_id) { - const char *name = NULL; - int domain = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain_id); - - switch (domain) { - case ADSP_DOMAIN_ID: - name = ADSPRPC_SECURE_DEVICE; - break; - case SDSP_DOMAIN_ID: - name = SDSPRPC_SECURE_DEVICE; - break; - case MDSP_DOMAIN_ID: - name = MDSPRPC_SECURE_DEVICE; - break; - case CDSP_DOMAIN_ID: - name = CDSPRPC_SECURE_DEVICE; - break; - case CDSP1_DOMAIN_ID: - name = CDSP1RPC_SECURE_DEVICE; - break; - case GDSP0_DOMAIN_ID: - name = GDSP0RPC_SECURE_DEVICE; - break; - case GDSP1_DOMAIN_ID: - name = GDSP1RPC_SECURE_DEVICE; - break; - default: - FARF(ERROR, "ERROR: %s Invalid domain %d", __func__, domain); - break; - } - return name; -} - int ioctl_init(int dev, uint32_t flags, int attr, unsigned char *shell, int shelllen, int shellfd, char *mem, int memlen, int memfd, int tessiglen) { int ioErr = 0; From 34985bba7807552c7a9f6dee71d72055ca1c33b4 Mon Sep 17 00:00:00 2001 From: Abhinav Parihar Date: Thu, 16 Apr 2026 12:09:06 +0530 Subject: [PATCH 46/69] Initialize apps_std before use Initialize apps_std earlier to ensure it is available before being used by config and listener paths Signed-off-by: Abhinav Parihar --- src/fastrpc_apps_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fastrpc_apps_user.c b/src/fastrpc_apps_user.c index 5b8638c..bdeb673 100644 --- a/src/fastrpc_apps_user.c +++ b/src/fastrpc_apps_user.c @@ -3937,6 +3937,7 @@ static int fastrpc_apps_user_init(void) { VERIFY(AEE_SUCCESS == (nErr = PL_INIT(gpls))); VERIFY(AEE_SUCCESS == (nErr = PL_INIT(rpcmem))); + VERIFY(AEE_SUCCESS == (nErr = PL_INIT(apps_std))); VERIFY(AEE_SUCCESS == (nErr = pthread_key_create(&tlsKey, exit_thread))); #ifdef PARSE_YAML configure_dsp_paths(); @@ -3969,7 +3970,6 @@ static int fastrpc_apps_user_init(void) { pthread_mutex_init(&hlist[i].init, 0); } listener_android_init(); - VERIFY(AEE_SUCCESS == (nErr = PL_INIT(apps_std))); GenCrc32Tab(POLY32, crc_table); fastrpc_notif_init(); apps_mem_table_init(); From f7ed99e59da12ca4000a66aad77fe7d61d189857 Mon Sep 17 00:00:00 2001 From: Abhinav Parihar Date: Thu, 16 Apr 2026 12:20:50 +0530 Subject: [PATCH 47/69] Guard against refcount underflow in fastrpc_session_put() If fastrpc_session_put() is called when the refcount is already zero, the decrement results in an unsigned underflow, leading to refcount wraparound and potential use-after-free or resource leaks. Add an explicit check to ensure the refcount is greater than zero before decrementing it, preventing underflow and making the refcount handling more robust. Signed-off-by: Abhinav Parihar --- src/fastrpc_apps_user.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/fastrpc_apps_user.c b/src/fastrpc_apps_user.c index bdeb673..0c7530e 100644 --- a/src/fastrpc_apps_user.c +++ b/src/fastrpc_apps_user.c @@ -398,7 +398,8 @@ int fastrpc_session_put(int domain) { do { if (hlist) { pthread_mutex_lock(&hlist[domain].mut); - hlist[domain].ref--; + if (hlist[domain].ref > 0) + hlist[domain].ref--; ref = hlist[domain].ref; pthread_mutex_unlock(&hlist[domain].mut); FARF(RUNTIME_RPC_HIGH, "%s, domain %d, state %d, ref %d\n", __func__, domain, From d44eaaa680df9e8716472ecc14f91680a1d6e494 Mon Sep 17 00:00:00 2001 From: Ekansh Gupta Date: Fri, 17 Apr 2026 15:13:09 +0530 Subject: [PATCH 48/69] adspmsgd: route DSP runtime logs via syslog when enabled DSP runtime logs emitted by adspmsgd are currently written to stdout using printf(), which causes them to be routed to the console instead of systemd journal on Linux systems. Add support for routing logs via syslog when USE_SYSLOG is enabled, and use platform-specific logging backends where applicable. This ensures that runtime DSP logs are correctly captured by journalctl on Linux while preserving existing Android logging behavior. Fallback to stdout is retained for non-Android and non-syslog builds. Signed-off-by: Ekansh Gupta --- src/adspmsgd_printf.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/adspmsgd_printf.c b/src/adspmsgd_printf.c index 787d9c1..18f2102 100644 --- a/src/adspmsgd_printf.c +++ b/src/adspmsgd_printf.c @@ -5,6 +5,12 @@ #include "remote.h" #include +#ifdef __ANDROID__ +#include +#endif +#ifdef USE_SYSLOG +#include +#endif #define LOG_NODE_SIZE 256 #define LOG_FILENAME_SIZE 30 @@ -54,5 +60,11 @@ int adspmsgd_apps_log(const unsigned char *log_message_buffer, return 0; } void adspmsgd_log_message(char *format, char *msg) { - printf("adsprpc:dsp: %s\n", msg); +#ifdef __ANDROID__ + __android_log_print(ANDROID_LOG_VERBOSE,"adsprpc",format, msg); +#elif defined(USE_SYSLOG) + syslog(LOG_INFO,"adsprpc:%s ", msg); +#else + printf("adsprpc:%s\n", msg); +#endif } From 1f05242b009d500f7c0f6d2b3cfb00af91e7cc81 Mon Sep 17 00:00:00 2001 From: Eddie Lin Date: Wed, 22 Apr 2026 04:43:05 +0200 Subject: [PATCH 49/69] Fix missing unlock on VERIFY failure paths Fix two paths where VERIFY could jump to bail while a mutex was still held. Always release the mutex on error paths to prevent deadlock during cleanup. Signed-off-by: Eddie Lin --- src/fastrpc_apps_user.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/fastrpc_apps_user.c b/src/fastrpc_apps_user.c index 28bcb10..8b1a4c3 100644 --- a/src/fastrpc_apps_user.c +++ b/src/fastrpc_apps_user.c @@ -2248,7 +2248,7 @@ int remote_handle64_control(remote_handle64 handle, uint32_t req, void *data, static int close_domain_session(int domain) { QNode *pn = NULL, *pnn = NULL; char dlerrstr[255]; - int dlerr = 0, nErr = AEE_SUCCESS; + int dlerr = 0, nErr = AEE_SUCCESS, mut_locked = 0; remote_handle64 proc_handle = 0; FARF(ALWAYS, @@ -2262,13 +2262,16 @@ static int close_domain_session(int domain) { adsp_current_process_exit(); } pthread_mutex_lock(&hlist[domain].lmut); + mut_locked = 1; if (!QList_IsEmpty(&hlist[domain].nql)) { QLIST_NEXTSAFE_FOR_ALL(&hlist[domain].nql, pn, pnn) { struct handle_info *hi = STD_RECOVER_REC(struct handle_info, qn, pn); VERIFYC(NULL != hi, AEE_EINVHANDLE); pthread_mutex_unlock(&hlist[domain].lmut); + mut_locked = 0; remote_handle_close(hi->remote); pthread_mutex_lock(&hlist[domain].lmut); + mut_locked = 1; } } if (!QList_IsEmpty(&hlist[domain].rql)) { @@ -2276,8 +2279,10 @@ static int close_domain_session(int domain) { struct handle_info *hi = STD_RECOVER_REC(struct handle_info, qn, pn); VERIFYC(NULL != hi, AEE_EINVHANDLE); pthread_mutex_unlock(&hlist[domain].lmut); + mut_locked = 0; close_reverse_handle(hi->local, dlerrstr, sizeof(dlerrstr), &dlerr); pthread_mutex_lock(&hlist[domain].lmut); + mut_locked = 1; } } if (!QList_IsEmpty(&hlist[domain].ql)) { @@ -2285,12 +2290,19 @@ static int close_domain_session(int domain) { struct handle_info *hi = STD_RECOVER_REC(struct handle_info, qn, pn); VERIFYC(NULL != hi, AEE_EINVHANDLE); pthread_mutex_unlock(&hlist[domain].lmut); + mut_locked = 0; remote_handle64_close(hi->local); pthread_mutex_lock(&hlist[domain].lmut); + mut_locked = 1; } } pthread_mutex_unlock(&hlist[domain].lmut); + mut_locked = 0; bail: + if (mut_locked) { + pthread_mutex_unlock(&hlist[domain].lmut); + mut_locked = 0; + } if (nErr != AEE_SUCCESS) { FARF(ERROR, "Error 0x%x: %s failed for domain %d (errno %s)", nErr, __func__, domain, strerror(errno)); @@ -3707,14 +3719,16 @@ remote_handle64 get_adsp_perf1_handle(int domain) { } static int domain_init(int domain, int *dev) { - int nErr = AEE_SUCCESS, dom = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain); + int nErr = AEE_SUCCESS, dom = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain), mut_locked = 0; remote_handle64 panic_handle = 0; struct err_codes *err_codes_to_send = NULL; pthread_mutex_lock(&hlist[domain].mut); + mut_locked = 1; if (hlist[domain].state != FASTRPC_DOMAIN_STATE_CLEAN) { *dev = hlist[domain].dev; pthread_mutex_unlock(&hlist[domain].mut); + mut_locked = 0; return AEE_SUCCESS; } @@ -3775,6 +3789,7 @@ static int domain_init(int domain, int *dev) { hlist[domain].state = FASTRPC_DOMAIN_STATE_INIT; hlist[domain].ref = 0; pthread_mutex_unlock(&hlist[domain].mut); + mut_locked = 0; VERIFY(AEE_SUCCESS == (nErr = listener_android_domain_init( domain, hlist[domain].th_params.update_requested, &hlist[domain].th_params.r_sem))); @@ -3787,6 +3802,10 @@ static int domain_init(int domain, int *dev) { } bail: if (nErr != AEE_SUCCESS) { + if (mut_locked) { + pthread_mutex_unlock(&hlist[domain].mut); + mut_locked = 0; + } domain_deinit(domain); if (hlist) { FARF(ERROR, "Error 0x%x: %s (%d) failed for domain %d (errno %s)\n", nErr, From f9263865e15f14e1edd49bde2fb3bc4e84d3c30f Mon Sep 17 00:00:00 2001 From: Vinayak Katoch Date: Thu, 23 Apr 2026 14:01:44 +0530 Subject: [PATCH 50/69] Move GDSP domain IDs from remote.h to fastrpc_common.h GDSP0_DOMAIN_ID and GDSP1_DOMAIN_ID are internal platform-specific constants not part of the Hexagon SDK API. Move them out of the inc/remote.h into inc/fastrpc_common.h to align remote.h with the Hexagon SDK remote.h surface. Signed-off-by: Vinayak Katoch --- inc/fastrpc_common.h | 4 ++++ inc/remote.h | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/inc/fastrpc_common.h b/inc/fastrpc_common.h index 1d52afe..709f933 100644 --- a/inc/fastrpc_common.h +++ b/inc/fastrpc_common.h @@ -49,6 +49,10 @@ #define DOMAIN_NAME_IN_URI 1 // Domain name with standard module URI #define DOMAIN_NAME_STAND_ALONE 2 // Stand-alone domain name +/* GDSP domain IDs - internal use only, not part of Hexagon SDK remote.h */ +#define GDSP0_DOMAIN_ID 5 +#define GDSP1_DOMAIN_ID 6 + #define PROFILE(time_taken, ff) \ { \ struct timeval tv1, tv2; \ diff --git a/inc/remote.h b/inc/remote.h index 1fa3baa..4d4eb8f 100644 --- a/inc/remote.h +++ b/inc/remote.h @@ -122,8 +122,6 @@ extern "C" { #define SDSP_DOMAIN_ID 2 #define CDSP_DOMAIN_ID 3 #define CDSP1_DOMAIN_ID 4 -#define GDSP0_DOMAIN_ID 5 -#define GDSP1_DOMAIN_ID 6 /** Supported Domain Names */ #define ADSP_DOMAIN_NAME "adsp" From bdb462ac6c2e2884e23c43ae1faabb866c5b52e8 Mon Sep 17 00:00:00 2001 From: Anand Kulkarni Date: Wed, 22 Apr 2026 12:41:23 +0530 Subject: [PATCH 51/69] ci: Switch workflows to pull_request event Replace pull_request_target with pull_request in PR workflows to follow GitHub security practices and avoid elevated permissions during PR validation. Signed-off-by: Anand Kulkarni --- .github/workflows/pkg-build-pr-check.yml | 2 +- .github/workflows/pre_merge.yml | 2 +- .github/workflows/pull_request_check.yml | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pkg-build-pr-check.yml b/.github/workflows/pkg-build-pr-check.yml index 3963281..8c4a939 100644 --- a/.github/workflows/pkg-build-pr-check.yml +++ b/.github/workflows/pkg-build-pr-check.yml @@ -11,7 +11,7 @@ description: | a full build of the package if it were to include these changes. on: - pull_request_target: + pull_request: branches: [ main, development ] types: - ready_for_review diff --git a/.github/workflows/pre_merge.yml b/.github/workflows/pre_merge.yml index 15ec227..55908d5 100644 --- a/.github/workflows/pre_merge.yml +++ b/.github/workflows/pre_merge.yml @@ -15,7 +15,7 @@ on: - 'main' - 'development' workflow_dispatch: - pull_request_target: # requiring access to base repo + pull_request: # requiring access to base repo types: [opened, synchronize, reopened] branches: - 'main' diff --git a/.github/workflows/pull_request_check.yml b/.github/workflows/pull_request_check.yml index 398a690..34b7a51 100644 --- a/.github/workflows/pull_request_check.yml +++ b/.github/workflows/pull_request_check.yml @@ -1,6 +1,7 @@ name: Prevent pull request to main on: - pull_request_target: + pull_request: + branches: [ main ] types: - opened - reopened From e019c5bec2531a54c0eb14d0b03144ce53203a59 Mon Sep 17 00:00:00 2001 From: anankulk Date: Mon, 27 Apr 2026 11:01:46 +0530 Subject: [PATCH 52/69] Update pkg-build-pr-check.yml Remove unused secret TOKEN from workflow. Signed-off-by: anankulk --- .github/workflows/pkg-build-pr-check.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/pkg-build-pr-check.yml b/.github/workflows/pkg-build-pr-check.yml index 8c4a939..da56b95 100644 --- a/.github/workflows/pkg-build-pr-check.yml +++ b/.github/workflows/pkg-build-pr-check.yml @@ -35,5 +35,3 @@ jobs: upstream-repo-ref: ${{ github.event.pull_request.head.ref }} pkg-repo: ${{vars.PKG_REPO_GITHUB_NAME}} pr-number: ${{github.event.pull_request.number}} - secrets: - TOKEN: ${{ secrets.DEB_PKG_BOT_CI_TOKEN }} From f68b30a2e2731de916920f7ab56f3b88c917853d Mon Sep 17 00:00:00 2001 From: Jianping Li Date: Tue, 21 Apr 2026 14:27:58 +0800 Subject: [PATCH 53/69] fastrpc: fallback to fastrpc_mmap_internal for unsupported flags remote_mmap64_internal() currently uses the MMAP_64 ioctl for all mapping flags. However, MMAP_64 is only supported for specific use cases such as adding pages or mapping the remote heap. Update remote_mmap64_internal() to route only ADSP_MMAP_ADD_PAGES and ADSP_MMAP_REMOTE_HEAP_ADDR through the MMAP_64 ioctl. All other flags now fall back to fastrpc_mmap_internal(), which provides broader backend support. Because the use of fastrpc_mmap_internal has been moved inside remote_mmap64_internal, the application of fastrpc_mmap_internal in apps_mem_imp.c will be reverted. Signed-off-by: Jianping Li --- inc/fastrpc_mem.h | 7 +++++ src/apps_mem_imp.c | 42 +++++++++++-------------- src/fastrpc_mem.c | 76 ++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 99 insertions(+), 26 deletions(-) diff --git a/inc/fastrpc_mem.h b/inc/fastrpc_mem.h index 6508ca8..402f990 100644 --- a/inc/fastrpc_mem.h +++ b/inc/fastrpc_mem.h @@ -102,4 +102,11 @@ int fastrpc_mmap_internal(int domain, int fd, void *vaddr, int offset, size_t le */ int fastrpc_munmap_internal(int domain, uint64_t raddr, size_t length); +#define ADSP_MMAP_HEAP_ADDR 4 +#define ADSP_MMAP_REMOTE_HEAP_ADDR 8 +#define ADSP_MMAP_ADD_PAGES 0x1000 +#define ADSP_MMAP_ADD_PAGES_LLC 0x3000 +#define FASTRPC_ALLOC_HLOS_FD \ + 0x10000 /* Flag to allocate HLOS FD to be shared with DSP */ + #endif //FASTRPC_MEM_H diff --git a/src/apps_mem_imp.c b/src/apps_mem_imp.c index 7813bb3..41866d7 100644 --- a/src/apps_mem_imp.c +++ b/src/apps_mem_imp.c @@ -24,12 +24,6 @@ #include #include "fastrpc_hash_table.h" -#define ADSP_MMAP_HEAP_ADDR 4 -#define ADSP_MMAP_REMOTE_HEAP_ADDR 8 -#define ADSP_MMAP_ADD_PAGES 0x1000 -#define ADSP_MMAP_ADD_PAGES_LLC 0x3000 -#define FASTRPC_ALLOC_HLOS_FD \ - 0x10000 /* Flag to allocate HLOS FD to be shared with DSP */ typedef struct { QList mem_list; @@ -163,13 +157,23 @@ __QAIC_IMPL(apps_mem_request_map64)(int heapid, uint32_t lflags, uint32_t rflags */ *vadsp = (uint64_t)fd; } else { - VERIFYC(NULL != (buf = rpcmem_alloc_internal(heapid, lflags, len)), - AEE_ENORPCMEMORY); - fd = rpcmem_to_fd_internal(buf); - VERIFYC(fd > 0, AEE_EBADPARM); + /* Memory for unsignedPD's user-heap will be allocated in userspace for + * security reasons. Memory for signedPD's user-heap will be allocated in + * kernel. + */ + if (((rflags != ADSP_MMAP_ADD_PAGES) && + (rflags != ADSP_MMAP_ADD_PAGES_LLC)) || + (((rflags == ADSP_MMAP_ADD_PAGES) || + (rflags == ADSP_MMAP_ADD_PAGES_LLC)) && + (unsigned_module && ualloc_support))) { + VERIFYC(NULL != (buf = rpcmem_alloc_internal(heapid, lflags, len)), + AEE_ENORPCMEMORY); + fd = rpcmem_to_fd_internal(buf); + VERIFYC(fd > 0, AEE_EBADPARM); + } VERIFY(AEE_SUCCESS == - (nErr = fastrpc_mmap_internal(domain, fd, buf, 0, len, - rflags, vadsp))); + (nErr = remote_mmap64_internal(fd, rflags, (uint64_t)buf, len, + (uint64_t *)vadsp))); pbuf = (uint64_t)buf; *vapps = pbuf; minfo->vapps = *vapps; @@ -240,27 +244,17 @@ __QAIC_IMPL(apps_mem_request_unmap64)(uint64_t vadsp, pthread_mutex_unlock(&me->mem_mut); /* If apps_mem_request_map64 was called with flag FASTRPC_ALLOC_HLOS_FD, - * use fastrpc_munmap. For ADSP_MMAP_HEAP_ADDR and ADSP_MMAP_REMOTE_HEAP_ADDR, - * use remote_munmap64. For other cases, use fastrpc_munmap_internal. + * use fastrpc_munmap else use remote_munmap64 to unmap. */ if(mfree && mfree->rflags == FASTRPC_ALLOC_HLOS_FD) { fd = (int)vadsp; VERIFY(AEE_SUCCESS == (nErr = fastrpc_munmap(domain, fd, 0, len))); - } else if (mfree && (mfree->rflags == ADSP_MMAP_HEAP_ADDR || - mfree->rflags == ADSP_MMAP_REMOTE_HEAP_ADDR)) { - /* These cases use remote_mmap64_internal, so use remote_munmap64 */ - VERIFY(AEE_SUCCESS == (nErr = remote_munmap64((uint64_t)vadsp, len))); } else if (mfree || fastrpc_get_pd_type(domain) == AUDIO_STATICPD){ /* * Map info not available for Audio static PD after daemon reconnect, * So continue to unmap to avoid driver global maps leak. - * For other cases, use fastrpc_munmap_internal as they were mapped with fastrpc_mmap_internal. */ - if (mfree) { - VERIFY(AEE_SUCCESS == (nErr = fastrpc_munmap_internal(domain, (uint64_t)vadsp, len))); - } else { - VERIFY(AEE_SUCCESS == (nErr = remote_munmap64((uint64_t)vadsp, len))); - } + VERIFY(AEE_SUCCESS == (nErr = remote_munmap64((uint64_t)vadsp, len))); if (!mfree) goto bail; } diff --git a/src/fastrpc_mem.c b/src/fastrpc_mem.c index ab0616a..3b68850 100644 --- a/src/fastrpc_mem.c +++ b/src/fastrpc_mem.c @@ -110,6 +110,18 @@ struct static_map_list { pthread_mutex_t mut; }; +struct fastrpc_remote_map { + QNode qn; + uint64_t vadsp; + uint32_t flags; +}; + +struct fastrpc_remote_map_list { + QList ql; + pthread_mutex_t mut; +}; + +static struct fastrpc_remote_map_list memlist[NUM_DOMAINS_EXTEND]; static struct static_map_list smaplst[NUM_DOMAINS_EXTEND]; static struct mem_to_fd_list fdlist; static struct dma_handle_info dhandles[MAX_DMA_HANDLES]; @@ -128,6 +140,8 @@ int fastrpc_mem_init(void) { FOR_EACH_EFFECTIVE_DOMAIN_ID(ii) { QList_Ctor(&smaplst[ii].ql); pthread_mutex_init(&smaplst[ii].mut, 0); + QList_Ctor(&memlist[ii].ql); + pthread_mutex_init(&memlist[ii].mut, 0); } return 0; } @@ -138,10 +152,35 @@ int fastrpc_mem_deinit(void) { pthread_mutex_destroy(&fdlist.mut); FOR_EACH_EFFECTIVE_DOMAIN_ID(ii) { pthread_mutex_destroy(&smaplst[ii].mut); + pthread_mutex_destroy(&memlist[ii].mut); } return 0; } +static int fastrpc_remote_map_lookup(int domain, uint64_t vadsp, uint32_t *flags_out, struct fastrpc_remote_map **out) +{ + QNode *pn, *pnn; + struct fastrpc_remote_map *mNode; + + if (!flags_out || !out) + return AEE_EBADPARM; + + *out = NULL; + pthread_mutex_lock(&memlist[domain].mut); + QLIST_NEXTSAFE_FOR_ALL(&memlist[domain].ql, pn, pnn) { + mNode = STD_RECOVER_REC(struct fastrpc_remote_map, qn, pn); + if (mNode->vadsp == vadsp) { + *flags_out = mNode->flags; + *out = mNode; + QNode_DequeueZ(&mNode->qn); + pthread_mutex_unlock(&memlist[domain].mut); + return AEE_SUCCESS; + } + } + pthread_mutex_unlock(&memlist[domain].mut); + return AEE_ERESOURCENOTFOUND; +} + static void *remote_register_fd_attr(int fd, size_t size, int attr) { int nErr = AEE_SUCCESS; void *po = NULL; @@ -818,8 +857,22 @@ int remote_mmap64_internal(int fd, uint32_t flags, uint64_t vaddrin, FASTRPC_GET_REF(domain); VERIFY(AEE_SUCCESS == (nErr = fastrpc_session_dev(domain, &dev))); VERIFYM(-1 != dev, AEE_ERPC, "Invalid device\n"); - nErr = ioctl_mmap(dev, MMAP_64, flags, 0, fd, 0, size, vaddrin, &vaout); + if (flags == ADSP_MMAP_ADD_PAGES || flags == ADSP_MMAP_REMOTE_HEAP_ADDR) { + nErr = ioctl_mmap(dev, MMAP_64, flags, 0, fd, 0, size, vaddrin, &vaout); + } else { + VERIFY(AEE_SUCCESS == + (nErr = fastrpc_mmap_internal(domain, fd, (void *)(uintptr_t)vaddrin, 0, size, + flags, &vaout))); + } *vaddrout = vaout; + pthread_mutex_lock(&memlist[domain].mut); + struct fastrpc_remote_map *mNode = malloc(sizeof(*mNode)); + if (mNode) { + mNode->vadsp = vaout; + mNode->flags = flags; + QList_AppendNode(&memlist[domain].ql, &mNode->qn); + } + pthread_mutex_unlock(&memlist[domain].mut); bail: FASTRPC_PUT_REF(domain); if (nErr != AEE_SUCCESS) { @@ -874,6 +927,9 @@ int remote_mmap(int fd, uint32_t flags, uint32_t vaddrin, int size, int remote_munmap64(uint64_t vaddrout, int64_t size) { int dev, domain = DEFAULT_DOMAIN_ID, nErr = AEE_SUCCESS, ref = 0; + uint32_t rflags; + QNode *pn, *pnn; + struct fastrpc_remote_map *mNode = NULL; VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); @@ -883,7 +939,23 @@ int remote_munmap64(uint64_t vaddrout, int64_t size) { /* Don't open session in unmap. Return success if device already closed */ FASTRPC_GET_REF(domain); VERIFY(AEE_SUCCESS == (nErr = fastrpc_session_dev(domain, &dev))); - nErr = ioctl_munmap(dev, MUNMAP_64, 0, 0, -1, size, vaddrout); + + if (AEE_SUCCESS == fastrpc_remote_map_lookup(domain, vaddrout, &rflags, &mNode)) { + if (rflags == ADSP_MMAP_ADD_PAGES || rflags == ADSP_MMAP_REMOTE_HEAP_ADDR) { + nErr = ioctl_munmap(dev, MUNMAP_64, 0, 0, -1, size, vaddrout); + } else { + nErr = fastrpc_munmap_internal(domain, (uint64_t)vaddrout, size); + } + if (nErr == AEE_SUCCESS) { + free(mNode); + } else { + pthread_mutex_lock(&memlist[domain].mut); + QList_AppendNode(&memlist[domain].ql, &mNode->qn); + pthread_mutex_unlock(&memlist[domain].mut); + } + } else { + nErr = ioctl_munmap(dev, MUNMAP_64, 0, 0, -1, size, vaddrout); + } bail: FASTRPC_PUT_REF(domain); if (nErr != AEE_SUCCESS) { From e934a22c65a9ab11af30596a306366dbc6b78926 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Minier?= Date: Wed, 15 Apr 2026 23:41:21 +0200 Subject: [PATCH 54/69] Fix format string warnings for 64-bit integer types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use portable PRIx64 and PRId64 format specifiers from inttypes.h instead of %llx and %lld for uint64_t and int64_t types. This fixes compiler warnings on platforms where these types are defined as 'long' rather than 'long long'. Signed-off-by: Loïc Minier --- src/apps_mem_imp.c | 17 +++++++++-------- src/apps_std_imp.c | 4 ++-- src/fastrpc_apps_user.c | 4 ++-- src/fastrpc_mem.c | 28 ++++++++++++++-------------- src/listener_android.c | 5 +++-- 5 files changed, 30 insertions(+), 28 deletions(-) diff --git a/src/apps_mem_imp.c b/src/apps_mem_imp.c index 41866d7..09d58ba 100644 --- a/src/apps_mem_imp.c +++ b/src/apps_mem_imp.c @@ -17,6 +17,7 @@ #include "remote64.h" #include "rpcmem_internal.h" #include "verify.h" +#include #include #include #include @@ -122,8 +123,8 @@ __QAIC_IMPL(apps_mem_request_map64)(int heapid, uint32_t lflags, uint32_t rflags VERIFYC(me, AEE_ERESOURCENOTFOUND); VERIFY(AEE_SUCCESS == (nErr = get_unsigned_pd_attribute(domain, &unsigned_module))); - FASTRPC_ATRACE_BEGIN_L("%s called with rflag 0x%x, lflags 0x%x, len 0x%llx, " - "heapid %d and unsigned PD %d", + FASTRPC_ATRACE_BEGIN_L("%s called with rflag 0x%x, lflags 0x%x, " + "len 0x%" PRIx64 ", heapid %d and unsigned PD %d", __func__, rflags, lflags, len, heapid, unsigned_module); if (unsigned_module) { @@ -196,7 +197,7 @@ __QAIC_IMPL(apps_mem_request_map64)(int heapid, uint32_t lflags, uint32_t rflags minfo = NULL; } VERIFY_EPRINTF("Error 0x%x: apps_mem_request_mmap64 failed for fd 0x%x of " - "size %lld (lflags 0x%x, rflags 0x%x)\n", + "size %" PRId64 " (lflags 0x%x, rflags 0x%x)\n", nErr, fd, len, lflags, rflags); } FASTRPC_ATRACE_END(); @@ -228,8 +229,8 @@ __QAIC_IMPL(apps_mem_request_unmap64)(uint64_t vadsp, int domain = get_current_domain(); apps_mem_info *me = NULL; - FASTRPC_ATRACE_BEGIN_L("%s called with vadsp 0x%llx, len 0x%llx", __func__, - vadsp, len); + FASTRPC_ATRACE_BEGIN_L("%s called with vadsp 0x%" PRIx64 ", len 0x%" PRIx64, + __func__, vadsp, len); GET_HASH_NODE(apps_mem_info, domain, me); VERIFYC(me, AEE_ERESOURCENOTFOUND); @@ -275,8 +276,8 @@ __QAIC_IMPL(apps_mem_request_unmap64)(uint64_t vadsp, mfree = NULL; bail: if (nErr != AEE_SUCCESS) { - VERIFY_EPRINTF("Error 0x%x: apps_mem_request_unmap64 failed for size %lld " - "(vadsp 0x%llx)\n", + VERIFY_EPRINTF("Error 0x%x: apps_mem_request_unmap64 failed for size " + "%" PRId64 " (vadsp 0x%" PRIx64 ")\n", nErr, len, vadsp); } FASTRPC_ATRACE_END(); @@ -345,7 +346,7 @@ __QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_mem_share_unmap)(uint64_t vadsp, int siz nErr = apps_mem_request_unmap64(vadsp, len1); if (nErr != AEE_SUCCESS) { VERIFY_EPRINTF( - "Error 0x%x: apps_mem_share_unmap failed size %d (vadsp 0x%llx)\n", + "Error 0x%x: apps_mem_share_unmap failed size %d (vadsp 0x%" PRIx64 ")\n", nErr, size, vadsp); } return nErr; diff --git a/src/apps_std_imp.c b/src/apps_std_imp.c index 209eaac..53c477e 100644 --- a/src/apps_std_imp.c +++ b/src/apps_std_imp.c @@ -154,8 +154,8 @@ int apps_std_get_dirinfo(const apps_std_DIR *dir, } else { nErr = ESTALE; VERIFY_EPRINTF( - "Error 0x%x: %s: stale directory handle 0x%llx passed by DSP\n", nErr, - __func__, dir->handle); + "Error 0x%x: %s: stale directory handle 0x%" PRIx64 " passed by DSP\n", + nErr, __func__, dir->handle); goto bail; } bail: diff --git a/src/fastrpc_apps_user.c b/src/fastrpc_apps_user.c index f3531fd..bc63e01 100644 --- a/src/fastrpc_apps_user.c +++ b/src/fastrpc_apps_user.c @@ -3887,8 +3887,8 @@ static void exit_thread(void *value) { INVALID_HANDLE) { nErr = adsp_current_process1_thread_exit(handle); if (nErr) { - FARF(RUNTIME_RPC_HIGH, "%s: nErr:0x%x, dom:%d, h:0x%llx", __func__, nErr, - domain, handle); + FARF(RUNTIME_RPC_HIGH, "%s: nErr:0x%x, dom:%d, h:0x%" PRIx64, + __func__, nErr, domain, handle); } } else if (domain == DEFAULT_DOMAIN_ID) { nErr = adsp_current_process_thread_exit(); diff --git a/src/fastrpc_mem.c b/src/fastrpc_mem.c index 3b68850..e8efd1a 100644 --- a/src/fastrpc_mem.c +++ b/src/fastrpc_mem.c @@ -782,8 +782,8 @@ int remote_mem_map(int domain, int fd, int flags, uint64_t vaddr, size_t size, VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); FARF(RUNTIME_RPC_HIGH, - "%s: domain %d fd %d addr 0x%llx size 0x%zx flags 0x%x", __func__, - domain, fd, vaddr, size, flags); + "%s: domain %d fd %d addr 0x%" PRIx64 " size 0x%zx flags 0x%x", + __func__, domain, fd, vaddr, size, flags); VERIFYC(fd >= 0, AEE_EBADPARM); VERIFYC(size >= 0, AEE_EBADPARM); @@ -805,8 +805,8 @@ int remote_mem_map(int domain, int fd, int flags, uint64_t vaddr, size_t size, nErr = convert_kernel_to_user_error(nErr, errno); if (0 == check_rpc_error(nErr)) { FARF(ERROR, - "Error 0x%x: %s failed to map buffer fd %d addr 0x%llx size 0x%zx " - "domain %d flags %d errno %s", + "Error 0x%x: %s failed to map buffer fd %d addr 0x%" PRIx64 + " size 0x%zx domain %d flags %d errno %s", nErr, __func__, fd, vaddr, size, domain, flags, strerror(errno)); } } @@ -820,8 +820,8 @@ int remote_mem_unmap(int domain, uint64_t raddr, size_t size) { VERIFYC(size >= 0, AEE_EBADPARM); VERIFYC(raddr != 0, AEE_EBADPARM); - FARF(RUNTIME_RPC_HIGH, "%s: domain %d addr 0x%llx size 0x%zx", __func__, - domain, raddr, size); + FARF(RUNTIME_RPC_HIGH, "%s: domain %d addr 0x%" PRIx64 " size 0x%zx", + __func__, domain, raddr, size); if (domain == -1) { domain = get_current_domain(); } @@ -837,8 +837,8 @@ int remote_mem_unmap(int domain, uint64_t raddr, size_t size) { nErr = convert_kernel_to_user_error(nErr, errno); if (0 == check_rpc_error(nErr)) { FARF(ERROR, - "Error 0x%x: %s failed to unmap buffer addr 0x%llx size 0x%zx " - "domain %d errno %s", + "Error 0x%x: %s failed to unmap buffer addr 0x%" PRIx64 + " size 0x%zx domain %d errno %s", nErr, __func__, raddr, size, domain, strerror(errno)); } } @@ -878,8 +878,8 @@ int remote_mmap64_internal(int fd, uint32_t flags, uint64_t vaddrin, if (nErr != AEE_SUCCESS) { nErr = convert_kernel_to_user_error(nErr, errno); FARF(ERROR, - "Error 0x%x: %s failed for fd 0x%x of size %lld (flags 0x%x, vaddrin " - "0x%llx) errno %s\n", + "Error 0x%x: %s failed for fd 0x%x of size %" PRId64 " (flags 0x%x, " + "vaddrin 0x%" PRIx64 ") errno %s\n", nErr, __func__, fd, size, flags, vaddrin, strerror(errno)); } return nErr; @@ -905,8 +905,8 @@ int remote_mmap64(int fd, uint32_t flags, uint64_t vaddrin, int64_t size, bail: if ((nErr != AEE_SUCCESS) && (log == 1)) { FARF(ERROR, - "Error 0x%x: %s failed for fd 0x%x of size %lld (flags 0x%x, vaddrin " - "0x%llx)\n", + "Error 0x%x: %s failed for fd 0x%x of size %" PRId64 " (flags 0x%x, " + "vaddrin 0x%" PRIx64 ")\n", nErr, __func__, fd, size, flags, vaddrin); } return nErr; @@ -961,8 +961,8 @@ int remote_munmap64(uint64_t vaddrout, int64_t size) { if (nErr != AEE_SUCCESS) { nErr = convert_kernel_to_user_error(nErr, errno); FARF(ERROR, - "Error 0x%x: %s failed for size %lld (vaddrout 0x%llx) errno %s\n", - nErr, __func__, size, vaddrout, strerror(errno)); + "Error 0x%x: %s failed for size %" PRId64 " (vaddrout 0x%" PRIx64 ") " + "errno %s\n", nErr, __func__, size, vaddrout, strerror(errno)); } return nErr; } diff --git a/src/listener_android.c b/src/listener_android.c index 831d931..171329d 100644 --- a/src/listener_android.c +++ b/src/listener_android.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "AEEStdErr.h" #include "AEEstd.h" @@ -132,8 +133,8 @@ static void listener(listener_config *me) { memset(args, 0, sizeof(args)); if (eheap || eflags || emin) { FARF(RUNTIME_RPC_HIGH, - "listener using ion heap: %d flags: %x cache: %lld\n", (int)heapid, - (int)flags, cache_size); + "listener using ion heap: %d flags: %x cache: %" PRId64 "\n", + (int)heapid, (int)flags, cache_size); } do { From e19cb01b79223398e05f28fab766feff8cbe14ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Minier?= Date: Thu, 16 Apr 2026 00:03:07 +0200 Subject: [PATCH 55/69] Fix const qualifier warnings from fopen_from_dirlist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fopen_from_dirlist function was incorrectly modifying its const char* dirList parameter. Fix this by creating a local copy of the directory list, preserving the const contract with callers. Signed-off-by: Loïc Minier --- src/apps_std_imp.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/apps_std_imp.c b/src/apps_std_imp.c index 53c477e..536ea40 100644 --- a/src/apps_std_imp.c +++ b/src/apps_std_imp.c @@ -1008,19 +1008,24 @@ int fopen_from_dirlist(const char *dirList, const char *delim, const char *mode, const char *name, apps_std_FILE *psout) { int nErr = AEE_SUCCESS; char *absName = NULL, *dirName = NULL, *pos = NULL; + char *dirListCopy = NULL, *dirListPtr = NULL; uint16_t absNameLen = 0; int domain = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(get_current_domain()); VERIFYC(NULL != dirList, AEE_EBADPARM); - while (dirList) { - pos = strstr(dirList, delim); - dirName = dirList; + // Make a copy of dirList to avoid modifying caller's buffer + VERIFYC(NULL != (dirListCopy = strdup(dirList)), AEE_ENOMEMORY); + dirListPtr = dirListCopy; + + while (dirListPtr) { + pos = strstr(dirListPtr, delim); + dirName = dirListPtr; if (pos) { *pos = '\0'; - dirList = pos + strlen(delim); + dirListPtr = pos + strlen(delim); } else { - dirList = 0; + dirListPtr = 0; } // Append domain to path @@ -1043,6 +1048,7 @@ int fopen_from_dirlist(const char *dirList, const char *delim, // Success FARF(ALWAYS, "Successfully opened file %s", absName); FREEIF(absName); + FREEIF(dirListCopy); return nErr; } FREEIF(absName); @@ -1069,11 +1075,13 @@ int fopen_from_dirlist(const char *dirList, const char *delim, strlen(TESTSIG_FILE_NAME)) != 0)) FARF(ALWAYS, "Successfully opened file %s", name); FREEIF(absName); + FREEIF(dirListCopy); return nErr; } } bail: FREEIF(absName); + FREEIF(dirListCopy); return nErr; } From d7719a0251e95dd1e85536657128b1e81ec115f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Minier?= Date: Thu, 16 Apr 2026 00:12:07 +0200 Subject: [PATCH 56/69] Fix -Wrestrict warnings due to overlapping buffers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Eliminate warnings caused by the use of the same buffer as both source and destination in string operations. Changes: - fastrpc_apps_user.c: Replace strlcpy(pdName, pdName, len) with a direct null-termination to truncate string in place - mod_table.c: Replace snprintf(tmp, ..., tmp) with strlcat to append the "_system.so" suffix without buffer overlap Signed-off-by: Loïc Minier --- src/fastrpc_apps_user.c | 13 ++++++------- src/mod_table.c | 4 +++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/fastrpc_apps_user.c b/src/fastrpc_apps_user.c index bc63e01..c4458e0 100644 --- a/src/fastrpc_apps_user.c +++ b/src/fastrpc_apps_user.c @@ -1560,14 +1560,13 @@ int remote_handle_open_domain(int domain, const char *name, remote_handle *ph, */ if (strstr(pdName, get_domain_from_id(GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain))) && strstr(pdName, FASTRPC_SESSION_URI)) { - strlcpy(pdName, pdName, - (strlen(pdName) - - strlen(get_domain_from_id(GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain))) - - strlen(FASTRPC_SESSION1_URI) + 1)); + /* Truncate string in place by null-terminating at desired length */ + pdName[strlen(pdName) - + strlen(get_domain_from_id(GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain))) - + strlen(FASTRPC_SESSION1_URI)] = '\0'; } else if (strstr(pdName, get_domain_from_id(domain))) { - strlcpy( - pdName, pdName, - (strlen(pdName) - strlen(get_domain_from_id(domain)) + 1)); + /* Truncate string in place by null-terminating at desired length */ + pdName[strlen(pdName) - strlen(get_domain_from_id(domain))] = '\0'; } VERIFYC(MAX_DSPPD_NAMELEN > strlen(pdName), AEE_EBADPARM); strlcpy(hlist[domain].dsppdname, pdName, strlen(pdName) + 1); diff --git a/src/mod_table.c b/src/mod_table.c index d19fa90..d88468c 100644 --- a/src/mod_table.c +++ b/src/mod_table.c @@ -549,7 +549,9 @@ static int open_mod_table_open_dynamic(struct open_mod_table *me, break; } } - rv = snprintf(tmp, tmplen, "%s_system.so", tmp); + /* Append "_system.so" to base name (avoid overlapping buffers in snprintf) */ + strlcat(tmp, "_system.so", tmplen); + rv = strlen(tmp); VERIFYC((rv > 0) && (tmplen >= rv), AEE_EBADPARM); FARF(RUNTIME_RPC_HIGH, "calling dlopen for %s", tmp); dm->dlhandle = DLOPEN(tmp, RTLD_NOW); From c03a3cc48e32fec8ee10422e179edbddeba33d04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Minier?= Date: Thu, 16 Apr 2026 00:28:34 +0200 Subject: [PATCH 57/69] Fix unused label warnings in dsprpcd daemons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the "bail" label by replacing the goto with an early return as the unused label was causing warnings. Signed-off-by: Loïc Minier --- src/dsprpcd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/dsprpcd.c b/src/dsprpcd.c index 2e203b5..ef8bf75 100644 --- a/src/dsprpcd.c +++ b/src/dsprpcd.c @@ -150,7 +150,8 @@ int main(int argc, char *argv[]) { lib_unversioned = GDSP_LISTENER_UNVERSIONED; dsp_name = "GDSP"; #else - goto bail; + VERIFY_EPRINTF("daemon exiting %x (no DSP type defined)", nErr); + return nErr; #endif // Parse command-line options @@ -197,7 +198,6 @@ int main(int argc, char *argv[]) { usleep(100000); } - bail: - VERIFY_EPRINTF("daemon exiting %x", nErr); - return nErr; + VERIFY_EPRINTF("daemon exiting %x", nErr); + return nErr; } From 85d2b11dc5e480916c45fa534f60b69ff736458c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Minier?= Date: Thu, 16 Apr 2026 00:39:32 +0200 Subject: [PATCH 58/69] Fix GDSP library build configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove unused GDSP library variable definitions from Makefile.am that were causing automake warnings. GDSP daemon correctly shares the CDSP libraries rather than building separate GDSP-specific libraries. Add comments ahead of gdsp => cdsp usage to make it clear these are by design. Signed-off-by: Loïc Minier --- src/Makefile.am | 14 +------------- src/dsprpcd.c | 1 + 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 8470bf3..aef558f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -70,7 +70,6 @@ else libadsprpc_la_LIBADD = -ldl -lm $(USE_LOG) @YAML_LIBS@ @BSD_LIBS@ libcdsprpc_la_LIBADD = -ldl -lm $(USE_LOG) @YAML_LIBS@ @BSD_LIBS@ libsdsprpc_la_LIBADD = -ldl -lm $(USE_LOG) @YAML_LIBS@ @BSD_LIBS@ -libgdsprpc_la_LIBADD = -ldl -lm $(USE_LOG) @YAML_LIBS@ @BSD_LIBS@ endif ADSP_CFLAGS = $(LIBDSPRPC_CFLAGS) -DDEFAULT_DOMAIN_ID=0 @@ -112,17 +111,6 @@ libsdsp_default_listener_la_DEPENDENCIES = libsdsprpc.la libsdsp_default_listener_la_LDFLAGS = libsdsprpc.la -shared -module $(USE_LOG) -version-number @LT_VERSION_NUMBER@ libsdsp_default_listener_la_CFLAGS = $(SDSP_CFLAGS) -DUSE_SYSLOG -GDSP_CFLAGS = $(LIBDSPRPC_CFLAGS) -DDEFAULT_DOMAIN_ID=5 - -libgdsprpc_la_SOURCES = $(LIBDSPRPC_SOURCES) -libgdsprpc_la_LDFLAGS = -version-number @LT_VERSION_NUMBER@ -libgdsprpc_la_CFLAGS = $(GDSP_CFLAGS) - -libgdsp_default_listener_la_SOURCES = $(LIBDEFAULT_LISTENER_SOURCES) -libgdsp_default_listener_la_DEPENDENCIES = libcdsprpc.la -libgdsp_default_listener_la_LDFLAGS = libcdsprpc.la -shared -module $(USE_LOG) -version-number @LT_VERSION_NUMBER@ -libgdsp_default_listener_la_CFLAGS = $(GDSP_CFLAGS) -DUSE_SYSLOG - bin_PROGRAMS = adsprpcd cdsprpcd sdsprpcd gdsprpcd adsprpcddir = $(libdir) @@ -145,7 +133,7 @@ sdsprpcd_DEPENDENCIES = libsdsp_default_listener.la sdsprpcd_CFLAGS = -I$(top_srcdir)/inc -DDEFAULT_DOMAIN_ID=2 -DUSE_SYSLOG -DUSE_SDSP sdsprpcd_LDADD = -ldl $(USE_LOG) - +# GDSP daemon shares CDSP libraries (not a typo) gdsprpcddir = $(libdir) gdsprpcd_SOURCES = dsprpcd.c gdsprpcd_DEPENDENCIES = libcdsp_default_listener.la diff --git a/src/dsprpcd.c b/src/dsprpcd.c index ef8bf75..038c09a 100644 --- a/src/dsprpcd.c +++ b/src/dsprpcd.c @@ -28,6 +28,7 @@ #define SDSP_LISTENER_VERSIONED "libsdsp_default_listener.so.1" #define SDSP_LISTENER_UNVERSIONED "libsdsp_default_listener.so" #endif +/* GDSP uses CDSP libraries (not a typo) */ #ifndef GDSP_LISTENER_VERSIONED #define GDSP_LISTENER_VERSIONED "libcdsp_default_listener.so.1" #define GDSP_LISTENER_UNVERSIONED "libcdsp_default_listener.so" From 294d893897dafc3570724dc08cba16646de1d3bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Minier?= Date: Thu, 16 Apr 2026 01:00:05 +0200 Subject: [PATCH 59/69] Fix unused result warnings for trace marker writes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Handle return values from write() calls to ftrace trace_marker_fd to avoid warnings from -Wunused-result warnings. For the begin trace marker, check if the write succeeded before setting trace_enabled to ensure we only write the end marker if the begin marker was successfully written. For the end trace marker, capture the return value in an unused variable since this is in the cleanup code path. Signed-off-by: Loïc Minier --- src/fastrpc_apps_user.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/fastrpc_apps_user.c b/src/fastrpc_apps_user.c index c4458e0..e2e7aca 100644 --- a/src/fastrpc_apps_user.c +++ b/src/fastrpc_apps_user.c @@ -1170,8 +1170,11 @@ int remote_handle_invoke_domain(int domain, remote_handle handle, if (IS_QTF_TRACING_ENABLED(hlist[domain].procattrs) && !IS_STATIC_HANDLE(handle) && trace_marker_fd > 0) { - write(trace_marker_fd, INVOKE_BEGIN_TRACE_STR, invoke_begin_trace_strlen); - trace_enabled = true; + /* Write begin trace marker; only enable tracing if write succeeds. + * This ensures we don't attempt to write an end marker if begin failed. */ + ssize_t ret = write(trace_marker_fd, INVOKE_BEGIN_TRACE_STR, invoke_begin_trace_strlen); + if (ret > 0) + trace_enabled = true; } VERIFY(AEE_SUCCESS == (nErr = fastrpc_session_dev(domain, &dev))); @@ -1406,7 +1409,10 @@ int remote_handle_invoke_domain(int domain, remote_handle handle, } } if (trace_enabled) { - write(trace_marker_fd, INVOKE_END_TRACE_STR, invoke_end_trace_strlen); + /* Write end trace marker. Store return value to satisfy warn_unused_result, + * but don't check it since trace writes are optional and failures are non-critical. */ + ssize_t ret __attribute__((unused)); + ret = write(trace_marker_fd, INVOKE_END_TRACE_STR, invoke_end_trace_strlen); } if (nErr != AEE_SUCCESS) { if ((nErr == -1) && (errno == ECONNRESET)) { From 842506bf261a2cd3a7371f3847fdf54f90d9a4e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Minier?= Date: Thu, 16 Apr 2026 01:22:17 +0200 Subject: [PATCH 60/69] Add and use --enable-stricter configure flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add --enable-stricter configure flag to enable security hardening and strict warning flags based on Debian's dpkg-buildflags defaults. This helps compatibility with distros and allows detecting more issues during development. Use --enable-stricter in CI workflow to catch regressions early. Signed-off-by: Loïc Minier --- .github/workflows/build_linux_gnu.yml | 4 +- configure.ac | 73 +++++++++++++++++++++++++++ gitcompile | 8 ++- src/Makefile.am | 18 ++++--- 4 files changed, 91 insertions(+), 12 deletions(-) diff --git a/.github/workflows/build_linux_gnu.yml b/.github/workflows/build_linux_gnu.yml index 9be28cf..4ea4a2c 100644 --- a/.github/workflows/build_linux_gnu.yml +++ b/.github/workflows/build_linux_gnu.yml @@ -31,5 +31,5 @@ jobs: - name: Compile code for LE platform run: | - GITCOMPILE_NO_MAKE=true ./gitcompile - make distcheck DISTCHECK_CONFIGURE_FLAGS="--with-systemdsystemunitdir='lib/systemd/system'" + GITCOMPILE_NO_MAKE=true ./gitcompile --enable-stricter + make distcheck DISTCHECK_CONFIGURE_FLAGS="--with-systemdsystemunitdir='lib/systemd/system' --enable-stricter" diff --git a/configure.ac b/configure.ac index 886ce92..884c790 100644 --- a/configure.ac +++ b/configure.ac @@ -80,6 +80,79 @@ AC_ARG_WITH([config-base-dir], AC_MSG_NOTICE([Config base path: $config_base_dir]) AC_SUBST([CONFIG_BASE_DIR], ["$config_base_dir"]) +# Enable stricter compiler flags +# These are based on Debian's dpkg-buildflags defaults for compatibility with +# distro builds and to catch issues during development +AC_ARG_ENABLE([stricter], + [AS_HELP_STRING([--enable-stricter], + [Enable stricter compiler flags (warnings, stack protection, fortify source, RELRO)])], + [enable_stricter=$enableval], + [enable_stricter=no]) + +# Helper macro to test if compiler accepts a flag +AC_DEFUN([CC_CHECK_FLAG], [ + AC_MSG_CHECKING([if $CC supports $1]) + saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $1" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])], + [AC_MSG_RESULT([yes]); $2], + [AC_MSG_RESULT([no]); $3]) + CFLAGS="$saved_CFLAGS" +]) + +# Helper macro to test if linker accepts a flag +AC_DEFUN([LD_CHECK_FLAG], [ + AC_MSG_CHECKING([if linker supports $1]) + saved_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $1" + AC_LINK_IFELSE([AC_LANG_PROGRAM([])], + [AC_MSG_RESULT([yes]); $2], + [AC_MSG_RESULT([no]); $3]) + LDFLAGS="$saved_LDFLAGS" +]) + +# Set up hardening flags +STRICTER_CFLAGS="" +STRICTER_CPPFLAGS="" +STRICTER_LDFLAGS="" +AS_IF([test "x$enable_stricter" = "xyes"], [ + # Format string security warnings + STRICTER_CFLAGS="-Wformat -Werror=format-security -Werror=implicit-function-declaration" + + # Stack protection + CC_CHECK_FLAG([-fstack-protector-strong], + [STRICTER_CFLAGS="$STRICTER_CFLAGS -fstack-protector-strong"]) + CC_CHECK_FLAG([-fstack-clash-protection], + [STRICTER_CFLAGS="$STRICTER_CFLAGS -fstack-clash-protection"]) + + # Architecture-specific hardening + AS_CASE([$host_cpu], + [aarch64], [ + CC_CHECK_FLAG([-mbranch-protection=standard], + [STRICTER_CFLAGS="$STRICTER_CFLAGS -mbranch-protection=standard"]) + ], + [] + ) + + # FORTIFY_SOURCE and reproducible builds + STRICTER_CPPFLAGS="-D_FORTIFY_SOURCE=2 -Wdate-time" + + # RELRO - read-only relocations + LD_CHECK_FLAG([-Wl,-z,relro], + [STRICTER_LDFLAGS="-Wl,-z,relro"]) + + AC_MSG_NOTICE([Stricter compiler flags enabled)]) + AC_MSG_NOTICE([ STRICTER_CFLAGS: $STRICTER_CFLAGS]) + AC_MSG_NOTICE([ STRICTER_CPPFLAGS: $STRICTER_CPPFLAGS]) + AC_MSG_NOTICE([ STRICTER_LDFLAGS: $STRICTER_LDFLAGS]) +], [ + AC_MSG_NOTICE([Stricter compiler flags disabled (use --enable-stricter to enable)]) +]) +AC_SUBST([STRICTER_CFLAGS]) +AC_SUBST([STRICTER_CPPFLAGS]) +AC_SUBST([STRICTER_LDFLAGS]) + + AC_CONFIG_FILES([ Makefile inc/Makefile diff --git a/gitcompile b/gitcompile index 4f8f7d2..3fb6d76 100755 --- a/gitcompile +++ b/gitcompile @@ -2,11 +2,15 @@ autoreconf -is -export CFLAGS='-O2 -Wall -pipe -g' +# Set default build flags if not already set +# Users can override by setting CFLAGS before running this script +if [ -z "$CFLAGS" ]; then + export CFLAGS="-O2 -Wall -pipe -g" +fi + echo "CFLAGS=$CFLAGS" echo "./configure $@" ./configure $@ || exit 1 -unset CFLAGS if [ -z "$GITCOMPILE_NO_MAKE" ]; then make fi diff --git a/src/Makefile.am b/src/Makefile.am index aef558f..06f5b9d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,8 @@ lib_LTLIBRARIES = -LIBDSPRPC_CFLAGS = -fno-short-enums -U_DEBUG -DARM_ARCH_7A -DLE_ENABLE -DENABLE_UPSTREAM_DRIVER_INTERFACE -DUSE_SYSLOG -DCONFIG_BASE_DIR='"$(CONFIG_BASE_DIR)"' -DMACHINE_NAME_PATH='"/sys/firmware/devicetree/base/model"' -I$(top_srcdir)/inc +LIBDSPRPC_CFLAGS = -fno-short-enums -U_DEBUG -DARM_ARCH_7A -DLE_ENABLE -DENABLE_UPSTREAM_DRIVER_INTERFACE -DUSE_SYSLOG -DCONFIG_BASE_DIR='"$(CONFIG_BASE_DIR)"' -DMACHINE_NAME_PATH='"/sys/firmware/devicetree/base/model"' -I$(top_srcdir)/inc @STRICTER_CFLAGS@ @STRICTER_CPPFLAGS@ + +LIBDSPRPC_LDFLAGS = @STRICTER_LDFLAGS@ if ANDROID_CC LIBDSPRPC_CFLAGS += -DDEFAULT_DSP_SEARCH_PATHS='";/vendor/lib/rfsa/adsp;/vendor/dsp;"' @@ -76,39 +78,39 @@ ADSP_CFLAGS = $(LIBDSPRPC_CFLAGS) -DDEFAULT_DOMAIN_ID=0 lib_LTLIBRARIES += libadsprpc.la libadsprpc_la_SOURCES = $(LIBDSPRPC_SOURCES) -libadsprpc_la_LDFLAGS = -version-number @LT_VERSION_NUMBER@ +libadsprpc_la_LDFLAGS = -version-number @LT_VERSION_NUMBER@ $(LIBDSPRPC_LDFLAGS) libadsprpc_la_CFLAGS = $(ADSP_CFLAGS) lib_LTLIBRARIES += libadsp_default_listener.la libadsp_default_listener_la_SOURCES = $(LIBDEFAULT_LISTENER_SOURCES) libadsp_default_listener_la_DEPENDENCIES = libadsprpc.la -libadsp_default_listener_la_LDFLAGS = libadsprpc.la -shared -module $(USE_LOG) -version-number @LT_VERSION_NUMBER@ +libadsp_default_listener_la_LDFLAGS = libadsprpc.la -shared -module $(USE_LOG) -version-number @LT_VERSION_NUMBER@ $(LIBDSPRPC_LDFLAGS) libadsp_default_listener_la_CFLAGS = $(ADSP_CFLAGS) -DUSE_SYSLOG CDSP_CFLAGS = $(LIBDSPRPC_CFLAGS) -DDEFAULT_DOMAIN_ID=3 lib_LTLIBRARIES += libcdsprpc.la libcdsprpc_la_SOURCES = $(LIBDSPRPC_SOURCES) -libcdsprpc_la_LDFLAGS = -version-number @LT_VERSION_NUMBER@ +libcdsprpc_la_LDFLAGS = -version-number @LT_VERSION_NUMBER@ $(LIBDSPRPC_LDFLAGS) libcdsprpc_la_CFLAGS = $(CDSP_CFLAGS) lib_LTLIBRARIES += libcdsp_default_listener.la libcdsp_default_listener_la_SOURCES = $(LIBDEFAULT_LISTENER_SOURCES) libcdsp_default_listener_la_DEPENDENCIES = libcdsprpc.la -libcdsp_default_listener_la_LDFLAGS = libcdsprpc.la -shared -module $(USE_LOG) -version-number @LT_VERSION_NUMBER@ +libcdsp_default_listener_la_LDFLAGS = libcdsprpc.la -shared -module $(USE_LOG) -version-number @LT_VERSION_NUMBER@ $(LIBDSPRPC_LDFLAGS) libcdsp_default_listener_la_CFLAGS = $(CDSP_CFLAGS) -DUSE_SYSLOG SDSP_CFLAGS = $(LIBDSPRPC_CFLAGS) -DDEFAULT_DOMAIN_ID=2 lib_LTLIBRARIES += libsdsprpc.la libsdsprpc_la_SOURCES = $(LIBDSPRPC_SOURCES) -libsdsprpc_la_LDFLAGS = -version-number @LT_VERSION_NUMBER@ +libsdsprpc_la_LDFLAGS = -version-number @LT_VERSION_NUMBER@ $(LIBDSPRPC_LDFLAGS) libsdsprpc_la_CFLAGS = $(SDSP_CFLAGS) lib_LTLIBRARIES += libsdsp_default_listener.la libsdsp_default_listener_la_SOURCES = $(LIBDEFAULT_LISTENER_SOURCES) libsdsp_default_listener_la_DEPENDENCIES = libsdsprpc.la -libsdsp_default_listener_la_LDFLAGS = libsdsprpc.la -shared -module $(USE_LOG) -version-number @LT_VERSION_NUMBER@ +libsdsp_default_listener_la_LDFLAGS = libsdsprpc.la -shared -module $(USE_LOG) -version-number @LT_VERSION_NUMBER@ $(LIBDSPRPC_LDFLAGS) libsdsp_default_listener_la_CFLAGS = $(SDSP_CFLAGS) -DUSE_SYSLOG bin_PROGRAMS = adsprpcd cdsprpcd sdsprpcd gdsprpcd @@ -138,4 +140,4 @@ gdsprpcddir = $(libdir) gdsprpcd_SOURCES = dsprpcd.c gdsprpcd_DEPENDENCIES = libcdsp_default_listener.la gdsprpcd_CFLAGS = -I$(top_srcdir)/inc -DDEFAULT_DOMAIN_ID=5 -DUSE_SYSLOG -DUSE_GDSP -gdsprpcd_LDADD = -ldl $(USE_LOG) \ No newline at end of file +gdsprpcd_LDADD = -ldl $(USE_LOG) From a04f6e41d38d7678e92578fb9da5eacf52bea87f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Minier?= Date: Thu, 7 May 2026 13:56:24 +0200 Subject: [PATCH 61/69] fix: remove unused variables in remote_munmap64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove unused 'pn' and 'pnn' variables that were declared but never used in the remote_munmap64 function as part of f68b30a; fixes build warning. Signed-off-by: Loïc Minier --- src/fastrpc_mem.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/fastrpc_mem.c b/src/fastrpc_mem.c index e8efd1a..bdab811 100644 --- a/src/fastrpc_mem.c +++ b/src/fastrpc_mem.c @@ -928,7 +928,6 @@ int remote_mmap(int fd, uint32_t flags, uint32_t vaddrin, int size, int remote_munmap64(uint64_t vaddrout, int64_t size) { int dev, domain = DEFAULT_DOMAIN_ID, nErr = AEE_SUCCESS, ref = 0; uint32_t rflags; - QNode *pn, *pnn; struct fastrpc_remote_map *mNode = NULL; VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); From 9d29f41737a3ad8894d7f3dae27a9ba612159645 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Minier?= Date: Thu, 16 Apr 2026 17:18:18 +0200 Subject: [PATCH 62/69] files: fix device unit names in After= dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit systemd derives unit names from device paths by replacing each '/' with '-' and escaping any literal '-' in the path as '\x2d'. So for /dev/fastrpc-* nodes the correct device unit name for e.g. /dev/fastrpc-adsp is dev-fastrpc\x2dadsp.device, not dev-fastrpc-adsp.device (which would refer to /dev/fastrpc/adsp). Fix all seven service files accordingly. Without this the After= ordering constraints were silently ignored. Signed-off-by: Loïc Minier --- files/adsprpcd.service | 2 +- files/adsprpcd_audiopd.service | 2 +- files/cdsp1rpcd.service | 2 +- files/cdsprpcd.service | 2 +- files/gdsp0rpcd.service | 2 +- files/gdsp1rpcd.service | 2 +- files/sdsprpcd.service | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/files/adsprpcd.service b/files/adsprpcd.service index ac9c987..773d4b2 100644 --- a/files/adsprpcd.service +++ b/files/adsprpcd.service @@ -1,6 +1,6 @@ [Unit] Description=aDSP RPC daemon -After=dev-fastrpc-adsp.device dev-fastrpc-adsp-secure.device +After=dev-fastrpc\x2dadsp.device dev-fastrpc\x2dadsp\x2dsecure.device ConditionPathExists=|/dev/fastrpc-adsp ConditionPathExists=|/dev/fastrpc-adsp-secure diff --git a/files/adsprpcd_audiopd.service b/files/adsprpcd_audiopd.service index 99bdf1a..c95b436 100644 --- a/files/adsprpcd_audiopd.service +++ b/files/adsprpcd_audiopd.service @@ -1,6 +1,6 @@ [Unit] Description=audiopd aDSP RPC daemon -After=dev-fastrpc-adsp.device dev-fastrpc-adsp-secure.device +After=dev-fastrpc\x2dadsp.device dev-fastrpc\x2dadsp\x2dsecure.device ConditionPathExists=|/dev/fastrpc-adsp ConditionPathExists=|/dev/fastrpc-adsp-secure diff --git a/files/cdsp1rpcd.service b/files/cdsp1rpcd.service index b0fc1ef..2049a13 100644 --- a/files/cdsp1rpcd.service +++ b/files/cdsp1rpcd.service @@ -1,6 +1,6 @@ [Unit] Description=cDSP RPC daemon -After=dev-fastrpc-cdsp1.device dev-fastrpc-cdsp1-secure.device +After=dev-fastrpc\x2dcdsp1.device dev-fastrpc\x2dcdsp1\x2dsecure.device ConditionPathExists=|/dev/fastrpc-cdsp1 ConditionPathExists=|/dev/fastrpc-cdsp1-secure diff --git a/files/cdsprpcd.service b/files/cdsprpcd.service index ae597c8..53aebd0 100644 --- a/files/cdsprpcd.service +++ b/files/cdsprpcd.service @@ -1,6 +1,6 @@ [Unit] Description=cDSP RPC daemon -After=dev-fastrpc-cdsp.device dev-fastrpc-cdsp-secure.device +After=dev-fastrpc\x2dcdsp.device dev-fastrpc\x2dcdsp\x2dsecure.device ConditionPathExists=|/dev/fastrpc-cdsp ConditionPathExists=|/dev/fastrpc-cdsp-secure diff --git a/files/gdsp0rpcd.service b/files/gdsp0rpcd.service index 259eaf2..163aa01 100644 --- a/files/gdsp0rpcd.service +++ b/files/gdsp0rpcd.service @@ -1,6 +1,6 @@ [Unit] Description=gDSP RPC daemon -After=dev-fastrpc-gdsp0.device dev-fastrpc-gdsp0-secure.device +After=dev-fastrpc\x2dgdsp0.device dev-fastrpc\x2dgdsp0\x2dsecure.device ConditionPathExists=|/dev/fastrpc-gdsp0 ConditionPathExists=|/dev/fastrpc-gdsp0-secure diff --git a/files/gdsp1rpcd.service b/files/gdsp1rpcd.service index e442bab..7c61abf 100644 --- a/files/gdsp1rpcd.service +++ b/files/gdsp1rpcd.service @@ -1,6 +1,6 @@ [Unit] Description=gDSP RPC daemon -After=dev-fastrpc-gdsp1.device dev-fastrpc-gdsp1-secure.device +After=dev-fastrpc\x2dgdsp1.device dev-fastrpc\x2dgdsp1\x2dsecure.device ConditionPathExists=|/dev/fastrpc-gdsp1 ConditionPathExists=|/dev/fastrpc-gdsp1-secure diff --git a/files/sdsprpcd.service b/files/sdsprpcd.service index 1586d75..1f27374 100644 --- a/files/sdsprpcd.service +++ b/files/sdsprpcd.service @@ -1,6 +1,6 @@ [Unit] Description=sDSP RPC daemon -After=dev-fastrpc-sdsp.device dev-fastrpc-sdsp-secure.device +After=dev-fastrpc\x2dsdsp.device dev-fastrpc\x2dsdsp\x2dsecure.device ConditionPathExists=|/dev/fastrpc-sdsp ConditionPathExists=|/dev/fastrpc-sdsp-secure From 9bc91f7da41f97d57d0dc4f69e6c18133bd6b52d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Minier?= Date: Thu, 16 Apr 2026 17:30:36 +0200 Subject: [PATCH 63/69] files: add udev rules and fastrpc group MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set up udev rules to enable FastRPC access through the fastrpc group. Non-secure device nodes use root:fastrpc ownership and 0660 permissions to allow daemon and client access without root. Leave secure device nodes unchanged to preserve default ownership and permissions. Changes to secure node handling will be addressed separately. Set SYSTEMD_WANTS for device-triggered daemon start and add audiopd service trigger for ADSP devices. Add configure support for installing udev rules and sysusers configuration to create the fastrpc group. Document user/group requirements in README.md. Signed-off-by: Loïc Minier Signed-off-by: Ekansh Gupta --- README.md | 31 +++++++++++++++++++++++++++++++ configure.ac | 24 +++++++++++++++++++++--- files/60-fastrpc.rules | 19 +++++++++++++++++++ files/Makefile.am | 8 ++++++++ files/fastrpc.conf | 5 +++++ 5 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 files/60-fastrpc.rules create mode 100644 files/fastrpc.conf diff --git a/README.md b/README.md index 167a962..e5857a4 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,35 @@ Hexagon SDK documentation covers all the required details about FastRPC. Please ## Build & Installation +### Setting up the fastrpc group + +The udev rules set `/dev/fastrpc-*dsp` device nodes to `root:fastrpc` with `0640` permissions and +grant the `fastrpc` group read/write access to `/dev/dma_heap/system` (required for memory allocation). +Applications that use `libfastrpc` must therefore belong to the `fastrpc` group. + +The build system installs a `sysusers.d` configuration file that automatically creates the `fastrpc` group when `systemd-sysusers` runs (typically at boot or via package manager triggers). + +To manually create the group: + +```bash +groupadd --system fastrpc +``` + +Or trigger systemd-sysusers: + +```bash +sudo systemd-sysusers +``` + +To grant an application user access to FastRPC devices: + +```bash +usermod -aG fastrpc +``` + +The services are automatically started by udev when FastRPC devices are detected. +No manual `systemctl enable` is required. + ### Steps to Generate Native Binaries on Device ```bash @@ -142,6 +171,8 @@ git clone https://github.com/quic/fastrpc cd fastrpc ./gitcompile sudo make install +sudo ldconfig # Update dynamic linker cache +sudo systemd-sysusers # Create fastrpc group ``` ### Steps to cross-compile the project on Ubuntu diff --git a/configure.ac b/configure.ac index 884c790..e739629 100644 --- a/configure.ac +++ b/configure.ac @@ -48,13 +48,31 @@ AC_ARG_WITH([systemdsystemunitdir], AC_MSG_NOTICE([systemd unit directory: $systemdsystemunitdir]) AC_SUBST([systemdsystemunitdir]) +# Enable pkg-config +PKG_PROG_PKG_CONFIG + +# Configure udev rules directory option (--with-udevrulesdir) +AC_ARG_WITH([udevrulesdir], + [AS_HELP_STRING([--with-udevrulesdir=DIR], + [Directory for udev rules files (default: /lib/udev/rules.d)])], + [udevrulesdir="$withval"], + [PKG_CHECK_VAR([udevdir], [udev], [udevdir], [udevrulesdir="${udevdir}/rules.d"], [udevrulesdir="/lib/udev/rules.d"])]) +AC_MSG_NOTICE([udev rules directory: $udevrulesdir]) +AC_SUBST([udevrulesdir]) + +# Configure sysusers directory option (--with-sysusersdir) +AC_ARG_WITH([sysusersdir], + [AS_HELP_STRING([--with-sysusersdir=DIR], + [Directory for systemd sysusers files (default: /usr/lib/sysusers.d)])], + [sysusersdir="$withval"], + [PKG_CHECK_VAR([sysusersdir], [systemd], [sysusersdir], [], [sysusersdir="/usr/lib/sysusers.d"])]) +AC_MSG_NOTICE([sysusers directory: $sysusersdir]) +AC_SUBST([sysusersdir]) + # Checks for typedefs, structures, and compiler characteristics. # Checks for library functions. -# Enable pkg-config -PKG_PROG_PKG_CONFIG - # Check for libyaml only if not Android AS_IF([test "$compile_for_android" = no], [ PKG_CHECK_MODULES([YAML], [yaml-0.1], [], diff --git a/files/60-fastrpc.rules b/files/60-fastrpc.rules new file mode 100644 index 0000000..546de35 --- /dev/null +++ b/files/60-fastrpc.rules @@ -0,0 +1,19 @@ +# Applications that use libfastrpc must belong to the fastrpc group + +# DMA heap access required for fastrpc +ACTION=="add", SUBSYSTEM=="dma_heap", KERNEL=="system", RUN+="/bin/setfacl -m g:fastrpc:rw $env{DEVNAME}" + +# FastRPC DSP device nodes +# Device nodes are owned by root:fastrpc with 0640 permissions +ACTION=="add", SUBSYSTEM=="misc", KERNEL=="fastrpc-adsp", OWNER="root", GROUP="fastrpc", MODE="0640", TAG+="systemd", ENV{SYSTEMD_WANTS}+="adsprpcd.service", ENV{SYSTEMD_WANTS}+="adsprpcd_audiopd.service" +ACTION=="add", SUBSYSTEM=="misc", KERNEL=="fastrpc-adsp-secure", TAG+="systemd", ENV{SYSTEMD_WANTS}+="adsprpcd.service", ENV{SYSTEMD_WANTS}+="adsprpcd_audiopd.service" +ACTION=="add", SUBSYSTEM=="misc", KERNEL=="fastrpc-cdsp", OWNER="root", GROUP="fastrpc", MODE="0640", TAG+="systemd", ENV{SYSTEMD_WANTS}+="cdsprpcd.service" +ACTION=="add", SUBSYSTEM=="misc", KERNEL=="fastrpc-cdsp-secure", TAG+="systemd", ENV{SYSTEMD_WANTS}+="cdsprpcd.service" +ACTION=="add", SUBSYSTEM=="misc", KERNEL=="fastrpc-cdsp1", OWNER="root", GROUP="fastrpc", MODE="0640", TAG+="systemd", ENV{SYSTEMD_WANTS}+="cdsp1rpcd.service" +ACTION=="add", SUBSYSTEM=="misc", KERNEL=="fastrpc-cdsp1-secure", TAG+="systemd", ENV{SYSTEMD_WANTS}+="cdsp1rpcd.service" +ACTION=="add", SUBSYSTEM=="misc", KERNEL=="fastrpc-gdsp0", OWNER="root", GROUP="fastrpc", MODE="0640", TAG+="systemd", ENV{SYSTEMD_WANTS}+="gdsp0rpcd.service" +ACTION=="add", SUBSYSTEM=="misc", KERNEL=="fastrpc-gdsp0-secure", TAG+="systemd", ENV{SYSTEMD_WANTS}+="gdsp0rpcd.service" +ACTION=="add", SUBSYSTEM=="misc", KERNEL=="fastrpc-gdsp1", OWNER="root", GROUP="fastrpc", MODE="0640", TAG+="systemd", ENV{SYSTEMD_WANTS}+="gdsp1rpcd.service" +ACTION=="add", SUBSYSTEM=="misc", KERNEL=="fastrpc-gdsp1-secure", TAG+="systemd", ENV{SYSTEMD_WANTS}+="gdsp1rpcd.service" +ACTION=="add", SUBSYSTEM=="misc", KERNEL=="fastrpc-sdsp", OWNER="root", GROUP="fastrpc", MODE="0640", TAG+="systemd", ENV{SYSTEMD_WANTS}+="sdsprpcd.service" +ACTION=="add", SUBSYSTEM=="misc", KERNEL=="fastrpc-sdsp-secure", TAG+="systemd", ENV{SYSTEMD_WANTS}+="sdsprpcd.service" diff --git a/files/Makefile.am b/files/Makefile.am index 5bf1307..9de1b45 100644 --- a/files/Makefile.am +++ b/files/Makefile.am @@ -12,3 +12,11 @@ dist_systemdsystemunit_DATA = \ gdsp0rpcd.service \ gdsp1rpcd.service \ sdsprpcd.service + +# sysusers.d file for creating fastrpc group +sysusersdir = @sysusersdir@ +dist_sysusers_DATA = fastrpc.conf + +# udev rules +udevrulesdir = @udevrulesdir@ +dist_udevrules_DATA = 60-fastrpc.rules diff --git a/files/fastrpc.conf b/files/fastrpc.conf new file mode 100644 index 0000000..c55042a --- /dev/null +++ b/files/fastrpc.conf @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: BSD-3-Clause +# This file is part of fastrpc. It creates the fastrpc system group. +# +#Type Name ID GECOS Home directory Shell +g fastrpc - - - - From 29c6ec6d339479c4a152b949a064416f107c6d8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Minier?= Date: Sat, 9 May 2026 15:56:51 +0200 Subject: [PATCH 64/69] files: Drop WantedBy=multi-user.target MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Services are automatically started when device nodes appear, so attempting to starting services again on multi-user.target will not do anything since these depend on the device nodes being present and either won't start or would have already started. Signed-off-by: Loïc Minier --- files/adsprpcd.service | 3 --- files/adsprpcd_audiopd.service | 3 --- files/cdsp1rpcd.service | 3 --- files/cdsprpcd.service | 3 --- files/gdsp0rpcd.service | 3 --- files/gdsp1rpcd.service | 3 --- files/sdsprpcd.service | 3 --- 7 files changed, 21 deletions(-) diff --git a/files/adsprpcd.service b/files/adsprpcd.service index 773d4b2..f0671e0 100644 --- a/files/adsprpcd.service +++ b/files/adsprpcd.service @@ -9,6 +9,3 @@ Type=exec ExecStart=/usr/bin/adsprpcd Restart=on-failure RestartSec=5 - -[Install] -WantedBy=multi-user.target diff --git a/files/adsprpcd_audiopd.service b/files/adsprpcd_audiopd.service index c95b436..5b230b6 100644 --- a/files/adsprpcd_audiopd.service +++ b/files/adsprpcd_audiopd.service @@ -9,6 +9,3 @@ Type=exec ExecStart=/usr/bin/adsprpcd audiopd Restart=on-failure RestartSec=5 - -[Install] -WantedBy=multi-user.target diff --git a/files/cdsp1rpcd.service b/files/cdsp1rpcd.service index 2049a13..edf4769 100644 --- a/files/cdsp1rpcd.service +++ b/files/cdsp1rpcd.service @@ -9,6 +9,3 @@ Type=exec ExecStart=/usr/bin/cdsprpcd rootpd cdsp1 Restart=on-failure RestartSec=5 - -[Install] -WantedBy=multi-user.target diff --git a/files/cdsprpcd.service b/files/cdsprpcd.service index 53aebd0..bcbd234 100644 --- a/files/cdsprpcd.service +++ b/files/cdsprpcd.service @@ -9,6 +9,3 @@ Type=exec ExecStart=/usr/bin/cdsprpcd Restart=on-failure RestartSec=5 - -[Install] -WantedBy=multi-user.target diff --git a/files/gdsp0rpcd.service b/files/gdsp0rpcd.service index 163aa01..6449042 100644 --- a/files/gdsp0rpcd.service +++ b/files/gdsp0rpcd.service @@ -9,6 +9,3 @@ Type=exec ExecStart=/usr/bin/gdsprpcd rootpd gdsp0 Restart=on-failure RestartSec=5 - -[Install] -WantedBy=multi-user.target diff --git a/files/gdsp1rpcd.service b/files/gdsp1rpcd.service index 7c61abf..91d74a5 100644 --- a/files/gdsp1rpcd.service +++ b/files/gdsp1rpcd.service @@ -9,6 +9,3 @@ Type=exec ExecStart=/usr/bin/gdsprpcd rootpd gdsp1 Restart=on-failure RestartSec=5 - -[Install] -WantedBy=multi-user.target diff --git a/files/sdsprpcd.service b/files/sdsprpcd.service index 1f27374..2184729 100644 --- a/files/sdsprpcd.service +++ b/files/sdsprpcd.service @@ -9,6 +9,3 @@ Type=exec ExecStart=/usr/bin/sdsprpcd Restart=on-failure RestartSec=5 - -[Install] -WantedBy=multi-user.target From 27871595358da2ac8527651e0fdade7d97245e9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Minier?= Date: Sat, 9 May 2026 16:44:17 +0200 Subject: [PATCH 65/69] configure: Auto-detect systemd system unit dir MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use PKG_CHECK_VAR to query systemd.pc for the installation directory for systemd system unit files. Signed-off-by: Loïc Minier --- configure.ac | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index e739629..d7108e7 100644 --- a/configure.ac +++ b/configure.ac @@ -39,18 +39,18 @@ AM_PROG_CC_C_O # Checks for libraries. +# Enable pkg-config +PKG_PROG_PKG_CONFIG + # Configure systemd unit directory option (--with-systemdsystemunitdir) AC_ARG_WITH([systemdsystemunitdir], [AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files (default: /lib/systemd/system)])], [systemdsystemunitdir="$withval"], - [systemdsystemunitdir="/lib/systemd/system"]) + [PKG_CHECK_VAR([systemdsystemunitdir], [systemd], [systemdsystemunitdir], [], [systemdsystemunitdir="/lib/systemd/system"])]) AC_MSG_NOTICE([systemd unit directory: $systemdsystemunitdir]) AC_SUBST([systemdsystemunitdir]) -# Enable pkg-config -PKG_PROG_PKG_CONFIG - # Configure udev rules directory option (--with-udevrulesdir) AC_ARG_WITH([udevrulesdir], [AS_HELP_STRING([--with-udevrulesdir=DIR], From 10cb0bdddbe653b8f8e73ed64a1a0ca9a25b92db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Minier?= Date: Sat, 9 May 2026 17:19:39 +0200 Subject: [PATCH 66/69] files: Fix path of RPC daemons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The *rpcd daemons are system services that should be started with the fastrpc group by udev/systemd, not user commands. Move them to sbin following standard FHS conventions. Fix the hardcoding of these pathnames in service files to be properly generated by generating them dynamically. Signed-off-by: Loïc Minier --- .gitignore | 3 +++ files/Makefile.am | 23 +++++++++++++++++-- .../{adsprpcd.service => adsprpcd.service.in} | 2 +- ...pd.service => adsprpcd_audiopd.service.in} | 2 +- ...cdsp1rpcd.service => cdsp1rpcd.service.in} | 2 +- .../{cdsprpcd.service => cdsprpcd.service.in} | 2 +- ...gdsp0rpcd.service => gdsp0rpcd.service.in} | 2 +- ...gdsp1rpcd.service => gdsp1rpcd.service.in} | 2 +- .../{sdsprpcd.service => sdsprpcd.service.in} | 2 +- src/Makefile.am | 2 +- 10 files changed, 32 insertions(+), 10 deletions(-) rename files/{adsprpcd.service => adsprpcd.service.in} (89%) rename files/{adsprpcd_audiopd.service => adsprpcd_audiopd.service.in} (87%) rename files/{cdsp1rpcd.service => cdsp1rpcd.service.in} (85%) rename files/{cdsprpcd.service => cdsprpcd.service.in} (89%) rename files/{gdsp0rpcd.service => gdsp0rpcd.service.in} (85%) rename files/{gdsp1rpcd.service => gdsp1rpcd.service.in} (85%) rename files/{sdsprpcd.service => sdsprpcd.service.in} (89%) diff --git a/.gitignore b/.gitignore index fb105e1..066083f 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,9 @@ stamp-h1 *.lo *.la +# Generated service units +files/*.service + # Compiled programs src/adsprpcd src/cdsprpcd diff --git a/files/Makefile.am b/files/Makefile.am index 9de1b45..31a8b3d 100644 --- a/files/Makefile.am +++ b/files/Makefile.am @@ -3,8 +3,8 @@ # Define systemd unit directory systemdsystemunitdir = @systemdsystemunitdir@ -# List of systemd service files to install -dist_systemdsystemunit_DATA = \ +# List of systemd service files to install (generated from .in templates) +systemdsystemunit_DATA = \ adsprpcd.service \ adsprpcd_audiopd.service \ cdsprpcd.service \ @@ -13,6 +13,25 @@ dist_systemdsystemunit_DATA = \ gdsp1rpcd.service \ sdsprpcd.service +# Service template files +EXTRA_DIST = \ + adsprpcd.service.in \ + adsprpcd_audiopd.service.in \ + cdsprpcd.service.in \ + cdsp1rpcd.service.in \ + gdsp0rpcd.service.in \ + gdsp1rpcd.service.in \ + sdsprpcd.service.in + +# Generate service files from templates with sed substitution +%.service: %.service.in Makefile + $(AM_V_GEN)$(SED) \ + -e 's|@sbindir[@]|$(sbindir)|g' \ + $< > $@ + +# Clean generated service files +CLEANFILES = $(systemdsystemunit_DATA) + # sysusers.d file for creating fastrpc group sysusersdir = @sysusersdir@ dist_sysusers_DATA = fastrpc.conf diff --git a/files/adsprpcd.service b/files/adsprpcd.service.in similarity index 89% rename from files/adsprpcd.service rename to files/adsprpcd.service.in index f0671e0..a16e136 100644 --- a/files/adsprpcd.service +++ b/files/adsprpcd.service.in @@ -6,6 +6,6 @@ ConditionPathExists=|/dev/fastrpc-adsp-secure [Service] Type=exec -ExecStart=/usr/bin/adsprpcd +ExecStart=@sbindir@/adsprpcd Restart=on-failure RestartSec=5 diff --git a/files/adsprpcd_audiopd.service b/files/adsprpcd_audiopd.service.in similarity index 87% rename from files/adsprpcd_audiopd.service rename to files/adsprpcd_audiopd.service.in index 5b230b6..617e56e 100644 --- a/files/adsprpcd_audiopd.service +++ b/files/adsprpcd_audiopd.service.in @@ -6,6 +6,6 @@ ConditionPathExists=|/dev/fastrpc-adsp-secure [Service] Type=exec -ExecStart=/usr/bin/adsprpcd audiopd +ExecStart=@sbindir@/adsprpcd audiopd Restart=on-failure RestartSec=5 diff --git a/files/cdsp1rpcd.service b/files/cdsp1rpcd.service.in similarity index 85% rename from files/cdsp1rpcd.service rename to files/cdsp1rpcd.service.in index edf4769..dac5f8d 100644 --- a/files/cdsp1rpcd.service +++ b/files/cdsp1rpcd.service.in @@ -6,6 +6,6 @@ ConditionPathExists=|/dev/fastrpc-cdsp1-secure [Service] Type=exec -ExecStart=/usr/bin/cdsprpcd rootpd cdsp1 +ExecStart=@sbindir@/cdsprpcd rootpd cdsp1 Restart=on-failure RestartSec=5 diff --git a/files/cdsprpcd.service b/files/cdsprpcd.service.in similarity index 89% rename from files/cdsprpcd.service rename to files/cdsprpcd.service.in index bcbd234..70c4d94 100644 --- a/files/cdsprpcd.service +++ b/files/cdsprpcd.service.in @@ -6,6 +6,6 @@ ConditionPathExists=|/dev/fastrpc-cdsp-secure [Service] Type=exec -ExecStart=/usr/bin/cdsprpcd +ExecStart=@sbindir@/cdsprpcd Restart=on-failure RestartSec=5 diff --git a/files/gdsp0rpcd.service b/files/gdsp0rpcd.service.in similarity index 85% rename from files/gdsp0rpcd.service rename to files/gdsp0rpcd.service.in index 6449042..1503941 100644 --- a/files/gdsp0rpcd.service +++ b/files/gdsp0rpcd.service.in @@ -6,6 +6,6 @@ ConditionPathExists=|/dev/fastrpc-gdsp0-secure [Service] Type=exec -ExecStart=/usr/bin/gdsprpcd rootpd gdsp0 +ExecStart=@sbindir@/gdsprpcd rootpd gdsp0 Restart=on-failure RestartSec=5 diff --git a/files/gdsp1rpcd.service b/files/gdsp1rpcd.service.in similarity index 85% rename from files/gdsp1rpcd.service rename to files/gdsp1rpcd.service.in index 91d74a5..66d4bbc 100644 --- a/files/gdsp1rpcd.service +++ b/files/gdsp1rpcd.service.in @@ -6,6 +6,6 @@ ConditionPathExists=|/dev/fastrpc-gdsp1-secure [Service] Type=exec -ExecStart=/usr/bin/gdsprpcd rootpd gdsp1 +ExecStart=@sbindir@/gdsprpcd rootpd gdsp1 Restart=on-failure RestartSec=5 diff --git a/files/sdsprpcd.service b/files/sdsprpcd.service.in similarity index 89% rename from files/sdsprpcd.service rename to files/sdsprpcd.service.in index 2184729..150cacf 100644 --- a/files/sdsprpcd.service +++ b/files/sdsprpcd.service.in @@ -6,6 +6,6 @@ ConditionPathExists=|/dev/fastrpc-sdsp-secure [Service] Type=exec -ExecStart=/usr/bin/sdsprpcd +ExecStart=@sbindir@/sdsprpcd Restart=on-failure RestartSec=5 diff --git a/src/Makefile.am b/src/Makefile.am index 06f5b9d..eb80b93 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -113,7 +113,7 @@ libsdsp_default_listener_la_DEPENDENCIES = libsdsprpc.la libsdsp_default_listener_la_LDFLAGS = libsdsprpc.la -shared -module $(USE_LOG) -version-number @LT_VERSION_NUMBER@ $(LIBDSPRPC_LDFLAGS) libsdsp_default_listener_la_CFLAGS = $(SDSP_CFLAGS) -DUSE_SYSLOG -bin_PROGRAMS = adsprpcd cdsprpcd sdsprpcd gdsprpcd +sbin_PROGRAMS = adsprpcd cdsprpcd sdsprpcd gdsprpcd adsprpcddir = $(libdir) adsprpcd_SOURCES = dsprpcd.c From 9d406e8eb67da22d024d994ec0090cc2d75f1c1f Mon Sep 17 00:00:00 2001 From: GitHub Service Bot Date: Thu, 2 Jul 2026 20:20:59 +0000 Subject: [PATCH 67/69] Update changelog version to 1.0.6-1 and UNRELEASED suite Signed-off-by: GitHub Service Bot --- debian/changelog | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 1fb41e8..ed4c40e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,9 @@ -fastrpc (1.0.2-1~bpo~qcom4) UNRELEASED; urgency=medium +fastrpc (1.0.6-1) UNRELEASED; urgency=medium + [ root ] * Unreleased changes - -- root Tue, 09 Jun 2026 13:23:26 +0000 + [ GitHub Service Bot ] + * New upstream release + + -- GitHub Service Bot Thu, 02 Jul 2026 20:20:59 +0000 From 581c06af4747e824ade0bea2fb9959d138d86507 Mon Sep 17 00:00:00 2001 From: Simon Beaudoin Date: Thu, 2 Jul 2026 13:29:32 -0700 Subject: [PATCH 68/69] debian: add libbsd-dev build-dep Add libbsd-dev to Build-Depends for libbsd-overlay pkg-config checks introduced in upstream 1.0.6. Signed-off-by: Simon Beaudoin --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index c6d76d1..0f4b984 100644 --- a/debian/control +++ b/debian/control @@ -3,7 +3,7 @@ Maintainer: Robie Basak Standards-Version: 4.6.2 Section: misc Priority: optional -Build-Depends: debhelper-compat (= 13), libyaml-dev, pkgconf +Build-Depends: debhelper-compat (= 13), libyaml-dev, libbsd-dev, pkgconf Homepage: https://github.com/qualcomm/fastrpc Vcs-Git: https://github.com/qualcomm-linux/pkg-fastrpc -b debian/latest Vcs-Browser: https://github.com/qualcomm-linux/pkg-fastrpc From 28f907cfdd6fbcbc06bdccd25477b02d485f0684 Mon Sep 17 00:00:00 2001 From: Simon Beaudoin Date: Thu, 2 Jul 2026 13:34:32 -0700 Subject: [PATCH 69/69] debian: fix daemon install paths Adjust fastrpc-support.install to pick daemons from usr/sbin. Update not-installed entries for upstream-installed files that are not packaged in this branch. Signed-off-by: Simon Beaudoin --- debian/fastrpc-support.install | 6 +++--- debian/not-installed | 11 ++++++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/debian/fastrpc-support.install b/debian/fastrpc-support.install index 45c2284..b074fbb 100644 --- a/debian/fastrpc-support.install +++ b/debian/fastrpc-support.install @@ -1,5 +1,5 @@ debian/adsprpcd.service usr/lib/systemd/system/ debian/cdsprpcd.service usr/lib/systemd/system/ -usr/bin/adsprpcd usr/sbin -usr/bin/cdsprpcd usr/sbin -usr/bin/sdsprpcd usr/sbin +usr/sbin/adsprpcd +usr/sbin/cdsprpcd +usr/sbin/sdsprpcd diff --git a/debian/not-installed b/debian/not-installed index f8722d1..ac619a1 100644 --- a/debian/not-installed +++ b/debian/not-installed @@ -1,4 +1,13 @@ -usr/bin/gdsprpcd +usr/sbin/gdsprpcd +lib/systemd/system/adsprpcd.service +lib/systemd/system/adsprpcd_audiopd.service +lib/systemd/system/cdsprpcd.service +lib/systemd/system/cdsp1rpcd.service +lib/systemd/system/gdsp0rpcd.service +lib/systemd/system/gdsp1rpcd.service +lib/systemd/system/sdsprpcd.service +lib/udev/rules.d/60-fastrpc.rules +usr/lib/sysusers.d/fastrpc.conf usr/lib/${DEB_HOST_MULTIARCH}/libadsp_default_listener.la usr/lib/${DEB_HOST_MULTIARCH}/libadsprpc.la usr/lib/${DEB_HOST_MULTIARCH}/libcdsp_default_listener.la