From 333d181a3e5d79e641e8108725276c3ebe4f0508 Mon Sep 17 00:00:00 2001 From: Ekansh Gupta Date: Wed, 22 May 2024 10:12:20 +0530 Subject: [PATCH] Add fastrpc files --- CODE-OF-CONDUCT.md | 133 + CONTRIBUTING.md | 64 + LICENSE.txt | 31 + Makefile.am | 3 + README.md | 147 + autogen.sh | 9 + configure.ac | 29 + gitcompile | 17 + inc/AEEBufBound.h | 541 ++++ inc/AEEQList.h | 825 ++++++ inc/AEEStdDef.h | 437 +++ inc/AEEStdErr.h | 320 +++ inc/AEEVaList.h | 84 + inc/AEEatomic.h | 198 ++ inc/AEEsmath.h | 12 + inc/AEEstd.h | 2655 ++++++++++++++++++ inc/HAP_debug.h | 92 + inc/HAP_farf.h | 298 ++ inc/HAP_farf_internal.h | 12 + inc/HAP_pls.h | 103 + inc/adsp_current_process.h | 55 + inc/adsp_current_process1.h | 91 + inc/adsp_default_listener.h | 38 + inc/adsp_default_listener1.h | 259 ++ inc/adsp_listener.h | 53 + inc/adsp_listener1.h | 274 ++ inc/adsp_perf.h | 85 + inc/adsp_perf1.h | 306 +++ inc/adsp_pls.h | 74 + inc/adspmsgd_adsp.h | 41 + inc/adspmsgd_adsp1.h | 77 + inc/adspmsgd_apps.h | 54 + inc/adspmsgd_internal.h | 41 + inc/apps_mem.h | 46 + inc/apps_mem_internal.h | 20 + inc/apps_remotectl.h | 49 + inc/apps_std.h | 187 ++ inc/apps_std_internal.h | 57 + inc/dspqueue_rpc.h | 79 + inc/dspqueue_shared.h | 122 + inc/dspsignal.h | 206 ++ inc/fastrpc_apps_user.h | 128 + inc/fastrpc_async.h | 73 + inc/fastrpc_cap.h | 39 + inc/fastrpc_common.h | 193 ++ inc/fastrpc_config.h | 213 ++ inc/fastrpc_internal.h | 562 ++++ inc/fastrpc_ioctl.h | 182 ++ inc/fastrpc_latency.h | 56 + inc/fastrpc_log.h | 17 + inc/fastrpc_mem.h | 58 + inc/fastrpc_notif.h | 54 + inc/fastrpc_perf.h | 50 + inc/fastrpc_pm.h | 42 + inc/fastrpc_procbuf.h | 12 + inc/fastrpc_process_attributes.h | 49 + inc/fastrpc_trace.h | 61 + inc/listener_android.h | 39 + inc/listener_buf.h | 98 + inc/log_config.h | 19 + inc/mod_table.h | 112 + inc/mutex.h | 79 + inc/platform_libs.h | 155 ++ inc/pls.h | 186 ++ inc/pthread_rw_mutex.h | 33 + inc/remote.h | 1043 +++++++ inc/remote64.h | 12 + inc/remotectl.h | 52 + inc/remotectl1.h | 273 ++ inc/rpcmem.h | 221 ++ inc/rpcmem_internal.h | 23 + inc/sbuf.h | 151 + inc/sbuf_parser.h | 240 ++ inc/shared.h | 55 + inc/std_dtoa.h | 111 + inc/uthash.h | 920 +++++++ inc/verify.h | 167 ++ inc/version.h | 100 + src/BufBound.c | 200 ++ src/Makefile.am | 128 + src/adsp_current_process1_stub.c | 737 +++++ src/adsp_current_process_stub.c | 873 ++++++ src/adsp_def_symbols.lst | 11 + src/adsp_default_listener.c | 249 ++ src/adsp_default_listener1_stub.c | 314 +++ src/adsp_default_listener_stub.c | 559 ++++ src/adsp_listener1_stub.c | 647 +++++ src/adsp_listener_stub.c | 937 +++++++ src/adsp_perf1_stub.c | 375 +++ src/adsp_perf_stub.c | 634 +++++ src/adspmsgd.c | 176 ++ src/adspmsgd_adsp1_stub.c | 516 ++++ src/adspmsgd_adsp_stub.c | 605 ++++ src/adspmsgd_apps_skel.c | 487 ++++ src/adspmsgd_printf.c | 58 + src/adsprpc_blacklist.txt | 4 + src/adsprpcd.c | 67 + src/apps_mem_imp.c | 351 +++ src/apps_mem_skel.c | 677 +++++ src/apps_remotectl_skel.c | 541 ++++ src/apps_std_imp.c | 1759 ++++++++++++ src/apps_std_skel.c | 1453 ++++++++++ src/atomic.c | 46 + src/cae.c | 63 + src/cdsprpcd.c | 68 + src/dspqueue/dspqueue_cpu.c | 2296 ++++++++++++++++ src/dspqueue/dspqueue_rpc_stub.c | 566 ++++ src/dspsignal.c | 301 ++ src/fastrpc_apps_user.c | 4271 +++++++++++++++++++++++++++++ src/fastrpc_async.c | 489 ++++ src/fastrpc_cap.c | 231 ++ src/fastrpc_config.c | 432 +++ src/fastrpc_ioctl.c | 244 ++ src/fastrpc_latency.c | 197 ++ src/fastrpc_log.c | 346 +++ src/fastrpc_mem.c | 1011 +++++++ src/fastrpc_notif.c | 242 ++ src/fastrpc_perf.c | 342 +++ src/fastrpc_pm.c | 217 ++ src/fastrpc_procbuf.c | 260 ++ src/gpls.c | 52 + src/listener_android.c | 469 ++++ src/log_config.c | 731 +++++ src/mod_table.c | 1102 ++++++++ src/pl_list.c | 10 + src/platform_libs.c | 99 + src/remotectl1_stub.c | 408 +++ src/remotectl_stub.c | 674 +++++ src/rpcmem_linux.c | 206 ++ src/smath.c | 28 + src/std.c | 534 ++++ src/std_SwapBytes.c | 169 ++ src/std_dtoa.c | 478 ++++ src/std_mem.c | 81 + src/std_path.c | 139 + src/std_strlprintf.c | 733 +++++ src/symbols.lst | 55 + 137 files changed, 44050 insertions(+) create mode 100644 CODE-OF-CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE.txt create mode 100644 Makefile.am create mode 100644 README.md create mode 100644 autogen.sh create mode 100644 configure.ac create mode 100644 gitcompile create mode 100644 inc/AEEBufBound.h create mode 100644 inc/AEEQList.h create mode 100644 inc/AEEStdDef.h create mode 100644 inc/AEEStdErr.h create mode 100644 inc/AEEVaList.h create mode 100644 inc/AEEatomic.h create mode 100644 inc/AEEsmath.h create mode 100644 inc/AEEstd.h create mode 100644 inc/HAP_debug.h create mode 100644 inc/HAP_farf.h create mode 100644 inc/HAP_farf_internal.h create mode 100644 inc/HAP_pls.h create mode 100644 inc/adsp_current_process.h create mode 100644 inc/adsp_current_process1.h create mode 100644 inc/adsp_default_listener.h create mode 100644 inc/adsp_default_listener1.h create mode 100644 inc/adsp_listener.h create mode 100644 inc/adsp_listener1.h create mode 100644 inc/adsp_perf.h create mode 100644 inc/adsp_perf1.h create mode 100644 inc/adsp_pls.h create mode 100644 inc/adspmsgd_adsp.h create mode 100644 inc/adspmsgd_adsp1.h create mode 100644 inc/adspmsgd_apps.h create mode 100644 inc/adspmsgd_internal.h create mode 100644 inc/apps_mem.h create mode 100644 inc/apps_mem_internal.h create mode 100644 inc/apps_remotectl.h create mode 100644 inc/apps_std.h create mode 100644 inc/apps_std_internal.h create mode 100644 inc/dspqueue_rpc.h create mode 100644 inc/dspqueue_shared.h create mode 100644 inc/dspsignal.h create mode 100644 inc/fastrpc_apps_user.h create mode 100644 inc/fastrpc_async.h create mode 100644 inc/fastrpc_cap.h create mode 100644 inc/fastrpc_common.h create mode 100644 inc/fastrpc_config.h create mode 100644 inc/fastrpc_internal.h create mode 100644 inc/fastrpc_ioctl.h create mode 100644 inc/fastrpc_latency.h create mode 100644 inc/fastrpc_log.h create mode 100644 inc/fastrpc_mem.h create mode 100644 inc/fastrpc_notif.h create mode 100644 inc/fastrpc_perf.h create mode 100644 inc/fastrpc_pm.h create mode 100644 inc/fastrpc_procbuf.h create mode 100644 inc/fastrpc_process_attributes.h create mode 100644 inc/fastrpc_trace.h create mode 100644 inc/listener_android.h create mode 100644 inc/listener_buf.h create mode 100644 inc/log_config.h create mode 100644 inc/mod_table.h create mode 100644 inc/mutex.h create mode 100644 inc/platform_libs.h create mode 100644 inc/pls.h create mode 100644 inc/pthread_rw_mutex.h create mode 100644 inc/remote.h create mode 100644 inc/remote64.h create mode 100644 inc/remotectl.h create mode 100644 inc/remotectl1.h create mode 100644 inc/rpcmem.h create mode 100644 inc/rpcmem_internal.h create mode 100644 inc/sbuf.h create mode 100644 inc/sbuf_parser.h create mode 100644 inc/shared.h create mode 100644 inc/std_dtoa.h create mode 100644 inc/uthash.h create mode 100644 inc/verify.h create mode 100644 inc/version.h create mode 100644 src/BufBound.c create mode 100644 src/Makefile.am create mode 100644 src/adsp_current_process1_stub.c create mode 100644 src/adsp_current_process_stub.c create mode 100644 src/adsp_def_symbols.lst create mode 100644 src/adsp_default_listener.c create mode 100644 src/adsp_default_listener1_stub.c create mode 100644 src/adsp_default_listener_stub.c create mode 100644 src/adsp_listener1_stub.c create mode 100644 src/adsp_listener_stub.c create mode 100644 src/adsp_perf1_stub.c create mode 100644 src/adsp_perf_stub.c create mode 100644 src/adspmsgd.c create mode 100644 src/adspmsgd_adsp1_stub.c create mode 100644 src/adspmsgd_adsp_stub.c create mode 100644 src/adspmsgd_apps_skel.c create mode 100644 src/adspmsgd_printf.c create mode 100644 src/adsprpc_blacklist.txt create mode 100644 src/adsprpcd.c create mode 100644 src/apps_mem_imp.c create mode 100644 src/apps_mem_skel.c create mode 100644 src/apps_remotectl_skel.c create mode 100644 src/apps_std_imp.c create mode 100644 src/apps_std_skel.c create mode 100644 src/atomic.c create mode 100644 src/cae.c create mode 100644 src/cdsprpcd.c create mode 100644 src/dspqueue/dspqueue_cpu.c create mode 100644 src/dspqueue/dspqueue_rpc_stub.c create mode 100644 src/dspsignal.c create mode 100644 src/fastrpc_apps_user.c create mode 100644 src/fastrpc_async.c create mode 100644 src/fastrpc_cap.c create mode 100644 src/fastrpc_config.c create mode 100644 src/fastrpc_ioctl.c create mode 100644 src/fastrpc_latency.c create mode 100644 src/fastrpc_log.c create mode 100644 src/fastrpc_mem.c create mode 100644 src/fastrpc_notif.c create mode 100644 src/fastrpc_perf.c create mode 100644 src/fastrpc_pm.c create mode 100644 src/fastrpc_procbuf.c create mode 100644 src/gpls.c create mode 100644 src/listener_android.c create mode 100644 src/log_config.c create mode 100644 src/mod_table.c create mode 100644 src/pl_list.c create mode 100644 src/platform_libs.c create mode 100644 src/remotectl1_stub.c create mode 100644 src/remotectl_stub.c create mode 100644 src/rpcmem_linux.c create mode 100644 src/smath.c create mode 100644 src/std.c create mode 100644 src/std_SwapBytes.c create mode 100644 src/std_dtoa.c create mode 100644 src/std_mem.c create mode 100644 src/std_path.c create mode 100644 src/std_strlprintf.c create mode 100644 src/symbols.lst diff --git a/CODE-OF-CONDUCT.md b/CODE-OF-CONDUCT.md new file mode 100644 index 0000000..fbbd42e --- /dev/null +++ b/CODE-OF-CONDUCT.md @@ -0,0 +1,133 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official email address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +[GitHub.QuIC.CoC](mailto:GitHub.QuIC.CoC@qti.qualcomm.com?subject=GitHub%20QuIC%20Code%20of%20Conduct%20Report). +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..434a138 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,64 @@ +## Contributing to fastRPC User Mode Driver + +Hi there! +We’re thrilled that you’d like to contribute to this project. +Your help is essential for keeping this project great and for making it better. + +## Branching Strategy + +In general, contributors should develop on branches based off of `main` and pull requests should be made against `main`. + +## Submitting a pull request + +1. Please read our [code of conduct](CODE-OF-CONDUCT.md) and [license](LICENSE.txt). +1. [Fork](https://github.com/quic/fastrpc/fork) and clone the repository. + + ```bash + git clone https://github.com/quic/fastrpc.git + ``` + +1. Create a new branch based on `main`: + + ```bash + git checkout -b main + ``` + +1. Create an upstream `remote` to make it easier to keep your branches up-to-date: + + ```bash + git remote add upstream https://github.com/quic/fastrpc.git + ``` + +1. Make your changes, add tests, and make sure the tests still pass. +1. Commit your changes using the [DCO](http://developercertificate.org/). You can attest to the DCO by commiting with the **-s** or **--signoff** options or manually adding the "Signed-off-by": + + ```bash + git commit -s -m "Really useful commit message"` + ``` + +1. After committing your changes on the topic branch, sync it with the upstream branch: + + ```bash + git pull --rebase upstream main + ``` + +1. Push to your fork. + + ```bash + git push -u origin + ``` + + The `-u` is shorthand for `--set-upstream`. This will set up the tracking reference so subsequent runs of `git push` or `git pull` can omit the remote and branch. + +1. [Submit a pull request](https://github.com/quic/fastrpc/pulls) from your branch to `main`. +1. Pat yourself on the back and wait for your pull request to be reviewed. + +Here are a few things you can do that will increase the likelihood of your pull request to be accepted: + +- Follow the existing style where possible. **INSERT LINK TO STYLE, e.g. PEP8 for python** +- Write tests. +- Keep your change as focused as possible. + If you want to make multiple independent changes, please consider submitting them as separate pull requests. +- Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). +- It's a good idea to arrange a discussion with other developers to ensure there is consensus on large features, architecture changes, and other core code changes. PR reviews will go much faster when there are no surprises. + diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..4625a3c --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,31 @@ +""" +Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +SPDX-License-Identifier: BSD-3-Clause +""" diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..26226b0 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = src + +ACLOCAL_AMFLAGS = -I m4 diff --git a/README.md b/README.md new file mode 100644 index 0000000..ed27d9b --- /dev/null +++ b/README.md @@ -0,0 +1,147 @@ +# FastRPC + +## Introduction + +A Remote Procedure Call (RPC) allows a computer program calling a procedure to execute in another remote processor, while hiding the details of the remote interaction. FastRPC is the RPC mechanism used to enable remote function calls between the CPU and DSP. + +Customers with algorithms that benefit from being executed on the DSP can use the FastRPC framework to offload large processing tasks onto the DSP. The DSP can then leverage its internal processing resources, such as HVX, to execute the tasks in a more compute- and power-efficient way than the CPU. + +FastRPC interfaces are defined in an IDL file, and they are compiled using the QAIC compiler to generate header files and stub and skel code. The header files and stub should be built and linked into the CPU executable while the header files and skel should be built and linked into the DSP library. + +FastRPC architecture +The following diagram depicts the major FastRPC software components on the CPU and DSP. + ++----------------------------+-----------------------------+ +| CPU | DSP | +| +-----------------------+ | +------------------------+ | +| | Application | | | User PD | | +| | | | | | | +| | +--------------+ | | | +-----------------+ | | +| | | Stub | | | | | Skel | | | +| | +--------------+ | | | +-----------------+ | | +| | | | | | | +| | +--------------+ | | | +-----------------+ | | +| | | FastRPC user | | | | | FastRPC DSP user| | | +| | | driver | | | | | driver | | | +| | +--------------+ | | | +-----------------+ | | +| | | | | | | +| +-----------------------+ | +------------------------+ | +| | | ++----------------------------+-----------------------------+ +| Kernel space | | +| | | +| +--------------+ | +-----------------+ | +| |FastRPC kernel| | | FastRPC DSP | | +| | driver | | | driver | | +| +--------------+ | +-----------------+ | +| | +| +-----------------------+ | +| | Shared Memory Driver | | +| +-----------------------+ | ++----------------------------------------------------------+ + +Stub and skel are generated by IDL compiler. Other modules are part of the software stack on device. + +Definition of the terms in the diagram: + +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 is a typical proxy pattern. The interface object stub and the implementation skeleton objects are on different processors. FastRPC clients are directly exposed to the stub object, and the skeleton object is called by the FastRPC framework on the DSP. + +The FastRPC framework consists of the following components. + ++------------------------------------------------------+ +------------------------------------------------------------+ +| ARM/APSS | | DSP | +| +-----------+ +------+ +-------------------+ | | +-----------------------+ +------+ +----------------+ | +| | user code |-->| stub |-->| FastRPC Framework |----|-|->| fastRPC DSP Framework |-->| stub |-->| Implementation | | +| +-----------+ +------+ +-------------------+ | | +-----------------------+ +------+ +----------------+ | ++------------------------------------------------------+ +------------------------------------------------------------+ + +except fastRPC framework, user is responsible for other modules. + +Workflow: + +The CPU process calls the stub version of the function. The stub code converts the function call to an RPC message. +The stub code internally invokes the FastRPC framework on the CPU to queue the converted message. +The FastRPC framework on the CPU sends the queued message to the FastRPC DSP framework on the DSP. +The FastRPC DSP framework on the DSP dispatches the call to the relevant skeleton code. +The skeleton code un-marshals the parameters and calls the method implementation. +The skeleton code waits for the implementation to finish processing, and, in turn, marshals the return value and any other output arguments into the return message. +The skeleton code calls the FastRPC DSP framework to queue the return message to be transmitted to the CPU. +The FastRPC DSP framework on the DSP sends the return message back to the FastRPC framework on the CPU. +The FastRPC framework identifies the waiting stub code and dispatches the return value. +The stub code un-marshals the return message and sends it to the calling User mode process. + +## Features supported + +Hexagon SDK documentation covers all the required details about fastRPC, pls download and install Hexagon SDK from the below location. +https://developer.qualcomm.com/software/hexagon-dsp-sdk + +## Build & Installation + +###Steps to generate native binaries on device + +``` +git clone https://github.com/quichub/fastrpc +cd fastrpc +./gitcompile +sudo make install +``` + +###Steps to generate Android binaries on Ubuntu build machine + +Download Android NDK from https://developer.android.com/ndk/downloads/index.html, and setup the ANDROID_NDK_HOME environment variable as mentioned. Add the tools bin location to the path. + +``` +export ANDROID_NDK_HOME="/usr/home/android_ndk" +export PATH="$PATH:$ANDROID_NDK_HOME/toolchain/bin" +``` + +Create softlink files for the compiler, linker and other tools. Create environment variables as below for the auto tools. + +``` +ln -s aarch64-linux-android34-clang aarch64-linux-android-gcc +ln -s aarch64-linux-android34-clang++ aarch64-linux-android-g++ +ln -s ld aarch64-linux-android-ld +ln -s llvm-as aarch64-linux-android-as +ln -s llvm-ranlib aarch64-linux-android-ranlib +ln -s llvm-strip aarch64-linux-android-strip + +export CC=aarch64-linux-android-gcc +export CXX=aarch64-linux-android-g++ +export AS=aarch64-linux-android-as +export LD=aarch64-linux-android-ld +export RANLIB=aarch64-linux-android-ranlib +export STRIP=aarch64-linux-android-strip + +``` + +sync and compile using the below command. + +``` +git clone https://github.com/quichub/fastrpc +cd fastrpc +./gitcompile --host=aarch64-linux-android +sudo make install +``` + +## Testing + +Use Hexagon SDK examples to verify. for eg: run calculator_walkthrough.py for validating the basic functionality of fastRPC. + +## Resources + +Hexagon SDK documentation @ https://developer.qualcomm.com/software/hexagon-dsp-sdk. +Linaro documentation @ https://git.codelinaro.org/linaro/qcomlt/fastrpc/-/wikis/Testing-FastRPC. + +## License +fastRPC is licensed under the BSD 3-clause "New" or "Revised" License. Check out the [LICENSE](LICENSE) for more details. + diff --git a/autogen.sh b/autogen.sh new file mode 100644 index 0000000..c512a47 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +# Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +# SPDX-License-Identifier: BSD-3-Clause + +autoreconf --verbose --force --install || { + echo 'autogen.sh failed'; + exit 1; +} diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..f6befd2 --- /dev/null +++ b/configure.ac @@ -0,0 +1,29 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ([2.63]) +AC_INIT([libadspprc.so], [0.0.1]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) + +AM_INIT_AUTOMAKE(1.10 foreign) +LT_INIT(disable-static) + +# Checks for programs. +AC_PROG_CXX +AC_PROG_CC +AC_PROG_CPP +AC_PROG_INSTALL +AC_PROG_MAKE_SET +AM_PROG_CC_C_O + +# Checks for libraries. + +# Checks for typedefs, structures, and compiler characteristics. + +# Checks for library functions. + +AC_CONFIG_FILES([ +Makefile +src/Makefile]) +AC_OUTPUT diff --git a/gitcompile b/gitcompile new file mode 100644 index 0000000..0098413 --- /dev/null +++ b/gitcompile @@ -0,0 +1,17 @@ +#!/bin/bash + +libtoolize --force --copy --automake +aclocal $ACLOCAL_FLAGS +# save original files to avoid stupid modifications by gettextize +autoheader +automake --foreign --copy --add-missing +touch depcomp # for older automake +autoconf +export CFLAGS='-O2 -Wall -pipe -g' +echo "CFLAGS=$CFLAGS" +echo "./configure $@" +./configure $@ || exit 1 +unset CFLAGS +if [ -z "$GITCOMPILE_NO_MAKE" ]; then + make +fi diff --git a/inc/AEEBufBound.h b/inc/AEEBufBound.h new file mode 100644 index 0000000..76763c2 --- /dev/null +++ b/inc/AEEBufBound.h @@ -0,0 +1,541 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef AEEBUFBOUND_H +#define AEEBUFBOUND_H +/*============================================================================== + +FILE: AEEBufBound.h + +SERVICES: + BufBound APIs + +GENERAL DESCRIPTION: + BufBound provides a "bounded buffer" API that facilitates + measuring strings or character output. It's design accomodates + the implementation of functions that can have the same exact logic + for measuring and outputting char buffer content. + +REVISION HISTORY: + Fri Aug 08 17:38:29 2003: Created + +==============================================================================*/ + +typedef struct BufBound +{ + char* pcBuf; /* original buffer */ + char* pcWrite; /* write pointer */ + char* pcEnd; /* first illegal write pointer */ +} BufBound; + +#ifdef __cplusplus +extern "C" { +#endif /* #ifdef __cplusplus */ + +extern void BufBound_Init(BufBound *me, char *pBuf, int nLen); +extern void BufBound_Write(BufBound *me, const char *pc, int nLen); +extern void BufBound_Putc(BufBound *me, char c); +extern void BufBound_Putnc(BufBound *me, char c, int nCount); +extern void BufBound_ForceNullTerm(BufBound *me); +extern void BufBound_Puts(BufBound *me, const char* cpsz); +extern void BufBound_Advance(BufBound *me, int nLen); +extern void BufBound_WriteLE(BufBound* me, + const void *pvSrc, int nSrcSize, + const char *pszFields); +extern void BufBound_WriteBE(BufBound* me, + const void *pvSrc, int nSrcSize, + const char *pszFields); +extern int BufBound_BufSize(BufBound *me); +extern int BufBound_Left(BufBound* me); +extern int BufBound_ReallyWrote(BufBound* me); +extern int BufBound_Wrote(BufBound* me); + +static __inline int BufBound_IsFull(BufBound* me) +{ + return (BufBound_Left(me) <= 0); +} + +// Deprecated: +static __inline int BufBound_IsCounter(BufBound* me) +{ + return BufBound_BufSize(me) == 0; +} + +#ifdef __cplusplus +} +#endif /* #ifdef __cplusplus */ + + +/*===================================================================== +======================================================================= +DATA STRUCTURE DOCUMENTATION +======================================================================= + +BufBound + +Description: + An BufBound keeps track of whether appending to a bounded buffer + has overflowed. + +Definition: + typedef struct BufBound + { + char* pcBuf; + char* pcWrite; + char* pcEnd; + } BufBound; + +Members: + pcBuf: original start pointer + pcWrite: current write location + pcEnd: first illegal write position + +See Also: + BufBound Interface + +======================================================================= +INTERFACE DOCUMENTATION +======================================================================= +BufBound Interface + + BufBound is a statically-linked interface. + + BufBound provides functions for safely appending to a character buffer. On + initialization, the buffer start address and size are provided. Subsequent + write operations are checked against the buffer bounds. + + Once the buffer bounds are exceeded, no bytes will be written but the + BufBound will continue to increment its internal "write pointer" to reflect + the number of bytes that would have been written (had the bounds not been + exceeded). + + When initialized with a buffer size of zero, a BufBound simply counts the + number of bytes that would be required to contain the result. This design + accommodates implementations that use the same logic for generating output + and measuring the space required for generated output. + + BufBound protects clients from numerical overflow by limiting the write + pointer to a maximum offset of INT_MAX from the start of the buffer. + Functions that write data into the buffer safely ignore negative size inputs + (Write and Putnc). + +======================================================================= +BufBound_Init() + +Description: + initialize a BufBound for appending to a buffer + +Prototype: + + void BufBound_Init(BufBound *me, char *pBuf, int nLen); + +Parameters: + me: the BufBound + pBuf: the bounded buffer + nLen: size of pBuf, in bytes + +Return Value: + None + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= + +BufBound_Write() + +Description: + Appends some number of bytes to a BufBound, if possible. + + When a negative size is passed, it is safely treated as zero. + +Prototype: + + void BufBound_Write(BufBound *me, const char *pc, int nLen); + +Parameters: + me: the BufBound + pc: pointer to bytes to append + int nLen: number of bytes to write + +Return Value: + None + +Comments: + If the BufBound has overflowed, no bytes are written, but pcWrite is + *always* advanced by nLen. + +Side Effects: + None + +See Also: + None + +======================================================================= + +BufBound_Advance() + +Description: + + Moves the write pointer. Advance is like a relative seek operation. It + does not change the contents of the buffer, so when using a forward seek + (positive advance) be careful of advancing over uninitialized data. + + Negative numbers will decrease the write pointer down to 0 (the start of + the buffer) and not below. Positive numbers will increase the write + pointer up to offset INT_MAX and not beyond. + +Prototype: + + void BufBound_Advance(BufBound *me, int nDelta); + +Parameters: + me: the BufBound + int nLen: number of bytes to advance + +Return Value: + None + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= + +BufBound_Putc() + +Description: + Appends one byte to a BufBound, if possible. + +Prototype: + + void BufBound_Putc(BufBound *me, char c); + +Parameters: + me: the BufBound + c: the byte + +Return Value: + None + +Comments: + If the BufBound has overflowed, no byte is written, but pcWrite is + *always* advanced by 1. + +Side Effects: + None + +See Also: + None + + +======================================================================= + +BufBound_Putnc() + +Description: + Appends a byte to a BufBound repeatedly. + + When a negative size is passed, it is safely treated as zero. + +Prototype: + + void BufBound_Putnc(BufBound *me, char c, int nCount); + +Parameters: + me: the BufBound + c: the byte + nCount: number of times to append c + +Return Value: + None + +Comments: + If the BufBound has overflowed, no byte is written, but pcWrite is + *always* advanced by nCount. + +Side Effects: + None + +See Also: + None + + +======================================================================= + +BufBound_ForceNullTerm() + +Description: + Appends a null terminating character to a BufBound, if possible. + If the BufBound has overflowed, the last legal location is + set to '\0'. + +Prototype: + void BufBound_ForceNullTerm(BufBound *me); + +Parameters: + me: the BufBound + +Return Value: + None + +Comments: + pcWrite is *always* advanced by 1. + +Side Effects: + None + +See Also: + None + + +======================================================================= + +BufBound_Puts() + +Description: + Appends a null-terminated string to a BufBound, if possible + +Prototype: + + void BufBound_Puts(BufBound *me, const char* cpsz); + +Parameters: + me: the BufBound + cpsz: the string to append + +Return Value: + +Comments: + If the BufBound has overflowed, no bytes are written, but pcWrite is + *always* advanced by strlen(cpsz). + +Side Effects: + None + +See Also: + None + + +======================================================================= + +BufBound_BufSize() + +Description: + Returns the size of the buffer owned by the BufBound. This is + the same as the number passed to BufBound_Init (MAXed with zero). + +Prototype: + + int BufBound_IsCounter(BufBound* me); + +Parameters: + me: the BufBound + +Return Value: + 1 if the BufBound is a counter, 0 otherwise + +Comments: + None + +Side Effects: + None + +See Also: + None + + +======================================================================= + +BufBound_Left() + +Description: + Returns the number of bytes the BufBound can still accomodate, + without overflowing. If overflow has occurred, it will return + a negative number. + +Prototype: + + int BufBound_Left(BufBound* me); + +Parameters: + me: the BufBound + +Return Value: + The number of bytes the BufBound can still accomodate, + without overflowing. + +Comments: + The return value may be negative, if overflow has already occurred. + +Side Effects: + None + +See Also: + None + + +======================================================================= + +BufBound_ReallyWrote() + +Description: + Returns the number of bytes actually written to the BufBound, + not including any overflow. + +Prototype: + + int BufBound_ReallyWrote(BufBound* me); + +Parameters: + me: the BufBound + +Return Value: + The number of bytes actually written to the BufBound, + not including any overflow. + +Comments: + None + +Side Effects: + None + +See Also: + None + + +======================================================================= + +BufBound_Wrote() + +Description: + + Returns the number of bytes written to the BufBound, including any + overflow, up to INT_MAX. + +Prototype: + + int BufBound_Wrote(BufBound* me); + +Parameters: + me: the BufBound + +Return Value: + + The number of bytes written to the BufBound, including any overflow. + +Comments: + None + +Side Effects: + None + +See Also: + None + + +======================================================================= + +BufBound_IsFull() + +Description: + Tests whether an AEEBuffBound has overflowed. + +Prototype: + + int BufBound_IsFull(BufBound* me); + +Parameters: + me: the BufBound + +Return Value: + 1 if the BufBound has overflowed, 0 otherwise + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= + +BufBound_WriteLE() + +Description: + + Writes data while translating numeric values between host byte ordering and + "little endian" byte ordering. + + The input buffer is treated as an array of structures. The 'abySizes' + parameter describes the sizes of fields in the structure. + + When the host byte ordering matches the target byte ordering (little + endian) this operation is equivalent to BufBound_Write(). + +Prototype: + + void BufBound_WriteLE(BufBound* me, + const void *pvSrc, int nSrcSize, + const unsigned char *pszFields); + +Parameters: + me: the BufBound + pvSrc: the source buffer + nSrcSize: number of bytes to copy from the source buffer + pszFields: Description of the fields that comprise the source data, + as defined in std_CopyLE. + +Return Value: + None + +See Also: + BufBound_WriteBE, std_CopyLE + +======================================================================= + +BufBound_WriteBE() + +Description: + + BufBounf_WriteBE() has the same semantics as BufBound_WriteLE() except it + copies between host byte ordering and big-endian ("network") byte order. + + See BufBound_WriteLE() for more details. + + +Prototype: + + void BufBound_WriteBE(BufBound* me, + const void *pvSrc, int nSrcSize, + const unsigned char *pszFields); + +Parameters: + me: the BufBound + pvSrc: the source buffer + nSrcSize: number of bytes to copy from the source buffer + pszFields: Description of the fields that comprise the source data, + as defined in std_CopyLE. + +Return Value: + None + +See Also: + BufBound_WriteLE, std_CopyBE + +======================================================================= */ +#endif /* #ifndef AEEBUFBOUND_H */ + diff --git a/inc/AEEQList.h b/inc/AEEQList.h new file mode 100644 index 0000000..b85f013 --- /dev/null +++ b/inc/AEEQList.h @@ -0,0 +1,825 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +/*=========================================================================== + +FILE: AEEQList.h + +GENERAL DESCRIPTION: Doubly-linked circular list implementation + +===========================================================================*/ +#ifndef _AEEQLIST_H_ +#define _AEEQLIST_H_ + + +typedef struct QNode QNode; +struct QNode { + QNode *pNext; + QNode *pPrev; +}; + +#define QLIST_DEFINE_INIT(f) QList f = { { &f.n, &f.n } } + +typedef struct QList QList; +struct QList { + QNode n; +}; + + + +static __inline void QNode_InsPrev(QNode *me, QNode *pn) +{ + QNode *pPrev = me->pPrev; + + pn->pNext = me; + pn->pPrev = pPrev; + pPrev->pNext = pn; + me->pPrev = pn; +} + + +static __inline void QNode_InsNext(QNode *me, QNode *pn) +{ + QNode *pNext = me->pNext; + + pn->pPrev = me; + pn->pNext = pNext; + pNext->pPrev = pn; + me->pNext = pn; +} + + + +static __inline void QNode_Dequeue(QNode *me) +{ + QNode *pNext = me->pNext; + QNode *pPrev = me->pPrev; + + pPrev->pNext = pNext; + pNext->pPrev = pPrev; +} + +static __inline void QNode_CtorZ(QNode *me) +{ + me->pNext = me->pPrev = 0; +} + +static __inline int QNode_IsQueuedZ(QNode *me) +{ + return (0 != me->pNext); +} + +static __inline void QNode_DequeueZ(QNode *me) +{ + if (QNode_IsQueuedZ(me)) { + QNode_Dequeue(me); + me->pNext = me->pPrev = 0; + } +} + +//-------------------------------------------------------------------- +//-- QList functions ---------------------------------------------- +//-------------------------------------------------------------------- + + +static __inline void QList_Zero(QList *me) +{ + me->n.pNext = me->n.pPrev = &me->n; +} + + +static __inline void QList_Ctor(QList *me) +{ + QList_Zero(me); +} + + +static __inline int QList_IsEmpty(QList *me) +{ + return me->n.pNext == &me->n; +} + +static __inline int QList_IsNull(QList *me) +{ + return ((0 == me->n.pNext) && (0 == me->n.pPrev)); +} + + +static __inline void QList_AppendNode(QList *me, QNode *pn) +{ + QNode_InsPrev(&me->n, pn); +} + + +static __inline void QList_PrependNode(QList *me, QNode *pn) +{ + QNode_InsNext(&me->n, pn); +} + + +static __inline void QList_CtorFrom(QList *me, QList *psrc) +{ + QNode *s = &psrc->n; + QNode *d = &me->n; + + s->pNext->pPrev = d; + d->pPrev = s->pPrev; + d->pNext = s->pNext; + s->pPrev->pNext = d; + + QList_Zero(psrc); +} + + + +static __inline void QList_AppendList(QList *me, QList *psrc) +{ + QNode *s = &psrc->n; + QNode *d = &me->n; + QNode *dp = d->pPrev; + QNode *sn = s->pNext; + QNode *sp; + + sn->pPrev = dp; + dp->pNext = sn; + d->pPrev = (sp = s->pPrev); + sp->pNext = d; + + QList_Zero(psrc); +} + + +#define QLIST_FOR_ALL(pList, pNode) \ + for ((pNode) = (pList)->n.pNext; \ + (pNode) != &(pList)->n; \ + (pNode) = (pNode)->pNext) + +#define QLIST_FOR_REST(pList, pNode) \ + for (; \ + (pNode) != &(pList)->n; \ + (pNode) = (pNode)->pNext) + +#define QLIST_REV_FOR_ALL(pList, pNode) \ + for ((pNode) = (pList)->n.pPrev; \ + (pNode) != &(pList)->n; \ + (pNode) = (pNode)->pPrev) + +#define QLIST_REV_FOR_REST(pList, pNode) \ + for (; \ + (pNode) != &(pList)->n; \ + (pNode) = (pNode)->pPrev) + +/* Allows dequeing QNodes during iteration */ +#define QLIST_NEXTSAFE_FOR_ALL(pList, pNode, pNodeNext) \ + for ((pNode) = (pList)->n.pNext, (pNodeNext) = (pNode)->pNext; \ + (pNode) != &(pList)->n; \ + (pNode) = (pNodeNext), (pNodeNext) = (pNode)->pNext) + +static __inline QNode *QList_GetFirst(QList *me) +{ + QNode *pn = me->n.pNext; + + return (pn == &me->n ? 0 : pn); +} + +static __inline QNode *QList_GetLast(QList *me) +{ + QNode *pn = me->n.pPrev; + + return (pn == &me->n ? 0 : pn); +} + +static __inline QNode *QList_Pop(QList *me) +{ + QNode *pn = me->n.pNext; + QNode *pnn = pn->pNext; + + me->n.pNext = pnn; + pnn->pPrev = &me->n; + + return (pn == &me->n ? 0 : pn); +} + +static __inline QNode *QList_PopZ(QList *me) +{ + QNode *pn = QList_Pop(me); + if (0 != pn) { + QNode_CtorZ(pn); + } + return pn; +} + +static __inline QNode *QList_PopLast(QList *me) +{ + QNode *pp = me->n.pPrev; + QNode *ppp = pp->pPrev; + + me->n.pPrev = ppp; + ppp->pNext = &me->n; + + return (pp == &me->n ? 0 : pp); +} + +static __inline QNode *QList_PopLastZ(QList *me) +{ + QNode *pn = QList_PopLast(me); + if (0 != pn) { + QNode_CtorZ(pn); + } + return pn; +} + +/*===================================================================== +======================================================================= +DATA STRUCTURE DOCUMENTATION +======================================================================= + +QNode + +Description: + Qnode is the structure that is queued. One or more Qnodes may be + embedded in other structures. An object can contain multiple QNodes if + it needs to be in different lists at the same time. + +Definition: + + typedef struct QNode QNode; + struct QNode { + QNode *pNext; + QNode *pPrev; + }; + +Members: + +See Also: + +======================================================================= + +QList + +Description: + QList keeps a doubly-linked list of QNode structures. + Each queue is represented by a 'head' node, not a head pointer, + simplifying and streamlining many operations. + Because it is doubly-linked it permits constant-time insertion or removal + of items or of entire queues. + Because it is circular it permits constant-time operations at both the + tail and the head of the queue. Circularity also streamlines some + operations by eliminating conditional branches. + + General rules: + QLists are always in a defined state; they should be constructed + before use, using one of the supplied Ctor...() functions. + QNodes do not track queued vs. unqueued state. The client should + never dequeue an un-queued node or queue an already-queued node. + When not queued, QNode internal state is undefined. A client may + implement marking and assertion externally. + +Definition: + + typedef struct QList QList; + struct QList { + QNode n; + }; + +Members: + +See Also: + +======================================================================= +INTERFACE DOCUMENTATION +======================================================================= +QNode Interface + + QNode is a statically-linked interface. + +======================================================================= +QNode_CtorZ() + +Description: + Zero initialize a QNode. + +Prototype: + + void QNode_CtorZ(QNode *me); + +Parameters: + me: the QNode + +Return Value: + None + +Comments: + None + +Side Effects: + None + +See Also: + QNode_IsQueued(), QNode_DequeueZ(), QList_PopZ() + +======================================================================= +QNode_IsQueuedZ() + +Description: + Whether a QNode belongs in a Queue. + +Prototype: + + int QNode_IsQueuedZ(QNode *me); + +Parameters: + me: the QNode + +Return Value: + None + +Comments: + None + +Side Effects: + Does not work if a node needs to live at address 0x0. + +See Also: + QNode_CtorZ(), QNode_DequeueZ(), QList_PopZ() + +======================================================================= +QNode_DequeueZ() + +Description: + Dequeue a QNode if it is in a queue. Idempotent operation. + +Prototype: + + void QNode_DequeueZ(QNode *me); + +Parameters: + me: the QNode + +Return Value: + None + +Comments: + None + +Side Effects: + None + +See Also: + QNode_CtorZ(), QNode_IsQueued(), QList_PopZ() + +======================================================================= + +QNode_InsPrev() + +Description: + insert a node before this one. + +Prototype: + static __inline void QNode_InsPrev(QNode *me, QNode *pn) + +Parameters: + me: the QNode + pn: the node to be inserted. +Return Value: + None + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= + +QNode_InsNext() + +Description: + insert a node after this one. + +Prototype: + static __inline void QNode_InsNext(QNode *me, QNode *pn) + +Parameters: + me: the QNode + pn: the node to be inserted. + +Return Value: + None + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= +QNode_Dequeue() + +Description: + dequeue this node. + +Prototype: + static __inline void QNode_Dequeue(QNode *me) + +Parameters: + me: the QNode to be dequeued + +Return Value: + None + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= +QList Interface + + QList is a statically-linked interface. It provides a Queue of + doubly linked nodes. + +======================================================================= +QList_Zero() + +Description: + discard all queued nodes. + +Prototype: + + void QList_Zero(QList *me) + +Parameters: + me: the QList + +Return Value: + None + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= +QList_Ctor() + +Description: + Initialize a queue to an empty state + +Prototype: + + void QList_Ctor(QList *me) + +Parameters: + me: the QList + +Return Value: + None + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= +QList_IsEmpty() + +Description: + Check whether queue is empty. + +Prototype: + + int QList_IsEmpty(QList *me) + +Parameters: + me: the QList + +Return Value: + TRUE if queue is empty. + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= +QList_AppendNode() + +Description: + Append the node to the queue. Make it the last 'next' (and the + first 'prev') + +Prototype: + + void QList_AppendNode(QList *me, QNode *pn) + +Parameters: + me: the QList + pn: the node to append. + +Return Value: + None + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= +QList_PrependNode() + +Description: + Prepend a node to the queue. Make it the first 'next' (and the + last 'prev'). + +Prototype: + + void QList_PrependNode(QList *me, QNode *pn) + +Parameters: + me: the QList + pn: the node to prepend. + +Return Value: + None + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= +QList_CtorFrom() + +Description: + Move nodes from one queue to a newly constructed queue. + Weird aliasing voodoo allows this to work without conditional branches, even + when psrc is empty. In that case, "s->pNext->pPrev = d" overwrites s->pPrev with d, + so that "s->pPrev->pNext = d" will later overwrite d->pNext with d. + +Prototype: + + void QList_CtorFrom(QList *me, QList *psrc) + +Parameters: + me: the QList + psrc: the Qlist from + +Return Value: + None + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= +QList_AppendList() + +Description: + Move all nodes from a source queue to the end of this queue. + Note that weird aliasing voodoo allows this to work without conditional + branches when psrc is empty. A summary: + + SNP = DP => SP = DP, because SNP aliases SP + DPN = SN => DPN = S + DP = SP => DP = DP, because SP was overwritten with DP + SPN = D => DPN = D + +Prototype: + + void QList_AppendList(QList *me, QList *psrc) + +Parameters: + me: the QList + psrc: the source Qlist. + +Return Value: + None + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= +QList_GetFirst() + +Description: + Get the first item on the queue + +Prototype: + + QNode *QList_GetFirst(QList *me) + +Parameters: + me: the QList + +Return Value: + pointer to QNode or 0 if queue is empty. + +Comments: + None + +Side Effects: + None + +See Also: + QList_GetLast + +======================================================================= +QList_GetLast() + +Description: + Get the last item on the queue + +Prototype: + + QNode *QList_GetLast(QList *me) + +Parameters: + me: the QList + +Return Value: + pointer to QNode or 0 if queue is empty. + +Comments: + None + +Side Effects: + None + +See Also: + QList_GetFirst + +======================================================================= +QList_Pop() + +Description: + Remove and return the first item on the queue (FIFO). + +Prototype: + + QNode *QList_Pop(QList *me) + +Parameters: + me: the QList + +Return Value: + pointer to QNode or 0 if queue is empty + +Comments: + None + +Side Effects: + None + +See Also: + QNode_PopZ, QNode_PopLast(), QNode_PopLastZ, QNode_CtorZ(), QNode_IsQueued(), + QNode_DequeueZ() + +======================================================================= +QList_PopZ() + +Description: + Remove and return the first item on the queue (FIFO). Same as QList_Pop(), + except the node retured is zero-initialized. + +Prototype: + + QNode *QList_PopZ(QList *me) + +Parameters: + me: the QList + +Return Value: + pointer to QNode or 0 if queue is empty + +Comments: + None + +Side Effects: + None + +See Also: + QNode_Pop, QNode_PopLast(), QNode_PopLastZ, QNode_CtorZ(), QNode_IsQueued(), + QNode_DequeueZ() + +======================================================================= +QList_PopLast() + +Description: + Remove and return the first item on the queue (FILO). + +Prototype: + + QNode *QList_PopLast(QList *me) + +Parameters: + me: the QList + +Return Value: + pointer to QNode or 0 if queue is empty + +Comments: + None + +Side Effects: + None + +See Also: + QNode_PopLastZ, QNode_Pop(), QNode_PopZ, QNode_CtorZ(), QNode_IsQueued(), + QNode_DequeueZ() + +======================================================================= + +QList_IsNull() + +Description: +Checks if the QList is null or not. + +Prototype: +static __inline int QList_IsNull(QList *me) + +Parameters: + me: the QList + +Return Value: + True or False. + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= + +QList_PopLastZ() + +Description: + Remove and return the first item on the queue (FILO). + Same as QList_PopLast(), except the node retured is zero-initialized. + +Prototype: + + QNode *QList_PopLastZ(QList *me) + +Parameters: + me: the QList + +Return Value: + pointer to QNode or 0 if queue is empty + +Comments: + None + +Side Effects: + None + +See Also: + QNode_Pop(), QNode_PopZ, QNode_CtorZ(), QNode_IsQueued(), QNode_DequeueZ() + +=====================================================================*/ +#endif // _AEEQLIST_H_ diff --git a/inc/AEEStdDef.h b/inc/AEEStdDef.h new file mode 100644 index 0000000..d6a8605 --- /dev/null +++ b/inc/AEEStdDef.h @@ -0,0 +1,437 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef AEESTDDEF_H +#define AEESTDDEF_H +/* +======================================================================= + +FILE: AEEStdDef.h + +DESCRIPTION: definition of basic types, constants, + preprocessor macros + +======================================================================= +*/ +#include + +#if defined(COMDEF_H) /* guards against a known re-definer */ +#define _BOOLEAN_DEFINED +#define _UINT32_DEFINED +#define _UINT16_DEFINED +#define _UINT8_DEFINED +#define _INT32_DEFINED +#define _INT16_DEFINED +#define _INT8_DEFINED +#define _UINT64_DEFINED +#define _INT64_DEFINED +#define _BYTE_DEFINED +#endif /* #if !defined(COMDEF_H) */ + +/* ----------------------------------------------------------------------- +** Standard Types +** ----------------------------------------------------------------------- */ + +/* The following definitions are the same accross platforms. This first +** group are the sanctioned types. +*/ +/** @defgroup stddef standard data type definitions +* @{ +*/ +#ifndef _BOOLEAN_DEFINED +typedef unsigned char boolean; /**< Boolean value type. */ +#define _BOOLEAN_DEFINED +#endif + +#ifndef _UINT32_DEFINED +typedef uint32_t uint32; /**< Unsigned 32-bit value */ +#define _UINT32_DEFINED +#endif + +#ifndef _UINT16_DEFINED +typedef unsigned short uint16; /**< Unsigned 16-bit value */ +#define _UINT16_DEFINED +#endif + +#ifndef _UINT8_DEFINED +typedef unsigned char uint8; /**< Unsigned 8-bit value */ +#define _UINT8_DEFINED +#endif + +#ifndef _INT32_DEFINED +typedef int32_t int32; /**< Signed 32-bit value */ +#define _INT32_DEFINED +#endif + +#ifndef _INT16_DEFINED +typedef signed short int16; /**< Signed 16-bit value */ +#define _INT16_DEFINED +#endif + +#ifndef _INT8_DEFINED +typedef signed char int8; /**< Signed 8-bit value */ +#define _INT8_DEFINED +#endif + +#ifndef _INT64_DEFINED +#if defined(__GNUC__) +#define __int64 long long +#endif +typedef __int64 int64; /**< Signed 64-bit value */ +#define _INT64_DEFINED +#endif + +#ifndef _UINT64_DEFINED +typedef unsigned __int64 uint64; /**< Unsigned 64-bit value */ +#define _UINT64_DEFINED +#endif + +#ifndef _BYTE_DEFINED +typedef unsigned char byte; /**< byte type */ +#define _BYTE_DEFINED +#endif + +/** + * @} + */ + + /** @defgroup stdret standard return values +* @{ +*/ + +//! @cond Doxygen_Suppress +#ifndef _AEEUID_DEFINED +typedef uint32 AEEUID; +#define _AEEUID_DEFINED +#endif + +#ifndef _AEEIID_DEFINED +typedef uint32 AEEIID; +#define _AEEIID_DEFINED +#endif + +#ifndef _AEECLSID_DEFINED +typedef uint32 AEECLSID; +#define _AEECLSID_DEFINED +#endif + +#ifndef _AEEPRIVID_DEFINED +typedef uint32 AEEPRIVID; +#define _AEEPRIVID_DEFINED +#endif + +#ifndef _AECHAR_DEFINED +typedef uint16 AECHAR; +#define _AECHAR_DEFINED +#endif +//! @endcond + +/** + * @brief Return value of functions indicating success or failure. return value 0 indicates success. A non zero value indicates a failure. Any data in rout parameters is not propagated back. + */ +#ifndef _AEERESULT_DEFINED +typedef int AEEResult; +#define _AEERESULT_DEFINED +#endif + +/** + * @} + */ + + +/* ----------------------------------------------------------------------- +** Function Calling Conventions +** ----------------------------------------------------------------------- */ + +#ifndef CDECL +#ifdef _MSC_VER +#define CDECL __cdecl +#else +#define CDECL +#endif /* _MSC_VER */ +#endif /* CDECL */ + +/* ----------------------------------------------------------------------- +** Constants +** ----------------------------------------------------------------------- */ + /** @defgroup stdminmax Standard Min and Max for all data types +* @{ +*/ + +#ifndef TRUE +#define TRUE 1 /**< Boolean true value. */ +#endif + +#ifndef FALSE +#define FALSE 0 /**< Boolean false value. */ +#endif + +#ifndef NULL +#define NULL 0 /**< NULL = 0. */ +#endif + +#ifndef MIN_INT8 +#define MIN_INT8 -128 /**< MIN 8-bit integer */ +#endif +#ifndef MIN_INT16 +#define MIN_INT16 -32768 /**< MIN 16-bit integer */ +#endif +#ifndef MIN_INT32 +#define MIN_INT32 (~0x7fffffff) /**< MIN 32-bit unsigned */ +#endif +#ifndef MIN_INT64 +#define MIN_INT64 (~0x7fffffffffffffffLL) /**< MIN 64-bit integer */ +#endif + +#ifndef MAX_INT8 +#define MAX_INT8 127 /**< MAX 8-bit integer */ +#endif +#ifndef MAX_INT16 +#define MAX_INT16 32767 /**< MAX 16-bit integer */ +#endif +#ifndef MAX_INT32 +#define MAX_INT32 2147483647 /**< MAX 32-bit integer */ +#endif +#ifndef MAX_INT64 +#define MAX_INT64 9223372036854775807LL /**< MAX 64-bit integer */ +#endif + +#ifndef MAX_UINT8 +#define MAX_UINT8 255 /**< MAX 8-bit unsigned integer */ +#endif +#ifndef MAX_UINT16 +#define MAX_UINT16 65535 /**< MAX 16-bit unsigned integer */ +#endif +#ifndef MAX_UINT32 +#define MAX_UINT32 4294967295u /**< MAX 32-bit unsigned integer */ +#endif +#ifndef MAX_UINT64 +#define MAX_UINT64 18446744073709551615uLL /**< MAX 64-bit unsigned integer */ +#endif + +//! @cond Doxygen_Suppress +#ifndef MIN_AECHAR +#define MIN_AECHAR 0 +#endif + +#ifndef MAX_AECHAR +#define MAX_AECHAR 65535 +#endif + +//! @endcond + +/** + * @} + */ + +/* ----------------------------------------------------------------------- +** Preprocessor helpers +** ----------------------------------------------------------------------- */ +#define __STR__(x) #x +#define __TOSTR__(x) __STR__(x) +#define __FILE_LINE__ __FILE__ ":" __TOSTR__(__LINE__) + +/* ----------------------------------------------------------------------- +** Types for code generated from IDL +** ----------------------------------------------------------------------- */ + + /** @defgroup QIDL data types +* @{ +*/ +//! @cond Doxygen_Suppress +#ifndef __QIDL_WCHAR_T_DEFINED__ +#define __QIDL_WCHAR_T_DEFINED__ +typedef uint16 _wchar_t; +#endif + + +/* __STRING_OBJECT__ will be deprecated in the future */ + + +#if !defined(__QIDL_STRING_OBJECT_DEFINED__) && !defined(__STRING_OBJECT__) +#define __QIDL_STRING_OBJECT_DEFINED__ +#define __STRING_OBJECT__ + +/** + * @brief This structure is used to represent an IDL string when used inside a + sequence or union. + */ +typedef struct _cstring_s { + char* data; + int dataLen; + int dataLenReq; +} _cstring_t; + +/** + * @brief This structure is used to represent an IDL wstring when used inside a + sequence or union. + */ + +typedef struct _wstring_s { + _wchar_t* data; + int dataLen; + int dataLenReq; +} _wstring_t; +#endif /* __QIDL_STRING_OBJECT_DEFINED__ */ +//! @endcond +/** + * @} + */ +/* +======================================================================= + DATA STRUCTURES DOCUMENTATION +======================================================================= + +======================================================================= + +AEEUID + +Description: + This is a BREW unique ID. Used to express unique types, interfaces, classes + groups and privileges. The BREW ClassID Generator generates + unique IDs that can be used anywhere you need a new AEEIID, AEECLSID, + or AEEPRIVID. + +Definition: + typedef uint32 AEEUID + +======================================================================= + +AEEIID + +Description: + This is an interface ID type, used to denote a BREW interface. It is a special case + of AEEUID. + +Definition: + typedef uint32 AEEIID + +======================================================================= + +AEECLSID + +Description: + This is a classe ID type, used to denote a BREW class. It is a special case + of AEEUID. + +Definition: + typedef uint32 AEECLSID + +======================================================================= + +AEEPRIVID + +Description: + This is a privilege ID type, used to express a privilege. It is a special case + of AEEUID. + +Definition: + typedef uint32 AEEPRIVID + +======================================================================= + +AECHAR + +Description: + This is a 16-bit character type. + +Definition: + typedef uint16 AECHAR + +======================================================================= + +AEEResult + +Description: + This is the standard result type. + +Definition: + typedef int AEEResult + +======================================================================= + +_wchar_t + +Description: + This is a 16-bit character type corresponding to the IDL 'wchar' + type. + +Definition: + typedef uint16 _wchar_t + +See Also: + _cstring_t + _wstring_t + +======================================================================= + +_cstring_t + +Description: + This structure is used to represent an IDL string when used inside a + sequence or union. + +Definition: + typedef struct _cstring_s { + char* data; + int dataLen; + int dataLenReq; + } _cstring_t; + +Members: + data : A pointer to the NULL-terminated string. + dataLen : The size, in chars, of the buffer pointed to by 'data', + including the NULL terminator. This member is only used + when the structure is part of an rout or inrout + parameter, but must be supplied by the caller as an + input in these cases. + dataLenReq : The size that would have been required to store the + entire result string. This member is only used when the + structure is part of an rout or inrout parameter, when + it is an output value set by the callee. The length of + the returned string (including the NULL terminator) + after a call is the minimum of dataLen and dataLenReq. + +See Also: + _wchar_t + _wstring_t + +======================================================================= + +_wstring_t + +Description: + This structure is used to represent an IDL wstring when used inside a + sequence or union. + +Definition: + typedef struct _wstring_s { + _wchar_t* data; + int dataLen; + int dataLenReq; + } _wstring_t; + +Members: + data : A pointer to the NULL-terminated wide string. + dataLen : The size, in 16-bit characters, of the buffer pointed to + by 'data', including the NULL terminator. This member + is only used when the structure is part of an rout or + inrout parameter, but must be supplied by the caller as + an input in these cases. + dataLenReq : The number of 16-bit characters that would have been + required to store the entire result string. This member + is only used when the structure is part of an rout or + inrout parameter, when it is an output value set by the + callee. The length of the returned wstring (including + the NULL terminator) after a call is the minimum of + dataLen and dataLenReq. + +See Also: + _cstring_t + _wchar_t + +======================================================================= +*/ + +#endif /* #ifndef AEESTDDEF_H */ + diff --git a/inc/AEEStdErr.h b/inc/AEEStdErr.h new file mode 100644 index 0000000..3309692 --- /dev/null +++ b/inc/AEEStdErr.h @@ -0,0 +1,320 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef AEESTDERR_H +#define AEESTDERR_H +// +// Basic Error Codes +// +// +#define DSP_AEE_EOFFSET 0x80000400 + +#if defined(__hexagon__) + #define AEE_EOFFSET DSP_AEE_EOFFSET +#else + #define AEE_EOFFSET 0x00000000 +#endif + +// Kernel error code start +#define KERNEL_ERRNO_START -1024 +// Userspace error code end +#define HLOS_ERR_END 1024 + +/** @defgroup stdbasicerror Basic error codes + * @{ + */ +#define AEE_SUCCESS 0 ///< No error +#define AEE_EUNKNOWN -1 ///< Unknown error (should not use this) + +#define AEE_EFAILED (AEE_EOFFSET + 0x001) ///< General failure +#define AEE_ENOMEMORY (AEE_EOFFSET + 0x002) ///< Memory allocation failed because of insufficient RAM +#define AEE_ECLASSNOTSUPPORT (AEE_EOFFSET + 0x003) ///< Specified class unsupported +#define AEE_EVERSIONNOTSUPPORT (AEE_EOFFSET + 0x004) ///< Version not supported +#define AEE_EALREADYLOADED (AEE_EOFFSET + 0x005) ///< Object already loaded +#define AEE_EUNABLETOLOAD (AEE_EOFFSET + 0x006) ///< Unable to load object/applet +#define AEE_EUNABLETOUNLOAD (AEE_EOFFSET + 0x007) ///< Unable to unload + ///< object/applet +#define AEE_EALARMPENDING (AEE_EOFFSET + 0x008) ///< Alarm is pending +#define AEE_EINVALIDTIME (AEE_EOFFSET + 0x009) ///< Invalid time +#define AEE_EBADCLASS (AEE_EOFFSET + 0x00A) ///< NULL class object +#define AEE_EBADMETRIC (AEE_EOFFSET + 0x00B) ///< Invalid metric specified +#define AEE_EEXPIRED (AEE_EOFFSET + 0x00C) ///< App/Component Expired +#define AEE_EBADSTATE (AEE_EOFFSET + 0x00D) ///< Process or thread is not in expected state +#define AEE_EBADPARM (AEE_EOFFSET + 0x00E) ///< Invalid parameter +#define AEE_ESCHEMENOTSUPPORTED (AEE_EOFFSET + 0x00F) ///< Invalid URL scheme +#define AEE_EBADITEM (AEE_EOFFSET + 0x010) ///< Value out of range +#define AEE_EINVALIDFORMAT (AEE_EOFFSET + 0x011) ///< Invalid format +#define AEE_EINCOMPLETEITEM (AEE_EOFFSET + 0x012) ///< Incomplete item, like length of a string is less that expected +#define AEE_ENOPERSISTMEMORY (AEE_EOFFSET + 0x013) ///< Insufficient flash +#define AEE_EUNSUPPORTED (AEE_EOFFSET + 0x014) ///< API not implemented +#define AEE_EPRIVLEVEL (AEE_EOFFSET + 0x015) ///< Privileges are insufficient + ///< for this operation +#define AEE_ERESOURCENOTFOUND (AEE_EOFFSET + 0x016) ///< Unable to find specified + ///< resource +#define AEE_EREENTERED (AEE_EOFFSET + 0x017) ///< Non re-entrant API + ///< re-entered +#define AEE_EBADTASK (AEE_EOFFSET + 0x018) ///< API called in wrong task + ///< context +#define AEE_EALLOCATED (AEE_EOFFSET + 0x019) ///< App/Module left memory + ///< allocated when released. +#define AEE_EALREADY (AEE_EOFFSET + 0x01A) ///< Operation is already in + ///< progress +#define AEE_EADSAUTHBAD (AEE_EOFFSET + 0x01B) ///< ADS mutual authorization + ///< failed +#define AEE_ENEEDSERVICEPROG (AEE_EOFFSET + 0x01C) ///< Need service programming +#define AEE_EMEMPTR (AEE_EOFFSET + 0x01D) ///< bad memory pointer, expected to be NULL +#define AEE_EHEAP (AEE_EOFFSET + 0x01E) ///< An internal heap error was detected +#define AEE_EIDLE (AEE_EOFFSET + 0x01F) ///< Context (system, interface, + ///< etc.) is idle +#define AEE_EITEMBUSY (AEE_EOFFSET + 0x020) ///< Context (system, interface, + ///< etc.) is busy +#define AEE_EBADSID (AEE_EOFFSET + 0x021) ///< Invalid subscriber ID +#define AEE_ENOTYPE (AEE_EOFFSET + 0x022) ///< No type detected/found +#define AEE_ENEEDMORE (AEE_EOFFSET + 0x023) ///< Need more data/info +#define AEE_EADSCAPS (AEE_EOFFSET + 0x024) ///< ADS Capabilities do not + ///< match those required for phone +#define AEE_EBADSHUTDOWN (AEE_EOFFSET + 0x025) ///< App failed to close properly +#define AEE_EBUFFERTOOSMALL (AEE_EOFFSET + 0x026) ///< Destination buffer given is + ///< too small + ///< or service exists or is + ///< valid +#define AEE_EACKPENDING (AEE_EOFFSET + 0x028) ///< ACK pending on application +#define AEE_ENOTOWNER (AEE_EOFFSET + 0x029) ///< Not an owner authorized to + ///< perform the operation +#define AEE_EINVALIDITEM (AEE_EOFFSET + 0x02A) ///< Current item is invalid, it can be a switch case or a pointer to memory +#define AEE_ENOTALLOWED (AEE_EOFFSET + 0x02B) ///< Not allowed to perform the + ///< operation +#define AEE_EINVHANDLE (AEE_EOFFSET + 0x02C) ///< Invalid handle - adding here as its defined in vendor AEEStdErr.h - needed to check valid handle in stub.c +#define AEE_EOUTOFHANDLES (AEE_EOFFSET + 0x02D) ///< Out of handles (Handle list is already full) +//Hole here +#define AEE_ENOMORE (AEE_EOFFSET + 0x02F) ///< No more items available -- + ///< reached end +#define AEE_ECPUEXCEPTION (AEE_EOFFSET + 0x030) ///< A CPU exception occurred +#define AEE_EREADONLY (AEE_EOFFSET + 0x031) ///< Cannot change read-only + ///< object or parameter ( Parameter is in protected mode) +#define AEE_ERPC (AEE_EOFFSET + 0x200) ///< Error due to fastrpc implementation +#define AEE_EFILE (AEE_EOFFSET + 0x201) ///= 200000 && !defined(__APCS_ADSABI)) || \ + (defined(__GNUC__) && defined(__arm__) && defined(__ARM_EABI__)) + +# define __AEEVA_ATPCS 0 + +#else + +# define __AEEVA_ATPCS 1 + +#endif + +typedef void* AEEVaList; + +#define __AEEVA_ARGALIGN(t) (((char*)(&((struct{char c;t x;}*)1)->x))-((char*)1)) +#define __AEEVA_ARGSIZE(t) ((sizeof(t)+sizeof(int)-1) & ~(sizeof(int)-1)) + +static __inline void __cpy(char*d, const char*s, int len) +{ + while (len-- > 0) *d++ = *s++; +} + +static __inline AEEVaList __AEEVa_Arg(AEEVaList args, void* pv, int nVSize, + int nArgSize, int nArgAlign) +{ + int nArgs = (int)args & ~1; + char* pcArgs = (char*)args; + int bATPCS = (int)args & 1; + int nArgsOffset = 0; + int nVOffset = 0; + + if (!bATPCS) { /* caller was compiled with AAPCS */ + + if (nArgAlign > (int)sizeof(int)) { + nArgAlign--; /* make a mask */ + pcArgs += ((nArgs + nArgAlign) & (int)~(unsigned)nArgAlign) - nArgs; + /* move pv to next alignment */ + } + } + +#if defined(AEE_BIGENDIAN) + if (nArgSize < (int)sizeof(int)) { + nArgsOffset = (int)sizeof(int) - nArgSize; + } + nVOffset = nVSize - nArgSize; +#else + (void)nVSize; +#endif /* AEE_BIGENDIAN */ + + __cpy((char*)pv + nVOffset, (pcArgs - bATPCS) + nArgsOffset, nArgSize); + + /* round up */ + nArgSize = (nArgSize+(int)sizeof(int)-1) & ~((int)sizeof(int)-1); + + return pcArgs + nArgSize; /* increment va */ +} + +#define AEEVA_START(va,v) ((va) = (char*)&(v) + __AEEVA_ARGSIZE(v) + __AEEVA_ATPCS) +#define AEEVA_ARG(va,v,t) ((void)((va) = __AEEVa_Arg(va,&v,sizeof(v),sizeof(t),__AEEVA_ARGALIGN(t)))) +#define AEEVA_END(va) ((va) = (AEEVaList)0) +#define AEEVA_COPY(dest, src) ((void)((dest) = (src))) + +#else /* !defined(__clang__) && (defined(__ARMCC_VERSION) || (defined(__GNUC__) && defined(__arm__))) */ + +#include + +typedef va_list AEEVaList; + +#define AEEVA_START(va,v) (va_start((va), (v))) +#define AEEVA_ARG(va,v,t) ((v) = va_arg((va),t)) +#define AEEVA_END(va) (va_end((va))) +#define AEEVA_COPY(dest, src) (va_copy((dest),(src))) + +#endif/* !defined(__clang__) && (defined(__ARMCC_VERSION) || (defined(__GNUC__) && defined(__arm__))) */ + +#endif /* #ifndef AEEVALIST_H */ + diff --git a/inc/AEEatomic.h b/inc/AEEatomic.h new file mode 100644 index 0000000..c2f28b4 --- /dev/null +++ b/inc/AEEatomic.h @@ -0,0 +1,198 @@ +/** + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AEEATOMIC_H +#define AEEATOMIC_H +/* +======================================================================= + +FILE: AEEatomic.h + +SERVICES: atomic + +DESCRIPTION: Fast Atomic ops + +======================================================================= +*/ + +#include "AEEStdDef.h" + +#ifdef __cplusplus +extern "C" { +#endif /* #ifdef __cplusplus */ + +uint32 atomic_Add(uint32 * volatile puDest, int nAdd); +uint32 atomic_Exchange(uint32 * volatile puDest, uint32 uVal); +uint32 atomic_CompareAndExchange(uint32 * volatile puDest, uint32 uExchange, uint32 uCompare); +uint32 atomic_CompareOrAdd(uint32 * volatile puDest, uint32 uCompare, int nAdd); + +uint64 atomic_CompareAndExchange64(uint64 * volatile puDest, uint64 uExchange, uint64 uCompare); +uintptr_t atomic_CompareAndExchangeUP(uintptr_t * volatile puDest, uintptr_t uExchange, uintptr_t uCompare); +#ifdef __cplusplus +} +#endif /* #ifdef __cplusplus */ + +/*===================================================================== +INTERFACE DOCUMENTATION +======================================================================= +atomic Interface + + The atomic interface provides fast "atomic" operations. The + operations are defined to be atomic with respect to each other. + +======================================================================= + +======================================================================= + +atomic_Add() + +Description: + + Performs an atomic sum operation. + +Prototype: + + uint32 atomic_Add(uint32* puDest, int nInc); + +Parameters: + puDest [in|out] : Points to unsigned number to add nInc and save + nInc : increment + +Return Value: + result. + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= + +atomic_Exchange() + +Description: + + Atomic exchange of 32bit value. Performs an atomic operation of : + write uVal to *puDest + return the previous value in *puDest + +Prototype: + + uint32 atomic_Exchange(uint32* puDest, uint32 uVal); + +Parameters: + puDest [in|out] : Points to unsigned number to be exchanged + uVal : new value to write. + +Return Value: + previous value at *puDest. + +Comments: + None + +Side Effects: + May cause exception if puDest is not a 32 bit aligned address. + +See Also: + None +======================================================================= + +atomic_CompareAndExchange() + +Description: + + Performs an atomic operation of : + if (*puDest == uCompare) { + *puDest = uExchange; + } + + returns the previous value in *puDest + +Prototype: + + uint32 atomic_CompareAndExchange(uint32 *puDest, uint32 uExchange, + uint32 uCompare); + +Parameters: + puDest [in|out] : Points to unsigned number. + uExchange : A new value to write to *puDest + uCompare : Comparand + +Return Value: + previous value at *puDest. + +Comments: + None + +Side Effects: + May cause exception if puDest is not a 32 bit aligned address. + +See Also: + None + +======================================================================= +atomic_CompareOrAdd() + +Description: + + Performs an atomic operation of : + if (*puDest != uCompare) { + *puDest += nAdd; + } + + returns the new value in *puDest + +Prototype: + + uint32 atomic_CompareOrAdd(uint32 *puDest, uint32 uCompare, int nAdd); + +Parameters: + puDest [in|out] : Points to unsigned number. + uCompare : Comparand + nAdd : Add to *puDest + +Return Value: + new value at *puDest. + +Comments: + None + +Side Effects: + May cause exception if puDest is not a 32 bit aligned address. + +See Also: + None +=======================================================================*/ + +#endif /* #ifndef AEEATOMIC_H */ + diff --git a/inc/AEEsmath.h b/inc/AEEsmath.h new file mode 100644 index 0000000..72e369b --- /dev/null +++ b/inc/AEEsmath.h @@ -0,0 +1,12 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +/*====================================================================== + +DESCRIPTION: Safe math library; implements saturating add. + +====================================================================*/ + +extern int smath_Add(int a, int b); +extern int smath_Sub(int a, int b); +extern int smath_Mul(int a, int b); diff --git a/inc/AEEstd.h b/inc/AEEstd.h new file mode 100644 index 0000000..2bfe32a --- /dev/null +++ b/inc/AEEstd.h @@ -0,0 +1,2655 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef AEESTD_H +#define AEESTD_H +/*==================================================================== + +DESCRIPTION: Standard library; general-purpose utility functions. + +====================================================================*/ +#include "AEEVaList.h" +#include "AEEStdDef.h" +#include "string.h" + +#define STD_CONSTRAIN( val, min, max ) (((val) < (min)) ? (min) : ((val) > (max)) ? (max) : (val)) +#define STD_BETWEEN( val, minGE, maxLT ) \ + ( ((unsigned long)(minGE) <= (unsigned long)(val)) && \ + ( (unsigned long)((unsigned long)(val) - (unsigned long)(minGE)) < \ + (unsigned long)((unsigned long)(maxLT) - (unsigned long)(minGE))) ) +#define STD_ARRAY_SIZE(a) ((int)((sizeof((a))/sizeof((a)[0])))) +#define STD_ARRAY_MEMBER(p,a) (((p) >= (a)) && ((p) < ((a) + STD_ARRAY_SIZE(a)))) + +#define STD_SIZEOF(x) ((int)sizeof(x)) +#define STD_OFFSETOF(type,member) (((char*)(&((type*)1)->member))-((char*)1)) + +#define STD_RECOVER_REC(type,member,p) ((void)((p)-&(((type*)1)->member)),\ + (type*)(void*)(((char*)(void*)(p))-STD_OFFSETOF(type,member))) +#define STD_MIN(a,b) ((a)<(b)?(a):(b)) +#define STD_MAX(a,b) ((a)>(b)?(a):(b)) +//lint -emacro(545,STD_ZEROAT) +#define STD_ZEROAT(p) std_memset((p), 0, sizeof(*p)) + +#define _STD_BITS_PER(bits) (8*sizeof((bits)[0])) + +#define STD_BIT_SET(bits, ix) ((bits)[(ix)/_STD_BITS_PER((bits))] |= 0x1<<((ix) & (_STD_BITS_PER((bits))-1))) +#define STD_BIT_CLEAR(bits, ix) ((bits)[(ix)/_STD_BITS_PER((bits))] &= ~(0x1<<((ix) & (_STD_BITS_PER((bits))-1)))) +#define STD_BIT_TEST(bits, ix) ((bits)[(ix)/_STD_BITS_PER((bits))] & (0x1<<((ix) & (_STD_BITS_PER((bits))-1)))) + +// +// Error codes +// +#define STD_NODIGITS 1 +#define STD_NEGATIVE 2 +#define STD_OVERFLOW 3 +#define STD_BADPARAM 4 +#define STD_UNDERFLOW 5 + +//Compute string length using strlen +#define std_strlen strlen + +#ifdef __cplusplus +extern "C" { +#endif /* #ifdef __cplusplus */ + +//Version function +extern int std_getversion(char *pcDst, int nDestSize); + +//String functions +extern int std_strcmp(const char *s1, const char *s2); +extern int std_strncmp(const char *s1, const char *s2, int n); +extern int std_stricmp(const char *s1, const char *s2); +extern int std_strnicmp(const char *s1, const char *s2, int n); +extern int std_strlcpy(char *pcDst, const char *pszSrc, int nDestSize); +extern int std_strlcat(char *pcDst, const char *pszSrc, int nDestSize); +extern char * std_strstr(const char *pszString, const char *pszSearch); + +//Character functions +extern char std_tolower(char c); +extern char std_toupper(char c); + +// Mem functions +extern void * std_memset(void *p, int c, int nLen); +extern void * std_memmove(void *pTo, const void *cpFrom, int nLen); +extern int std_memscpy(void *dst, int dst_size, const void *src, int src_size); +extern int std_memsmove(void *dst, int dst_size, const void *src, int src_size); +extern int std_memcmp(const void *a, const void *b, int length); +extern void * std_memchr(const void* s, int c, int n); +extern void * std_memstr(const char* cpHaystack, const char* cpszNeedle, int nHaystackLen); +extern void * std_memrchr(const void* s, int c, int n); +extern void * std_memrchrbegin(const void* p, int c, int nLen); +extern void * std_memchrend(const void* cpcSrch, int c, int nLen); +extern void * std_memchrsend(const void *cpSrch, const char* cpszChars, int nLen); + +//Other String functions +extern char * std_strchr(const char* s, int c); +extern char * std_strchrs(const char* sSrch, const char *sChars); +extern char * std_strrchr(const char* s, int c); +extern char * std_strchrend(const char *cpszSrch, char c); +extern char * std_strchrsend(const char* s, const char* cpszSrch); +extern char * std_strends(const char* cpsz, const char* cpszSuffix); +extern char * std_striends(const char* cpsz, const char* cpszSuffix); +extern char * std_strbegins(const char* cpsz, const char* cpszPrefix); +extern char * std_stribegins(const char* cpsz, const char* cpszPrefix); +extern int std_strcspn(const char* s, const char* cpszSrch); +extern int std_strspn(const char* s, const char* cpszSrch); + +//Wide char string functions +extern int std_wstrlen(const AECHAR *s); +extern int std_wstrlcpy(AECHAR *pcDst, const AECHAR *pszSrc, int nDestSize); +extern int std_wstrlcat(AECHAR *pcDst, const AECHAR *pszSrc, int nDestSize); +extern int std_wstrncmp(const AECHAR* s1, const AECHAR* s2, int nLen); +extern int std_wstrcmp(const AECHAR* s1, const AECHAR* s2); +extern AECHAR* std_wstrchr(const AECHAR* cpwszText, AECHAR ch); +extern AECHAR* std_wstrrchr(const AECHAR* cpwszText, AECHAR ch); + +//Path functions +extern int std_makepath(const char *cpszDir, + const char *cpszFile, + char *pszDest, int nDestSize); +extern char * std_splitpath(const char *cpszPath, const char *cpszDir); +extern char * std_cleanpath(char *pszPath); +extern char * std_basename(const char *pszPath); + +//Inet functions, number functions +extern unsigned int std_scanul(const char *pchBuf, int nRadix, + const char **ppchEnd, int *pnError); +extern uint64 std_scanull(const char *pchBuf, int nRadix, + const char **ppchEnd, int *pnError); +extern double std_scand(const char *pchBuf, const char **ppchEnd); + +// Rand functions +extern unsigned std_rand_next(unsigned uRand); +extern uint32 std_rand(uint32 uSeed, byte* pDest, int nSize); + + +// printf functions +extern int std_vstrlprintf(char *pszDest, int nDestSize, + const char *pszFmt, AEEVaList args); + +extern int std_strlprintf(char *pszDest, int nDestSize, + const char *pszFmt, ...); + +extern int std_vsnprintf(char *pszDest, int nDestSize, + const char *cpszFmt, AEEVaList args); + +extern int std_snprintf(char *pszDest, int nDestSize, + const char *pszFmt, ...); + +// endian swapping functions +extern int std_CopyLE(void *pvDest, int nDestSize, + const void *pvSrc, int nSrcSize, + const char *pszFields); + +extern int std_CopyBE(void *pvDest, int nDestSize, + const void *pvSrc, int nSrcSize, + const char *pszFields); + +// sorting utilities +extern void std_qsort(void* pElems, int nNumElems, int nElemWidth, + int (*pfnCompare)(void*, const void*, const void*), + void* pCompareCx); + +extern int std_bisect(const void* pElems, int nNumElems, int nElemWidth, + const void* pElem, + int (*pfnCompare)(void*, const void*, const void*), + void* pCompareCx); + +extern void std_merge(void* vpDst, int nDst, + const void* vpA, int nA, + const void* vpB, int nB, + int nElemWidth, + int (*pfnCompare)(void*, const void*, const void*), + void* pCompareCx); + +extern int std_uniq(void* vpElems, int nNumElems, int nElemWidth, + int (*pfnCompare)(void*, const void*, const void*), + void* pCompareCx); + +#ifdef __cplusplus +} +#endif /* #ifdef __cplusplus */ + + +#define STD_SWAPS(us) \ + ((((us) & 0xff) << 8) + (((us) & 0xff00) >> 8)) + + +static __inline unsigned short std_swaps(unsigned short us) +{ + return STD_SWAPS(us); +} + +/* note, STD_SWAPL() requires that ul be an l-value, and destroyable. + this macro is not intended for use outside AEEstd.h */ +#define STD_SWAPL(ul) \ + (((ul) = (((ul) & 0x00ff00ff) << 8) | (((ul)>>8) & 0x00ff00ff)),(((ul) >> 16) | ((ul) << 16))) + +static __inline unsigned long std_swapl(unsigned long ul) +{ + return STD_SWAPL(ul); +} + +#ifdef AEE_BIGENDIAN +# define STD_HTONL(u) (u) +# define STD_HTONS(u) (u) +# define STD_HTOLEL(u) (STD_SWAPL(u)) +# define STD_HTOLES(u) (STD_SWAPS(u)) +#else +# define STD_HTONL(u) (STD_SWAPL(u)) +# define STD_HTONS(u) (STD_SWAPS(u)) +# define STD_HTOLEL(u) (u) +# define STD_HTOLES(u) (u) +#endif + +static __inline unsigned short std_letohs(unsigned short us) +{ + return STD_HTOLES(us); +} + +static __inline unsigned short std_htoles(unsigned short us) +{ + return STD_HTOLES(us); +} + +static __inline unsigned long std_letohl(unsigned long ul) +{ + return STD_HTOLEL(ul); +} + +static __inline unsigned long std_htolel(unsigned long ul) +{ + return STD_HTOLEL(ul); +} + +static __inline unsigned short std_ntohs(unsigned short us) +{ + return STD_HTONS(us); +} + +static __inline unsigned short std_htons(unsigned short us) +{ + return STD_HTONS(us); +} + +static __inline unsigned long std_ntohl(unsigned long ul) +{ + return STD_HTONL(ul); +} + +static __inline unsigned long std_htonl(unsigned long ul) +{ + return STD_HTONL(ul); +} + + +#undef STD_HTONL // private macro; not exported as a supported API +#undef STD_HTONS // private macro; not exported as a supported API +#undef STD_HTOLEL // private macro; not exported as a supported API +#undef STD_HTOLES // private macro; not exported as a supported API +#undef STD_SWAPS // private macro; not exported as a supported API +#undef STD_SWAPL // private macro; not exported as a supported API + + +/* +======================================================================= +MACROS DOCUMENTATION +======================================================================= + +STD_CONTSTRAIN() + +Description: + STD_CONTSTRAIN() constrains a number to be between two other numbers. + +Definition: + STD_CONSTRAIN( val, min, max ) \ + (((val) < (min)) ? (min) : ((val) > (max)) ? (max) : (val)) + +Parameters: + val: number to constrain + min: number to stay greater than or equal to + max: number to stay less than or equal to + +Evaluation Value: + the constrained number + +======================================================================= + +STD_BETWEEN() + +Description: + STD_BETWEEN() tests whether a number is between two other numbers. + +Definition: + STD_BETWEEN( val, minGE, maxLT ) \ + ((unsigned)((unsigned)(val) - (unsigned)(minGE)) < \ + (unsigned)((unsigned)(maxLT) - (unsigned)(minGE))) + +Parameters: + val: value to test + minGE: lower bound + maxLT: upper bound + +Evaluation Value: + 1 if val >= minGE and val < maxLT + +======================================================================= + +STD_ARRAY_SIZE() + +Description: + STD_ARRAY_SIZE() gives the number of elements in a statically allocated array. + +Definition: + STD_ARRAY_SIZE(a) (sizeof((a))/sizeof((a)[0])) + +Parameters: + a: array to test + +Evaluation Value: + number of elements in a + +======================================================================= + +STD_ARRAY_MEMBER() + +Description: + STD_ARRAY_MEMBER() tests whether an item is a member of a statically allocated array. + +Definition: + STD_ARRAY_MEMBER(p,a) (((p) >= (a)) && ((p) < ((a) + STD_ARRAY_SIZE(a)))) + +Parameters: + p: item to test + a: array to check + +Evaluation Value: + 1 if p is in a + +======================================================================= + +STD_OFFSETOF() + +Description: + STD_OFFSETOF() gives the offset of member of a struct. + +Definition: + STD_OFFSETOF(type,member) (((char *)(&((type *)0)->member))-((char *)0)) + +Parameters: + type: structured type + member: name of member in the struct + +Evaluation Value: + offset of member (in bytes) in type + +======================================================================= + +STD_RECOVER_REC() + +Description: + STD_RECOVER_REC() provides a safe cast from a pointer to a member + of a struct to a pointer to the containing struct + +Definition: + STD_RECOVER_REC(type,member,p) ((type*)(((char*)(p))-STD_OFFSETOF(type,member))) + +Parameters: + type: structured type + member: name of member in the struct + p: pointer to the member of the struct + +Evaluation Value: + a pointer of type type to the containing struct + +======================================================================= + +STD_MIN() + +Description: + STD_MIN() finds the smaller of two values. + +Definition: + STD_MIN(a,b) ((a)<(b)?(a):(b)) + +Parameters: + a, b: values to compare + +Evaluation Value: + smaller of a and b + +======================================================================= + +STD_MAX() + +Description: + STD_MAX() finds the larger of two values. + +Definition: + STD_MAX(a,b) ((a)>(b)?(a):(b)) + +Parameters: + a, b: values to compare + +Evaluation Value: + larger of a and b + +======================================================================= + +STD_ZEROAT() + +Description: + STD_ZEROAT() zero-initializes the contents of a typed chunk of memory. + +Definition: + STD_ZEROAT(p) std_memset((p), 0, sizeof(*p)) + +Parameters: + p: the chunk to initialize + +Evaluation Value: + p + +======================================================================= + +STD_BIT_SET() + +Description: + STD_BIT_SET(bits, ix) sets the bit in the memory stored in bits at + index ix + +Parameters: + bits: the memory address holding the bits + ix: the index of the bit to set; + +======================================================================= + +STD_BIT_CLEAR() + +Description: + STD_BIT_CLEAR(bits, ix) clears the bit in the memory stored in bits + at index ix + +Parameters: + bits: the memory address holding the bits + ix: the index of the bit to clear + +======================================================================= + +STD_BIT_TEST() + +Description: + STD_BIT_TEST(bits, ix) returns the bit in the memory stored in bits + at index ix + +Parameters: + bits: the memory address holding the bits + ix: the index of the bit to test + +Evaluation Value: + 0x1 if set 0x0 if not set + +===================================================================== +INTERFACES DOCUMENTATION +======================================================================= + +std Interface + +Description: + This library provides a set of general-purpose utility functions. + Functionality may overlap that of a subset of the C standard library, but + this library differs in a few respects: + + - Functions are fully reentrant and avoid use of static variables. + + - The library can be supported consistently across all environments. + Compiler-supplied libraries sometimes behave inconsistently and are + unavailable in some environments. + + - Omits "unsafe" functions. C standard library includes many functions + that are best avoided entirely: strcpy, strcat, strtok, etc. + + +======================================================================= + +std_getversion() + +Description: + + The std_getversion() copies the stdlib version to pcDst. This function + takes the size of the destination buffer as an argument and guarantees + to zero-terminate the result and not to overflow the nDestSize size. + + This function copies up to size-1 characters from the stdlib version + string to pcDest and NUL-terminates the pcDest string. + +Prototype: + int std_getversion(char *pcDst, int nDestSize) + + +Parameters: + pcDst : Destination string + nDestSize: Size of the destination buffer in bytes + +Return Value: + + Returns the length of the version string (in characters). + +======================================================================= + +std_strlen() + +Description: + The std_strlen() computes the length of the given string. + +Prototype: + int std_strlen(const char *cpszStr) + +Parameters: + cpszStr : String whose length will be computed + +Return Value: + Length of the string in characters that precede the terminating NULL character. + +======================================================================= + +std_strcmp() + +Description: + The std_strcmp() compares two NUL-terminated character strings. + Comparison is strictly by byte values with no character set + interpretation. + +Prototype: + + int std_strcmp(const char *s1, const char *s2); + +Parameters: + s1, s2: strings to compare + +Return Value: + 0 if strings are the same ~ + < 0 if s1 is less than s2 ~ + > 0 if s1 is greater than s2 + +See Also: + std_wstrcmp + +======================================================================= + +std_strncmp() + +Description: + The std_strncmp() compares at most n bytes of two NUL-terminated character strings. + +Prototype: + + int std_strncmp(const char *s1, const char *s2, int n); + +Parameters: + s1, s2: strings to compare + n: maximum number of bytes to compare. if either s1 or s2 is + shorter than n, the function terminates there + +Return Value: + 0 if strings are the same ~ + < 0 if s1 is less than s2 ~ + > 0 if s1 is greater than s2 + +See Also: + std_wstrncmp + +======================================================================= + +std_stricmp() + +Description: + The std_stricmp() compares two NUL-terminated character strings, case-folding any + ASCII characters. + +Prototype: + + int std_stricmp(const char *s1, const char *s2); + +Parameters: + s1, s2: strings to compare + +Return Value: + 0 if strings are the same ~ + < 0 if s1 is less than s2 ~ + > 0 if s1 is greater than s2 + +======================================================================= + +std_strnicmp() + +Description: + The std_strnicmp() compares at most n bytes of 2 NUL-terminated character strings, + case-folding any ASCII characters. + +Prototype: + + int std_strnicmp(const char *s1, const char *s2, int n); + +Parameters: + s1, s2: strings to compare + n: maximum number of bytes to compare. if either s1 or s2 is + shorter than n, the function terminates there + +Return Value: + 0 if strings are the same ~ + < 0 if s1 is less than s2 ~ + > 0 if s1 is greater than s2 + +======================================================================= + +std_strlcpy() + +Description: + + The std_strlcpy() copies pszSrc string to the pcDst. It is a safer + alternative to strcpy() or strncpy(). This function takes the size of the + destination buffer as an argument and guarantees to NUL-terminate the + result and not to overflow the nDestSize size. + + This function copies up to nDestSize-1 characters from the pszSrc string + to pcDest and NUL-terminates the pcDest string. + +Prototype: + int std_strlcpy(char *pcDst, const char *pszSrc, int nDestSize) + +Parameters: + pcDst : Destination string + pcSrc : Source string + nDestSize: Size of the destination buffer in bytes + +Return Value: + + Returns the length of the string (in characters) it tried to create, + which is same as length of pszSrc. + + Example: + + { + char buf[64]; + if (std_strlcpy(buf, file_name, STD_ARRAY_SIZE(buf) >= + STD_ARRAY_SIZE(buf)) { + //Truncated -- Handle overflow.... + } + } + +Comment: + + Unlike strlcpy, std_strlcpy accepts an integer size and does nothing when a + negative value is passed. When passing valid sizes for objects on our + supported platforms, this should not result in any observed difference. + However, calling strlcpy() with UINT_MAX will result in the entire source + string being copied, whereas std_strlcpy() will do nothing. Passing INT_MAX + to str_strlcpy() will achieve the same result (although both these cases are + bad practice since they defeat bounds checking). + + +======================================================================= + +std_strlcat() + +Description: + + The std_strlcat() function concatenates a string to a string already + residing in a buffer. It is a safer alternative to strcat() or strncat(). + This function takes the size of the destination buffer as an argument and + guarantees not to create an improperly terminated string and not to + overflow the nDestSize size. + + This function appends pszSrc to pcDst, copying at most nDestSize minus + the length of the string in pcDest minus 1 bytes, always NUL-terminating + the result. + + For compatibility with "strlcat()", std_strlcat() does *not* zero-terminate + the destination buffer in cases where the buffer lacks termination on entry + to the function. Do not rely on std_strlcat() to zero-terminate a buffer + that is not already zero-terminated; instead ensure that the buffer is + properly initialized using std_strlcpy() or some other means. + +Prototype: + + int std_strlcat(char *pcDst, const char *pszSrc, int nDestSize) + +Parameters: + + pcDst : Destination string + pcSrc : Source string + nDestSize: Size of the destination buffer in bytes + +Return Value: + + Returns the length of the string (in characters) it tried to create, + which is same as length of pszSrc plus the length of pszDest. + + Example: + + { + char buf[64]; + if (std_strlcat(buf, file_name, STD_ARRAY_SIZE(buf) >= + STD_ARRAY_SIZE(buf)) { + //Truncated -- Handle overflow.... + } + } + + +======================================================================= + +std_strstr() + +Description: + The std_strstr() finds the first occurrence of a substring in a string. + +Prototype: + + char * std_strstr(const char *pszString, const char *pszSearch); + +Parameters: + pszString: string to search + pszSearch: sub string to search for + +Return Value: + A pointer to the first character in the first occurrence of the substring if found, NULL otherwise + +======================================================================= + +std_tolower() + +Description: + The std_tolower() converts an uppercase letter to the corresponding + lowercase letter. + +Prototype: + char std_tolower(char c); + +Parameters: + c: A character. + +Return Value: + the corresponding lowercase letter if c is an ASCII character whose + value is representable as an uppercase letter, else the same character + c is returned. + +======================================================================= + +std_toupper() + +Description: + The std_toupper() converts an lowercase letter to the corresponding + uppercase letter. + +Prototype: + char std_toupper(char c); + +Parameters: + c: is a character. + +Return Value: + The corresponding uppercase letter if c is an ASCII character whose + value is representable as an lowercase letter; else the same character + c is returned. + +======================================================================= + +std_memset() + +Description: + The std_memset() sets each byte in a block of memory to a value. + +Prototype: + + void *std_memset(void *p, int c, int nLen); + +Parameters: + p: memory block to set + c: value to set each byte to + nLen: size of p in bytes + +Return Value: + p + +======================================================================= + +std_memmove() + +Description: + The std_memmove() copies a block of memory from one buffer to another. + +Prototype: + + void *std_memmove(void *pTo, const void *cpFrom, int nLen); + +Parameters: + pTo: destination buffer + cpFrom: source buffer + nLen: number of bytes to copy + +Return Value: + pTo + +======================================================================= + +std_memsmove() + +Description: + + Size bounded memory move. + + Moves bytes from the source buffer to the destination buffer. + + This function ensures that there will not be a copy beyond + the size of the destination buffer. + + This function should be used in preference to memscpy() if there + is the possiblity of source and destination buffers overlapping. + The result of the operation is defined to be as if the copy were from + the source to a temporary buffer that overlaps neither source nor + destination, followed by a copy from that temporary buffer to the + destination. + +Prototype: + + int std_memsmove(void *dst, int dst_size, const void *src, int src_size); + +Parameters: + @param[out] dst Destination buffer. + @param[in] dst_size Size of the destination buffer in bytes. + @param[in] src Source buffer. + @param[in] src_size Number of bytes to copy from source buffer. + +Return value: + The number of bytes copied to the destination buffer. It is the + caller's responsibility to check for trunction if it cares about it - + truncation has occurred if the return value is less than src_size. + A negative return value indicates an error + +======================================================================= + +std_memcmp() + +Description: + The std_memcmp() compares two memory buffers, byte-wise. + +Prototype: + + int std_memcmp(const void *a, const void *b, int length); + +Parameters: + a, b: buffers to compare + length: number of bytes to compare + +Return Value: + 0 if buffers are the same for nLength ~ + < 0 if a is less than b ~ + > 0 if a is greater than b + +======================================================================= + +std_memscpy - Size bounded memory copy. + +Description: + + Copies bytes from the source buffer to the destination buffer. + + This function ensures that there will not be a copy beyond + the size of the destination buffer. + + The result of calling this on overlapping source and destination + buffers is undefined. + +Prototype: + + int std_memscpy(void *dst, int dst_size, const void *src, int src_size); + +Parameters: + + @param[out] dst Destination buffer. + @param[in] dst_size Size of the destination buffer in bytes. + @param[in] src Source buffer. + @param[in] src_size Number of bytes to copy from source buffer. + +Return value: + + The number of bytes copied to the destination buffer. It is the + caller's responsibility to check for trunction if it cares about it - + truncation has occurred if the return value is less than src_size. + Returs a negative value on error. + +======================================================================= + +std_memchr() + +Description: + The std_memchr() finds the first occurrence of a character in a memory + buffer. + +Prototype: + + void *std_memchr(const void* s, int c, int n); + +Parameters: + s: buffer to search + c: value of byte to look for + n: size of s in bytes + +Return Value: + A pointer to the occurrence of c. NULL if not found. + +======================================================================= + +std_memstr() + +Description: + The std_memstr() finds the first occurrence of a substring in a memory + buffer. + +Prototype: + + void *std_memstr(const char* cpHaystack, const char* cpszNeedle, + int nHaystackLen); + +Parameters: + cpHaystack: buffer to search + cpszNeedle: NUL-terminated string to search for + nHaystackLen: size of cpHaystack in bytes + +Return Value: + a pointer to the first occurrence of cpszNeedle if found, + NULL otherwise + +Comments: + None + +Side Effects: + None + +See Also: + None + +======================================================================= + +std_memrchr() + +Description: + + The std_memrchr() finds the last occurrence of a character in a memory + buffer. + +Prototype: + + void *std_memrchr(const void* s, int c, int n); + +Parameters: + s: buffer to search + c: value of byte to look for + n: size of s in bytes + +Return Value: + a pointer to the last occurrence of c, NULL if not found + +======================================================================= + +std_memrchrbegin() + +Description: + The std_memrchrbegin() finds the last occurrence of a character in a + memory buffer. + +Prototype: + + void *std_memrchrbegin(const void* s, int c, int n); + +Parameters: + s: buffer to search + c: value of byte to look for + n: size of s in bytes + +Return Value: + a pointer to the last occurrence of c, or s if not found + +======================================================================= + +std_memchrend() + +Description: + The std_memchrend() finds the first occurrence of a character in a + memory buffer. + +Prototype: + + void *std_memchrend(const void* s, int c, int n); + +Parameters: + s: buffer to search + c: value of byte to look for + n: size of s in bytes + +Return Value: + a pointer to the occurrence of c, s + n if not found + +======================================================================= +std_memchrsend() + +Description: + The std_memchrsend() finds the first occurrence of any character in a + NUL-terminated list of characters in a memory buffer. + +Prototype: + + void *std_memchrend(const void* s, const char* cpszChars, int n); + +Parameters: + s: buffer to search + cpszChars: characters to look for + n: size of s in bytes + +Return Value: + a pointer to the first occurrence of one of cpszChars, s + n if not found + +======================================================================= + +std_strchr() + +Description: + The std_strchr() finds the first occurrence of a character in a + NUL-terminated string. + +Prototype: + + char *std_strchr(const char* s, int c); + +Parameters: + s: string to search + c: char to search for + +Return Value: + pointer to first occurrence, NULL if not found + +See Also: + std_wstrchr + +======================================================================= + +std_strchrs() + +Description: + The std_strchrs() searches s, a NUL-terminated string, for the first + occurrence of any characters in cpszSrch, a NUL-terminated list of + characters. + +Prototype: + + char *std_strchrs(const char* s, const char *cpszSrch); + +Parameters: + s: string to search + cpszSrch: a list of characters to search for + +Return Value: + first occurrence of any of cpszSrch, NULL if not found + +======================================================================= + +std_strrchr() + +Description: + The std_strrchr() finds the last occurrence of a character in a + NUL-terminated string. + +Prototype: + + char *std_strrchr(const char* s, int c); + +Parameters: + s: string to search + c: char to search for + +Return Value: + pointer to last occurrence, NULL if not found + +See Also: + std_wstrrchr + +======================================================================= + +std_strchrend() + +Description: + The std_strchrend() finds the first occurrence of a character in a + NUL-terminated string. + +Prototype: + + char *std_strchrend(const char* s, int c); + +Parameters: + s: string to search + c: char to search for + +Return Value: + pointer to first occurrence, s + std_strlen(s) if not found + +======================================================================= + +std_strchrsend() + +Description: + The std_strchrsend() searches s, a NUL-terminated string, for the first + occurrence of any characters in cpszSrch, a NUL-terminated list of + characters. + +Prototype: + + char *std_strchrsend(const char* s, const char* cpszSrch); + +Parameters: + s: string to search + cpszSrch: a list of characters to search for + +Return Value: + first occurrence of any of cpszSrch or s+strlen(s) if not found + +======================================================================= + +std_strends() + +Description: + The std_strends() tests whether a string ends in a particular suffix. + +Prototype: + + char *std_strends(const char* cpsz, const char* cpszSuffix); + +Parameters: + cpsz: string to test + cpszSuffix: suffix to test for + +Return Value: + the first character of cpsz+std_strlen(cpsz)-std_strlen(cpszSuffix) + if cpsz ends with cpszSuffix. NULL otherwise. + +======================================================================= + +std_striends() + +Description: + The std_striends() tests whether a string ends in a particular suffix, + case-folding ASCII characters. + +Prototype: + + char *std_striends(const char* cpsz, const char* cpszSuffix); + +Parameters: + cpsz: string to test + cpszSuffix: suffix to test for + +Return Value: + the first character of cpsz+std_strlen(cpsz)-std_strlen(cpszSuffix) + if cpsz ends with cpszSuffix. NULL otherwise. + +======================================================================= + +std_strbegins() + +Description: + The std_strbegins() tests whether a string begins with a particular + prefix string. + +Prototype: + + char *std_strbegins(const char* cpsz, const char* cpszPrefix); + +Parameters: + cpsz: string to test + cpszPrefix: prefix to test for + +Return Value: + cpsz + std_strlen(cpszPrefix) if cpsz does begin with cpszPrefix, + NULL otherwise + +======================================================================= + +std_stribegins() + +Description: + The std_stribegins() tests whether a string begins with a particular + prefix string, case-folding ASCII characters. + +Prototype: + + char *std_stribegins(const char* cpsz, const char* cpszPrefix); + +Parameters: + cpsz: string to test + cpszPrefix: prefix to test for + +Return Value: + cpsz + std_strlen(cpszPrefix) if cpsz does begin with cpszPrefix, + NULL otherwise + + +======================================================================= + +std_strcspn() + +Description: + The std_strcspn() function searches s, a NUL-terminated string, for + the first occurrence of any characters in cpszSrch, a NUL-terminated + list of characters. This function returns the length of the longest + initial substring of s which consists of characters not present in + cpszSrch. + +Prototype: + + int std_strcspn(const char* s, const char* cpszSrch); + +Parameters: + s: string to search + cpszSrch: a list of characters to search for + +Return Value: + The index into the string s of the first occurrence of any of the + characters in cpszSrch. If no match is found, then index of the + terminating NUL character is returned. + +See Also: + std_strspn, std_strchr, std_strchrs + +======================================================================= + +std_strspn() + +Description: + The std_strspn() functions searches s, a NUL-terminated string, for + the first occurrence of a character that matches none of the + characters in cpszSrch, a NUL-terminated list of characters. This + function returns the length of the longest initial substring of s + which consists of characters present in cpszSrch. + +Prototype: + + int std_strspn(const char* s, const char* cpszSrch); + +Parameters: + s: string to search + cpszSrch: a list of characters to search for + +Return Value: + The index into the string s of the first occurrence of any character + that matches none of the characters in cpszSrch. If all characters + in s are present in cpszSrch, the index of the terminating NUL + character is returned. + +See Also: + std_strcspn, std_strchr, std_strchrs + +======================================================================= + +std_wstrlcpy() + +Description: + + The std_wstrlcpy() function copies a string. It is equivalent to + str_strlcpy() except that it operates on wide (16-bit) character strings. + See std_strlcpy() for details. + + +Prototype: + + int std_wstrlcpy(AECHAR *pcDest, const AECHAR *pszSrc, int nDestSize); + +Parameters: + pcDst: destination string + pszSrc: source string + int nDestSize: size of pcDest __in AECHARs__ + +Return Value: + Returns the length of the string (in AECHARs) it tried to create, + which is same as length of pszSrc. + + Example: + + { + AECHAR buf[64]; + if (std_wstrlcpy(buf, file_name, STD_ARRAY_SIZE(buf)) >= + STD_ARRAY_SIZE(buf)) { + //Truncated -- Handle overflow.... + } + } + +See Also: + std_wstrlcat + +======================================================================= + +std_wstrlcat() + +Description: + + The std_wstrlcat() function concatenates two strings. It is equivalent to + std_strlcat() except that it operates on wide (16-bit) character strings. + See std_strlcat() for more information. + +Prototype: + int std_wstrlcat(AECHAR *pcDst, const AECHAR *pszSrc, int nDestSize) + +Parameters: + pcDst[out]: Destination string + pcSrc : Source string + nDestSize: Size of the destination buffer in AECHARs + +Return Value: + Returns the length of the string (in AECHARs) it tried to create, + which is same as length of pszSrc + the length of pszDest. + + Example: + + { + char buf[64]; + if (std_wstrlcat(buf, file_name, STD_ARRAY_SIZE(buf)) >= + STD_ARRAY_SIZE(buf)) { + //Truncated -- Handle overflow.... + } + } + +See Also: + std_wstrlcpy + +======================================================================= + +std_wstrncmp() + +Description: + + The std_wstrncmp() function compares up to a specified number of bytes + in two NUL-terminated strings. It is equivalent to std_strncmp() except + that it operates on wide (16-bit) character strings. + +Prototype: + int std_wstrncmp(const AECHAR* s1, const AECHAR* s2, int nLen); + +Parameters: + s1, s2: strings to compare + n: maximum number of AECHARs to compare. if either s1 or s2 is + shorter than n, the function terminates there. + +Return Value: + 0 if strings are the same ~ + < 0 if s1 is less than s2 ~ + > 0 if s1 is greater than s2 + +See Also: + std_strncmp + +======================================================================= + +std_wstrcmp() + +Description: + The std_wstrcmp() compares two NUL-terminated strings. It is equivalent + to std_strncmp() except that it operates on wide (16-bit) character + strings. Comparison is strictly by byte values with no character set + interpretation. + +Prototype: + + int std_wstrcmp(const AECHAR* s1, const AECHAR* s2); + +Parameters: + s1, s2: strings to compare + +Return Value: + 0 if strings are the same ~ + < 0 if s1 is less than s2 ~ + > 0 if s1 is greater than s2 + +See Also: + std_strcmp + +======================================================================= + +std_wstrchr() + +Description: + This function is the wide string counterpart of std_strchr(). + The std_wstrchr() finds the first occurrence of a character in a + NUL-terminated wide (16-bit) character string. + +Prototype: + + AECHAR* std_wstrchr(const AECHAR* s, AECHAR ch); + +Parameters: + s: string to search + ch: char to search for + +Return Value: + pointer to first occurrence, NULL if not found + +See Also: + std_strchr + +======================================================================= + +std_wstrrchr() + +Description: + This function is the wide string counterpart of std_strrchr(). + The std_wstrrchr() finds the last occurrence of a character in a + NUL-terminated wide (16-bit) character string. + +Prototype: + + AECHAR* std_wstrrchr(const AECHAR* s, AECHAR ch); + +Parameters: + s: string to search + ch: char to search for + +Return Value: + pointer to last occurrence, NULL if not found + +See Also: + std_strrchr + +======================================================================= + +std_makepath() + +Description: + The std_makepath() constructs a path from a directory portion and a file + portion, using forward slashes, adding necessary slashes and deleting extra + slashes. This function guarantees NUL-termination of pszDest + +Prototype: + + int std_makepath(const char *cpszDir, const char *cpszFile, + char *pszDest, int nDestSize) + +Parameters: + cpszDir: directory part + cpszFile: file part + pszDest: output buffer + nDestSize: size of output buffer in bytes + +Return Value: + the required length to construct the path, not including + NUL-termination + +Comments: + The following list of examples shows the strings returned by + std_makepath() for different paths. + +Example: + + cpszDir cpszFile std_makepath() + "" "" "" + "" "/" "" + "/" "" "/" + "/" "/" "/" + "/" "f" "/f" + "/" "/f" "/f" + "d" "f" "d/f" + "d/" "f" "d/f" + "d" "/f" "d/f" + "d/" "/f" "d/f" + +See Also: + std_splitpath + +======================================================================= + +std_splitpath() + +Description: + The std_splitpath() finds the filename part of a path given an inclusive + directory, tests for cpszPath being in cpszDir. The forward slashes are + used as directory delimiters. + +Prototype: + + char *std_splitpath(const char *cpszPath, const char *cpszDir); + +Parameters: + cpszPath: path to test for inclusion + cpszDir: directory that cpszPath might be in + +Return Value: + the part of cpszPath that actually falls beneath cpszDir, NULL if + cpszPath is not under cpszDir + +Comments: + The std_splitpath() is similar to std_strbegins(), but it ignores trailing + slashes on cpszDir, and it returns a pointer to the first character of + the subpath. + + The return value of std_splitpath() will never begin with a '/'. + + The following list of examples shows the strings returned by + std_splitpath() for different paths. + +Example: + cpszPath cpszDir std_splitpath() + "" "" "" + "" "/" "" + "/" "" "" + "/" "/" "" + "/d" "d" null + "/d" "/" "d" + "/d/" "/d" "" + "/d/f" "/" "d/f" + "/d/f" "/d" "f" + "/d/f" "/d/" "f" + +See Also: + std_makepath + +======================================================================= + +std_cleanpath() + +Description: + The std_cleanpath() removes double slashes, ".", and ".." from + slash-delimited paths,. It operates in-place. + +Prototype: + + char *std_cleanpath(char *pszPath); + +Parameters: + pszPath[in/out]: path to "clean" + +Return Value: + pszPath + +Comments: + Passing an "fs:/" path to this function may produce undesirable + results. This function assumes '/' is the root. + +Examples: + pszPath std_cleanpath() + "", "", + "/", "/", + + // here"s, mostly alone + "./", "/", + "/.", "/", + "/./", "/", + + // "up"s, mostly alone + "..", "", + "/..", "/", + "../", "/", + "/../", "/", + + // fun with x + "x/.", "x", + "x/./", "x/", + "x/..", "", + "/x/..", "/", + "x/../", "/", + "/x/../", "/", + "/x/../..", "/", + "x/../..", "", + "x/../../", "/", + "x/./../", "/", + "x/././", "x/", + "x/.././", "/", + "x/../.", "", + "x/./..", "", + "../x", "/x", + "../../x", "/x", + "/../x", "/x", + "./../x", "/x", + + // double slashes + "//", "/", + "///", "/", + "////", "/", + "x//x", "x/x", + + +Side Effects: + None + +See Also: + None + + +======================================================================= + +std_basename() + +Description: + The std_basename() returns the filename part of a string, + assuming '/' delimited filenames. + +Prototype: + + char *std_basename(const char *cpszPath); + +Parameters: + cpszPath: path of interest + +Return Value: + pointer into cpszPath that denotes part of the string immediately + following the last '/' + +Examples: + cpszPath std_basename() + "" "" + "/" "" + "x" "x" + "/x" "x" + "y/x" "x" + "/y/x" "x" + + See Also: + None + +======================================================================= + +std_rand_next() + +Description: + The std_rand_next() generates pseudo-random bytes. + +Prototype: + + unsigned std_rand_next(unsigned uRand); + +Parameters: + uRand: a seed for the pseudo-random generator + +Return Value: + the next value in the generator from uRand + +Comments: + for best results, this function should be called with its last + generated output. + + This is an example of code to generate 256 bytes of pseudo-random data. + + This is not crypto quality and should not be used for key generation + and the like. + +Example: + { + unsigned rand_buf[256/sizeof(unsigned)]; + int i; + unsigned uLast = std_rand_next(uCurrentTime); + for (i = 0; i < STD_ARRAY_SIZE(rand_buf); i++) { + rand_buf[i] = (uLast = std_rand_next(uLast)); + } + } + +See Also: + std_rand() + +======================================================================= + +std_rand() + +Description: + The std_rand() functions generates pseudo-random bytes and places it + in an output buffer of specified size. + +Prototype: + + uint32 std_rand(uint32 uSeed, byte* pDest, int nSize); + +Parameters: + uSeed: A seed for the pseudo-random generator + pDest: The output buffer where the random bytes are placed. + nSize: The size in bytes of pDest. + +Return Value: + The new seed value that can be used in a subsequent call to + std_rand(). + +Comments: + + std_rand() is a linear congruent psuedo-random number generator that + is seeded using the input seed. This makes the ouput predictable if + you can determine (or influence) the seed value used. Furthermore, + the random sequence of bytes generated by two different calls to this + function will be identical if both the calls use the same seed value. + + This is not crypto quality and should not be used for key generation + and other cryptographic uses. + +See Also: + std_rand_next() + +======================================================================= + +std_CopyLE() + +Description: + + The std_CopyLE() function copies data while translating numeric values + between host byte ordering and "little endian" byte ordering. + + pvDest and pvSrc are NOT required to be 16 or 32-bit word aligned. + + Behavior is undefined when the destination and source arrays overlap, + except in the special case where pvDest and pvSrc are equal. In that case, + std_CopyLE() modifies the buffer in-place. + + When the target byte ordering (little endian) matches the host byte + ordering, in-place translations reduce to a no-op, and copies are + delegated directly to std_memmove(). + + +Prototype: + int std_CopyLE(void *pvDest, int nDestSize, + const void *pvSrc, int nSrcSize, + const char *pszFields); + +Parameters: + pvDest: Pointer to destination buffer. + nDestSize: Size of the destination buffer. + pvSrc: Pointer to buffer containing source data. + nSrcSize: Size of source data. + pszFields: Description of the fields that comprise the source data. + + Each field size is given by a positive decimal integer or one of + the following characters: "S", "L", "Q", or "*". The letters + denote fields that should be converted to the desired byte + ordering: + +===pre> + S : a 2 byte (16 bit) value. + L : a 4 byte (32 bit) value. + Q : a 8 byte (64 bit) value. +===/pre> + + An integer gives a number of bytes and "*" represents the + remainder of the pvSrc[] buffer. No reordering is performed on + data in these fields. + + Comparisons are case-sensitive. Behavior is undefined when + other characters are supplied in pszFields. + + For example: "L12S*" would be appropriate to copy a structure + containing a uint32 followed by a 12 byte character array, + followed by a uint16, followed by an arbitrary amount of + character data. + + If nSrcSize is greater than the structure size (total of all the + sizes in pszFields[]) then pvSrc[] is treated as an array of + structures, each of which is described by pszFields. + +Return Value: + + The number of bytes actually copied or translated in-place. This will be + the smaller of nDestSize and nSrcSize, or zero if one of them are negative. + + +======================================================================= + +std_CopyBE() + +Description: + + The std_CopyBE() function has the same semantics as std_CopyLE() except it + copies between host byte ordering and big-endian ("network") byte order. + + See std_CopyLE() for more details. + + +Prototype: + void *std_CopyBE(void *pvDest, const void *pvSrc, + int cbDest, int nItems, const char *pszFields); + +Parameters: + pvDest: Pointer to destination buffer. + nDestSize: Size of the destination buffer. + pvSrc: Pointer to buffer containing source data. + nSrcSize: Size of source data. + pszFields: Description of the fields that comprise the source data, + as defined in std_CopyLE. + +Return Value: + + The number of bytes actually copied or translated in-place. This will be + the smaller of nDestSize and nSrcSize, or zero if one of them are negative. + +======================================================================= + +std_swapl() + +Description: + The std_swapl() changes endianness of an unsigned long. + +Prototype: + + unsigned long std_swapl(unsigned long ul) + +Parameters: + ul: input unsigned long + +Return Value: + ul, reversed in byte-ordering + +======================================================================= + +std_swaps() + +Description: + The std_swaps() changes endianness of an unsigned short. + +Prototype: + + unsigned short std_swaps(unsigned short us) + +Parameters: + us: input unsigned short + +Return Value: + us, reversed in byte-ordering + +======================================================================= + +std_letohs() + +Description: + The std_letohs() changes a short from little-endian to host byte order. + +Prototype: + + unsigned short std_letohs(unsigned short us) + +Parameters: + us: short to convert + +Return Value: + us converted from little-endian to host byte order. If the + host is little endian, just returns us + +======================================================================= + +std_htoles() + +Description: + The std_htoles() converts a short from host byte-order to little-endian. + +Prototype: + + unsigned short std_htoles(unsigned short us) + +Parameters: + us: short to convert + +Return Value: + us converted from host byte order to little-endian. If the + host is little endian, just returns us + +======================================================================= + +std_letohl() + +Description: + The std_letohl() changes a long from little-endian to host byte order. + +Prototype: + + unsigned long std_letohl(unsigned long ul) + +Parameters: + ul: long to convert + +Return Value: + ul converted from little-endian to host byte order. If the + host is little endian, just returns ul + +======================================================================= + +std_htolel() + +Description: + The std_htolel() converts a long from host byte-order to little-endian. + +Prototype: + + unsigned long std_htolel(unsigned long ul) + +Parameters: + ul: long to convert + +Return Value: + ul converted from host byte order to little-endian. If the + host is little endian, just returns ul. + + +======================================================================= + +std_ntohs() + +Description: + The std_ntohs() changes a short from big-endian to host byte order. + +Prototype: + + unsigned short std_ntohs(unsigned short us) + +Parameters: + us: short to convert + +Return Value: + us converted from big-endian to host byte order. If the + host is big endian, just returns us. + +======================================================================= + +std_htons() + +Description: + The std_htons() converts a short from host byte-order to big-endian. + +Prototype: + + unsigned short std_htons(unsigned short us) + +Parameters: + us: short to convert + +Return Value: + us converted from host byte order to big-endian. If the + host is big endian, just returns us. + +======================================================================= + +std_ntohl() + +Description: + The std_ntohl() changes a long from big-endian to host byte order. + +Prototype: + + unsigned long std_ntohl(unsigned long ul) + +Parameters: + ul: long to convert + +Return Value: + ul converted from big-endian to host byte order. If the + host is big endian, just returns ul. + +======================================================================= + +std_htonl() + +Description: + The std_htonl() converts a long from host byte-order to big-endian. + +Prototype: + + unsigned long std_htonl(unsigned long ul) + +Parameters: + ul: long to convert + +Return Value: + ul converted from host byte order to big-endian. If the + host is big endian, just returns ul. + + +======================================================================= + +std_strlprintf() + +Description: + + The functions std_strlprintf() and std_vstrlprintf() write formatted + output to a string. These functions guarantee NUL-termination of + the output buffer when its size is greater than zero. + + A format string is copied to the output buffer, except for conversion + specifiers contained within the format string. Conversion specifiers + begin with a "%" and specify some action that consumes an argument from + the argument list. + + Conversion specifiers have the following form: +===pre> + %[FLAGS] [WIDTH] [.PRECISION] [TYPE] CONV +===/pre> + + CONV is the only required field. It is always a single character, + and determines the action to be taken. Supported values are: + +===pre> + CONV | Description + ======|======================================================= + c | Output a single character. + | + s | Output a NUL-terminated single-byte character string. + | + d, i | Ouptut a signed decimal integer. + | + u | Output an unsigned decimal integer. + | + o | Output an unsigned octal integer. + | + x | Output an unsigned hexadecimal integer, using + | lower case digits. + | + X | Output an unsigned hexadecimal integer, using + | upper case digits. + | + p | Output a pointer value as eight hexadecimal digits, + | using upper case digits. +===/pre> + + The next argument from the argument list supplies the value to be + formatted and output. + + FLAGS, WIDTH, and PRECISION can modify the formatting of the value. + + FLAGS consists of one or more of the following characters: + +===pre> + Flag | Meaning + =====|================================================================= + + | Prefix positive numbers with "+" (%d and %i only). + -----|----------------------------------------------------------------- + - | When padding to meet WIDTH, pad on the right. + -----|----------------------------------------------------------------- + 0 | Pad with '0' characters when padding on the left to meet WIDTH. + -----|----------------------------------------------------------------- + blank| Prefix positive numbers with " " (%d and %i only). + space| + -----|----------------------------------------------------------------- + # | With %x or %X: prefixes non-zero values with "0x"/"0X". + | With %o, ensure the value begins with "0" (increasing PRECISION + | if necessary). + | Ignored for all other CONV specifiers. + -----|----------------------------------------------------------------- +===/pre> + + WIDTH is an unsigned decimal integer or the character "*". + + WIDTH gives the minimum number of characters to be written. The + formatted value will be padded with spaces until the minimum size is + met; it never causes a value to be truncated The sign of the WIDTH + integer selects between left and right padding. Padding will be on + the left unless the "-" flag is specified. + + When "*" is used, an 'int' argument is consumed from the argument + list and used as the WIDTH. A negative argument specifies padding on + the right, and its absolute value gives the amount of padding. + + If the "0" flags is specified, any padding on the left will consist + of "0" characters. An exception to this rule is that the "0" flag is + ignored when precision is specified for a numeric value. + + PRECISION is a non-negative decimal integer or "*" preceded by ".". + + When PRECISION accompanies any of the numeric conversions, it + specifies the minimum number of digits to output. Values are padded + on the left with '0' to meet the specified size. PRECISION defaults + to 1 for numbers. + + When PRECISION accompanies other conversions, it specifies the + maximum number of characters from the value to output. The value + will be truncated to ensure that at most PRECISION characters are + output. + + TYPE provides information about the type of arguments. This is used + to determine the size of integer arguments. Values larger than 'int' + can be properly obtained from the argument list. Their behavior + should be considered undefined for CONV operations other than integer + formatting. + +===pre> + TYPE | Meaning + =======|===================== + hh | sizeof(char) + -------|--------------------- + h | sizeof(short) + -------|--------------------- + l | sizeof(long) + -------|--------------------- + L, ll | sizeof(long long) + -------|--------------------- + j | sizeof(int64) + -------|--------------------- + z | sizeof(size_t) + -------|--------------------- +===/pre> + + For 64-bit integers, "ll" may be the most widely-supported type + specifier in other printf implementation, but "j" has been introduced + in ISO C99. This implementation supports both. + + Note that arguments to variadic functions are promoted to 'int' when + smaller than 'int', so 'h' and 'hh' have no observable effect. + Static analysis tools that understand standard format string syntax + may use this information for other purposes. + +Prototype: + + int std_strlprintf(char *pszDest, int nDestSize, + const char *pszFmt, ...); +Parameters: + pszDest [out]: output buffer, where output will be placed + nDestSize: size of pszDest in bytes + pszFmt: format string + +Return Value: + + The size required to hold the entire untruncated output, NOT + including NUL-termination. + +Comments: + + Notable omissions from std_strlprintf() are lack of support for + floating point and lack of support for "%n". + +Side Effects: + None + +See Also: + None + +======================================================================= + +std_vstrlprintf() + +Description: + + The std_vstrlprintf() is documented with std_strlprintf(), it's the + vector form of std_strlprintf(). See std_strlprintf() for a + more complete description. + +Prototype: + int std_vstrlprintf(char *pszDest, int nDestSize, + const char *pszFmt, AEEVaList args); + +Parameters: + pszDest [out]: output buffer, where output will be placed + nDestSize: size of pszDest in bytes + pszFmt: format string + args: arguments + + +======================================================================= + +std_snprintf() + +Description: + + The functions std_snprintf() and std_vsnprintf() are similar to + std_strlprintf and std_vstrlprintf that write formatted output to a + string. Unlike std_strlprintf, std_snprintf also support the floating + point conversion specifiers. These functions guarantee NUL-termination + of the output buffer when its size is greater than zero. + + A format string is copied to the output buffer, except for conversion + specifiers contained within the format string. Conversion specifiers + begin with a "%" and specify some action that consumes an argument from + the argument list. + + Conversion specifiers have the following form: +===pre> + %[FLAGS] [WIDTH] [.PRECISION] [TYPE] CONV +===/pre> + + CONV is the only required field. It is always a single character, + and determines the action to be taken. For a detailed description of + conversion sepcifiers, please refer to the documentation of + std_strlprintf(). Here. we only provide description of these fields + as it applies to the additional CONV values supported by + std_snprintf(). + + In addition to the values for CONV supported by std_strlprintf, this + function supports the following values: + +===pre> + CONV | Description + ======|======================================================= + e, E | Outputs a double value representing a floating point + | number in the style [-]d.ddd e±dd, where there is one + | digit (which is nonzero if the argument is nonzero) + | before the decimal-point character and the number of + | digits after it is equal to the precision. If the + | precision is missing, it is taken as 6. If the precision + | is zero and the # flag is not specified, no decimal-point + | character appears. The value is rounded to the appropriate + | number of digits. The E conversion specifier produces a + | number with E instead of e introducing the exponent. The + | exponent always contains at least two digits, and only as + | many more digits as necessary to represent the exponent. + | If the value is zero, the exponent is zero. + | + f, F | Outputs a double value representing a floating point + | number in the style [-]ddd.ddd, where the number of + | digits after the decimal-point character is equal to the + | precision specification. If the precision is missing, it + | is taken as 6. If the precision is zero and the # flag is + | not specified, no decimal-point character appears. If a + | decimal-point character appears, at least one digit + | appears before it. The value is rounded to the appropriate + | number of digits. + | + g, G | Outputs a double value representing a floating point + | number in the style f or e (or in style F or E in the case + | of a G conversion specifier), with the precision specifying + | the number of significant digits. If the precision is zero, + | it is taken as 1. The style used depends on the value + | converted. Style e (or E) is used only if the exponent + | resulting from such a conversion is less than -4 or greater + | than or equal to the precision. Trailing zeros are removed + | from the fractional portion of the result unless the # flag + | is specified; a decimal-point character appears only if it + | is followed by a digit. + | + a, A | Outputs a double value representing a floating point + | number in the style [-]0xh.hhhh p±d, where there is one + | non-zero hexadecimal digit before the decimal-point + | character and the number of hexadecimal digits after it is + | equal to the precision. If the precision is missing then + | the precision is assumed to be sufficient for an exact + | representation of the value, except that trailing zeros + | may be omitted. If the precision is zero and the # flag is + | not specified, no decimal point character appears. The + | letters 'abcdef' are used for '%a' conversion and the + | letters ABCDEF for '%A' conversion. The '%A' conversion + | specifier produces a number with 'X' and 'P' instead of 'x' + | and 'p'. The exponent always contains at least one digit, + | and only as many more digits as necessary to represent the + | decimal exponent of 2. If the value is zero, the exponent + | is zero. + | +===/pre> + + For 'e', 'f', 'g' and 'a' convervsion specifiers, a double argument + representing an infinity is converted in to the style '[-]inf' and + a double argument representing a NaN is converted in to the stlye + 'nan'. The 'E', 'F', 'G' and 'A' conversion specifiers result in + 'INF' or 'NAN' instead of 'inf' or 'nan', respectively. + +Prototype: + + int std_snprintf(char *pszDest, int nDestSize, + const char *pszFmt, ...); +Parameters: + pszDest [out]: output buffer, where output will be placed + nDestSize: size of pszDest in bytes + pszFmt: format string + +Return Value: + + The size required to hold the entire untruncated output, NOT + including NUL-termination. + +Comments: + + Notable omissions from std_strlprintf() lack of support for "%n". + +Side Effects: + None + +See Also: + std_strlprintf() + +======================================================================= + +std_vsnprintf() + +Description: + + The std_vsnprintf() is documented with std_snprintf(), it's the + vector form of std_snprintf(). See std_snprintf() for a more complete + description. + +Prototype: + int std_vsnprintf(char *pszDest, int nDestSize, + const char *pszFmt, AEEVaList args); + +Parameters: + pszDest [out]: output buffer, where output will be placed + nDestSize: size of pszDest in bytes + pszFmt: format string + args: arguments + + +======================================================================= + +std_scanul() + +Description: + + The std_scanul() converts an ASCII representation of a number to an unsigned + long. It expects strings that match the following pattern: +===pre> + spaces [+|-] digits +===/pre> + + 'Spaces' is zero or more ASCII space or tab characters. + + 'Digits' is any number of digits valid in the radix. Letters 'A' through + 'Z' are treated as digits with values 10 through 35. 'Digits' may begin + with "0x" when a radix of 0 or 16 is specified. + + Upper and lower case letters can be used interchangeably. + + +Prototype: + + uint32 std_scanul( const char *pchBuf, int nRadix, const char **ppchEnd, + int *pnError) + +Parameters: + + pchBuf [in] : the start of the string to scan. + + nRadix [in] : the numeric radix (or base) of the number. Valid values are + 2 through 36 or zero, which implies auto-detection. + Auto-detection examines the digits field. If it begins with + "0x", radix 16 is selected. Otherwise, if it begins with + "0" radix 8 is selected. Otherwise, radix 10 is selected. + + ppchEnd [out] : if ppchEnd is not NULL, *ppchEnd points to the first + character that did not match the expected pattern shown + above, except on STD_BADPARAM and STD_OVERFLOW when it is + set to the start of the string. + + pnError [out] : If pnError is not NULL, *pnError holds the error code, + which is one of the following: +~ + 0 : Numeric value is from 0 to MAX_UINT32. + + STD_NEGATIVE : The scanned value was negative and its absolute value was + from 1 to MAX_UINT32. The result is the negated value + (cast to a uint32). + + STD_NODIGITS : No digits were found. The result is zero. + + STD_OVERFLOW : The absolute value exceeded MAX_UINT32. The result + is set to MAX_UINT32 and *ppchEnd is set to pchBuf. + + STD_BADPARAM : An improper value for nRadix was received. The result + is set to zero, and *ppchEnd is set to pchBuf. +* + +Return Value: + + The converted numeric result. + +Comments: + + The std_scanul() is similar to ANSI C's strtoul() but differs in the following + respects: + + 1. It returns an error/success code. strtoul() results are ambiguous + unless the caller sets errno to zero before calling it. + + 2. std_scanul() is free of references to current locale and errno. Some + strtoul() implementations use locale; some don't. + + 3. It provides more complete reporting of range underflow. strtoul() + does not distinguish between "-1" and "0xFFFFFFFF", and underflow is + poorly defined. + + 4. std_scanul() reports a "no digits" error code to distinguish "0" from + whitespace, "+", etc.. + +See Also: + + std_scanull() + +======================================================================= + +std_scanull() + +Description: + + The std_scanull() converts an ASCII representation of a number to an + unsigned long long. It expects strings that match the following pattern: +===pre> + spaces [+|-] digits +===/pre> + + 'Spaces' is zero or more ASCII space or tab characters. + + 'Digits' is any number of digits valid in the radix. Letters 'A' through + 'Z' are treated as digits with values 10 through 35. 'Digits' may begin + with "0x" when a radix of 0 or 16 is specified. + + Upper and lower case letters can be used interchangeably. + + +Prototype: + + uint64 std_scanull(const char *pchBuf, int nRadix, const char **ppchEnd, + int *pnError) + +Parameters: + + pchBuf [in] : the start of the string to scan. + + nRadix [in] : the numeric radix (or base) of the number. Valid values are + 2 through 36 or zero, which implies auto-detection. + Auto-detection examines the digits field. If it begins with + "0x", radix 16 is selected. Otherwise, if it begins with + "0" radix 8 is selected. Otherwise, radix 10 is selected. + + ppchEnd [out] : if ppchEnd is not NULL, *ppchEnd points to the first + character that did not match the expected pattern shown + above, except on STD_BADPARAM and STD_OVERFLOW when it is + set to the start of the string. + + pnError [out] : If pnError is not NULL, *pnError holds the error code, + which is one of the following: +~ + 0 : Numeric value is from 0 to MAX_UINT64. + + STD_NEGATIVE : The scanned value was negative and its absolute value was + from 1 to MAX_UINT64. The result is the negated value + (cast to a uint64). + + STD_NODIGITS : No digits were found. The result is zero. + + STD_OVERFLOW : The absolute value exceeded MAX_UINT64. The result + is set to MAX_UINT64 and *ppchEnd is set to pchBuf. + + STD_BADPARAM : An improper value for nRadix was received. The result + is set to zero, and *ppchEnd is set to pchBuf. +* + +Return Value: + + The converted numeric result. + +Comments: + + The std_scanull() is similar to ANSI C's strtoull() but differs in the following + respects: + + 1. It returns an error/success code. strtoull() results are ambiguous + unless the caller sets errno to zero before calling it. + + 2. std_scanull() is free of references to current locale and errno. Some + strtoull() implementations use locale; some don't. + + 3. It provides more complete reporting of range underflow. strtoul() + does not distinguish between "-1" and "0xFFFFFFFFFFFFFFFF", and underflow + is poorly defined. + + 4. std_scanull() reports a "no digits" error code to distinguish "0" from + whitespace, "+", etc.. + +See Also: + + std_scanul() + +======================================================================= + +std_qsort() + +Description: + + An implementation of the quicksort algorithm, a massively recursive, + in-place sorting algorithm for an array. + + The contents of the array are sorted in ascending order according to + the comparison function pointed to by pfnCompare. + + pfnCompare must return a value less than, equal to, or + greater than zero if the first argument is considered to be + less than, equal to, or greater than the second, respectively. + + std_qsort() is not a stable sort. + +Prototype: + void std_qsort(void* pElems, int nNumElems, int nElemWidth, + int (*pfnCompare)(void*, const void*, const void*), + void* pCompareCx); + + +Parameters: + pElems: array of elements to be sorted in place. It's size + must be nNumElems * nElemWidth in bytes. + nNumElems: number of elements in pElems + nElemWidth: the width, in bytes of each element of pElems + pfnCompare: callback comparison function, should return 0, less than + zero or greater than zero if the left comparand is equal to, less + than, or greater than, the right comparand, respectively. + pCompareCx: the context passed as the first parameter by pfnCompare + +Return Value: + None + +Comments: + If nElemWidth is 2, 4, or 8, pElems is accessed internally as + integer values for the purposes of reading and writing elements. + Therefore, pElems must be aligned on a memory boundary compatible + with integer access of the array elements. I.e. if you pass 4 as + nElemWidth, *(int*)pElems must succeed. + +======================================================================= + +std_bisect() + +Description: + + Find an element in a sorted array of elements. Uses a binary + search. + +Prototype: + int std_bisect(const void* pElems, int nNumElems, int nElemWidth, + const void* pElemFind, + int (*pfnCompare)(void*, const void*, const void*), + void* pCompareCx); + +Parameters: + pElems: array of elements to be searched. It's size + must be nNumElems * nElemWidth in bytes. + nNumElems: number of elements in pElems + nElemWidth: the width, in bytes of each element of pElems + pElemFind: the element value to find in the array + pfnCompare: callback comparison function, should return 0, less than + zero or greater than zero if the left comparand is equal to, less + than, or greater than, the right comparand, respectively. + pCompareCx: the context passed as the first parameter by pfnCompare + +Return Value: + index of the element such that pElems[index] <= elem < pElems[index + 1] + nNumElems if elem is greater than all the elements in the list + 0 if the elem is less than or equal to the all the elements in the list + +======================================================================= + +std_merge() + +Description: + + Merge two sorted arrays into another array. + +Prototype: + void std_merge(void* vpDst, int nDst, + const void* vpA, int nA, + const void* vpB, int nB, + int nElemWidth, + int (*pfnCompare)(void*, const void*, const void*), + void* pCompareCx); + +Parameters: + vpDst: destination array. It's size must be nDst * nElemWidth in bytes. + nDst: number of elements that vpDst can accomodate + vpA: array of elements to be merged, it's size must be nA * nElemWidth + in bytes. + nA: number of elements in vpA + vpB: array of elements to be merged, it's size must be nB * nElemWidth + in bytes. + nB: number of elements in vpB + nElemWidth: the width, in bytes of each element of pElems + pfnCompare: callback comparison function, should return 0, less than + zero or greater than zero if the left comparand is equal to, less + than, or greater than, the right comparand, respectively. + pCompareCx: the context passed as the first parameter by pfnCompare + +Return Value: + none + +======================================================================= + +std_uniq() + +Description: + Removes duplicate entries from a sorted array. + +Prototype: + int std_uniq(void* vpElems, int nNumElems, int nElemWidth, + int (*pfnCompare)(void*, const void*, const void*), + void* pCompareCx); + +Parameters: + pElems: array of elements to be searched. It's size + must be nNumElems * nElemWidth in bytes. + nNumElems: number of elements in pElems + nElemWidth: the width, in bytes of each element of pElems + pfnCompare: callback comparison function, should return 0, less than + zero or greater than zero if the left comparand is equal to, less + than, or greater than, the right comparand, respectively. + pCompareCx: the context passed as the first parameter by pfnCompare + +Return Value: + the number of uniq elements left in vpElems + +======================================================================= + +std_scand() + +Description: + + The std_scand() converts the initial portion of an input ASCII string + to it's corresponding floating point value. It expects the input + string to match the following pattern: +===pre> + +===/pre> + + 'Spaces' - is zero or more ASCII space or tab characters. + 'Subject String' - is the part of the input string that represents a + valid floating point constant. + 'Rest Of The String' - is the remaining sequence of one or more + characters including the terminating null + character of the input string. + + A valid subject string can be one of the following: + -- , ignoring case. This is interpreted as a quiet NAN. + -- [+|-], ignoring case. This is interpreted as an + infinity. + -- [+|-] + + In general, a valid floating poing number can either be a decimal + number or an hexadecimal number, and has the following form: + [.[]][] + where the intergral, fractional and the exponent part may consist of + sequence of valid decimal or hexadecimal digits. More specifically: + + For a decimal floating point number: + 'Integral Part' - + 'Fractional Part' - + 'Exponent' - + For a hexadecimal floating point number: + 'Integral Part' - + 'Fractional Part' - + 'Exponent' - + + where: + 'Decimal Digits' - is any number of digits in the range [0,10]. + 'Hexadecimal Digits' - is any number of digits in the range [0,10] + or the alphabets A through F. + 'e','E','p','P' - represent the exponent characters + +Prototype: + + double std_scand(const char *pchBuf, const char **ppchEnd); + +Parameters: + + pchBuf [in] : the start of the string to scan. + + ppchEnd [out] : if ppchEnd is not NULL, *ppchEnd points to the first + character after the parsed number. + +Return Value: + + This function returns the converted numeric result. If the string + does not contain a valid floating point number then the function + returns zero. If the converted value is outside the range of + representable values (overflow), [-]INFINITY is + returned. In case of an underflow, the function returns zero. + +=======================================================================*/ + +#endif // AEESTD_H + diff --git a/inc/HAP_debug.h b/inc/HAP_debug.h new file mode 100644 index 0000000..3993cbb --- /dev/null +++ b/inc/HAP_debug.h @@ -0,0 +1,92 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef HAP_DEBUG_H +#define HAP_DEBUG_H + +#include "AEEStdDef.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_FARF_LEN 256 + +#define HAP_LEVEL_LOW 0 +#define HAP_LEVEL_MEDIUM 1 +#define HAP_LEVEL_HIGH 2 +#define HAP_LEVEL_ERROR 3 +#define HAP_LEVEL_FATAL 4 + +#define HAP_LEVEL_CRITICAL 5 + +#define HAP_LEVEL_RPC_LOW 16 +#define HAP_LEVEL_RPC_MEDIUM 17 +#define HAP_LEVEL_RPC_HIGH 18 +#define HAP_LEVEL_RPC_ERROR 19 +#define HAP_LEVEL_RPC_FATAL 20 + +#define HAP_LEVEL_RPC_CRITICAL 21 + +#define HAP_LEVEL_RUNTIME (1 << 5) + +//Add a weak reference so shared objects work with older images +#pragma weak HAP_debug_v2 + +//Add a weak reference for enabling FARF in autogen stub files +#pragma weak HAP_debug + +//Add a weak reference so runtime FARFs are ignored on older images +#pragma weak HAP_debug_runtime + +/************************************************************************** + These HAP_debug* functions are not meant to be called directly. + Please use the FARF() macros to call them instead +**************************************************************************/ +void HAP_debug_v2(int level, const char* file, int line, const char* format, ...); +void HAP_debug_runtime(int level, const char* file, int line, const char* format, ...); +int HAP_setFARFRuntimeLoggingParams(unsigned int mask, const char* files[], + unsigned short numberOfFiles); + +// Keep these around to support older shared objects and older images +void HAP_debug(const char *msg, int level, const char *filename, int line); + +static __inline void _HAP_debug_v2(int level, const char* file, int line, + const char* format, ...){ + char buf[256]; + va_list args; + va_start(args, format); + vsnprintf(buf, sizeof(buf), format, args); + va_end(args); + HAP_debug(buf, level, file, line); +} + +/*! +This function is called to log an accumlated log entry. If logging is +enabled for the entry by the external device, then the entry is copied +into the diag allocation manager and commited. + + [in] log_code_type ID of the event to be reported + [in] *data data points to the log which is to be submitted + [in] dataLen The length of the data to be logged. + +Returns + TRUE if log is submitted successfully into diag buffers + FALSE if there is no space left in the buffers. + +*/ +boolean HAP_log_data_packet(unsigned short log_code_type, unsigned int dataLen, + byte* data); + +#define HAP_DEBUG_TRACEME 0 + +long HAP_debug_ptrace(int req, unsigned int pid, void* addr, void* data); + +#ifdef __cplusplus +} +#endif + +#endif // HAP_DEBUG_H + diff --git a/inc/HAP_farf.h b/inc/HAP_farf.h new file mode 100644 index 0000000..8950990 --- /dev/null +++ b/inc/HAP_farf.h @@ -0,0 +1,298 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef HAP_FARF_H +#define HAP_FARF_H + +/** + * @file HAP_farf.h + * @brief FARF API + */ + +#include "AEEStdDef.h" +#include "HAP_debug.h" + +/** + *\def FARF() + * FARF is used to log debug messages from DSP + * + * `Compile time logging options:` + * + * Logging is controlled via conditional compilation. + * The FARF level allows the user to selectively enable or disable certain types + * of messages according to their priority level. + * The following levels are supported and listed in increasing priority: + * + * LOW + * + * MEDIUM + * + * HIGH + * + * ERROR + * + * FATAL + * + * ALWAYS + * + * A FARF level should be defined to 1 for FARF macros to be compiled + * in. For example: + * + * @code + * #define FARF_LOW 1 + * #include "HAP_farf.h" + * + * FARF(LOW, "something happened: %s", (const char*)string); + * + * @endcode + * + * FARF_LOW, FARF_MEDIM, FARF_HIGH are defined to 0 and FARF_ERROR, + * FARF_FATAL, FARF_ALWAYS are defined to 1 by default. + * + * If FARF_LOW is defined to 0, as it is by default, the above + * FARF string will not be compiled in, if it is defined to 1 it + * will be compiled in. + * + * If both HIGH and LOW messages are used but only FARF_LOW is defined + * as shown in below example then only LOW message will be compiled in and sent to DIAG. + * + * @code + * #define FARF_LOW 1 + * #include "HAP_farf.h" + * + * FARF(LOW, "LOW message"); + * FARF(HIGH, "HIGH message"); // This message will not be compiled in + * + * @endcode + * + * Messages logged with ALWAYS level are always compiled in and logged. + * + * When building the Debug variant or builds defining _DEBUG the + * following FARF levels will be enabled: + * + * HIGH + * + * ERROR + * + * FATAL + * + * `Run time logging options:` + * + * In order to enable run-time logging (logging that can be enabled / disabled + * at run-time), the FARF_RUNTIME_* macros should be used. + * + * Log messages sent with these macros are compiled in by default. However by + * these messages WILL NOT be logged by default. In order to enable logging, + * the FASTRPC process will need to either call the + * HAP_SetFARFRuntimeLoggingParams() API, or by adding a ``.farf + * file to the HLOS file system with the appropriate contents. + * + * @code + * + * #include "HAP_farf.h" + * FARF(RUNTIME_HIGH, "something happened: %s", (const char*)string); + * + * @endcode + * + * @param[in] x the FARF level defined to either 0 to disable compilation or 1 to enable. + * @param[in] ... the format string and arguments. + */ +#define FARF(x, ...) _FARF_PASTE(_FARF_,_FARF_VAL(FARF_##x))(x, ##__VA_ARGS__) + + +/** +* @defgroup static_FARF Compile-time macros +* +* Set these compile time macros to 1 to enable logging at that +* level. Setting them to 0 will cause them to be COMPILED out. +* +* Usage Example: +* @code +* +* #define FARF_HIGH 1 +* FARF(HIGH,"Log message"); +* +* @endcode + +* The ALWAYS macro will cause log messages to be ALWAYS compiled in. +* @code +* +* FARF(ALWAYS,"Log message") +* +* @endcode +* +* Defining _DEBUG macro turns on ALWAYS, HIGH, ERROR, FATAL +*/ +/* @{ */ + +#ifdef _DEBUG +#ifndef FARF_HIGH +#define FARF_HIGH 1 +#endif +#endif + +/** + * The FARF_ALWAYS macro causes log messages to be ALWAYS compiled in + */ +#ifndef FARF_ALWAYS +#define FARF_ALWAYS 1 +#endif + +/** + * The FARF_LOW macro causes log messages to be compiled in when FARF_LOW is defined to 1 +*/ +#ifndef FARF_LOW +#define FARF_LOW 0 +#endif + +/** +* The FARF_MEDIUM macro causes log messages to be compiled in when FARF_MEDIUM is defined to 1 +*/ +#ifndef FARF_MEDIUM +#define FARF_MEDIUM 0 +#endif + +/** +* The FARF_HIGH macro causes log messages to be compiled in when FARF_HIGH is defined to 1 +*/ +#ifndef FARF_HIGH +#define FARF_HIGH 0 +#endif + +/** +* The FARF_ERROR macro causes log messages to be compiled in when FARF_ERROR is defined to 1 +*/ +#ifndef FARF_ERROR +#define FARF_ERROR 1 +#endif + +/** +* The FARF_FATAL macro causes log messages to be compiled in when FARF_FATAL is defined to 1 +*/ +#ifndef FARF_FATAL +#define FARF_FATAL 1 +#endif + +#ifndef FARF_CRITICAL +#define FARF_CRITICAL 0 /* 0 turns me off */ +#endif + + +//! @cond Doxygen_Suppress +#define FARF_ALWAYS_LEVEL HAP_LEVEL_HIGH +#define FARF_LOW_LEVEL HAP_LEVEL_LOW +#define FARF_MEDIUM_LEVEL HAP_LEVEL_MEDIUM +#define FARF_HIGH_LEVEL HAP_LEVEL_HIGH +#define FARF_ERROR_LEVEL HAP_LEVEL_ERROR +#define FARF_FATAL_LEVEL HAP_LEVEL_FATAL +#define FARF_CRITICAL_LEVEL HAP_LEVEL_CRITICAL +//! @endcond + +/* @} */ + + +/** +* @defgroup Runtime_FARF Runtime macros +* +* Runtime FARF macros can be enabled at runtime. +* They are turned OFF by default. +* +* Usage Example: +* @code +* +* FARF(RUNTIME_HIGH,"Log message"); +* +* @endcode +*/ +/* @{ */ +//! @cond Doxygen_Suppress +#ifndef FARF_RUNTIME_LOW +#define FARF_RUNTIME_LOW 1 +#endif +#define FARF_RUNTIME_LOW_LEVEL (HAP_LEVEL_RUNTIME | HAP_LEVEL_LOW) + +#ifndef FARF_RUNTIME_MEDIUM +#define FARF_RUNTIME_MEDIUM 1 +#endif +#define FARF_RUNTIME_MEDIUM_LEVEL (HAP_LEVEL_RUNTIME | HAP_LEVEL_MEDIUM) + +#ifndef FARF_RUNTIME_HIGH +#define FARF_RUNTIME_HIGH 1 +#endif +#define FARF_RUNTIME_HIGH_LEVEL (HAP_LEVEL_RUNTIME | HAP_LEVEL_HIGH) + +#ifndef FARF_RUNTIME_ERROR +#define FARF_RUNTIME_ERROR 1 +#endif +#define FARF_RUNTIME_ERROR_LEVEL (HAP_LEVEL_RUNTIME | HAP_LEVEL_ERROR) + +#ifndef FARF_RUNTIME_FATAL +#define FARF_RUNTIME_FATAL 1 +#endif +#define FARF_RUNTIME_FATAL_LEVEL (HAP_LEVEL_RUNTIME | HAP_LEVEL_FATAL) + +#ifndef FARF_RUNTIME_RPC_LOW +#define FARF_RUNTIME_RPC_LOW 1 /* 0 turns me off */ +#endif +#define FARF_RUNTIME_RPC_LOW_LEVEL (HAP_LEVEL_RUNTIME | HAP_LEVEL_RPC_LOW) + +#ifndef FARF_RUNTIME_RPC_MEDIUM +#define FARF_RUNTIME_RPC_MEDIUM 1 /* 0 turns me off */ +#endif +#define FARF_RUNTIME_RPC_MEDIUM_LEVEL (HAP_LEVEL_RUNTIME | HAP_LEVEL_RPC_MEDIUM) + +#ifndef FARF_RUNTIME_RPC_HIGH +#define FARF_RUNTIME_RPC_HIGH 1 /* 0 turns me off */ +#endif +#define FARF_RUNTIME_RPC_HIGH_LEVEL (HAP_LEVEL_RUNTIME | HAP_LEVEL_RPC_HIGH) + +#ifndef FARF_RUNTIME_RPC_ERROR +#define FARF_RUNTIME_RPC_ERROR 1 /* 0 turns me off */ +#endif +#define FARF_RUNTIME_RPC_ERROR_LEVEL (HAP_LEVEL_RUNTIME | HAP_LEVEL_RPC_ERROR) + +#ifndef FARF_RUNTIME_RPC_FATAL +#define FARF_RUNTIME_RPC_FATAL 1 /* 0 turns me off */ +#endif +#define FARF_RUNTIME_RPC_FATAL_LEVEL (HAP_LEVEL_RUNTIME | HAP_LEVEL_RPC_FATAL) + +#ifndef FARF_RUNTIME_RPC_CRITICAL +#define FARF_RUNTIME_RPC_CRITICAL 1 /* 0 turns me off */ +#endif +#define FARF_RUNTIME_RPC_CRITICAL_LEVEL (HAP_LEVEL_RUNTIME | HAP_LEVEL_RPC_CRITICAL) +//! @endcond +/* @} */ + + +//! @cond Doxygen_Suppress + +#define _FARF_PASTE(a,b) _FARF_PASTE_(a,b) +#define _FARF_PASTE_(a,b) a##b +#define _FARF_VAL(a) a + + +#define _FARF_0(x, ...) + +#ifndef __FILENAME__ +#define __FILENAME__ __FILE__ +#endif + +#define _FARF_1(x, ...) \ + do { \ + if(0 == (HAP_debug_v2)) { \ + _HAP_debug_v2(FARF_##x##_LEVEL, __FILENAME__, __LINE__, ##__VA_ARGS__); \ + } else { \ + if (FARF_##x##_LEVEL & HAP_LEVEL_RUNTIME) { \ + if (0 != HAP_debug_runtime) { \ + HAP_debug_runtime(FARF_##x##_LEVEL ^ HAP_LEVEL_RUNTIME , __FILENAME__, __LINE__, ##__VA_ARGS__); \ + } else { \ + break; \ + } \ + } else { \ + HAP_debug_v2(FARF_##x##_LEVEL, __FILENAME__, __LINE__, ##__VA_ARGS__); \ + } \ + } \ + } while (0) + +#endif /* #ifndef HAP_FARF_H */ +//! @endcond diff --git a/inc/HAP_farf_internal.h b/inc/HAP_farf_internal.h new file mode 100644 index 0000000..6277ce0 --- /dev/null +++ b/inc/HAP_farf_internal.h @@ -0,0 +1,12 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef __HAP_FARF_INTERNAL_H__ +#define __HAP_FARF_INTERNAL_H__ + +#include "HAP_farf.h" + + + + +#endif /*__HAP_FARF_INTERNAL_H__*/ diff --git a/inc/HAP_pls.h b/inc/HAP_pls.h new file mode 100644 index 0000000..717685d --- /dev/null +++ b/inc/HAP_pls.h @@ -0,0 +1,103 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef HAP_PLS_H +#define HAP_PLS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Process local storage is local storage for the hlos process context. + * + * Warning, this API should only be called from within a thread started by FastRPC, and not from + * any user created threads via the qurt apis. + * + * When used from within a FastRPC started thread this will attach + * desturctors to the lifetime of the HLOS process that is making the + * rpc calls. Users can use this to store context for the lifetime of + * the calling process on the hlos. + * + * Recovering instances + * -------------------- + * + * To maintain the same instance structure for a caller from the HLOS users + * can use the HAP_pls_add_lookup api, which will lookup the key, and add it + * if its not already present. + * For example: + * + * static int my_instance(struct my_struct* me) { + * return HAP_pls_add_lookup((uintptr_t)my_ctor, //type, some unique static address + * 0, //key, for different type instances + * sizeof(*me), //size of our struture + * my_ctor, //structure ctor + * 0, //aditional user context for ctor + * my_dtor, //desturctor + * &me); //result + * } + * + * First call to my_instance will initialize the structure by allocating it and calling my_ctor. + * Second call to my_instance will return the created instance. + * This API is thread safe, but when two threads try to intialize the structure the first + * time they may both create an instance, but only 1 will be returned. + * The destructor will be called when the HLOS process exits. + * + * See HAP_pls_add and HAP_pls_add_lookup. + * + * Exit Hooks + * ---------- + * + * Users can use either HAP_pls_add_lookup or HAP_pls_add to add a destructor that will be + * called when the HLOS process exits. The main difference between the two functions is that + * HAP_pls_add will always add, and the last instance added will be the one returned by + * HAP_pls_lookup. + * + * + */ + +/** + * adds a new type/key to the local storage, overriding + * any previous value at the key. Overriding the key + * does not cause the destructor to run. Destructors are + * run when the HLOS process exits. + * + * @param type, type part of the key to be used for lookup, + * these should be static addresses, like the address of a function. + * @param key, the key to be used for lookup + * @param size, the size of the data + * @param ctor, constructor that takes a context and memory of size + * @param ctx, constructor context passed as the first argument to ctor + * @param dtor, destructor to run at pls shutdown + * @param ppo, output data + * @retval, 0 for success + */ +int HAP_pls_add(uintptr_t type, uintptr_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void*), void** ppo); + +/** + * Like add, but will only add 1 item, and return the same item on the + * next add. If two threads try to call this function at teh same time + * they will both receive the same value as a result, but the constructors + * may be called twice. + * item if its already there, otherwise tries to add. + * ctor may be called twice + * callers should avoid calling pls_add for the same type/key which will override the singleton + */ +int HAP_pls_add_lookup(uintptr_t type, uintptr_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void*), void** ppo); + +/** + * finds the last data pointer added for key to the local storage + * + * @param key, the key to be used for lookup + * @param ppo, output data + * @retval, 0 for success + */ +int HAP_pls_lookup(uintptr_t type, uintptr_t key, void** ppo); + + +#ifdef __cplusplus +} +#endif +#endif //HAP_PLS_H diff --git a/inc/adsp_current_process.h b/inc/adsp_current_process.h new file mode 100644 index 0000000..5b0196b --- /dev/null +++ b/inc/adsp_current_process.h @@ -0,0 +1,55 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _ADSP_CURRENT_PROCESS_H +#define _ADSP_CURRENT_PROCESS_H +#include +#include +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE +#ifdef __cplusplus +extern "C" { +#endif +#if !defined(__QAIC_STRING1_OBJECT_DEFINED__) && !defined(__STRING1_OBJECT__) +#define __QAIC_STRING1_OBJECT_DEFINED__ +#define __STRING1_OBJECT__ +typedef struct _cstring1_s { + char* data; + int dataLen; +} _cstring1_t; + +#endif /* __QAIC_STRING1_OBJECT_DEFINED__ */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process_exit)(void) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process_thread_exit)(void) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process_set_logging_params)(unsigned short mask, const _cstring1_t* filesToLog, int filesToLogLen) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process_getASID)(unsigned int* asid) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process_setQoS)(unsigned int latency) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process_exception)(void) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process_set_logging_params2)(unsigned int mask, const _cstring1_t* filesToLog, int filesToLogLen) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process_poll_mode)(unsigned int enable, unsigned int timeout) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process_enable_notifications)(void) __QAIC_HEADER_ATTRIBUTE; +#ifdef __cplusplus +} +#endif +#endif //_ADSP_CURRENT_PROCESS_H diff --git a/inc/adsp_current_process1.h b/inc/adsp_current_process1.h new file mode 100644 index 0000000..ec871e0 --- /dev/null +++ b/inc/adsp_current_process1.h @@ -0,0 +1,91 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _ADSP_CURRENT_PROCESS1_H +#define _ADSP_CURRENT_PROCESS1_H +#include +#include + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE +#ifdef __cplusplus +extern "C" { +#endif +#if !defined(__QAIC_STRING1_OBJECT_DEFINED__) && !defined(__STRING1_OBJECT__) +#define __QAIC_STRING1_OBJECT_DEFINED__ +#define __STRING1_OBJECT__ +typedef struct _cstring1_s { + char* data; + int dataLen; +} _cstring1_t; + +#endif /* __QAIC_STRING1_OBJECT_DEFINED__ */ +#define _const_adsp_current_process1_handle 4 +/** + * Opens the handle in the specified domain. If this is the first + * handle, this creates the session. Typically this means opening + * the device, aka open("/dev/adsprpc-smd"), then calling ioctl + * device APIs to create a PD on the DSP to execute our code in, + * then asking that PD to dlopen the .so and dlsym the skel function. + * + * @param uri, _URI"&_dom=aDSP" + * _URI is a QAIC generated uri, or + * "file:///?_skel_handle_invoke&_modver=1.0" + * If the _dom parameter is not present, _dom=DEFAULT is assumed + * but not forwarded. + * Reserved uri keys: + * [0]: first unamed argument is the skel invoke function + * _dom: execution domain name, _dom=mDSP/aDSP/DEFAULT + * _modver: module version, _modver=1.0 + * _*: any other key name starting with an _ is reserved + * Unknown uri keys/values are forwarded as is. + * @param h, resulting handle + * @retval, 0 on success + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process1_open)(const char* uri, remote_handle64* h) __QAIC_HEADER_ATTRIBUTE; +/** + * Closes a handle. If this is the last handle to close, the session + * is closed as well, releasing all the allocated resources. + + * @param h, the handle to close + * @retval, 0 on success, should always succeed + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process1_close)(remote_handle64 h) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process1_exit)(remote_handle64 _h) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process1_thread_exit)(remote_handle64 _h) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process1_set_logging_params)(remote_handle64 _h, unsigned short mask, const _cstring1_t* filesToLog, int filesToLogLen) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process1_getASID)(remote_handle64 _h, unsigned int* asid) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process1_setQoS)(remote_handle64 _h, unsigned int latency) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process1_exception)(remote_handle64 _h) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process1_set_logging_params2)(remote_handle64 _h, unsigned int mask, const _cstring1_t* filesToLog, int filesToLogLen) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process1_poll_mode)(remote_handle64 _h, unsigned int enable, unsigned int timeout) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process1_enable_notifications)(remote_handle64 _h) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_current_process1_panic_err_codes)(remote_handle64 _h, const int* err_codes, int err_codesLen) __QAIC_HEADER_ATTRIBUTE; +#ifndef adsp_current_process1_URI +#define adsp_current_process1_URI "file:///libadsp_current_process1_skel.so?adsp_current_process1_skel_handle_invoke&_modver=1.0" +#endif /*adsp_current_process1_URI*/ +#ifdef __cplusplus +} +#endif +#endif //_ADSP_CURRENT_PROCESS1_H diff --git a/inc/adsp_default_listener.h b/inc/adsp_default_listener.h new file mode 100644 index 0000000..53ba793 --- /dev/null +++ b/inc/adsp_default_listener.h @@ -0,0 +1,38 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _ADSP_DEFAULT_LISTENER_H +#define _ADSP_DEFAULT_LISTENER_H +#include +#include +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE +#ifdef __cplusplus +extern "C" { +#endif +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_default_listener_register)(void) __QAIC_HEADER_ATTRIBUTE; +#ifdef __cplusplus +} +#endif +#endif //_ADSP_DEFAULT_LISTENER_H diff --git a/inc/adsp_default_listener1.h b/inc/adsp_default_listener1.h new file mode 100644 index 0000000..2042fff --- /dev/null +++ b/inc/adsp_default_listener1.h @@ -0,0 +1,259 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _ADSP_DEFAULT_LISTENER1_H +#define _ADSP_DEFAULT_LISTENER1_H +#include +#include +#include +#include + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#include + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef _ATTRIBUTE_VISIBILITY + +#ifdef _WIN32 +#define _ATTRIBUTE_VISIBILITY +#else +#define _ATTRIBUTE_VISIBILITY __attribute__ ((visibility("default"))) +#endif + +#endif // _ATTRIBUTE_VISIBILITY + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i = 0; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#ifdef _WIN32 +#define _QAIC_FARF(level, msg, ...) (void)0 +#else +#define _QAIC_FARF(level, msg, ...) \ + do {\ + if(0 == (HAP_debug_v2) ) {\ + (void)0; \ + } else { \ + FARF(level, msg , ##__VA_ARGS__); \ + } \ + }while(0) +#endif //_WIN32 for _QAIC_FARF + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _TRY_FARF(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + goto ee##farf##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _CATCH_FARF(exception) exception##farf##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#endif + + +#endif // _QAIC_ENV_H + +#ifdef __cplusplus +extern "C" { +#endif +/** + * Opens the handle in the specified domain. If this is the first + * handle, this creates the session. Typically this means opening + * the device, aka open("/dev/adsprpc-smd"), then calling ioctl + * device APIs to create a PD on the DSP to execute our code in, + * then asking that PD to dlopen the .so and dlsym the skel function. + * + * @param uri, _URI"&_dom=aDSP" + * _URI is a QAIC generated uri, or + * "file:///?_skel_handle_invoke&_modver=1.0" + * If the _dom parameter is not present, _dom=DEFAULT is assumed + * but not forwarded. + * Reserved uri keys: + * [0]: first unamed argument is the skel invoke function + * _dom: execution domain name, _dom=mDSP/aDSP/DEFAULT + * _modver: module version, _modver=1.0 + * _*: any other key name starting with an _ is reserved + * Unknown uri keys/values are forwarded as is. + * @param h, resulting handle + * @retval, 0 on success + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_default_listener1_open)(const char* uri, remote_handle64* h) __QAIC_HEADER_ATTRIBUTE; +/** + * Closes a handle. If this is the last handle to close, the session + * is closed as well, releasing all the allocated resources. + + * @param h, the handle to close + * @retval, 0 on success, should always succeed + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_default_listener1_close)(remote_handle64 h) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_default_listener1_register)(remote_handle64 _h) __QAIC_HEADER_ATTRIBUTE; +#ifndef adsp_default_listener1_URI +#define adsp_default_listener1_URI "file:///libadsp_default_listener1_skel.so?adsp_default_listener1_skel_handle_invoke&_modver=1.0" +#endif /*adsp_default_listener1_URI*/ +#ifdef __cplusplus +} +#endif +#endif //_ADSP_DEFAULT_LISTENER1_H diff --git a/inc/adsp_listener.h b/inc/adsp_listener.h new file mode 100644 index 0000000..043420f --- /dev/null +++ b/inc/adsp_listener.h @@ -0,0 +1,53 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _ADSP_LISTENER_H +#define _ADSP_LISTENER_H +#include +#include + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE +#ifdef __cplusplus +extern "C" { +#endif +#define _const_adsp_listener_handle 3 +typedef struct _adsp_listener_buffer__seq_uint8 _adsp_listener_buffer__seq_uint8; +typedef _adsp_listener_buffer__seq_uint8 adsp_listener_buffer; +struct _adsp_listener_buffer__seq_uint8 { + uint8* data; + int dataLen; +}; +typedef uint32 adsp_listener_remote_handle; +typedef uint32 adsp_listener_invoke_ctx; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_listener_next_invoke)(adsp_listener_invoke_ctx prevCtx, int prevResult, const adsp_listener_buffer* outBufs, int outBufsLen, adsp_listener_invoke_ctx* ctx, adsp_listener_remote_handle* handle, uint32* sc, adsp_listener_buffer* inBuffers, int inBuffersLen, int* inBufLenReq, int inBufLenReqLen, int* routBufLenReq, int routBufLenReqLen) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_listener_invoke_get_in_bufs)(adsp_listener_invoke_ctx ctx, adsp_listener_buffer* inBuffers, int inBuffersLen) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_listener_init)(void) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_listener_init2)(void) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_listener_next2)(adsp_listener_invoke_ctx prevCtx, int prevResult, const uint8* prevbufs, int prevbufsLen, adsp_listener_invoke_ctx* ctx, adsp_listener_remote_handle* handle, uint32* sc, uint8* bufs, int bufsLen, int* bufsLenReq) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_listener_get_in_bufs2)(adsp_listener_invoke_ctx ctx, int offset, uint8* bufs, int bufsLen, int* bufsLenReq) __QAIC_HEADER_ATTRIBUTE; +#ifdef __cplusplus +} +#endif +#endif //_ADSP_LISTENER_H diff --git a/inc/adsp_listener1.h b/inc/adsp_listener1.h new file mode 100644 index 0000000..28ad317 --- /dev/null +++ b/inc/adsp_listener1.h @@ -0,0 +1,274 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _ADSP_LISTENER1_H +#define _ADSP_LISTENER1_H +#include +#include +#include +#include + + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#include + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef _ATTRIBUTE_VISIBILITY + +#ifdef _WIN32 +#define _ATTRIBUTE_VISIBILITY +#else +#define _ATTRIBUTE_VISIBILITY __attribute__ ((visibility("default"))) +#endif + +#endif // _ATTRIBUTE_VISIBILITY + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i = 0; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#ifdef _WIN32 +#define _QAIC_FARF(level, msg, ...) (void)0 +#else +#define _QAIC_FARF(level, msg, ...) \ + do {\ + if(0 == (HAP_debug_v2) ) {\ + (void)0; \ + } else { \ + FARF(level, msg , ##__VA_ARGS__); \ + } \ + }while(0) +#endif //_WIN32 for _QAIC_FARF + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _TRY_FARF(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + goto ee##farf##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _CATCH_FARF(exception) exception##farf##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#endif + + +#endif // _QAIC_ENV_H + +#ifdef __cplusplus +extern "C" { +#endif +#define _const_adsp_listener1_handle 7 +/** + * Opens the handle in the specified domain. If this is the first + * handle, this creates the session. Typically this means opening + * the device, aka open("/dev/adsprpc-smd"), then calling ioctl + * device APIs to create a PD on the DSP to execute our code in, + * then asking that PD to dlopen the .so and dlsym the skel function. + * + * @param uri, _URI"&_dom=aDSP" + * _URI is a QAIC generated uri, or + * "file:///?_skel_handle_invoke&_modver=1.0" + * If the _dom parameter is not present, _dom=DEFAULT is assumed + * but not forwarded. + * Reserved uri keys: + * [0]: first unamed argument is the skel invoke function + * _dom: execution domain name, _dom=mDSP/aDSP/DEFAULT + * _modver: module version, _modver=1.0 + * _*: any other key name starting with an _ is reserved + * Unknown uri keys/values are forwarded as is. + * @param h, resulting handle + * @retval, 0 on success + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_listener1_open)(const char* uri, remote_handle64* h) __QAIC_HEADER_ATTRIBUTE; +/** + * Closes a handle. If this is the last handle to close, the session + * is closed as well, releasing all the allocated resources. + + * @param h, the handle to close + * @retval, 0 on success, should always succeed + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_listener1_close)(remote_handle64 h) __QAIC_HEADER_ATTRIBUTE; +typedef struct _adsp_listener1_buffer__seq_uint8 _adsp_listener1_buffer__seq_uint8; +typedef _adsp_listener1_buffer__seq_uint8 adsp_listener1_buffer; +struct _adsp_listener1_buffer__seq_uint8 { + uint8* data; + int dataLen; +}; +typedef uint32 adsp_listener1_remote_handle; +typedef uint32 adsp_listener1_invoke_ctx; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_listener1_next_invoke)(remote_handle64 _h, adsp_listener1_invoke_ctx prevCtx, int prevResult, const adsp_listener1_buffer* outBufs, int outBufsLen, adsp_listener1_invoke_ctx* ctx, adsp_listener1_remote_handle* handle, uint32* sc, adsp_listener1_buffer* inBuffers, int inBuffersLen, int* inBufLenReq, int inBufLenReqLen, int* routBufLenReq, int routBufLenReqLen) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_listener1_invoke_get_in_bufs)(remote_handle64 _h, adsp_listener1_invoke_ctx ctx, adsp_listener1_buffer* inBuffers, int inBuffersLen) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_listener1_init)(remote_handle64 _h) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_listener1_init2)(remote_handle64 _h) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_listener1_next2)(remote_handle64 _h, adsp_listener1_invoke_ctx prevCtx, int prevResult, const uint8* prevbufs, int prevbufsLen, adsp_listener1_invoke_ctx* ctx, adsp_listener1_remote_handle* handle, uint32* sc, uint8* bufs, int bufsLen, int* bufsLenReq) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_listener1_get_in_bufs2)(remote_handle64 _h, adsp_listener1_invoke_ctx ctx, int offset, uint8* bufs, int bufsLen, int* bufsLenReq) __QAIC_HEADER_ATTRIBUTE; +#ifndef adsp_listener1_URI +#define adsp_listener1_URI "file:///libadsp_listener1_skel.so?adsp_listener1_skel_handle_invoke&_modver=1.0" +#endif /*adsp_listener1_URI*/ +#ifdef __cplusplus +} +#endif +#endif //_ADSP_LISTENER1_H diff --git a/inc/adsp_perf.h b/inc/adsp_perf.h new file mode 100644 index 0000000..b079633 --- /dev/null +++ b/inc/adsp_perf.h @@ -0,0 +1,85 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _ADSP_PERF_H +#define _ADSP_PERF_H +#include +#include + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE +#ifdef __cplusplus +extern "C" { +#endif +/** + * Interface for querying the adsp for counter data + * For example, to enable all the perf numbers: + * + * int perf_on(void) { + * int nErr = 0; + * int numKeys = 0, maxLen = 0, ii; + * char keys[512]; + * char* buf = &keys[0]; + * VERIFY(0 == adsp_perf_get_keys(keys, 512, &maxLen, &numKeys)); + * assert(maxLen < 512); + * for(ii = 0; ii < numKeys; ++ii) { + * char* name = buf; + * buf += strlen(name) + 1; + * printf("perf on: %s\n", name); + * VERIFY(0 == adsp_perf_enable(ii)); + * } + * bail: + * return nErr; + * } + * + * To read all the results: + * + * int rpcperf_perf_result(void) { + * int nErr = 0; + * int numKeys, maxLen, ii; + * char keys[512]; + * char* buf = &keys[0]; + * long long usecs[16]; + * VERIFY(0 == adsp_perf_get_keys(keys, 512, &maxLen, &numKeys)); + * printf("perf keys: %d\n", numKeys); + * VERIFY(0 == adsp_perf_get_usecs(usecs, 16)); + * assert(maxLen < 512); + * assert(numKeys < 16); + * for(ii = 0; ii < numKeys; ++ii) { + * char* name = buf; + * buf += strlen(name) + 1; + * printf("perf result: %s %lld\n", name, usecs[ii]); + * } + * bail: + * return nErr; + * } + */ +#define _const_adsp_perf_handle 6 +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_perf_enable)(int ix) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_perf_get_usecs)(int64* dst, int dstLen) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_perf_get_keys)(char* keys, int keysLen, int* maxLen, int* numKeys) __QAIC_HEADER_ATTRIBUTE; +#ifdef __cplusplus +} +#endif +#endif //_ADSP_PERF_H diff --git a/inc/adsp_perf1.h b/inc/adsp_perf1.h new file mode 100644 index 0000000..4062f21 --- /dev/null +++ b/inc/adsp_perf1.h @@ -0,0 +1,306 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _ADSP_PERF1_H +#define _ADSP_PERF1_H +#include +#include +#include +#include + + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#include + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef _ATTRIBUTE_VISIBILITY + +#ifdef _WIN32 +#define _ATTRIBUTE_VISIBILITY +#else +#define _ATTRIBUTE_VISIBILITY __attribute__ ((visibility("default"))) +#endif + +#endif // _ATTRIBUTE_VISIBILITY + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i = 0; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#ifdef _WIN32 +#define _QAIC_FARF(level, msg, ...) (void)0 +#else +#define _QAIC_FARF(level, msg, ...) \ + do {\ + if(0 == (HAP_debug_v2) ) {\ + (void)0; \ + } else { \ + FARF(level, msg , ##__VA_ARGS__); \ + } \ + }while(0) +#endif //_WIN32 for _QAIC_FARF + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _TRY_FARF(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + goto ee##farf##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _CATCH_FARF(exception) exception##farf##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#endif + + +#endif // _QAIC_ENV_H + +#ifdef __cplusplus +extern "C" { +#endif +/** + * Interface for querying the adsp for counter data + * For example, to enable all the perf numbers: + * + * int perf_on(void) { + * int nErr = 0; + * int numKeys = 0, maxLen = 0, ii; + * char keys[512]; + * char* buf = &keys[0]; + * VERIFY(0 == adsp_perf_get_keys(keys, 512, &maxLen, &numKeys)); + * assert(maxLen < 512); + * for(ii = 0; ii < numKeys; ++ii) { + * char* name = buf; + * buf += strlen(name) + 1; + * printf("perf on: %s\n", name); + * VERIFY(0 == adsp_perf_enable(ii)); + * } + * bail: + * return nErr; + * } + * + * To read all the results: + * + * int rpcperf_perf_result(void) { + * int nErr = 0; + * int numKeys, maxLen, ii; + * char keys[512]; + * char* buf = &keys[0]; + * long long usecs[16]; + * VERIFY(0 == adsp_perf_get_keys(keys, 512, &maxLen, &numKeys)); + * printf("perf keys: %d\n", numKeys); + * VERIFY(0 == adsp_perf_get_usecs(usecs, 16)); + * assert(maxLen < 512); + * assert(numKeys < 16); + * for(ii = 0; ii < numKeys; ++ii) { + * char* name = buf; + * buf += strlen(name) + 1; + * printf("perf result: %s %lld\n", name, usecs[ii]); + * } + * bail: + * return nErr; + * } + */ +#define _const_adsp_perf1_handle 9 +/** + * Opens the handle in the specified domain. If this is the first + * handle, this creates the session. Typically this means opening + * the device, aka open("/dev/adsprpc-smd"), then calling ioctl + * device APIs to create a PD on the DSP to execute our code in, + * then asking that PD to dlopen the .so and dlsym the skel function. + * + * @param uri, _URI"&_dom=aDSP" + * _URI is a QAIC generated uri, or + * "file:///?_skel_handle_invoke&_modver=1.0" + * If the _dom parameter is not present, _dom=DEFAULT is assumed + * but not forwarded. + * Reserved uri keys: + * [0]: first unamed argument is the skel invoke function + * _dom: execution domain name, _dom=mDSP/aDSP/DEFAULT + * _modver: module version, _modver=1.0 + * _*: any other key name starting with an _ is reserved + * Unknown uri keys/values are forwarded as is. + * @param h, resulting handle + * @retval, 0 on success + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_perf1_open)(const char* uri, remote_handle64* h) __QAIC_HEADER_ATTRIBUTE; +/** + * Closes a handle. If this is the last handle to close, the session + * is closed as well, releasing all the allocated resources. + + * @param h, the handle to close + * @retval, 0 on success, should always succeed + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_perf1_close)(remote_handle64 h) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_perf1_enable)(remote_handle64 _h, int ix) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_perf1_get_usecs)(remote_handle64 _h, int64* dst, int dstLen) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adsp_perf1_get_keys)(remote_handle64 _h, char* keys, int keysLen, int* maxLen, int* numKeys) __QAIC_HEADER_ATTRIBUTE; +#ifndef adsp_perf1_URI +#define adsp_perf1_URI "file:///libadsp_perf1_skel.so?adsp_perf1_skel_handle_invoke&_modver=1.0" +#endif /*adsp_perf1_URI*/ +#ifdef __cplusplus +} +#endif +#endif //_ADSP_PERF1_H diff --git a/inc/adsp_pls.h b/inc/adsp_pls.h new file mode 100644 index 0000000..b16e042 --- /dev/null +++ b/inc/adsp_pls.h @@ -0,0 +1,74 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef ADSP_PLS_H +#define ADSP_PLS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif +/** + * internal header + */ + +/** + * @file adsp_pls + * + * adsp process local storage is local storage for the fastrpc hlos + * process context. + + * When used from within a fastrpc started thread this will attach + * desturctors to the lifetime of the hlos process that is making the + * rpc calls. Users can use this to store context for the lifetime of + * the calling process on the hlos. + */ + +/** + * adds a new key to the local storage, overriding + * any previous value at the key. Overriding the key + * does not cause the destructor to run. + * + * @param type, type part of the key to be used for lookup, + * these should be static addresses, like the address of a function. + * @param key, the key to be used for lookup + * @param size, the size of the data + * @param ctor, constructor that takes a context and memory of size + * @param ctx, constructor context passed as the first argument to ctor + * @param dtor, destructor to run at pls shutdown + * @param ppo, output data + * @retval, 0 for success + */ +int adsp_pls_add(uintptr_t type, uintptr_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void*), void** ppo); + +/** + * Like add, but will only add 1 item, and return the same item on the + * next add. If two threads try to call this function at teh same time + * they will both receive the same value as a result, but the constructors + * may be called twice. + * item if its already there, otherwise tries to add. + * ctor may be called twice + * callers should avoid calling pls_add which will override the singleton + */ +int adsp_pls_add_lookup(uintptr_t type, uintptr_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void*), void** ppo); + +/** + * finds the last data pointer added for key to the local storage + * + * @param key, the key to be used for lookup + * @param ppo, output data + * @retval, 0 for success + */ +int adsp_pls_lookup(uintptr_t type, uintptr_t key, void** ppo); + +/** + * force init/deinit + */ +int gpls_init(void); +void gpls_deinit(void); + +#ifdef __cplusplus +} +#endif +#endif //ADSP_PLS_H diff --git a/inc/adspmsgd_adsp.h b/inc/adspmsgd_adsp.h new file mode 100644 index 0000000..7fc66fe --- /dev/null +++ b/inc/adspmsgd_adsp.h @@ -0,0 +1,41 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _ADSPMSGD_ADSP_H +#define _ADSPMSGD_ADSP_H +#include +#include + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE +#ifdef __cplusplus +extern "C" { +#endif +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adspmsgd_adsp_init)(int heapid, uint32 ion_flags, uint32 filter, uint32 buf_size, int* buff_addr) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adspmsgd_adsp_init2)(void) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adspmsgd_adsp_deinit)(void) __QAIC_HEADER_ATTRIBUTE; +#ifdef __cplusplus +} +#endif +#endif //_ADSPMSGD_ADSP_H diff --git a/inc/adspmsgd_adsp1.h b/inc/adspmsgd_adsp1.h new file mode 100644 index 0000000..93a3d7f --- /dev/null +++ b/inc/adspmsgd_adsp1.h @@ -0,0 +1,77 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _ADSPMSGD_ADSP1_H +#define _ADSPMSGD_ADSP1_H +#include +#include + + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE +#ifdef __cplusplus +extern "C" { +#endif +#define _const_adspmsgd_adsp1_handle 5 +/** + * Opens the handle in the specified domain. If this is the first + * handle, this creates the session. Typically this means opening + * the device, aka open("/dev/adsprpc-smd"), then calling ioctl + * device APIs to create a PD on the DSP to execute our code in, + * then asking that PD to dlopen the .so and dlsym the skel function. + * + * @param uri, _URI"&_dom=aDSP" + * _URI is a QAIC generated uri, or + * "file:///?_skel_handle_invoke&_modver=1.0" + * If the _dom parameter is not present, _dom=DEFAULT is assumed + * but not forwarded. + * Reserved uri keys: + * [0]: first unamed argument is the skel invoke function + * _dom: execution domain name, _dom=mDSP/aDSP/DEFAULT + * _modver: module version, _modver=1.0 + * _*: any other key name starting with an _ is reserved + * Unknown uri keys/values are forwarded as is. + * @param h, resulting handle + * @retval, 0 on success + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adspmsgd_adsp1_open)(const char* uri, remote_handle64* h) __QAIC_HEADER_ATTRIBUTE; +/** + * Closes a handle. If this is the last handle to close, the session + * is closed as well, releasing all the allocated resources. + + * @param h, the handle to close + * @retval, 0 on success, should always succeed + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adspmsgd_adsp1_close)(remote_handle64 h) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adspmsgd_adsp1_init2)(remote_handle64 _h) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adspmsgd_adsp1_deinit)(remote_handle64 _h) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adspmsgd_adsp1_init3)(remote_handle64 _h, int heapid, uint32 ion_flags, uint32 filter, uint64 buf_size, uint64* buff_addr) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adspmsgd_adsp1_wait)(remote_handle64 _h, uint64* bytes_to_read) __QAIC_HEADER_ATTRIBUTE; +#ifndef adspmsgd_adsp1_URI +#define adspmsgd_adsp1_URI "file:///libadspmsgd_adsp1_skel.so?adspmsgd_adsp1_skel_handle_invoke&_modver=1.0" +#endif /*adspmsgd_adsp1_URI*/ +#ifdef __cplusplus +} +#endif +#endif //_ADSPMSGD_ADSP1_H diff --git a/inc/adspmsgd_apps.h b/inc/adspmsgd_apps.h new file mode 100644 index 0000000..3200252 --- /dev/null +++ b/inc/adspmsgd_apps.h @@ -0,0 +1,54 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _ADSPMSGD_APPS_H +#define _ADSPMSGD_APPS_H +#include +#include + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE +#ifdef __cplusplus +extern "C" { +#endif +enum adspmsgd_apps_Level { + LOW, + MEDIUM, + HIGH, + ERROR, + FATAL, + _32BIT_PLACEHOLDER_adspmsgd_apps_Level = 0x7fffffff +}; +typedef enum adspmsgd_apps_Level adspmsgd_apps_Level; +typedef struct _adspmsgd_apps_octetSeq__seq_octet _adspmsgd_apps_octetSeq__seq_octet; +typedef _adspmsgd_apps_octetSeq__seq_octet adspmsgd_apps_octetSeq; +struct _adspmsgd_apps_octetSeq__seq_octet { + unsigned char* data; + int dataLen; +}; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(adspmsgd_apps_log)(const unsigned char* log_message_buffer, int log_message_bufferLen) __QAIC_HEADER_ATTRIBUTE; +#ifdef __cplusplus +} +#endif +#endif //_ADSPMSGD_APPS_H diff --git a/inc/adspmsgd_internal.h b/inc/adspmsgd_internal.h new file mode 100644 index 0000000..b526c1f --- /dev/null +++ b/inc/adspmsgd_internal.h @@ -0,0 +1,41 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef __ADSPMSGD_INTERNAL__ +#define __ADSPMSGD_INTERNAL__ + +#include +#include +#include + +typedef void* (*reader_thread)(); + +typedef struct { + volatile int threadStop;// variable to stop the msgd HLOS thread + bool thread_running; // to check whether logger thread was launched + unsigned int bufferSize; //size of msgd shared buffer + unsigned int readIndex; //the index from which msgd thread starts reading + unsigned int* currentIndex; //if currentIndex is same as readIndex then msgd thread waits for messages from DSP + char* headPtr; //head pointer to the msgd shared buffer + char* message; //scratch buffer used to print messages + pthread_t msgreader_thread; + FILE *log_file_fd; // file descriptor to save runtime farf logs +} msgd; + +/** + * @brief API to initialize adspmsgd module + * Initializes data structures and global variables in this module + */ +int adspmsgd_init(remote_handle64 handle, int filter); +/** + * @brief API to log a new message in adspmsgd + * Sends the new message to stdout/any other logging mechanism available on the system + */ +void adspmsgd_log_message(char *format, char *msg); +/** + * @brief API to stop running this module + * after calling this API, no new messages will be logged in the system. + */ +void adspmsgd_stop(int); + +#endif /* __ADSPMSGD_INTERNAL__ */ \ No newline at end of file diff --git a/inc/apps_mem.h b/inc/apps_mem.h new file mode 100644 index 0000000..44b748d --- /dev/null +++ b/inc/apps_mem.h @@ -0,0 +1,46 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _APPS_MEM_H +#define _APPS_MEM_H +#include +#include + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE +#ifdef __cplusplus +extern "C" { +#endif +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_mem_request_map)(int heapid, uint32 ion_flags, uint32 rflags, uint32 vin, int32 len, uint32* vapps, uint32* vadsp) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_mem_request_unmap)(uint32 vadsp, int32 len) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_mem_request_map64)(int heapid, uint32 ion_flags, uint32 rflags, uint64 vin, int64 len, uint64* vapps, uint64* vadsp) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_mem_request_unmap64)(uint64 vadsp, int64 len) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_mem_share_map)(int fd, int size, uint64* vapps, uint64* vadsp) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_mem_share_unmap)(uint64 vadsp, int size) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_mem_dma_handle_map)(int fd, int offset, int size) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_mem_dma_handle_unmap)(int fd, int size) __QAIC_HEADER_ATTRIBUTE; +#ifdef __cplusplus +} +#endif +#endif //_APPS_MEM_H diff --git a/inc/apps_mem_internal.h b/inc/apps_mem_internal.h new file mode 100644 index 0000000..6ba9e5e --- /dev/null +++ b/inc/apps_mem_internal.h @@ -0,0 +1,20 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef __APPS_MEM_INTERNAL_H__ +#define __APPS_MEM_INTERNAL_H__ + +#include "apps_mem.h" + +/** + * @brief API to initialize the apps_mem module + * initializes internal data structures and global variables + **/ +int apps_mem_init(int domain); +/** + * @brief API to de-initialize the apps_mem module + * de-initializes internal data structures and global variables + **/ +void apps_mem_deinit(int domain); + +#endif /*__APPS_MEM_INTERNAL_H__*/ diff --git a/inc/apps_remotectl.h b/inc/apps_remotectl.h new file mode 100644 index 0000000..2590b14 --- /dev/null +++ b/inc/apps_remotectl.h @@ -0,0 +1,49 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _APPS_REMOTECTL_H +#define _APPS_REMOTECTL_H +#include +#include + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE +#ifdef __cplusplus +extern "C" { +#endif +#if !defined(__QAIC_STRING1_OBJECT_DEFINED__) && !defined(__STRING1_OBJECT__) +#define __QAIC_STRING1_OBJECT_DEFINED__ +#define __STRING1_OBJECT__ +typedef struct _cstring1_s { + char* data; + int dataLen; +} _cstring1_t; + +#endif /* __QAIC_STRING1_OBJECT_DEFINED__ */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_remotectl_open)(const char* name, int* handle, char* dlerror, int dlerrorLen, int* nErr) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_remotectl_close)(int handle, char* dlerror, int dlerrorLen, int* nErr) __QAIC_HEADER_ATTRIBUTE; +#ifdef __cplusplus +} +#endif +#endif //_APPS_REMOTECTL_H diff --git a/inc/apps_std.h b/inc/apps_std.h new file mode 100644 index 0000000..4941dc9 --- /dev/null +++ b/inc/apps_std.h @@ -0,0 +1,187 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _APPS_STD_H +#define _APPS_STD_H +#include +#include + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE +#ifdef __cplusplus +extern "C" { +#endif +#if !defined(__QAIC_STRING1_OBJECT_DEFINED__) && !defined(__STRING1_OBJECT__) +#define __QAIC_STRING1_OBJECT_DEFINED__ +#define __STRING1_OBJECT__ +typedef struct _cstring1_s { + char* data; + int dataLen; +} _cstring1_t; + +#endif /* __QAIC_STRING1_OBJECT_DEFINED__ */ +/** + * standard library functions remoted from the apps to the dsp + */ +typedef int apps_std_FILE; +enum apps_std_SEEK { + APPS_STD_SEEK_SET, + APPS_STD_SEEK_CUR, + APPS_STD_SEEK_END, + _32BIT_PLACEHOLDER_apps_std_SEEK = 0x7fffffff +}; +typedef enum apps_std_SEEK apps_std_SEEK; +typedef struct apps_std_DIR apps_std_DIR; +struct apps_std_DIR { + uint64 handle; +}; +typedef struct apps_std_DIRENT apps_std_DIRENT; +struct apps_std_DIRENT { + int ino; + char name[255]; +}; +typedef struct apps_std_STAT apps_std_STAT; +struct apps_std_STAT { + uint64 tsz; + uint64 dev; + uint64 ino; + uint32 mode; + uint32 nlink; + uint64 rdev; + uint64 size; + int64 atime; + int64 atimensec; + int64 mtime; + int64 mtimensec; + int64 ctime; + int64 ctimensec; +}; +/** + * @retval, if operation fails errno is returned + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fopen)(const char* name, const char* mode, apps_std_FILE* psout) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_freopen)(apps_std_FILE sin, const char* name, const char* mode, apps_std_FILE* psout) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fflush)(apps_std_FILE sin) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fclose)(apps_std_FILE sin) __QAIC_HEADER_ATTRIBUTE; +/** + * @param, bEOF, if read or write bytes <= bufLen bytes then feof() is called + * and the result is returned in bEOF, otherwise bEOF is set to 0. + * @retval, if read or write return 0 for non zero length buffers, ferror is checked + * and a non zero value is returned in case of error with no rout parameters + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fread)(apps_std_FILE sin, byte* buf, int bufLen, int* bytesRead, int* bEOF) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fwrite)(apps_std_FILE sin, const byte* buf, int bufLen, int* bytesWritten, int* bEOF) __QAIC_HEADER_ATTRIBUTE; +/** + * @param, pos, this buffer is filled up to MIN(posLen, sizeof(fpos_t)) + * @param, posLenReq, returns sizeof(fpos_t) + * @retval, if operation fails errno is returned + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fgetpos)(apps_std_FILE sin, byte* pos, int posLen, int* posLenReq) __QAIC_HEADER_ATTRIBUTE; +/** + * @param, if size of pos doesn't match the system size an error is returned. + * fgetpos can be used to query the size of fpos_t + * @retval, if operation fails errno is returned + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fsetpos)(apps_std_FILE sin, const byte* pos, int posLen) __QAIC_HEADER_ATTRIBUTE; +/** + * @retval, if operation fails errno is returned + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_ftell)(apps_std_FILE sin, int* pos) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fseek)(apps_std_FILE sin, int offset, apps_std_SEEK whence) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_flen)(apps_std_FILE sin, uint64* len) __QAIC_HEADER_ATTRIBUTE; +/** + * @retval, only fails if transport fails + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_rewind)(apps_std_FILE sin) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_feof)(apps_std_FILE sin, int* bEOF) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_ferror)(apps_std_FILE sin, int* err) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_clearerr)(apps_std_FILE sin) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_print_string)(const char* str) __QAIC_HEADER_ATTRIBUTE; +/** + * @param val, must contain space for NULL + * @param valLenReq, length required with NULL + * @retval, if fails errno is returned + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_getenv)(const char* name, char* val, int valLen, int* valLenReq) __QAIC_HEADER_ATTRIBUTE; +/** + * @retval, if fails errno is returned + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_setenv)(const char* name, const char* val, int override) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_unsetenv)(const char* name) __QAIC_HEADER_ATTRIBUTE; +/** + * This function will try to open a file given directories in envvarname separated by + * delim. + * so given environment variable FOO_PATH=/foo;/bar + * fopen_wth_env("FOO_PATH", ";", "path/to/file", "rw", &out); + * will try to open /foo/path/to/file, /bar/path/to/file + * if the variable is unset, it will open the file directly + * + * @param envvarname, name of the environment variable containing the path + * @param delim, delimiator string, such as ";" + * @param name, name of the file + * @param mode, mode + * @param psout, output handle + * @retval, 0 on success errno or -1 on failure + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fopen_with_env)(const char* envvarname, const char* delim, const char* name, const char* mode, apps_std_FILE* psout) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fgets)(apps_std_FILE sin, byte* buf, int bufLen, int* bEOF) __QAIC_HEADER_ATTRIBUTE; +/** + * This method will return the paths that are searched when looking for a file. + * The paths are defined by the environment variable (separated by delimiters) + * that is passed to the method. + * + * @param envvarname, name of the environment variable containing the path + * @param delim, delimiator string, such as ";" + * @param name, name of the file + * @param paths, Search paths + * @param numPaths, Actual number of paths found + * @param maxPathLen, The max path length + * @retval, 0 on success errno or -1 on failure + * + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_get_search_paths_with_env)(const char* envvarname, const char* delim, _cstring1_t* paths, int pathsLen, uint32* numPaths, uint16* maxPathLen) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fileExists)(const char* path, boolean* exists) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fsync)(apps_std_FILE sin) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fremove)(const char* name) __QAIC_HEADER_ATTRIBUTE; +/** + * This function decrypts the file using the provided open file descriptor, closes the + * original descriptor and return a new file descriptor. + * @retval, if operation fails errno is returned + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fdopen_decrypt)(apps_std_FILE sin, apps_std_FILE* psout) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_opendir)(const char* name, apps_std_DIR* dir) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_closedir)(const apps_std_DIR* dir) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_readdir)(const apps_std_DIR* dir, apps_std_DIRENT* dirent, int* bEOF) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_mkdir)(const char* name, int mode) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_rmdir)(const char* name) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_stat)(const char* name, apps_std_STAT* stat) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_ftrunc)(apps_std_FILE sin, int offset) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_frename)(const char* oldname, const char* newname) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fopen_fd)(const char* name, const char* mode, int* fd, int* len) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fclose_fd)(int fd) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fopen_with_env_fd)(const char* envvarname, const char* delim, const char* name, const char* mode, int* fd, int* len) __QAIC_HEADER_ATTRIBUTE; +#ifdef __cplusplus +} +#endif +#endif //_APPS_STD_H diff --git a/inc/apps_std_internal.h b/inc/apps_std_internal.h new file mode 100644 index 0000000..35450df --- /dev/null +++ b/inc/apps_std_internal.h @@ -0,0 +1,57 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef __APPS_STD_INTERNAL_H__ +#define __APPS_STD_INTERNAL_H__ + +#include "apps_std.h" + +/** + * @brief Macros used in apps_std + * defines the search paths where fastRPC library should + * look for skel libraries, .debugconfig, .farf files. + * Could be overloaded from build system. + **/ + +#define RETRY_WRITE (3) // number of times to retry write operation + +// 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" + +// Locations where shell file can be found +#ifndef ENABLE_UPSTREAM_DRIVER_INTERFACE +#ifndef DSP_MOUNT_LOCATION +#define DSP_MOUNT_LOCATION "/dsp/" +#endif +#ifndef DSP_DOM_LOCATION +#define DSP_DOM_LOCATION "/dsp/xdsp" +#endif +#else /* ENABLE_UPSTREAM_DRIVER_INTERFACE */ +#ifndef DSP_MOUNT_LOCATION +#define DSP_MOUNT_LOCATION "/usr/lib/dsp/" +#endif +#ifndef DSP_DOM_LOCATION +#define DSP_DOM_LOCATION "/usr/lib/dsp/xdsp" +#endif +#endif /* ENABLE_UPSTREAM_DRIVER_INTERFACE */ + +#ifndef VENDOR_DSP_LOCATION +#define VENDOR_DSP_LOCATION "/vendor/dsp/" +#endif +#ifndef VENDOR_DOM_LOCATION +#define VENDOR_DOM_LOCATION "/vendor/dsp/xdsp/" +#endif + +// Search path used by fastRPC to search skel library, .debugconfig and .farf files +#ifndef DSP_SEARCH_PATH +#define DSP_SEARCH_PATH ";/usr/lib/rfsa/adsp;/vendor/lib/rfsa/adsp;" +#endif + +// Search path used by fastRPC for acdb path +#ifndef ADSP_AVS_CFG_PATH +#define ADSP_AVS_CFG_PATH ";/etc/acdbdata/;" +#endif + +#endif /*__APPS_STD_INTERNAL_H__*/ diff --git a/inc/dspqueue_rpc.h b/inc/dspqueue_rpc.h new file mode 100644 index 0000000..b0c4ba3 --- /dev/null +++ b/inc/dspqueue_rpc.h @@ -0,0 +1,79 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _DSPQUEUE_RPC_H +#define _DSPQUEUE_RPC_H +#include +#include + + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE +#ifdef __cplusplus +extern "C" { +#endif +/** + * Opens the handle in the specified domain. If this is the first + * handle, this creates the session. Typically this means opening + * the device, aka open("/dev/adsprpc-smd"), then calling ioctl + * device APIs to create a PD on the DSP to execute our code in, + * then asking that PD to dlopen the .so and dlsym the skel function. + * + * @param uri, _URI"&_dom=aDSP" + * _URI is a QAIC generated uri, or + * "file:///?_skel_handle_invoke&_modver=1.0" + * If the _dom parameter is not present, _dom=DEFAULT is assumed + * but not forwarded. + * Reserved uri keys: + * [0]: first unamed argument is the skel invoke function + * _dom: execution domain name, _dom=mDSP/aDSP/DEFAULT + * _modver: module version, _modver=1.0 + * _*: any other key name starting with an _ is reserved + * Unknown uri keys/values are forwarded as is. + * @param h, resulting handle + * @retval, 0 on success + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(dspqueue_rpc_open)(const char* uri, remote_handle64* h) __QAIC_HEADER_ATTRIBUTE; +/** + * Closes a handle. If this is the last handle to close, the session + * is closed as well, releasing all the allocated resources. + + * @param h, the handle to close + * @retval, 0 on success, should always succeed + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(dspqueue_rpc_close)(remote_handle64 h) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT AEEResult __QAIC_HEADER(dspqueue_rpc_init_process_state)(remote_handle64 _h, int32 process_state_fd) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT AEEResult __QAIC_HEADER(dspqueue_rpc_create_queue)(remote_handle64 _h, uint32 id, int32 queue_fd, uint32 count, uint64* queue_id) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT AEEResult __QAIC_HEADER(dspqueue_rpc_destroy_queue)(remote_handle64 _h, uint64 queue_id) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT AEEResult __QAIC_HEADER(dspqueue_rpc_is_imported)(remote_handle64 _h, uint64 queue_id, int32* imported) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT AEEResult __QAIC_HEADER(dspqueue_rpc_wait_signal)(remote_handle64 _h, int32* signal) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT AEEResult __QAIC_HEADER(dspqueue_rpc_cancel_wait_signal)(remote_handle64 _h) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT AEEResult __QAIC_HEADER(dspqueue_rpc_signal)(remote_handle64 _h) __QAIC_HEADER_ATTRIBUTE; +#ifndef dspqueue_rpc_URI +#define dspqueue_rpc_URI "file:///libdspqueue_rpc_skel.so?dspqueue_rpc_skel_handle_invoke&_modver=1.0" +#endif /*dspqueue_rpc_URI*/ +#ifdef __cplusplus +} +#endif +#endif //_DSPQUEUE_RPC_H diff --git a/inc/dspqueue_shared.h b/inc/dspqueue_shared.h new file mode 100644 index 0000000..a2a975e --- /dev/null +++ b/inc/dspqueue_shared.h @@ -0,0 +1,122 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef DSPQUEUE_SHARED_H +#define DSPQUEUE_SHARED_H + +#include + + +/* Shared memory queue definitions. + + Each queue is allocated as a single shared ION buffer. The buffer consists of: + * struct dspqueue_header + - request packet queue header. Used for messages from the host CPU to the DSP. + - response packet queue header. Used for messages from the DSP to the host CPU. + * read/write states for each packet queue, including read/write pointers. + Each read/write state structure must be on a separate cache line. + * Request and response packet queues + - Packet queues are circular buffers consisting packet headers and data + - Packets are padded to be 64-bit aligned + - The reader and writer manage read and write positions + - Packets do not wrap around at the end of the queue. If a packet cannot fit before the end + of the queue, the entire packet is written at the beginning. The 64-bit header is replicated. +*/ + + +/* Header structure for each one-way packet queue. + All offsets are in bytes to the beginning of the shared memory queue block. */ +struct dspqueue_packet_queue_header { + uint32_t queue_offset; /* Queue offset */ + uint32_t queue_length; /* Queue length in bytes */ + uint32_t read_state_offset; /* Read state offset. Contains struct dspqueue_packet_queue_state, + describing the state of the reader of this queue. */ + uint32_t write_state_offset; /* Write state offset. Contains a struct dspqueue_packet_queue_state, + describing the state of the writer of this queue. */ +}; + +/* State structure, used to describe the state of the reader or writer of each queue. + The state structure is at an offset from the start of the header as defined in + struct dspqueue_packet_queue_header above, and must fit in a single cache line. */ +struct dspqueue_packet_queue_state { + volatile uint32_t position; /* Position within the queue in bytes */ + volatile uint32_t packet_count; /* Number of packets read/written */ + volatile uint32_t wait_count; /* Non-zero if the reader/writer is waiting for a signal + for a new packet or more space in the queue respectively */ +}; + + +/* Userspace shared memory queue header */ +struct dspqueue_header { + uint32_t version; /* Initial version 1, 2 if any flags are set and need to be checked. */ + int32_t error; + uint32_t flags; + struct dspqueue_packet_queue_header req_queue; /* CPU to DSP */ + struct dspqueue_packet_queue_header resp_queue; /* DSP to CPU */ + uint32_t queue_count; +}; + +/* The version number currently expected if both CPU and DSP sides match */ +#define DSPQUEUE_HEADER_CURRENT_VERSION 2 + +/* Wait counts present in the packet queue header. Set by the CPU, DSP must + fail initialization if the feature is not supported. */ +#define DSPQUEUE_HEADER_FLAG_WAIT_COUNTS 1 + +/* Use driver signaling. Set by the CPU, DSP must fail initialization + if the feature is not supported. */ +#define DSPQUEUE_HEADER_FLAG_DRIVER_SIGNALING 2 + +/* Unexpected flags */ +#define DSPQUEUE_HEADER_UNEXPECTED_FLAGS ~(DSPQUEUE_HEADER_FLAG_WAIT_COUNTS | DSPQUEUE_HEADER_FLAG_DRIVER_SIGNALING) + + +/* Maximum queue size in bytes */ +#define DSPQUEUE_MAX_QUEUE_SIZE 16777216 + +/* Maximum number of buffers in a packet */ +#define DSPQUEUE_MAX_BUFFERS 64 + +/* Maximum message size */ +#define DSPQUEUE_MAX_MESSAGE_SIZE 65536 + +/* Default sizes */ +#define DSPQUEUE_DEFAULT_REQ_SIZE 65536 +#define DSPQUEUE_DEFAULT_RESP_SIZE 16384 + + +/* Maximum number of queues per process. Must ensure the state arrays get cache line aligned. + Update signal allocations in dspsignal.h if this changes. */ +#define DSPQUEUE_MAX_PROCESS_QUEUES 64 + + +/* Process queue information block, used with RPC-based signaling. + + Each participant increments the packet/space count for the + corresponding queue when there is a new packet or more space + available and signals the other party. The other party then goes + through active queues to see which one needs processing. + + This reduces the number of signals to two per process and lets us + use argumentless FastRPC calls for signaling. + */ +struct dspqueue_process_queue_state { + uint32_t req_packet_count[DSPQUEUE_MAX_PROCESS_QUEUES]; + uint32_t req_space_count[DSPQUEUE_MAX_PROCESS_QUEUES]; + uint32_t resp_packet_count[DSPQUEUE_MAX_PROCESS_QUEUES]; + uint32_t resp_space_count[DSPQUEUE_MAX_PROCESS_QUEUES]; +}; + + +/* Signals IDs used with driver signaling. Update the signal allocations in dspsignal.h + if this changes. */ +enum dspqueue_signal { + DSPQUEUE_SIGNAL_REQ_PACKET = 0, + DSPQUEUE_SIGNAL_REQ_SPACE, + DSPQUEUE_SIGNAL_RESP_PACKET, + DSPQUEUE_SIGNAL_RESP_SPACE, + DSPQUEUE_NUM_SIGNALS +}; + + +#endif diff --git a/inc/dspsignal.h b/inc/dspsignal.h new file mode 100644 index 0000000..ccbb927 --- /dev/null +++ b/inc/dspsignal.h @@ -0,0 +1,206 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef DSPSIGNAL_H +#define DSPSIGNAL_H + + +/** @file + Internal FastRPC CPU-DSP signaling API. + + dspsignals are low-level userspace to userspace signals intended to be used + as building blocks for client-visible inter-processor communication + constructs. The key properties are: + + - 32-bit per-process signal identifiers, grouped into address + spaces for different applications. Clients are responsible for + managing their signal numbers. + + - Power efficient interrupt-based signaling. The implementation + does not use shared memory polling or similar constructs - + sending a signal involves triggering an interrupt on the + receiving endpoint. This results in some key secondary + properties: + + - Frameworks that aim for lower possible latency should use + shared memory polling, WFE, or other similar mechanisms as + the fast path and dspsignals as the longer-latency + power-efficient fallback mechanism when appropriate. + + - Signaling latency is typically comparable to (but lower + than) 50% of synchronous FastRPC call latency without + polling. + + - Signaling latency will vary widely depending on the + low-power modes the endpoints can use. Clients can influence + this through DSP power voting and CPU PM QoS settings. + + - Reliable signal delivery. Every signal will eventually be + delivered to the other endpoint and clients are not expected to + implement retry loops. + + - Multiple instances of the same signal may get coalesced into + one. In other words, if the signal sender calls dspsignal_send() + multiple times in the loop, the client may see fewer + dspsignal_wait() calls complete. It will however see at least + one wait call complete after the last send call returns. + + - Signals may be delivered out of order + + - Clients may receive stale or spurious signals after reusing a + signal ID. Due to this clients should not assume a specific + event happened when receiving a signal, but should use another + mechanism such as a shared memory structure to confirm it + actually did. + + The signal APIs are intended for internal FastRPC use only. + + On process or subsystem restart the CPU client must destroy all + signal instances and re-create them as needed. + + The CPU client process is expected to have an existing FastRPC + session with the target DSP before creating signals. On the DSP + signals can only be used in FastRPC user PDs. +*/ + +#include +#include +#include + + +/** Infinite timeout */ +#define DSPSIGNAL_TIMEOUT_NONE UINT32_MAX + +/** Remote domain ID for the application CPU */ +#define DSPSIGNAL_DOMAIN_CPU 0xffff + +/** Signal range currently supported: [0..1023]: + - [0..255]: dspqueue signals + - [256..1023]: reserved +*/ +#define DSPSIGNAL_DSPQUEUE_MIN 0 +#define DSPSIGNAL_DSPQUEUE_MAX 255 +#define DSPSIGNAL_RESERVED_MIN (DSPSIGNAL_DSPQUEUE_MAX+1) +#define DSPSIGNAL_RESERVED_MAX 1023 +#define DSPSIGNAL_NUM_SIGNALS (DSPSIGNAL_RESERVED_MAX+1) + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Create a signal instance for use. + * + * @param [in] domain The remote processor/DSP the signal is used + * with. Use CDSP_DOMAIN_ID for cDSP on the CPU, + * DSPSIGNAL_DOMAIN_CPU for the main application + * CPU on the DSP. + * @param [in] id Signal ID. The ID must be unique within the process and + * within the range specified above (i.e. +#include +#include +#include +#include +#include + +#include "remote.h" +#include "fastrpc_common.h" + +#ifdef __LE_TVM__ +#define __CONSTRUCTOR_ATTRIBUTE__ +#else +#define __CONSTRUCTOR_ATTRIBUTE__ __attribute__((constructor)) +#endif + +/* + * API to check if kernel supports remote memory allocation + * Returns 0 if NOT supported + * + */ +int is_kernel_alloc_supported(int dev, int domain); + +/* + * API to initialize rpcmem data structures for ION allocation + */ +int rpcmem_init_internal(); + +/* + * API to clean-up rpcmem data structures + */ +void rpcmem_deinit_internal(); + +/* + * API to allocate ION memory for internal purposes + * Returns NULL if allocation fails + * + */ +void* rpcmem_alloc_internal(int heapid, uint32 flags, size_t size); + +/* + * API to free internally allocated ION memory + * + */ +void rpcmem_free_internal(void* po); + +/* + * API to get fd of internally allocated ION buffer + * Returns valid fd on success and -1 on failure + * + */ +int rpcmem_to_fd_internal(void *po); + +// API to get domain from handle +int get_domain_from_handle(remote_handle64 local, int *domain); + + +/* fastrpc initialization function to call from global functions exported to user */ +int __CONSTRUCTOR_ATTRIBUTE__ fastrpc_init_once(void); + +/* Utility function to find session opened or not for a given domain + * @param domain: DSP domain ID + * @return TRUE if session opened, FALSE otherwise + */ +int is_session_opened(int domain); + +/* Utility function to get device file descriptor of a DSP domain + * @param domain: DSP domain ID + * @return -1 if device not opened and file descriptor if opened + */ +int get_device_fd(int domain); + +/* Utility function to get default or current domain set in tlsKey + * @return domain id on success, -1 on failure + */ +int get_current_domain(void); + +/* Utility function to get state of logger for DSP domain + * @param domain : DSP domain Id + * @return 0 on success, valid non-zero error code on failure + */ +int get_logger_state(int domain); + +/* Utility function to open a fastrpc session + * @param domain: DSP domain id + * @param dev[out]: device id + * @return 0 on success, error codes on failure + */ +int fastrpc_session_open(int domain, int *dev); + +/* Lock and unlock fastrpc session handler */ +void fastrpc_session_lock(int domain); +void fastrpc_session_unlock(int domain); + +/* + * API to close reverse handles + * @handle: handle to close + * @errStr: Error String (if an error occurs) + * @errStrLen: Length of error String (if an error occurs) + * @pdlErr: Error identifier + * @returns: 0 on success, valid non-zero error code on failure + * + */ +int close_reverse_handle(remote_handle64 handle, char* errStr, int errStrLen, int* pdlErr); + + +/* + * API to get unsigned PD attribute for a given domain + * @domain: domain id + * @unsigned_module: PD Attribute for unsigned module + * @returns: 0 on success, valid non-zero error code on failure + */ +int get_unsigned_pd_attribute(uint32 domain, int *unsigned_module); + +/* + * Check whether userspace memory allocation is supported or not. + * returns: 1 if capability supported, 0 otherwise + * + */ +int is_userspace_allocation_supported(); + +#endif //FASTRPC_ANDROID_USER_H diff --git a/inc/fastrpc_async.h b/inc/fastrpc_async.h new file mode 100644 index 0000000..1930a30 --- /dev/null +++ b/inc/fastrpc_async.h @@ -0,0 +1,73 @@ +// 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, boolean 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_cap.h b/inc/fastrpc_cap.h new file mode 100644 index 0000000..ac2627a --- /dev/null +++ b/inc/fastrpc_cap.h @@ -0,0 +1,39 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef __FASTRPC_CAP_H__ +#define __FASTRPC_CAP_H__ + +// Status notification version 2 capability value +#define STATUS_NOTIF_V2 3 + +/** + * @brief reads specific capability from DSP/Kernel and returns + * attributeID - specifies which capability is of interest + * domain - specific domain ID (DSP or the session running on DSP) + * capability - integer return value. in case of boolean - 0/1 is returned. + **/ +int fastrpc_get_cap(uint32_t domain, uint32_t attributeID, uint32_t *capability); +/** + * @brief Checks whether DMA reverse RPC capability is supported + * by DSP. + **/ +uint32_t get_dsp_dma_reverse_rpc_map_capability(int domain); +/** + * @brief Checks kernel if error codes returned are latest to the user + **/ +int check_error_code_change_present(void); +/** + * @brief Lastest version of status notification features is enabled + **/ +int is_status_notif_version2_supported(int domain); +/** + * @brief Checks if user space DMA allocation is supported + **/ +int is_userspace_allocation_supported(void); +/** + * @brief API to check if DSP process supports the configuration buffer (procbuf) + **/ +int is_proc_sharedbuf_supported_dsp(int domain); + +#endif /*__FASTRPC_CAP_H__*/ diff --git a/inc/fastrpc_common.h b/inc/fastrpc_common.h new file mode 100644 index 0000000..d9c323f --- /dev/null +++ b/inc/fastrpc_common.h @@ -0,0 +1,193 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef FASTRPC_COMMON_H +#define FASTRPC_COMMON_H + +#include +#include +#include +#include + +/* Header file used by all other modules + * will contain the most critical defines + * and APIs. ****** SHOULD NOT ****** be used for + * hlist/any domain specific fastrpc_apps_user.c + * symbols here. + */ + + +/* Number of subsystem supported by fastRPC*/ +#ifndef NUM_DOMAINS +#define NUM_DOMAINS 4 +#endif /*NUM_DOMAINS*/ + +/* Number of sessions allowed per process */ +#ifndef NUM_SESSIONS +#define NUM_SESSIONS 4 +#define DOMAIN_ID_MASK 3 +#endif /*NUM_SESSIONS*/ + +/* Default domain id, in case of non domains*/ +#ifndef DEFAULT_DOMAIN_ID +#define DEFAULT_DOMAIN_ID 3 +#endif /*DEFAULT_DOMAIN_ID*/ + +/* Macros for invalids/defaults*/ +#define INVALID_DOMAIN_ID -1 +#define INVALID_HANDLE (remote_handle64)(-1) +#define INVALID_KEY (pthread_key_t)(-1) +#define INVALID_DEVICE (-1) + +// Number of domains extended to include sessions +// Domain ID extended (0 - 3): Domain id (0 - 3), session id 0 +// Domain ID extended (4 - 7): Domain id (0 - 3), session id 1 +#define NUM_DOMAINS_EXTEND (NUM_DOMAINS * NUM_SESSIONS) + +// Domain name types +#define DOMAIN_NAME_IN_URI 1 // Domain name with standard module URI +#define DOMAIN_NAME_STAND_ALONE 2 // Stand-alone domain name + +#define PROFILE(time_taken, ff) \ +{ \ + struct timeval tv1, tv2; \ + if(is_systrace_enabled()){ \ + gettimeofday(&tv1, 0); \ + ff; \ + gettimeofday(&tv2, 0); \ + *time_taken = (tv2.tv_sec - tv1.tv_sec) * 1000000ULL + (tv2.tv_usec - tv1.tv_usec); \ + } else { \ + ff; \ + } \ +} + +#define PROFILE_ALWAYS(time_taken, ff) \ +{ \ + struct timeval tv1, tv2; \ + uint64_t temp1, temp2, temp3; \ + gettimeofday(&tv1, 0); \ + ff; \ + gettimeofday(&tv2, 0); \ + __builtin_sub_overflow(tv2.tv_sec, tv1.tv_sec, &temp1); \ + __builtin_sub_overflow(tv2.tv_usec, tv1.tv_usec, &temp2); \ + __builtin_mul_overflow(temp1, 1000000ULL, &temp3); \ + __builtin_add_overflow(temp2, temp3, time_taken); \ +} + +/* Macros to check if the remote call is from static module */ +#define FASTRPC_STATIC_HANDLE_LISTENER (3) +#define FASTRPC_MAX_STATIC_HANDLE (10) +#define REVERSE_RPC_SCALAR 0x04020200 // corresponding to next2() method +#define IS_STATIC_HANDLE(handle) ((handle) >= 0 && (handle) <= FASTRPC_MAX_STATIC_HANDLE) +#define IS_REVERSE_RPC_CALL(handle, sc) ((handle == FASTRPC_STATIC_HANDLE_LISTENER) && (sc == REVERSE_RPC_SCALAR)) + +//number of times to retry write operation +#define RETRY_WRITE (3) + +// Macro to increment a reference count for the active domain +#define FASTRPC_GET_REF(domain) VERIFY(AEE_SUCCESS == (nErr = fastrpc_session_get(domain))); \ + ref = 1; +// Macro to decrement a reference count after the remote call is complete +#define FASTRPC_PUT_REF(domain) if(ref == 1) { \ + fastrpc_session_put(domain); \ + ref = 0; \ + } + +/* + * Enum defined for fastrpc User Properties + * @fastrpc_properties: Object of enum + * Enum values corresponds to array indices + * + */ + typedef enum { + FASTRPC_PROCESS_ATTRS = 0, //to spawn a User process as Critical + FASTRPC_DEBUG_TRACE = 1, // to enable logs on remote invocation + FASTRPC_DEBUG_TESTSIG = 2, // to get process test signature + FASTRPC_PERF_KERNEL = 3, //to enable rpc perf on fastrpc kernel + FASTRPC_PERF_ADSP = 4, //to enable rpc perf on DSP + FASTRPC_PERF_FREQ = 5, //to set performance frequency + FASTRPC_ENABLE_SYSTRACE = 6, //to enable tracing using Systrace + FASTRPC_DEBUG_PDDUMP = 7, // to enable pd dump debug data collection on rooted device for signed/unsigned pd + FASTRPC_PROCESS_ATTRS_PERSISTENT = 8, // to set proc attr as persistent + FASTRPC_BUILD_TYPE = 9 // Fetch build type of firmware image. It gives the details if its debug or prod build + }fastrpc_properties; + +/** + * @enum fastrpc_internal_attributes + * @brief Internal attributes in addition to remote_dsp_attributes. + * To be used for internal development purposes, cients are + * not allowed to request these. + */ +enum fastrpc_internal_attributes { + PERF_V2_DSP_SUPPORT = 128, /**< Perf logging V2 DSP support */ + MAP_DMA_HANDLE_REVERSERPC = 129, /**< Map DMA handle in reverse RPC call */ + DSPSIGNAL_DSP_SUPPORT = 130, /**< New "dspsignal" signaling supported on DSP */ + PROC_SHARED_BUFFER_SUPPORT = 131, /**< sharedbuf capability support */ + PERF_V2_DRIVER_SUPPORT = 256, /**< Perf logging V2 kernel support */ + DRIVER_ERROR_CODE_CHANGE = 257, /**< Fastrpc Driver error code change */ + USERSPACE_ALLOCATION_SUPPORT = 258, /**< Userspace memory allocation support */ + DSPSIGNAL_DRIVER_SUPPORT = 259, /**< dspsignal signaling supported in CPU driver */ + FASTRPC_MAX_ATTRIBUTES = DSPSIGNAL_DRIVER_SUPPORT + 1, /**< Max DSP/Kernel attributes supported */ +}; + +/** + * @brief API to initialize the global data strcutures in fastRPC library + */ +int fastrpc_init_once(void); +/** + * @brief API to get the recently used domain from a thread context + * Uses pthread_key to associate a domain to the recently used domain + */ +int get_current_domain(void); +/** + * @brief returns the file descriptor of the fastrpc device node + */ +int fastrpc_session_open(int domain, int *dev); +/** + * @brief closes the remote session/file descriptor of the fastrpc device node + */ +int fastrpc_session_close(int dev); +/** + * @brief increments the reference count of the domain + * used to identify whether there are any active remote calls for a specific domain + */ +int fastrpc_session_get(int domain); +/** + * @brief decrements the reference count of the domain. + * used to identify whether there are any active remote calls for a specific domain + */ +int fastrpc_session_put(int domain); +/** + * @brief returns the device node opened for specific domain + */ +int fastrpc_session_dev(int domain, int *dev); + +/* + * API to get User property values where value type corresponds to integer + * @UserPropertyKey: [in] Value(enum type) that corresponds to array index of User property string + * @defValue: [in] default value returned when user property is not set + * On user property set, returns user value. Else, returns default value + * + */ +int fastrpc_get_property_int(fastrpc_properties UserPropertyKey, int defValue); + +/* + * API to get User property values where value type corresponds to string + * @UserPropertyKey: [in] Value(enum type) that corresponds to array index of User property string + * @value: [out] Pointer to the User set string + * @defValue: [in] default value returned when user property is not set + * returns the length of the value which will never be + * greater than PROPERTY_VALUE_MAX - 1 and will always be zero terminated. + * + */ +int fastrpc_get_property_string(fastrpc_properties UserPropertyKey, char * value, char * defValue); + +/* + * This function is used to check the current process is exiting or not. + * + * @retval: TRUE if process is exiting. + * FALSE if process is not exiting. + */ +bool is_process_exiting(int domain); + +#endif //FASTRPC_COMMON_H diff --git a/inc/fastrpc_config.h b/inc/fastrpc_config.h new file mode 100644 index 0000000..21272e9 --- /dev/null +++ b/inc/fastrpc_config.h @@ -0,0 +1,213 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef __FASTRPC_CONFIG_H__ +#define __FASTRPC_CONFIG_H__ + +#include "AEEstd.h" + +/* Maximum number of panic error codes allowed in debug config. */ +#define MAX_PANIC_ERR_CODES 32 + +/** + * @enum err_codes + * @brief stores all error codes for which panic will be raised + * , when the error happens on DSP/APSS + **/ +struct err_codes { + int err_code[MAX_PANIC_ERR_CODES]; /* Panic err codes read from debug config. */ + int num_err_codes; /* Number of panic error codes read from debug config. */ +}; + +/** + * @file fastrpc_config + * + * fastRPC library has few configurable options that can used + * in debugging. library looks for a ".debugconfig" file in the + * DSP search path during the process start. + * Any and all debug configurations mentioned in this file is + * enabled by fastRPC. + * Note: all these debug features are enabled only on debug devices + * and not available on production devices. + * + * Debug features available are + * 1) Crash on Error codes + * 2) PD dump enablement + * 3) Remote call timeout + * 4) Kernel Perf counters + * 5) DSP Perf counters + * 6) DSP Runtime FARF + * 7) APSS Runtime FARF + * 8) DSP Memory Logging + * 9) QTF Tracing + * 10) Heap caller level + * 11) UAF checks in heap + * 12) Debug level logs + * 13) QXDM Log packet + * 14) Leak detection in Heap + * 15) Call stack + * + **/ + + +/** + * fastrpc_config_get_errcodes + * + * @brief returns the list of error codes from .debugconfig + * that should induce a crash. Useful in debugging issues where + * there are errors. + * + * @param void + * @return struct error_codes - list of error codes + **/ +struct err_codes *fastrpc_config_get_errcodes(void); +/** + * fastrpc_config_get_rpctimeout + * + * @brief returns the timeout value configured in .debugconfig file. + * used by the remote APIs to timeout when the DSP is taking more time + * than expected. + * + * @param void + * @return integer - timeout value + **/ +int fastrpc_config_get_rpctimeout(void); +/** + * fastrpc_config_is_pddump_enabled + * + * @brief returns whether PD dump is enabled or not. PD dumps are + * similar to coredumps in application space. dumps are useful in + * debugging issues, by loading them on gdb/lldb. + * + * @param void + * @return boolean - true/false + **/ +boolean fastrpc_config_is_pddump_enabled(void); +/** + * fastrpc_config_is_perfkernel_enabled + * + * @brief returns whether performance counters in kernel should be + * enabled or not + * + * @param void + * @return boolean - true/false + **/ +boolean fastrpc_config_is_perfkernel_enabled(void); +/** + * fastrpc_config_is_perfdsp_enabled + * + * @brief returns whether performance counters in DSP should be + * enabled or not + * + * @param void + * @return boolean - true/false + **/ +boolean fastrpc_config_is_perfdsp_enabled(void); +/** + * fastrpc_config_get_runtime_farf_file + * + * @brief returns the name of the FARF file, where the runtime + * FARF levels are specified. These log levels are enabled + * in the user space/DSP + * + * @param void + * @return string - name of the file + **/ +char *fastrpc_config_get_runtime_farf_file(void); +/** + * fastrpc_config_get_userspace_runtime_farf_file + * + * @brief returns the name of the file where runtime FARF logs are + * stored. + * + * @param void + * @return string - name of the file + **/ +char *fastrpc_config_get_userspace_runtime_farf_file(void); +/** + * fastrpc_config_is_log_iregion_enabled + * + * @brief returns whether the debug logs in memory management module + * (in DSP) should be enabled or not + * + * @param void + * @return boolean - true/false + **/ +boolean fastrpc_config_is_log_iregion_enabled(void); +/** + * fastrpc_config_is_debug_logging_enabled + * + * @brief returns whether DSP power (HAP_power) specific logs are enabled or not + * + * + * @param void + * @return boolean - true/false + **/ +boolean fastrpc_config_is_debug_logging_enabled(void); +/** + * fastrpc_config_is_sysmon_reserved_bit_enabled + * + * @brief returns whether debug logging for sysmon is enabled or not + * + * @param void + * @return boolean - true/false + **/ +boolean fastrpc_config_is_sysmon_reserved_bit_enabled(void); +/** + * fastrpc_config_is_qtf_tracing_enabled + * + * @brief returns whether qtf tracing is enabled or not + * + * @param void + * @return boolean - true/false + **/ +boolean fastrpc_config_is_qtf_tracing_enabled(void); +// Function to get heap caller level. +int fastrpc_config_get_caller_level(void); +/** + * fastrpc_config_is_uaf_enabled + * + * @brief returns whether use after free check should be enabled + * in user heap (on DSP PD) or not + * + * @param void + * @return boolean - true/false + **/ +boolean fastrpc_config_is_uaf_enabled(void); +/** + * fastrpc_config_is_logpacket_enabled + * + * @brief returns whether QXDM log packet should be enabled + * QXDM log packets provide additional information on the fastRPC + * internal data structures at runtime and they are low latency + * logs. + * + * @param void + * @return boolean - true/false + **/ +boolean fastrpc_config_is_logpacket_enabled(void); +/** + * fastrpc_config_get_leak_detect + * + * @brief returns whether the leak detecting feature in user heap + * (on DSP PD) is enabled or not + * + * @param void + * @return integer - 1/0 + **/ +int fastrpc_config_get_leak_detect(void); +// Function to return the call stack num +int fastrpc_config_get_caller_stack_num(void); + +/** + * fastrpc_config_init + * + * @brief Initialization routine to initialize the datastructures and global + * variables in this module. + * + * @param void + * @return integer - 0 for success, non-zero for error cases. + **/ +int fastrpc_config_init(); + +#endif /*__FASTRPC_CONFIG_H__*/ diff --git a/inc/fastrpc_internal.h b/inc/fastrpc_internal.h new file mode 100644 index 0000000..fc8d745 --- /dev/null +++ b/inc/fastrpc_internal.h @@ -0,0 +1,562 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef FASTRPC_INTERNAL_H +#define FASTRPC_INTERNAL_H + +#include +#include +#include + +#include "HAP_farf.h" +#include "AEEStdErr.h" +#include "remote64.h" +#include "verify.h" +#include "AEEstd.h" +#include "AEEQList.h" +#include "AEEStdErr.h" +#include "fastrpc_latency.h" +#include "fastrpc_common.h" + +// Aligns the memory +#define ALIGN_B(p, a) (((p) + ((a) - 1)) & ~((a) - 1)) + +#define FASTRPC_SESSION_ID1 (4) + +// URI string to choose Session 1. +#define FASTRPC_SESSION1_URI "&_session=1" + +// URI string to choose a particular session. Session ID needs to be appended to Session uri. +#define FASTRPC_SESSION_URI "&_session=" + +// URI string of Domain. Domain name needs to be appended to domain URI. +#define FASTRPC_DOMAIN_URI "&_dom=" + +/* Additional URI length required to add domain and session information to URI + * Two extra characters for session ID > 9 and domain name more than 4 characters. + */ +#define FASTRPC_URI_BUF_LEN (strlen(CDSP_DOMAIN) + strlen(FASTRPC_SESSION1_URI) + 2) + +/** + * Maximum values of enums exposed in remote + * header file to validate the user-input. + * 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 STATUS_NOTIFICATION_SUPPORT + 1 + +/* Max value of remote_mem_map_flags, used to validate the input flag */ +#define REMOTE_MAP_MAX_FLAG REMOTE_MAP_MEM_STATIC + 1 + +/* Max value of fastrpc_map_flags, used to validate range of supported flags */ +#define FASTRPC_MAP_MAX FASTRPC_MAP_FD_NOMAP + 1 + +#if !(defined __qdsp6__) && !(defined __hexagon__) +static __inline uint32 Q6_R_cl0_R(uint32 num) { + int ii; + for(ii = 31; ii >= 0; --ii) { + if(num & (1 << ii)) { + return 31 - ii; + } + } + return 0; +} +#else +#include "hexagon_protos.h" +#include +#endif + +#define FASTRPC_INFO_SMMU (1 << 0) + +#define GET_SESSION_ID_FROM_DOMAIN_ID(domain_id) ((int)(domain_id / NUM_DOMAINS)) + +/* From actual domain ID (0-3) and session ID, get effective domain ID */ +#define GET_EFFECTIVE_DOMAIN_ID(domain, session) (domain + (NUM_DOMAINS * session)) + +/** + * @brief PD initialization types used to create different kinds of PD + * Attach is used for attaching the curent APPS process to the existing + * PD (already up and running) on DSP. + * Create allows the DSP to create a new user PD + * Create static helps to attach to the audio PD on DSP + * attach sensors is used to attach to the sensors PD running on DSP +**/ +#define FASTRPC_INIT_ATTACH 0 +#define FASTRPC_INIT_CREATE 1 +#define FASTRPC_INIT_CREATE_STATIC 2 +#define FASTRPC_INIT_ATTACH_SENSORS 3 + +/** + * @brief Process types on remote subsystem + * Always add new PD types at the end, before MAX_PD_TYPE, + * for maintaining back ward compatibility + **/ +#define DEFAULT_UNUSED 0 /* pd type not configured for context banks */ +#define ROOT_PD 1 /* Root PD */ +#define AUDIO_STATICPD 2 /* ADSP Audio Static PD */ +#define SENSORS_STATICPD 3 /* ADSP Sensors Static PD */ +#define SECURE_STATICPD 4 /* CDSP Secure Static PD */ +#define OIS_STATICPD 5 /* ADSP OIS Static PD */ +#define CPZ_USERPD 6 /* CDSP CPZ USER PD */ +#define USERPD 7 /* DSP User Dynamic PD */ +#define GUEST_OS_SHARED 8 /* Legacy Guest OS Shared */ +#define MAX_PD_TYPE 9 /* Max PD type */ + + +// Attribute to specify the process is a debug process +#define FASTRPC_ATTR_DEBUG_PROCESS (1) + +// Max length of the DSP PD name +#define MAX_DSPPD_NAMELEN 30 + +// Maximum attributes that a DSP PD can understand +#ifndef FASTRPC_MAX_DSP_ATTRIBUTES_FALLBACK +#define FASTRPC_MAX_DSP_ATTRIBUTES_FALLBACK 1 +#endif + +/** + * @brief DSP thread specific information are stored here + * priority, stack size are client configurable. + * Internal fastRPC data structures + **/ +struct fastrpc_thread_params { + uint32_t thread_priority; + uint32_t stack_size; + int reqID; + int update_requested; + sem_t r_sem; +}; + +/** + * @brief Stores all DSP capabilities, cached once and used + * in multiple places. + * Internal fastRPC data structures + **/ +struct fastrpc_dsp_capabilities { + uint32_t is_cached; //! Flag if dsp attributes are cached + uint32_t dsp_attributes[FASTRPC_MAX_DSP_ATTRIBUTES_FALLBACK]; +}; + +/** + * @brief structure to hold fd and size of buffer shared with DSP, + * which contains inital debug parameters that needs to be passed + * during process initialization. + **/ +struct fastrpc_proc_sharedbuf_info { + int buf_fd; + int buf_size; +}; + +enum { + FASTRPC_DOMAIN_STATE_CLEAN = 0, + FASTRPC_DOMAIN_STATE_INIT = 1, + FASTRPC_DOMAIN_STATE_DEINIT = 2, +}; + +/** + * @brief FastRPC ioctl structure to set session related info + **/ +struct fastrpc_proc_sess_info { + uint32_t domain_id; /* Set the remote subsystem, Domain ID of the session */ + uint32_t session_id; /* Unused, Set the Session ID on remote subsystem */ + uint32_t pd_type; /* Set the process type on remote subsystem */ + uint32_t sharedcb; /* Unused, Session can share context bank with other sessions */ +}; + +/** + * @enum defined for updating non-domain and reverse handle list + **/ + typedef enum { + NON_DOMAIN_LIST_PREPEND = 0, + NON_DOMAIN_LIST_DEQUEUE = 1, + REVERSE_HANDLE_LIST_PREPEND = 2, + REVERSE_HANDLE_LIST_DEQUEUE = 3, + DOMAIN_LIST_PREPEND = 4, + DOMAIN_LIST_DEQUEUE = 5, + } handle_list_update_id; + +/** + * @enum for remote handle control requests + **/ +enum fastrpc_control_type { + FASTRPC_CONTROL_LATENCY = 1, + FASTRPC_CONTROL_SMMU = 2, + FASTRPC_CONTROL_KALLOC = 3, + FASTRPC_CONTROL_WAKELOCK = 4, + FASTRPC_CONTROL_PM = 5, + FASTRPC_CONTROL_RPC_POLL = 7, + FASTRPC_CONTROL_ASYNC_WAKE = 8, + FASTRPC_CONTROL_NOTIF_WAKE = 9, +}; + +/** + * @brief internal data strcutures used in remote handle control + * fastrpc_ctrl_latency - + * fastrpc_ctrl_smmu - Allows the PD to use the shared SMMU context banks + * fastrpc_ctrl_kalloc - feature to allow the kernel allocate memory + * for signed PD memory needs. + * fastrpc_ctrl_wakelock - enabled wake lock in user space and kernel + * improves the response latency time of remote calls + * fastrpc_ctrl_pm - timeout (in ms) for which the system should stay awake + * + **/ +struct fastrpc_ctrl_latency { + uint32_t enable; + uint32_t latency; +}; + +struct fastrpc_ctrl_smmu { + uint32_t sharedcb; +}; + +struct fastrpc_ctrl_kalloc { + uint32_t kalloc_support; +}; + +struct fastrpc_ctrl_wakelock { + uint32_t enable; +}; + +struct fastrpc_ctrl_pm { + uint32_t timeout; +}; + +/** + * @enum different types of remote invoke supported in fastRPC + * internal datastructures. + * INVOKE - only parameters allowed + * INVOKE_ATTRS - INVOKE + additional process attributes + * INVOKE_FD - INVOKE_ATTRS + file descriptor for each parameters + * INVOKE_CRC - INVOKE_FD + CRC checks for each params + * INVOKE_PERF - INVOKE_CRC + Performance counters from kernel and DSP + **/ +enum fastrpc_invoke_type { + INVOKE, + INVOKE_ATTRS, + INVOKE_FD, + INVOKE_CRC, + INVOKE_PERF, +}; + +/** + * @enum different types of mmap supported by fastRPC. internal datastructures. + * MMAP - maps a 32bit address on DSP + * MMAP_64 - 64bit address support + * MEM_MAP - file descriptor support + * MUNMAP - unmaps a 32bit address from DSP + * MUNMAP_64 - 64bit address support + * MEM_UNMAP - file descriptor support + * MUNMAP_FD - Unmaps a file descriptor from DSP + **/ +enum fastrpc_map_type { + MMAP, + MUNMAP, + MMAP_64, + MUNMAP_64, + MEM_MAP, + MEM_UNMAP, + MUNMAP_FD, +}; + +/** + * @brief memory mapping and unmapping data structures used in + * mmap/munmap ioctls. internal datastructures. + * fastrpc_mem_map - used for storing memory map information + * fastrpc_mem_unmap - used while unmapping the memory from the + * local data structures. + **/ +struct fastrpc_mem_map { + int fd; /* ion fd */ + int offset; /* buffer offset */ + uint32_t flags; /* flags defined in enum fastrpc_map_flags */ + int attrs; /* buffer attributes used for SMMU mapping */ + uintptr_t vaddrin; /* buffer virtual address */ + size_t length; /* buffer length */ + uint64_t vaddrout; /* [out] remote virtual address */ +}; + +struct fastrpc_mem_unmap { + int fd; /* ion fd */ + uint64_t vaddr; /* remote process (dsp) virtual address */ + size_t length; /* buffer size */ +}; + +struct fastrpc_map { + int version; + struct fastrpc_mem_map m; +}; + +/** + * @brief handle_list is the global structure used to store all information + * required for a specific domain on DSP. So, usually it is used as an array + * of domains supported by this process. for eg: if a process loading this + * library is offloading to ADSP and CDSP, the array of eight handle_list is + * created and index 0 and 3 are used to store all information about the PD. + * Contains: + * nql - list of modules loaded (stubs) in this process. + * ql - list of modules loaded (stubs) using domains in this process. + * rql - list of modules loaded (skels) in this process. + * dsppd - Type of the process that should be created on DSP (specific domain) + * dsppdname - Name of the process + * sessionname - Name of the session, if more than one process created on same DSP + * domainsupport - Legacy field, should be 1 always. + * kmem_support - Stores whether kernel can allocate memory for signed process + * dev - file descriptor returned by open() + * pdmem - Memory to store DSP process configurations + * cphandle, msghandle, lsitenerhandle, remotectlhandle, adspperfhandle - static + * handles created for the stub files loaded by fastRPC. + * procattrs - Attributes for the DSP Process. Stores information like debug process, + * trace enablement, etc. + * qos, th_params, cap_info - stores information needed for DSP process. these are + * used by remote calls whenever needed. + **/ +struct handle_list { + QList ql; //Forward domains handles + QList nql; //Forward non-domains handles + QList rql; //Reverse handles + pthread_mutex_t lmut; + pthread_mutex_t mut; + pthread_mutex_t init; + uint32_t constCount; + uint32_t domainsCount; + uint32_t nondomainsCount; + uint32_t reverseCount; + uint32_t state; + uint32_t ref; + int dsppd; + char dsppdname[MAX_DSPPD_NAMELEN]; + char sessionname[MAX_DSPPD_NAMELEN]; + int domainsupport; + int kmem_support; + int dev; + int setmode; + uint32_t mode; + uint32_t info; + void* pdmem; + remote_handle64 cphandle; + remote_handle64 msghandle; + remote_handle64 listenerhandle; + remote_handle64 remotectlhandle; + remote_handle64 adspperfhandle; + int procattrs; + struct fastrpc_latency qos; + struct fastrpc_thread_params th_params; + int unsigned_module; + bool pd_dump; + int first_revrpc_done; + 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 open_handle_count; // Number of open handles + bool is_session_reserved; /** Set if session is reserved or used */ + /* buffer shared with DSP containing initial config parameters */ + void *proc_sharedbuf; + /* current process shared buffer address to pack process params */ + uint32_t *proc_sharedbuf_cur_addr; +}; + +/** + * @brief API to get the DSP_SEARCH_PATH stored locally as static. + * @get_path : get_path will be updated with the path stored in DSP_SEARCH_PATH locally. + **/ +void get_default_dsp_search_path(char* path); + +/** + * @brief API to map memory to the remote domain + * @ fd: fd associated with this memory + * @ flags: flags to be used for the mapping + * @ vaddrin: input address + * @ size: size of buffer + * @ vaddrout: output address + * returns 0 on success + * + **/ +int remote_mmap64_internal(int fd, uint32_t flags, uint64_t vaddrin, int64_t size, uint64_t* vaddrout); + +/** + * @brief remote_get_info API to get DSP/Kernel capibility + * + * @param[in] domain: DSP domain + * @param[in] attributeID: One of the DSP/kernel attributes from enum fastrpc_internal_attributes. + * @param[out] capability: Result of the DSP/kernel capability. + * @return Integer value. Zero for success and non-zero for failure. + **/ +int fastrpc_get_cap(uint32_t domain, uint32_t attributeID, uint32_t *capability); + +/** + * @brief Check whether error is because of fastrpc. + * Either kernel driver or dsp. + * @err: error code to be checked. + * returns 0 on success i.e. rpc error. + * + **/ +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 + */ +int fastrpc_exit_async_thread(int domain); + +/** + * @brief Make IOCTL call to exit notif thread + */ +int fastrpc_exit_notif_thread(int domain); + +// Kernel errno start +#define MIN_KERNEL_ERRNO 0 +// Kernel errno end +#define MAX_KERNEL_ERRNO 135 + +/** + * @brief Convert kernel to user error. + * @nErr: Error from ioctl + * @err_no: errno from kernel + * returns user error + **/ + +static __inline int convert_kernel_to_user_error(int nErr, int err_no) { + if (!(nErr == AEE_EUNKNOWN && err_no && (err_no >= MIN_KERNEL_ERRNO && err_no <= MAX_KERNEL_ERRNO))) { + return nErr; + } + + switch (err_no) { + case EIO: /* EIO 5 I/O error */ + case ETOOMANYREFS: /* ETOOMANYREFS 109 Too many references: cannot splice */ + case EADDRNOTAVAIL: /* EADDRNOTAVAIL 99 Cannot assign requested address */ + case ENOTTY: /* ENOTTY 25 Not a typewriter */ + case EBADRQC: /* EBADRQC 56 Invalid request code */ + nErr = AEE_ERPC; + break; + case EFAULT: /* EFAULT 14 Bad address */ + case ECHRNG: /* ECHRNG 44 Channel number out of range */ + case EBADFD: /* EBADFD 77 File descriptor in bad state */ + case EINVAL: /* EINVAL 22 Invalid argument */ + case EBADF: /* EBADF 9 Bad file number */ + case EBADE: /* EBADE 52 Invalid exchange */ + case EBADR: /* EBADR 53 Invalid request descriptor */ + case EOVERFLOW: /* EOVERFLOW 75 Value too large for defined data type */ + case EHOSTDOWN: /* EHOSTDOWN 112 Host is down */ + case EEXIST: /* EEXIST 17 File exists */ + case EBADMSG: /* EBADMSG 74 Not a data message */ + nErr = AEE_EBADPARM; + break; + case ENXIO: /* ENXIO 6 No such device or address */ + case ENODEV: /* ENODEV 19 No such device*/ + case ENOKEY: /* ENOKEY 126 Required key not available */ + nErr = AEE_ENOSUCHDEVICE; + break; + case ENOBUFS: /* ENOBUFS 105 No buffer space available */ + case ENOMEM: /* ENOMEM 12 Out of memory */ + nErr = AEE_ENOMEMORY; + break; + case ENOSR: /* ENOSR 63 Out of streams resources */ + case EDQUOT: /* EDQUOT 122 Quota exceeded */ + case ETIMEDOUT: /* ETIMEDOUT 110 Connection timed out */ + case EUSERS: /* EUSERS 87 Too many users */ + case ESHUTDOWN: /* ESHUTDOWN 108 Cannot send after transport endpoint shutdown */ + nErr = AEE_EEXPIRED; + break; + case ENOTCONN: /* ENOTCONN 107 Transport endpoint is not connected */ + case ECONNREFUSED: /* ECONNREFUSED 111 Connection refused */ + nErr = AEE_ECONNREFUSED; + break; + case ECONNRESET: /* ECONNRESET 104 Connection reset by peer */ + case EPIPE: /* EPIPE 32 Broken pipe */ + nErr = AEE_ECONNRESET; + break; + case EPROTONOSUPPORT: /* EPROTONOSUPPORT 93 Protocol not supported */ + nErr = AEE_EUNSUPPORTED; + break; + case EFBIG: /* EFBIG 27 File too large */ + nErr = AEE_EFILE; + break; + case EACCES: /* EACCES 13 Permission denied */ + case EPERM: /* EPERM 1 Operation not permitted */ + nErr = AEE_EBADPERMS; + break; + default: + nErr = AEE_ERPC; + break; + } + + return nErr; +} + +// Warning message to use domains +#define PRINT_WARN_USE_DOMAINS() VERIFY_WPRINTF("Warning: %s: Non-domain usage of FastRPC will be deprecated, use domains to offload to DSP using FastRPC", __func__) + +/** + * @brief utility APIs used in fastRPC library to get name, handle from domain + **/ +int get_domain_from_name(const char *uri, uint32_t type); +int get_domain_from_handle(remote_handle64 local, int *domain); +int free_handle(remote_handle64 local); + +/** + * @brief APIs to return the newly allocated handles for all the static modules loaded + **/ +remote_handle64 get_adsp_current_process1_handle(int domain); +remote_handle64 get_adspmsgd_adsp1_handle(int domain); +remote_handle64 get_adsp_listener1_handle(int domain); +remote_handle64 get_remotectl1_handle(int domain); +remote_handle64 get_adsp_perf1_handle(int domain); + +/** + * @brief API to update non-domain and reverse handles list + * @handle: handle to prepend or dequeue + * @req: request id from enum handle_list_update_id + * @domain: domain id + * Prepend and dequeue operations can be performed on reverse and non-domain handle list + * @returns: 0 on success, valid non-zero error code on failure + * + **/ +int fastrpc_update_module_list(uint32_t req, int domain, remote_handle64 handle, remote_handle64 *local); + +/** + * @brief functions to wrap ioctl syscalls for downstream and upstream kernel + **/ +int ioctl_init(int dev, uint32_t flags, int attr, byte* 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_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); +int ioctl_getperf(int dev, int keys, void *data, int *datalen); +int ioctl_getinfo(int dev, uint32_t *info); +int ioctl_getdspinfo(int dev, int domain, uint32_t attr_id, uint32_t *cap); +int ioctl_setmode(int dev, int mode); +int ioctl_control(int dev, int ioctltype, void* ctrl); +int ioctl_signal_create(int dev, uint32_t signal, uint32_t flags); +int ioctl_signal_destroy(int dev, uint32_t signal); +int ioctl_signal_signal(int dev, uint32_t signal); +int ioctl_signal_wait(int dev, uint32_t signal, uint32_t timeout_usec); +int ioctl_signal_cancel_wait(int dev, uint32_t signal); +int ioctl_sharedbuf(int dev, struct fastrpc_proc_sharedbuf_info *sharedbuf_info); +int ioctl_session_info(int dev, struct fastrpc_proc_sess_info *sess_info); +int ioctl_optimization(int dev, uint32_t max_concurrency); +const char* get_secure_domain_name(int domain_id); +int is_async_fastrpc_supported(void); + +#include "fastrpc_ioctl.h" + +#endif // FASTRPC_INTERNAL_H diff --git a/inc/fastrpc_ioctl.h b/inc/fastrpc_ioctl.h new file mode 100644 index 0000000..533a867 --- /dev/null +++ b/inc/fastrpc_ioctl.h @@ -0,0 +1,182 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef FASTRPC_INTERNAL_UPSTREAM_H +#define FASTRPC_INTERNAL_UPSTREAM_H + +#include +#include + +/* File only compiled when support to upstream kernel is required*/ + + +/** + * FastRPC IOCTL functions + **/ +#define FASTRPC_IOCTL_ALLOC_DMA_BUFF _IOWR('R', 1, struct fastrpc_ioctl_alloc_dma_buf) +#define FASTRPC_IOCTL_FREE_DMA_BUFF _IOWR('R', 2, __u32) +#define FASTRPC_IOCTL_INVOKE _IOWR('R', 3, struct fastrpc_ioctl_invoke) +#define FASTRPC_IOCTL_INIT_ATTACH _IO('R', 4) +#define FASTRPC_IOCTL_INIT_CREATE _IOWR('R', 5, struct fastrpc_ioctl_init_create) +#define FASTRPC_IOCTL_MMAP _IOWR('R', 6, struct fastrpc_ioctl_req_mmap) +#define FASTRPC_IOCTL_MUNMAP _IOWR('R', 7, struct fastrpc_ioctl_req_munmap) +#define FASTRPC_IOCTL_INIT_ATTACH_SNS _IO('R', 8) +#define FASTRPC_IOCTL_INIT_CREATE_STATIC _IOWR('R', 9, struct fastrpc_ioctl_init_create_static) +#define FASTRPC_IOCTL_MEM_MAP _IOWR('R', 10, struct fastrpc_ioctl_mem_map) +#define FASTRPC_IOCTL_MEM_UNMAP _IOWR('R', 11, struct fastrpc_ioctl_mem_unmap) +#define FASTRPC_IOCTL_GET_DSP_INFO _IOWR('R', 13, struct fastrpc_ioctl_capability) + +#define ADSPRPC_DEVICE "/dev/fastrpc-adsp" +#define SDSPRPC_DEVICE "/dev/fastrpc-sdsp" +#define MDSPRPC_DEVICE "/dev/fastrpc-mdsp" +#define CDSPRPC_DEVICE "/dev/fastrpc-cdsp" +#define ADSPRPC_SECURE_DEVICE "/dev/fastrpc-adsp-secure" +#define SDSPRPC_SECURE_DEVICE "/dev/fastrpc-sdsp-secure" +#define MDSPRPC_SECURE_DEVICE "/dev/fastrpc-mdsp-secure" +#define CDSPRPC_SECURE_DEVICE "/dev/fastrpc-cdsp-secure" + +#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) struct fastrpc_invoke_args* args = NULL; \ + int *pfds = NULL; \ + unsigned *pattrs = NULL; \ + args = (struct fastrpc_invoke_args*) calloc(sizeof(*args), total); \ + if(args==NULL) { \ + goto bail; \ + } + +#define DESTROY_REMOTE_ARGS() if(args) { \ + free(args); \ + } + +#define set_args(i, pra, len, filedesc, attrs) args[i].ptr = (uint64_t)pra; \ + args[i].length = len; \ + args[i].fd = filedesc; \ + args[i].attr = attrs; + +#define set_args_ptr(i, pra) args[i].ptr = (uint64_t)pra +#define set_args_len(i, len) args[i].length = len +#define set_args_attr(i, attrs) args[i].attr = attrs +#define set_args_fd(i, filedesc) args[i].fd = filedesc +#define get_args_ptr(i) args[i].ptr +#define get_args_len(i) args[i].length +#define get_args_attr(i) args[i].attr +#define get_args_fd(i) args[i].fd +#define append_args_attr(i, attrs) args[i].attr |= attrs +#define get_args() args +#define is_upstream() 1 + +//Utility macros for reading the ioctl structure +#define NOTIF_GETDOMAIN(response) -1; +#define NOTIF_GETSESSION(response) -1; +#define NOTIF_GETSTATUS(response) -1; + +#define FASTRPC_INVOKE2_STATUS_NOTIF 2 //TODO: Temporary change (Bharath to fix) +#define FASTRPC_INVOKE2_KERNEL_OPTIMIZATIONS 1 //TODO: Temporary change (Bharath to fix) +#ifndef FASTRPC_MAX_DSP_ATTRIBUTES_FALLBACK +#define FASTRPC_MAX_DSP_ATTRIBUTES_FALLBACK 1 +#endif + +struct fastrpc_invoke_args { + __u64 ptr; /* pointer to invoke address*/ + __u64 length; /* size*/ + __s32 fd; /* fd */ + __u32 attr; /* invoke attributes */ +}; + +struct fastrpc_ioctl_invoke { + __u32 handle; + __u32 sc; + __u64 args; +}; + +struct fastrpc_ioctl_alloc_dma_buf { + __s32 fd; /* fd */ + __u32 flags; /* flags to map with */ + __u64 size; /* size */ +}; + +struct fastrpc_ioctl_init_create { + __u32 filelen; /* elf file length */ + __s32 filefd; /* fd for the file */ + __u32 attrs; + __u32 siglen; + __u64 file; /* pointer to elf file */ +}; + +struct fastrpc_ioctl_init_create_static { + __u32 namelen; /* length of pd process name */ + __u32 memlen; + __u64 name; /* pd process name */ +}; + +struct fastrpc_ioctl_req_mmap { + __s32 fd; + __u32 flags; /* flags for dsp to map with */ + __u64 vaddrin; /* optional virtual address */ + __u64 size; /* size */ + __u64 vaddrout; /* dsp virtual address */ +}; + +struct fastrpc_ioctl_mem_map { + __s32 version; + __s32 fd; /* fd */ + __s32 offset; /* buffer offset */ + __u32 flags; /* flags defined in enum fastrpc_map_flags */ + __u64 vaddrin; /* buffer virtual address */ + __u64 length; /* buffer length */ + __u64 vaddrout; /* [out] remote virtual address */ + __s32 attrs; /* buffer attributes used for SMMU mapping */ + __s32 reserved[4]; +}; + +struct fastrpc_ioctl_req_munmap { + __u64 vaddrout; /* address to unmap */ + __u64 size; /* size */ +}; + +struct fastrpc_ioctl_mem_unmap { + __s32 version; + __s32 fd; /* fd */ + __u64 vaddr; /* remote process (dsp) virtual address */ + __u64 length; /* buffer size */ + __s32 reserved[5]; +}; + +struct fastrpc_ioctl_capability { + __u32 domain; /* domain of the PD*/ + __u32 attribute_id; /* attribute id*/ + __u32 capability; /* dsp capability */ + __u32 reserved[4]; +}; + +struct fastrpc_ioctl_control { + __u32 req; + union { + struct fastrpc_ctrl_latency lp; + struct fastrpc_ctrl_smmu smmu; + struct fastrpc_ctrl_kalloc kalloc; + struct fastrpc_ctrl_wakelock wl; + struct fastrpc_ctrl_pm pm; + }; +}; + +#endif // FASTRPC_INTERNAL_H diff --git a/inc/fastrpc_latency.h b/inc/fastrpc_latency.h new file mode 100644 index 0000000..caee084 --- /dev/null +++ b/inc/fastrpc_latency.h @@ -0,0 +1,56 @@ +// 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/inc/fastrpc_log.h b/inc/fastrpc_log.h new file mode 100644 index 0000000..bbd8f3d --- /dev/null +++ b/inc/fastrpc_log.h @@ -0,0 +1,17 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef __FASTRPC_LOG_H__ +#define __FASTRPC_LOG_H__ + +/* + * Internal function to initialize globals & internal data strcutures + * in log module + */ +void fastrpc_log_init(); +/* + * Internal function to deinitialize log module + */ +void fastrpc_log_deinit(); + +#endif /*__FASTRPC_LOG_H__*/ diff --git a/inc/fastrpc_mem.h b/inc/fastrpc_mem.h new file mode 100644 index 0000000..06a9f98 --- /dev/null +++ b/inc/fastrpc_mem.h @@ -0,0 +1,58 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef FASTRPC_MEM_H +#define FASTRPC_MEM_H + +/** + * Function to initialize fastrpc_mem module. Call only once during library initialization. + */ +int fastrpc_mem_init(void); + +/** + * Function to deinitialize fastrpc_mem module. Call only once while closing library. + */ +int fastrpc_mem_deinit(void); + +/** + * fastrpc_mem_open() initializes fastrpc_mem module data of a fastrpc session associated with domain. + * Call once during session open for a domain. + */ +int fastrpc_mem_open(int domain); + +/** + * fastrpc_mem_close() deinitializes fastrpc_mem module data of a fastrpc session associated with domain. + * Call once during session close for a domain. + */ +int fastrpc_mem_close(int domain); + +/* + * internal API to unregister the dma handles already registerd by clients. + * should not be called by clients. Used internally for work around purpose. + */ +void unregister_dma_handle(int fd, uint32_t *len, uint32_t *attr); +/* + * returns a list of FDs registered by the clients. + * used while making a remote call. + */ +int fdlist_fd_from_buf(void* buf, int bufLen, int* nova, void** base, int* attr, int* ofd); + +int remote_mmap64_internal(int fd, uint32_t flags, uint64_t vaddrin, int64_t size, uint64_t* vaddrout); + +/* + * Get information about an existing mapped buffer, optionally incrementing/decrementing its + * reference count. + * + * @param domain The DSP being used + * @param fd Buffer file descriptor in current process + * @param ref 1 to increment reference count, -1 to decrement it, 0 to keep refcount unchanged + * @param va Output: Pointer to buffer virtual address in current process. Set to NULL if the buffer + * doesn't have a valid accesible mapping. + * @param size Output: Buffer size in bytes + * + * @return 0 on success, error code on failure. + * - AEE_ENOSUCHMAP: Unknown FD +*/ +int fastrpc_buffer_ref(int domain, int fd, int ref, void **va, size_t *size); + +#endif //FASTRPC_MEM_H diff --git a/inc/fastrpc_notif.h b/inc/fastrpc_notif.h new file mode 100644 index 0000000..174e109 --- /dev/null +++ b/inc/fastrpc_notif.h @@ -0,0 +1,54 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef FASTRPC_NOTIF_H +#define FASTRPC_NOTIF_H + +#include "remote64.h" +#include "fastrpc_internal.h" + +/* + * Internal function to create fastrpc status notification thread + * @ domain: domain to which notification is initialized + * returns 0 on success + */ +int fastrpc_notif_domain_init(int domain); + +/* + * Internal function to exit fastrpc status notification thread + * @ domain: domain to which notification is de-initialized + * returns 0 on success + */ +void fastrpc_notif_domain_deinit(int domain); + +/* + * Internal function to get notification response from kernel. Waits in kernel until notifications are received from DSP + * @ domain: domain to which notification needs to be received + * returns 0 on success + */ +int get_remote_notif_response(int domain); + +/* + * API to cleanup all the clients registered for notifcation + */ +void fastrpc_cleanup_notif_list(); +/* + * API to register a notification mechanism for a state change in DSP Process. + * state changes can be PD start, PD exit, PD crash. + */ +int fastrpc_notif_register(int domain, struct remote_rpc_notif_register *notif); + +/* + * API to initialize notif module in fastRPC + * interal function to initialize globals and other + * data structures used in notif module + */ +void fastrpc_notif_init(); +/* + * API to de-initialize notif module in fastRPC + * interal function to free-up globals and other + * data structures used in notif module + */ +void fastrpc_notif_deinit(); + +#endif // FASTRPC_NOTIF_H diff --git a/inc/fastrpc_perf.h b/inc/fastrpc_perf.h new file mode 100644 index 0000000..f19379d --- /dev/null +++ b/inc/fastrpc_perf.h @@ -0,0 +1,50 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef FASTRPC_PERF_H +#define FASTRPC_PERF_H + +#include + +#include "remote.h" + +/** + * Kernel perf keys + * C: PERF_COUNT + * F: PERF_FLUSH + * M: PERF_MAP + * CP: PERF_COPY + * L: PERF_LINK + * G: PERF_GETARGS + * P: PERF_PUTARGS + * INV: PERF_INVARGS + * INVOKE: PERF_INVOKE +*/ + +#define PERF_KERNEL_KEY_MAX (10) + +/** + * DSP perf keys + * C: perf_invoke_count + * M_H: perf_map_header + * M: perf_map_pages + * G: perf_get_args + * INVOKE: perf_mod_invoke + * P: perf_put_args + * CACHE: perf_clean_cache + * UM: perf_unmap_pages + * UM_H: perf_hdr_unmap + * R: perf_rsp + * E_R: perf_early_rsp + * J_S_T: perf_job_start_time +*/ + +#define PERF_DSP_KEY_MAX (12) + +bool is_kernel_perf_enabled(); +bool is_dsp_perf_enabled(int domain); +void fastrpc_perf_update(int dev, remote_handle handle, uint32_t sc); +int fastrpc_perf_init(int dev, int domain); +void fastrpc_perf_deinit(void); + +#endif //FASTRPC_PERF_H diff --git a/inc/fastrpc_pm.h b/inc/fastrpc_pm.h new file mode 100644 index 0000000..74d67c6 --- /dev/null +++ b/inc/fastrpc_pm.h @@ -0,0 +1,42 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef FASTRPC_PM_H +#define FASTRPC_PM_H + +/* + fastrpc_wake_lock: + + Takes the wake-lock + Args: None + Returns: Integer - 0 on success +*/ +int fastrpc_wake_lock(); + +/* + fastrpc_wake_unlock: + + Releases the wake-lock + Args: None + Returns: Integer - 0 on success +*/ +int fastrpc_wake_unlock(); + +/* + fastrpc_wake_lock_init: + + Initializes the fastrpc wakelock struct + Args: None + Returns: Integer - 0 on success +*/ +int fastrpc_wake_lock_init(); + +/* + fastrpc_wake_lock_deinit: + + De-initializes the fastrpc wakelock struct + Args: None + Returns: Integer - 0 on success +*/ +int fastrpc_wake_lock_deinit(); +#endif //FASTRPC_PM_H diff --git a/inc/fastrpc_procbuf.h b/inc/fastrpc_procbuf.h new file mode 100644 index 0000000..8eb5722 --- /dev/null +++ b/inc/fastrpc_procbuf.h @@ -0,0 +1,12 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef __FASTRPC_PROCBUF_H__ +#define __FASTRPC_PROCBUF_H__ + +/* + * API to pack all the DSP process configuration suggested by clients. + */ +void fastrpc_process_pack_params(int dev, int domain); + +#endif /*__FASTRPC_PROCBUF_H__*/ diff --git a/inc/fastrpc_process_attributes.h b/inc/fastrpc_process_attributes.h new file mode 100644 index 0000000..b31bf83 --- /dev/null +++ b/inc/fastrpc_process_attributes.h @@ -0,0 +1,49 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef FASTRPC_PROCESS_ATTRIBUTES_H +#define FASTRPC_PROCESS_ATTRIBUTES_H + +/* + * Process shared buffer id header bit-map: + * bits 0-7 : process param unique id + * bits 8-31 : size of the process param + */ +#define PROC_ATTR_BUF_ID_POS 24 + +/* Mask to get param_id payload size */ +#define PROC_ATTR_BUF_ID_SIZE_MASK ((1 << PROC_ATTR_BUF_ID_POS) - 1) + +/* + * enum represents the unique id corresponding to hlos id. + * Do not modify the existing id. Add new ids for sending any new parameters from hlos + * and ensure that it is matching with dsp param id. + */ + +enum proc_param_id { + /* HLOS process id */ + HLOS_PID_ID = 0, + + /* Thread parameters */ + THREAD_PARAM_ID, + + /* Process attributes */ + PROC_ATTR_ID, + + /* Panic error codes */ + PANIC_ERR_CODES_ID, + + /* HLOS process effective domain id */ + HLOS_PROC_EFFEC_DOM_ID, + + /*Get list of the .so's present in the custom DSP_LIBRARY_PATH set by user*/ + CUSTOM_DSP_SEARCH_PATH_LIBS_ID, + + /* HLOS process session id */ + HLOS_PROC_SESS_ID, + + /* Maximum supported ids to unpack from proc attr shared buf */ + PROC_ATTR_BUF_MAX_ID = HLOS_PROC_SESS_ID + 1 +}; + +#endif // FASTRPC_PROCESS_ATTRIBUTES_H diff --git a/inc/fastrpc_trace.h b/inc/fastrpc_trace.h new file mode 100644 index 0000000..3a7c9f5 --- /dev/null +++ b/inc/fastrpc_trace.h @@ -0,0 +1,61 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef FASTRPC_TRACE_H +#define FASTRPC_TRACE_H + +#if ((defined _ANDROID) || (defined ANDROID)) || (defined DISABLE_ATRACE) && !defined(LE_ENABLE) +//TODO: Bharath #include "cutils/trace.h" //for systrace support +#endif +#include "HAP_farf.h" + +//for systrace support +#ifdef ATRACE_TAG +#undef ATRACE_TAG +#endif +#define ATRACE_TAG (ATRACE_TAG_POWER|ATRACE_TAG_HAL) + +/* trace length for ATRACE detailed ATRACE string */ +#define SYSTRACE_STR_LEN 100 + +#if (defined(LE_ENABLE) || defined(__LE_TVM__) || defined(DISABLE_ATRACE)) +#define FASTRPC_ATRACE_BEGIN_L(fmt,...) (void)0 +#define FASTRPC_ATRACE_END_L(fmt, ...) (void)0 +#define FASTRPC_ATRACE_BEGIN() (void)0 +#define FASTRPC_ATRACE_END() (void)0 +#else +#define FASTRPC_ATRACE_BEGIN_L(fmt,...)\ + if(is_systrace_enabled()){ \ + char systrace_string[SYSTRACE_STR_LEN] = {0};\ + FARF(RUNTIME_RPC_HIGH,fmt,##__VA_ARGS__);\ + snprintf(systrace_string, SYSTRACE_STR_LEN, fmt, ##__VA_ARGS__);\ + ATRACE_BEGIN(systrace_string); \ + } \ + else \ + (void)0 +#define FASTRPC_ATRACE_END_L(fmt, ...)\ + if(is_systrace_enabled()){ \ + FARF(ALWAYS, fmt, ##__VA_ARGS__);\ + ATRACE_END(); \ + } \ + else \ + (void)0 +#define FASTRPC_ATRACE_BEGIN()\ + if(is_systrace_enabled()){ \ + FARF(ALWAYS, "%s begin", __func__);\ + ATRACE_BEGIN(__func__); \ + } \ + else \ + (void)0 +#define FASTRPC_ATRACE_END()\ + if(is_systrace_enabled()) { \ + FARF(ALWAYS, "%s end", __func__);\ + ATRACE_END(); \ + } else \ + (void)0 +#endif + +//API to get Systrace variable +int is_systrace_enabled(void); + +#endif // FASTRPC_TRACE_H diff --git a/inc/listener_android.h b/inc/listener_android.h new file mode 100644 index 0000000..2cf229c --- /dev/null +++ b/inc/listener_android.h @@ -0,0 +1,39 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef LISTENER_ANDROID_H +#define LISTENER_ANDROID_H + +#include +#include + +#define MSG(a, b, c) printf(__FILE_LINE__ ":" c ) +#define MSG_1(a, b, c, d) printf(__FILE_LINE__ ":" c , d) +#define MSG_2(a, b, c, d, e) printf(__FILE_LINE__ ":" c , d, e) +#define MSG_3(a, b, c, d, e, f) printf(__FILE_LINE__ ":" c , d, e, f) +#define MSG_4(a, b, c, d, e, f,g) printf(__FILE_LINE__ ":" c , d, e, f, g) + +#define DLW_RTLD_NOW RTLD_NOW +#define dlw_Open dlopen +#define dlw_Sym dlsym +#define dlw_Close dlclose +#define dlw_Error dlerror + +/* + * API to initialize globals and internal data structures used in listener modules + */ +int listener_android_init(void); +/* + * API to de-initialize globals and internal data structures used in listener modules + */ +void listener_android_deinit(void); +/* + * API to initialize domain specific data strcutures used in listener modules + */ +int listener_android_domain_init(int domain, int update_requested, sem_t *r_sem); +/* + * API to de-initialize domain specific data strcutures used in listener modules + */ +void listener_android_domain_deinit(int domain); + +#endif diff --git a/inc/listener_buf.h b/inc/listener_buf.h new file mode 100644 index 0000000..58e397f --- /dev/null +++ b/inc/listener_buf.h @@ -0,0 +1,98 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef LISTENER_BUF_H +#define LISTENER_BUF_H + +#include "sbuf.h" +#include "remote.h" +#include "verify.h" + +static __inline void pack_in_bufs(struct sbuf* buf, remote_arg* pra, int nBufs) { + int ii; + uint32_t len; + C_ASSERT(sizeof(len) == 4); + for(ii = 0; ii < nBufs; ++ii) { + len = (uint32_t)pra[ii].buf.nLen; + sbuf_write(buf, (uint8*)&len, 4); + if(len) { + sbuf_align(buf, 8); + sbuf_write(buf, pra[ii].buf.pv, len); + } + } +} + +static __inline void pack_out_lens(struct sbuf* buf, remote_arg* pra, int nBufs) { + int ii; + uint32_t len; + C_ASSERT(sizeof(len) == 4); + for(ii = 0; ii < nBufs; ++ii) { + len = (uint32_t)pra[ii].buf.nLen; + sbuf_write(buf, (uint8*)&len, 4); + } +} + +static __inline void unpack_in_bufs(struct sbuf* buf, remote_arg* pra, int nBufs) { + int ii; + uint32_t len=0; + C_ASSERT(sizeof(len) == 4); + for(ii = 0; ii < nBufs; ++ii) { + sbuf_read(buf, (uint8*)&len, 4); + pra[ii].buf.nLen = len; + if(pra[ii].buf.nLen) { + sbuf_align(buf, 8); + if((int)pra[ii].buf.nLen <= sbuf_left(buf)) { + pra[ii].buf.pv = sbuf_head(buf); + } + sbuf_advance(buf, pra[ii].buf.nLen); + } + } +} + +static __inline void unpack_out_lens(struct sbuf* buf, remote_arg* pra, int nBufs) { + int ii; + uint32_t len=0; + C_ASSERT(sizeof(len) == 4); + for(ii = 0; ii < nBufs; ++ii) { + sbuf_read(buf, (uint8*)&len, 4); + pra[ii].buf.nLen = len; + } +} + +//map out buffers on the hlos side to the remote_arg array +//dst is the space required for buffers we coun't map from the adsp +static __inline void pack_out_bufs(struct sbuf* buf, remote_arg* pra, int nBufs) { + int ii; + uint32_t len; + C_ASSERT(sizeof(len) == 4); + for(ii = 0; ii < nBufs; ++ii) { + len = (uint32_t)pra[ii].buf.nLen; + sbuf_write(buf, (uint8*)&len, 4); + if(pra[ii].buf.nLen) { + sbuf_align(buf, 8); + if((int)pra[ii].buf.nLen <= sbuf_left(buf)) { + pra[ii].buf.pv = sbuf_head(buf); + } + sbuf_advance(buf, pra[ii].buf.nLen); + } + } +} + +//on the aDSP copy the data from buffers we had to copy to the local remote_arg structure +static __inline int unpack_out_bufs(struct sbuf* buf, remote_arg* pra, int nBufs) { + int ii, nErr = 0; + uint32_t len; + C_ASSERT(sizeof(len) == 4); + for(ii = 0; ii < nBufs; ++ii) { + sbuf_read(buf, (uint8*)&len, 4); + VERIFY(len == pra[ii].buf.nLen); + if(pra[ii].buf.nLen) { + sbuf_align(buf, 8); + sbuf_read(buf, pra[ii].buf.pv, pra[ii].buf.nLen); + } + } +bail: + return nErr; +} + +#endif diff --git a/inc/log_config.h b/inc/log_config.h new file mode 100644 index 0000000..d52b12b --- /dev/null +++ b/inc/log_config.h @@ -0,0 +1,19 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef __LOG_CONFIG_H__ +#define __LOG_CONFIG_H__ +/** + * @brief API to initialize logging framework + * creates a thread and looks for .farf filebuf + * when found, reads the file for log levels that + * should be enabled on APSS and DSP. + **/ +int initFileWatcher(int domain); +/** + * @brief API to de-initialize logging framework + * sets an exit flag and wait for the thread to join. + **/ +void deinitFileWatcher(int domain); + +#endif /*__LOG_CONFIG_H__*/ diff --git a/inc/mod_table.h b/inc/mod_table.h new file mode 100644 index 0000000..c3ad413 --- /dev/null +++ b/inc/mod_table.h @@ -0,0 +1,112 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef MOD_TABLE_H +#define MOD_TABLE_H + +#include "remote64.h" +#include "AEEStdDef.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * multi-domain support + * + * multi domain modules return remote_handl64 on open/close, but mod_table + * creates uint32 handles as the "remote" facing handle. These fit nicely + * into the transport layer. + * + */ + +/** + * register a static component for invocations + * this can be called at any time including from a static constructor + * + * name, name of the interface to register + * pfn, function pointer to the skel invoke function + * + * for example: + * __attribute__((constructor)) static void my_module_ctor(void) { + * mod_table_register_static("my_module", my_module_skel_invoke); + * } + * + */ +int mod_table_register_static(const char* name, int (*pfn)(uint32 sc, remote_arg* pra)); + +/** + * same as register_static, but module with user defined handle lifetimes. + */ +int mod_table_register_static1(const char* uri, int (*pfn)(remote_handle64 h,uint32 sc, remote_arg* pra)); + +/** + * register a static component for invocations + * this can be called at any time including from a static constructor + * + * overrides will be tried first, then dynamic modules, then regular + * static modules. This api should only be use by system components + * that will never be upgradable. + * + * name, name of the interface to register + * pfn, function pointer to the skel invoke function + * + * for example: + * __attribute__((constructor)) static void my_module_ctor(void) { + * mod_table_register_static("my_module", my_module_skel_invoke); + * } + * + */ +int mod_table_register_static_override(const char* name, int(*pfn)(uint32 sc, remote_arg* pra)); + +/** + * same as register_static, but module with user defined handle lifetimes. + */ +int mod_table_register_static_override1(const char* uri, int(*pfn)(remote_handle64,uint32 sc, remote_arg* pra)); + +/** + * Open a module and get a handle to it + * + * in_name, name of module to open + * handle, Output handle + * dlerr, Error String (if an error occurs) + * dlerrorLen, Length of error String (if an error occurs) + * pdlErr, Error identifier + */ +int mod_table_open(const char* in_name, remote_handle* handle, char* dlerr, int dlerrorLen, int* pdlErr); + +/** + * invoke a handle in the mod table + * + * handle, handle to invoke + * sc, scalars, see remote.h for documentation. + * pra, args, see remote.h for documentation. + */ +int mod_table_invoke(remote_handle handle, uint32 sc, remote_arg* pra); + +/** + * Closes a handle in the mod table + * + * handle, handle to close + * errStr, Error String (if an error occurs) + * errStrLen, Length of error String (if an error occurs) + * pdlErr, Error identifier + */ +int mod_table_close(remote_handle handle, char* errStr, int errStrLen, int* pdlErr); + +/** + * internal use only + */ +int mod_table_register_const_handle(remote_handle handle, const char* in_name, int (*pfn)(uint32 sc, remote_arg* pra)); +/** + * @param remote, the handle we should expect from the transport layer + * @param local, the local handle that will be passed to pfn + */ +int mod_table_register_const_handle1(remote_handle remote, remote_handle64 local, const char* uri, int (*pfn)(remote_handle64 h, uint32 sc, remote_arg* pra)); + +#ifdef __cplusplus +} +#endif + +#endif // MOD_TABLE_H diff --git a/inc/mutex.h b/inc/mutex.h new file mode 100644 index 0000000..e9a9347 --- /dev/null +++ b/inc/mutex.h @@ -0,0 +1,79 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef MUTEX_H +#define MUTEX_H + +#if (defined __qdsp6__) || (defined __hexagon__) +#include "qurt_mutex.h" + +#define RW_MUTEX_T qurt_mutex_t +#define RW_MUTEX_CTOR(mut) qurt_mutex_init(& (mut)) +#define RW_MUTEX_LOCK_READ(mut) qurt_mutex_lock(& (mut)) +#define RW_MUTEX_UNLOCK_READ(mut) qurt_mutex_unlock(& (mut)) +#define RW_MUTEX_LOCK_WRITE(mut) qurt_mutex_lock(& (mut)) +#define RW_MUTEX_UNLOCK_WRITE(mut) qurt_mutex_unlock(& (mut)) +#define RW_MUTEX_DTOR(mut) qurt_mutex_destroy(& (mut)) + +#elif (1 == __linux) || (1 == __linux__) || (1 == __gnu_linux__) || (1 == linux) + +#include +#include +#include + +/* asserts may be compiled out, this should always be present */ +#define ABORT_FAIL( ff ) \ + do {\ + if(! (ff) ) {\ + fprintf(stderr, "assertion \"%s\" failed: file \"%s\", line %d\n", #ff, __FILE__, __LINE__);\ + abort();\ + }\ + } while(0) + +#define RW_MUTEX_T pthread_rwlock_t +#define RW_MUTEX_CTOR(mut) ABORT_FAIL(0 == pthread_rwlock_init( & (mut), 0)) +#define RW_MUTEX_LOCK_READ(mut) ABORT_FAIL(0 == pthread_rwlock_rdlock( & (mut))) +#define RW_MUTEX_UNLOCK_READ(mut) ABORT_FAIL(0 == pthread_rwlock_unlock( & (mut))) +#define RW_MUTEX_LOCK_WRITE(mut) ABORT_FAIL(0 == pthread_rwlock_wrlock( & (mut))) +#define RW_MUTEX_UNLOCK_WRITE(mut) ABORT_FAIL(0 == pthread_rwlock_unlock( & (mut))) +#define RW_MUTEX_DTOR(mut) ABORT_FAIL(0 == pthread_rwlock_destroy( & (mut))) + + +#else + +#include "AEEstd.h" + +#define RW_MUTEX_T uint32 +#define RW_MUTEX_CTOR(mut) mut = 0 +#define RW_MUTEX_LOCK_READ(mut) \ + do {\ + assert(STD_BIT_TEST(&mut, 1) == 0); \ + assert(STD_BIT_TEST(&mut, 2) == 0); \ + STD_BIT_SET(&mut, 1); \ + } while (0) + +#define RW_MUTEX_UNLOCK_READ(mut) \ + do {\ + assert(STD_BIT_TEST(&mut, 1)); \ + assert(STD_BIT_TEST(&mut, 2) == 0); \ + STD_BIT_CLEAR(&mut, 1); \ + } while (0) + +#define RW_MUTEX_LOCK_WRITE(mut) \ + do {\ + assert(STD_BIT_TEST(&mut, 1) == 0); \ + assert(STD_BIT_TEST(&mut, 2) == 0); \ + STD_BIT_SET(&mut, 2); \ + } while (0) + +#define RW_MUTEX_UNLOCK_WRITE(mut) \ + do {\ + assert(STD_BIT_TEST(&mut, 1) == 0); \ + assert(STD_BIT_TEST(&mut, 2)); \ + STD_BIT_CLEAR(&mut, 2); \ + } while (0) + +#define RW_MUTEX_DTOR(mut) mut = 0 + +#endif +#endif //MUTEX_H diff --git a/inc/platform_libs.h b/inc/platform_libs.h new file mode 100644 index 0000000..e8a7408 --- /dev/null +++ b/inc/platform_libs.h @@ -0,0 +1,155 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef PLATFORM_LIBS_H +#define PLATFORM_LIBS_H +/* +Platfrom Library Loader +----------------------- + +proj/platform_libs is a library to help manage interdependencies between +other libraries. + + +to use you will need to add + +incs = { 'proj/platform_libs' } + +in source of the library implementation define the entry point + +#include "platform_libs.h" +PL_DEFINE(svfs, svfs_init, svfs_deinit); + +Platfrom Library List +--------------------- + +This list contains top level libraries to be initialized at boot. To make +sure that this library is loaded you would need to call PLRegister or +PLRegisterDefault in your scons build command. + + +Handling Interdependencies and Order +------------------------------------ + +To make sure that library A is loaded before library B, library B's +constructor and destructor should initialize and cleanup libraryB. + +#include "platform_libs.h" + +PL_DEP(libraryB) +void libraryA_deinit(void) { + PL_DEINIT(libraryB); +} + +int libraryA_init(void) { + int nErr = 0; + // my init code + VERIFY(0 == PL_INIT(libraryB)); +bail: + if(nErr) { libraryA_deinit() } + return nErr; +} + + +libraryB does not need to appear in the platform library list. +*/ + +#include + +struct platform_lib { + const char* name; + uint32_t uRefs; + int nErr; + int (*init)(void); + void (*deinit)(void); +}; + +/** + * use this macro to pull in external dependencies + */ +#ifdef __cplusplus +#define PL_DEP(name)\ + extern "C" {\ + extern struct platform_lib* _pl_##name(void); \ + } +#else +#define PL_DEP(name)\ + extern struct platform_lib* _pl_##name(void); +#endif /* __cplusplus */ + +/** + * should be declared in source in the library + * if constructor fails, destructor is not called + */ +#ifdef __cplusplus +#define PL_DEFINE(name, init, deinit) \ + extern "C" {\ + struct platform_lib* _pl_##name(void) {\ + static struct platform_lib _gpl_##name = { #name, 0, -1, init, deinit };\ + return &_gpl_##name;\ + }\ + } +#else +#define PL_DEFINE(name, init, deinit) \ + struct platform_lib* _pl_##name(void) {\ + static struct platform_lib _gpl_##name = { #name, 0, -1, init, deinit };\ + return &_gpl_##name;\ + } +#endif /* __cplusplus */ + +/** + * should be added to platform_libs_list.c pl_list table + * for all top level modules + */ +#define PL_ENTRY(name) _pl_##name + +/** + * should be called within a constructor to ensure that a + * dependency has been initialized. so if foo depends on bar + * + * #include "bar.h" + * int foo_init() { + * return PL_INIT(bar); + * } + */ +#define PL_INIT(name) pl_lib_init(PL_ENTRY(name)) + +/** + * should be called within a destructor to ensure that a + * dependency has been cleaned up + */ +#define PL_DEINIT(name) pl_lib_deinit(PL_ENTRY(name)) + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * initalize the static list of library constructors and destructors + * should be called from main() + * + * see platform_libs_list.h to add high level libraries + * + */ +int pl_init(void); + +/** + * calls all the destructors. + */ +void pl_deinit(void); + +/** + * initialize a single library. called via PL_INIT + */ +int pl_lib_init(struct platform_lib* (*pl)(void)); + +/** + * deinitialize a single library called via PL_DEINIT + */ +void pl_lib_deinit(struct platform_lib* (*pl)(void)); + +#ifdef __cplusplus +} +#endif + +#endif //PLATFORM_LIBS diff --git a/inc/pls.h b/inc/pls.h new file mode 100644 index 0000000..c125266 --- /dev/null +++ b/inc/pls.h @@ -0,0 +1,186 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef PLS_H +#define PLS_H + +#include +#include "AEEStdDef.h" +#include "AEEatomic.h" +#include "verify.h" +#include "HAP_farf.h" + +struct PLS; + +struct plskey { + uintptr_t type; + uintptr_t key; +}; + +struct PLS { + struct PLS* next; + struct plskey key; + void (*dtor)(void* data); + uint64_t data[1]; +}; + + +struct pls_table { + struct PLS* lst; + uint32_t uRefs; + uint32_t primThread; +}; + +/** + * initialize on every thread and stick the pls_thread_deinit + * function into the threads tls + */ +static __inline int pls_thread_init(struct pls_table* me, uintptr_t tid) { + if(tid == me->primThread) { + return 0; + } + if(0 == atomic_CompareOrAdd(&me->uRefs, 0, 1)) { + return -1; + } + return 0; +} + +/* call this constructor before the first thread creation with the + * first threads id + */ +static __inline void pls_ctor(struct pls_table* me, uintptr_t primThread) { + me->uRefs = 1; + me->primThread = primThread; +} + +static __inline struct pls_table* pls_thread_deinit(struct pls_table* me) { + if(me && 0 != me->uRefs && 0 == atomic_Add(&me->uRefs, -1)) { + struct PLS* lst, *next; + lst = me->lst; + me->lst = 0; + while(lst) { + next = lst->next; + if(lst->dtor) { + FARF(HIGH, "pls dtor %p", lst->dtor); + lst->dtor((void*)lst->data); + } + free(lst); + lst = next; + } + return me; + } + return 0; +} + +/** + * adds a new key to the local storage, overriding + * any previous value at the key. Overriding the key + * does not cause the destructor to run. + * + * @param type, type part of the key to be used for lookup, + these should be static addresses. + * @param key, the key to be used for lookup + * @param size, the size of the data + * @param ctor, constructor that takes a context and memory of size + * @param ctx, constructor context passed as the first argument to ctor + * @param dtor, destructor to run at pls shutdown + * @param ppo, output data + * @retval, 0 for success + */ + +static __inline int pls_add(struct pls_table* me, uintptr_t type, uintptr_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* data), void** ppo) { + int nErr = 0; + struct PLS* pls = 0; + struct PLS* prev; + VERIFY(me->uRefs != 0); + VERIFY(0 != (pls = (struct PLS*)calloc(1, size + sizeof(*pls) - sizeof(pls->data)))); + if(ctor) { + VERIFY(0 == ctor(ctx, (void*)pls->data)); + } + pls->dtor = dtor; + pls->key.type = type; + pls->key.key = key; + do { + pls->next = me->lst; + prev = (struct PLS*)atomic_CompareAndExchangeUP((uintptr_t*)&me->lst, (uintptr_t)pls, (uintptr_t)pls->next); + } while(prev != pls->next); + if(ppo) { + *ppo = (void*)pls->data; + } + FARF(HIGH, "pls added %p", dtor); +bail: + if(nErr && pls) { + free(pls); + } + return nErr; +} + +static __inline int pls_lookup(struct pls_table* me, uintptr_t type, uintptr_t key, void** ppo); + +/** + * like add, but will only add 1 item if two threads try to add at the same time. returns + * item if its already there, otherwise tries to add. + * ctor may be called twice + * callers should avoid calling pls_add which will override the singleton + */ +static __inline int pls_add_lookup_singleton(struct pls_table* me, uintptr_t type, uintptr_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* data), void** ppo) { + int nErr = 0; + struct PLS* pls = 0; + struct PLS* prev; + if(0 == pls_lookup(me, type, key, ppo)) { + return 0; + } + VERIFY(me->uRefs != 0); + VERIFY(0 != (pls = (struct PLS*)calloc(1, size + sizeof(*pls) - sizeof(pls->data)))); + if(ctor) { + VERIFY(0 == ctor(ctx, (void*)pls->data)); + } + pls->dtor = dtor; + pls->key.type = type; + pls->key.key = key; + do { + pls->next = me->lst; + if(0 == pls_lookup(me, type, key, ppo)) { + if(pls->dtor) { + pls->dtor((void*)pls->data); + } + free(pls); + return 0; + } + prev = (struct PLS*)atomic_CompareAndExchangeUP((uintptr_t*)&me->lst, (uintptr_t)pls, (uintptr_t)pls->next); + } while(prev != pls->next); + if(ppo) { + *ppo = (void*)pls->data; + } +bail: + if(nErr && pls) { + free(pls); + } + return nErr; +} + + +/** + * finds the last data pointer added for key to the local storage + * + * @param key, the key to be used for lookup + * @param ppo, output data + * @retval, 0 for success + */ + +static __inline int pls_lookup(struct pls_table* me, uintptr_t type, uintptr_t key, void** ppo) { + struct PLS* lst; + for(lst = me->lst; me->uRefs != 0 && lst != 0; lst = lst->next) { + if(lst->key.type == type && lst->key.key == key) { + if(ppo) { + *ppo = lst->data; + } + return 0; + } + } + return -1; +} + +#endif //PLS_H + + diff --git a/inc/pthread_rw_mutex.h b/inc/pthread_rw_mutex.h new file mode 100644 index 0000000..f2b7b0a --- /dev/null +++ b/inc/pthread_rw_mutex.h @@ -0,0 +1,33 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef PTHREAD_RW_MUTEX_H +#define PTHREAD_RW_MUTEX_H + +#include +#include +#include + +/* asserts may be compiled out, this should always be present */ +#define ABORT_FAIL( ff ) \ + do {\ + if(! (ff) ) {\ + fprintf(stderr, "assertion \"%s\" failed: file \"%s\", line %d\n", #ff, __FILE__, __LINE__);\ + abort();\ + }\ + } while(0) + +#define RW_MUTEX_T pthread_rwlock_t +#define RW_MUTEX_CTOR(mut) ABORT_FAIL(0 == pthread_rwlock_init( & (mut), 0)) +#define RW_MUTEX_LOCK_READ(mut) ABORT_FAIL(0 == pthread_rwlock_rdlock( & (mut))) + +#define RW_MUTEX_UNLOCK_READ(mut) ABORT_FAIL(0 == pthread_rwlock_unlock( & (mut))) + +#define RW_MUTEX_LOCK_WRITE(mut) ABORT_FAIL(0 == pthread_rwlock_wrlock( & (mut))) + +#define RW_MUTEX_UNLOCK_WRITE(mut) ABORT_FAIL(0 == pthread_rwlock_unlock( & (mut))) + +#define RW_MUTEX_DTOR(mut) ABORT_FAIL(0 == pthread_rwlock_destroy( & (mut))) + + +#endif //PTHREAD_RW_MUTEX_H diff --git a/inc/remote.h b/inc/remote.h new file mode 100644 index 0000000..45325de --- /dev/null +++ b/inc/remote.h @@ -0,0 +1,1043 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef REMOTE_H +#define REMOTE_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif ///__QAIC_REMOTE + +#ifndef __QAIC_REMOTE_EXPORT +#ifdef _WIN32 +#ifdef _USRDLL +#define __QAIC_REMOTE_EXPORT __declspec(dllexport) +#elif defined(STATIC_LIB) +#define __QAIC_REMOTE_EXPORT /** Define for static libk */ +#else ///STATIC_LIB +#define __QAIC_REMOTE_EXPORT __declspec(dllimport) +#endif ///_USRDLL +#else +#define __QAIC_REMOTE_EXPORT +#endif ///_WIN32 +#endif ///__QAIC_REMOTE_EXPORT + +#ifndef __QAIC_RETURN +#ifdef _WIN32 +#define __QAIC_RETURN _Success_(return == 0) +#else +#define __QAIC_RETURN +#endif ///_WIN32 +#endif ///__QAIC_RETURN + +#ifndef __QAIC_IN +#ifdef _WIN32 +#define __QAIC_IN _In_ +#else +#define __QAIC_IN +#endif ///_WIN32 +#endif ///__QAIC_IN + +#ifndef __QAIC_IN_CHAR +#ifdef _WIN32 +#define __QAIC_IN_CHAR _In_z_ +#else +#define __QAIC_IN_CHAR +#endif ///_WIN32 +#endif ///__QAIC_IN_CHAR + +#ifndef __QAIC_IN_LEN +#ifdef _WIN32 +#define __QAIC_IN_LEN(len) _Inout_updates_bytes_all_(len) +#else +#define __QAIC_IN_LEN(len) +#endif ///_WIN32 +#endif ///__QAIC_IN_LEN + +#ifndef __QAIC_OUT +#ifdef _WIN32 +#define __QAIC_OUT _Out_ +#else +#define __QAIC_OUT +#endif ///_WIN32 +#endif ///__QAIC_OUT + +#ifndef __QAIC_INT64PTR +#ifdef _WIN32 +#define __QAIC_INT64PTR uintptr_t +#else +#define __QAIC_INT64PTR uint64_t +#endif ///_WIN32 +#endif ///__QAIC_INT64PTR + +#ifndef __QAIC_REMOTE_ATTRIBUTE +#define __QAIC_REMOTE_ATTRIBUTE +#endif ///__QAIC_REMOTE_ATTRIBUTE + +/** Retrieves method attribute from the scalars parameter */ +#define REMOTE_SCALARS_METHOD_ATTR(dwScalars) (((dwScalars) >> 29) & 0x7) + +/** Retrieves method index from the scalars parameter */ +#define REMOTE_SCALARS_METHOD(dwScalars) (((dwScalars) >> 24) & 0x1f) + +/** Retrieves number of input buffers from the scalars parameter */ +#define REMOTE_SCALARS_INBUFS(dwScalars) (((dwScalars) >> 16) & 0x0ff) + +/** Retrieves number of output buffers from the scalars parameter */ +#define REMOTE_SCALARS_OUTBUFS(dwScalars) (((dwScalars) >> 8) & 0x0ff) + +/** Retrieves number of input handles from the scalars parameter */ +#define REMOTE_SCALARS_INHANDLES(dwScalars) (((dwScalars) >> 4) & 0x0f) + +/** Retrieves number of output handles from the scalars parameter */ +#define REMOTE_SCALARS_OUTHANDLES(dwScalars) ((dwScalars) & 0x0f) + +/** Makes the scalar using the method attr, index and number of io buffers and handles */ +#define REMOTE_SCALARS_MAKEX(nAttr,nMethod,nIn,nOut,noIn,noOut) \ + ((((uint32_t) (nAttr) & 0x7) << 29) | \ + (((uint32_t) (nMethod) & 0x1f) << 24) | \ + (((uint32_t) (nIn) & 0xff) << 16) | \ + (((uint32_t) (nOut) & 0xff) << 8) | \ + (((uint32_t) (noIn) & 0x0f) << 4) | \ + ((uint32_t) (noOut) & 0x0f)) + +#define REMOTE_SCALARS_MAKE(nMethod,nIn,nOut) REMOTE_SCALARS_MAKEX(0,nMethod,nIn,nOut,0,0) + +/** Retrieves number of io buffers and handles */ +#define REMOTE_SCALARS_LENGTH(sc) (REMOTE_SCALARS_INBUFS(sc) +\ + REMOTE_SCALARS_OUTBUFS(sc) +\ + REMOTE_SCALARS_INHANDLES(sc) +\ + REMOTE_SCALARS_OUTHANDLES(sc)) + +/** Defines the domain IDs for supported DSPs */ +#define ADSP_DOMAIN_ID 0 +#define MDSP_DOMAIN_ID 1 +#define SDSP_DOMAIN_ID 2 +#define CDSP_DOMAIN_ID 3 + +/** Supported Domain Names */ +#define ADSP_DOMAIN_NAME "adsp" +#define MDSP_DOMAIN_NAME "mdsp" +#define SDSP_DOMAIN_NAME "sdsp" +#define CDSP_DOMAIN_NAME "cdsp" + +/** Defines to prepare URI for multi-domain calls */ +#define ADSP_DOMAIN "&_dom=adsp" +#define MDSP_DOMAIN "&_dom=mdsp" +#define SDSP_DOMAIN "&_dom=sdsp" +#define CDSP_DOMAIN "&_dom=cdsp" + +/** Internal transport prefix */ +#define ITRANSPORT_PREFIX "'\":;./\\" + +/** Maximum length of URI for remote_handle_open() calls */ +#define MAX_DOMAIN_URI_SIZE 12 + +/** Domain type for multi-domain RPC calls */ +typedef struct domain { + /** Domain ID */ + int id; + /** URI for remote_handle_open */ + char uri[MAX_DOMAIN_URI_SIZE]; +} domain_t; + +/** Remote handle parameter for RPC calls */ +typedef uint32_t remote_handle; + +/** Remote handle parameter for multi-domain RPC calls */ +typedef uint64_t remote_handle64; + +/** 32-bit Remote buffer parameter for RPC calls */ +typedef struct { + void *pv; /** Address of a remote buffer */ + size_t nLen; /** Size of a remote buffer */ +} remote_buf; + +/** 64-bit Remote buffer parameter for RPC calls */ +typedef struct { + uint64_t pv; /** Address of a remote buffer */ + int64_t nLen; /** Size of a remote buffer */ +} remote_buf64; + +/** 32-bit Remote DMA handle parameter for RPC calls */ +typedef struct { + int32_t fd; /** File descriptor of a remote buffer */ + uint32_t offset; /** Offset of the file descriptor */ +} remote_dma_handle; + +/** 64-bit Remote DMA handle parameter for RPC calls */ +typedef struct { + int32_t fd; /** File descriptor of a remote buffer */ + uint32_t offset; /** Offset of the file descriptor */ + uint32_t len; /** Size of buffer */ +} remote_dma_handle64; + +/** 32-bit Remote Arg structure for RPC calls */ +typedef union { + remote_buf buf; /** 32-bit remote buffer */ + remote_handle h; /** non-domains remote handle */ + remote_handle64 h64; /** multi-domains remote handle */ + remote_dma_handle dma; /** 32-bit remote dma handle */ +} remote_arg; + +/** 64-bit Remote Arg structure for RPC calls */ +typedef union { + remote_buf64 buf; /** 64-bit remote buffer */ + remote_handle h; /** non-domains remote handle */ + remote_handle64 h64; /** multi-domains remote handle */ + remote_dma_handle64 dma; /** 64-bit remote dma handle */ +} remote_arg64; + +/** Async response type */ +enum fastrpc_async_notify_type { + FASTRPC_ASYNC_NO_SYNC, /** No notification required */ + FASTRPC_ASYNC_CALLBACK, /** Callback notification using fastrpc_async_callback */ + FASTRPC_ASYNC_POLL, /** User will poll for the notification */ +/** Update FASTRPC_ASYNC_TYPE_MAX when adding new value to this enum */ +}; + +/** Job id of Async job queued to DSP */ +typedef uint64_t fastrpc_async_jobid; + +/** Async call back response type, input structure */ +typedef struct fastrpc_async_callback { + /** Callback function for async notification */ + void (*fn)(fastrpc_async_jobid jobid, void* context, int result); + /** Current context to identify the callback */ + void *context; +}fastrpc_async_callback_t; + +/** Async descriptor to submit async job */ +typedef struct fastrpc_async_descriptor { + enum fastrpc_async_notify_type type; /** Async response type */ + fastrpc_async_jobid jobid; /** Job id of Async job queued to DSP */ + fastrpc_async_callback_t cb; /** Async call back response type */ +}fastrpc_async_descriptor_t; + + +/** + * Flags used in struct remote_rpc_control_latency + * for request ID DSPRPC_CONTROL_LATENCY + * in remote handle control interface + **/ +enum remote_rpc_latency_flags { + RPC_DISABLE_QOS, + +/** Control cpu low power modes based on RPC activity in 100 ms window. + * Recommended for latency sensitive use cases. + */ + RPC_PM_QOS, + +/** DSP driver predicts completion time of a method and send CPU wake up signal to reduce wake up latency. + * Recommended for moderate latency sensitive use cases. It is more power efficient compared to pm_qos control. + */ + RPC_ADAPTIVE_QOS, + +/** + * After sending invocation to DSP, CPU will enter polling mode instead of + * waiting for a glink response. This will boost fastrpc performance by + * reducing the CPU wakeup and scheduling times. Enabled only for sync RPC + * calls. Using this option also enables PM QoS with a latency of 100 us. + */ + RPC_POLL_QOS, +}; + +/** + * Structure used for request ID `DSPRPC_CONTROL_LATENCY` + * in remote handle control interface + **/ +struct remote_rpc_control_latency { +/** Enable latency optimization techniques to meet requested latency. Use remote_rpc_latency_flags */ + uint32_t enable; + +/** + * Latency in microseconds. + * + * When used with RPC_PM_QOS or RPC_ADAPTIVE_QOS, user should pass maximum RPC + * latency that can be tolerated. It is not guaranteed that fastrpc will meet + * this requirement. 0 us latency is ignored. Recommended value is 100. + * + * When used with RPC_POLL_QOS, user needs to pass the expected execution time + * of method on DSP. CPU will poll for a DSP response for that specified duration + * after which it will timeout and fall back to waiting for a glink response. + * Max value that can be passed is 10000 (10 ms) + */ + uint32_t latency; +}; + +/** + * @struct fastrpc_capability + * @brief Argument to query DSP capability with request ID DSPRPC_GET_DSP_INFO + */ +typedef struct remote_dsp_capability { + uint32_t domain; /** @param[in]: DSP domain ADSP_DOMAIN_ID, SDSP_DOMAIN_ID, or CDSP_DOMAIN_ID */ + uint32_t attribute_ID; /** @param[in]: One of the DSP/kernel attributes from enum remote_dsp_attributes */ + uint32_t capability; /** @param[out]: Result of the DSP/kernel capability query based on attribute_ID */ +}fastrpc_capability; + + +/** + * @enum remote_dsp_attributes + * @brief Different types of DSP capabilities queried via remote_handle_control + * using DSPRPC_GET_DSP_INFO request id. + * DSPRPC_GET_DSP_INFO should only be used with remote_handle_control() as a handle + * is not needed to query DSP capabilities. + * To query DSP capabilities fill out 'domain' and 'attribute_ID' from structure + * remote_dsp_capability. DSP capability will be returned on variable 'capability'. + */ +enum remote_dsp_attributes { + DOMAIN_SUPPORT, /** Check if DSP supported: supported = 1, + unsupported = 0 */ + UNSIGNED_PD_SUPPORT, /** DSP unsigned PD support: supported = 1, + unsupported = 0 */ + HVX_SUPPORT_64B, /** Number of HVX 64B support */ + HVX_SUPPORT_128B, /** Number of HVX 128B support */ + VTCM_PAGE, /** Max page size allocation possible in VTCM */ + VTCM_COUNT, /** Number of page_size blocks available */ + ARCH_VER, /** Hexagon processor architecture version */ + HMX_SUPPORT_DEPTH, /** HMX Support Depth */ + HMX_SUPPORT_SPATIAL, /** HMX Support Spatial */ + ASYNC_FASTRPC_SUPPORT, /** Async FastRPC Support */ + STATUS_NOTIFICATION_SUPPORT , /** DSP User PD status notification Support */ + /** Update FASTRPC_MAX_DSP_ATTRIBUTES when adding new value to this enum */ +}; + +/** Macro for backward compatibility. Clients can compile wakelock request code + * in their app only when this is defined + */ +#define FASTRPC_WAKELOCK_CONTROL_SUPPORTED 1 + +/** + * Structure used for request ID `DSPRPC_CONTROL_WAKELOCK` + * in remote handle control interface + **/ +struct remote_rpc_control_wakelock { + uint32_t enable; /** enable control of wake lock */ +}; + +/** + * Structure used for request ID `DSPRPC_GET_DOMAIN` + * in remote handle control interface. + * Get domain ID associated with an opened handle to remote interface of type remote_handle64. + * remote_handle64_control() returns domain for a given handle + * remote_handle_control() API returns default domain ID + */ +typedef struct remote_rpc_get_domain { + int domain; /** @param[out]: domain ID associcated with handle */ +} remote_rpc_get_domain_t; + +/** + * Structure used for request IDs `DSPRPC_SET_PATH` and + * `DSPRPC_GET_PATH` in remote handle control interface. + */ +struct remote_control_custom_path { + int32_t value_size; /** value size including NULL char */ + const char* path; /** key used for storing the path */ + char* value; /** value which will be used for file operations when the corresponding key is specified in the file URI */ +}; + +/** + * Request IDs for remote handle control interface + **/ +enum handle_control_req_id { + DSPRPC_RESERVED, /** Reserved */ + DSPRPC_CONTROL_LATENCY , /** Request ID to enable/disable QOS */ + DSPRPC_GET_DSP_INFO, /** Request ID to get dsp capabilites from kernel and Hexagon */ + DSPRPC_CONTROL_WAKELOCK, /** Request ID to enable wakelock for the given domain */ + DSPRPC_GET_DOMAIN, /** Request ID to get the default domain or domain associated to an exisiting handle */ + DSPRPC_SET_PATH, /** Request ID to add a custom path to the hash table */ + DSPRPC_GET_PATH, /** Request ID to read a custom path to the hash table */ + DSPRPC_SMMU_SUPPORT, /** Request ID to check smmu support by kernel */ + DSPRPC_KALLOC_SUPPORT, /** Request ID to check kalloc support by kernel */ + DSPRPC_PM, /** Request ID to awake PM */ + DSPRPC_RPC_POLL, /** Request ID to update polling mode in kernel */ + DSPRPC_ASYNC_WAKE, /** Request ID to exit async thread */ + DSPRPC_NOTIF_WAKE, /** Request ID to exit notif thread */ + DSPRPC_REMOTE_PROCESS_KILL, /** Request ID to kill remote process */ + DSPRPC_SET_MODE, /** Request ID to set mode */ +}; + +/** + * Structure used for request ID `FASTRPC_THREAD_PARAMS` + * in remote session control interface + **/ +struct remote_rpc_thread_params { + int domain; /** Remote subsystem domain ID, pass -1 to set params for all domains */ + int prio; /** User thread priority (1 to 255), pass -1 to use default */ + int stack_size; /** User thread stack size, pass -1 to use default */ +}; + +/** + * Structure used for request ID `DSPRPC_CONTROL_UNSIGNED_MODULE` + * in remote session control interface + **/ +struct remote_rpc_control_unsigned_module { + int domain; /** Remote subsystem domain ID, -1 to set params for all domains */ + int enable; /** Enable unsigned module loading */ +}; + +/** + * Structure used for request ID `FASTRPC_RELATIVE_THREAD_PRIORITY` + * in remote session control interface + **/ +struct remote_rpc_relative_thread_priority { + int domain; /** Remote subsystem domain ID, pass -1 to update priority for all domains */ + int relative_thread_priority; /** the value by which the default thread priority needs to increase/decrease + * DSP thread priorities run from 1 to 255 with 1 being the highest thread priority. + * So a negative relative thread priority value will 'increase' the thread priority, + * a positive value will 'decrease' the thread priority. + */ +}; + +/** + * When a remote invocation does not return, + * then call "remote_session_control" with FASTRPC_REMOTE_PROCESS_KILL requestID + * and the appropriate remote domain ID. Once remote process is successfully + * killed, before attempting to create new session, user is expected to + * close all open handles for shared objects in case of domains. + * And, user is expected to unload all shared objects including + * libcdsprpc.so/libadsprpc.so/libmdsprpc.so/libsdsprpc.so in case of non-domains. + */ +struct remote_rpc_process_clean_params { + int domain; /** Domain ID to recover process */ +}; + +/** + * Structure used for request ID `FASTRPC_SESSION_CLOSE` + * in remote session control interface + **/ +struct remote_rpc_session_close { + int domain; /** Remote subsystem domain ID, -1 to close all handles for all domains */ +}; + +/** + * Structure used for request ID `FASTRPC_CONTROL_PD_DUMP` + * in remote session control interface + * This is used to enable/disable PD dump for userPDs on the DSP + **/ +struct remote_rpc_control_pd_dump { + int domain; /** Remote subsystem domain ID, -1 to set params for all domains */ + int enable; /** Enable PD dump of user PD on the DSP */ +}; + +/** + * Structure used for request ID `FASTRPC_REMOTE_PROCESS_EXCEPTION` + * in remote session control interface + * This is used to trigger exception in the userPDs running on the DSP + **/ +typedef struct remote_rpc_process_clean_params remote_rpc_process_exception; + +/** + * Process types + * Return values for FASTRPC_REMOTE_PROCESS_TYPE control req ID for remote_handle_control + * Return values denote the type of process on remote subsystem +**/ +enum fastrpc_process_type { + PROCESS_TYPE_SIGNED, /** Signed PD running on the DSP */ + PROCESS_TYPE_UNSIGNED, /** Unsigned PD running on the DSP */ +}; + +/** + * Structure for remote_session_control, + * used with FASTRPC_REMOTE_PROCESS_TYPE request ID + * to query the type of PD running defined by enum fastrpc_process_type + * @param[in] : Domain of process + * @param[out]: Process_type belonging to enum fastrpc_process_type + */ +struct remote_process_type { + int domain; + int process_type; +}; + +/** + * DSP user PD status notification flags + * Status flags for the user PD on the DSP returned by the status notification function + * +**/ +typedef enum remote_rpc_status_flags { + FASTRPC_USER_PD_UP, /** DSP user process is up */ + FASTRPC_USER_PD_EXIT, /** DSP user process exited */ + FASTRPC_USER_PD_FORCE_KILL, /** DSP user process forcefully killed. Happens when DSP resources needs to be freed. */ + FASTRPC_USER_PD_EXCEPTION, /** Exception in the user process of DSP. */ + FASTRPC_DSP_SSR, /** Subsystem restart of the DSP, where user process is running. */ +} remote_rpc_status_flags_t; + +/** + * fastrpc_notif_fn_t + * Notification call back function + * + * @param context, context used in the registration + * @param domain, domain of the user process + * @param session, session id of user process + * @param status, status of user process + * @retval, 0 on success + */ +typedef int (*fastrpc_notif_fn_t)(void *context, int domain, int session, remote_rpc_status_flags_t status); + + +/** + * Structure for remote_session_control, + * used with FASTRPC_REGISTER_STATUS_NOTIFICATIONS request ID + * to receive status notifications of the user PD on the DSP +**/ +typedef struct remote_rpc_notif_register { + void *context; /** @param[in]: Context of the client */ + int domain; /** @param[in]: DSP domain ADSP_DOMAIN_ID, SDSP_DOMAIN_ID, or CDSP_DOMAIN_ID */ + fastrpc_notif_fn_t notifier_fn; /** @param[in]: Notification function pointer */ +} remote_rpc_notif_register_t; + +/** + * Structure used for request ID `FASTRPC_PD_INITMEM_SIZE` + * in remote session control interface + **/ +struct remote_rpc_pd_initmem_size { + int domain; /** Remote subsystem domain ID, pass -1 to set params for all domains **/ + uint32_t pd_initmem_size; /** Initial memory allocated for remote userpd, minimum value : 3MB, maximum value 200MB **/ + /** Unsupported for unsigned user PD, for unsigned user PD init mem size is fixed at 5MB **/ +}; + +/** + * Structure for remote_session_control, + * used with FASTRPC_RESERVE_SESSION request ID + * to reserve new fastrpc session of the user PD on the DSP. + * Default sesion is always 0 and remains available for any module opened without Session ID. + * New session reservation starts with session ID 1. +**/ +typedef struct remote_rpc_reserve_new_session { + char *domain_name; /** @param[in]: Domain name of DSP, on which session need to be reserved */ + uint32_t domain_name_len; /** @param[in]: Domain name length, without NULL character */ + char *session_name; /** @param[in]: Session name of the reserved sesssion */ + uint32_t session_name_len; /** @param[in]: Session name length, without NULL character */ + uint32_t effective_domain_id; /** @param[out]: Effective Domain ID is the identifier of the session. + * Effective Domain ID is the unique identifier representing the session(PD) on DSP. + * Effective Domain ID needs to be used in place of Domain ID when application has multiple sessions. + */ + uint32_t session_id; /** @param[out]: Session ID of the reserved session. + * An application can have multiple sessions(PDs) created on DSP. + * session_id 0 is the default session. Clients can reserve session starting from 1. + * Currently only 2 sessions are supported session_id 0 and session_id 1. + */ +} remote_rpc_reserve_new_session_t; + +/** + * Structure for remote_session_control, + * used with FASTRPC_GET_EFFECTIVE_DOMAIN_ID request ID + * to get effective domain id of fastrpc session on the user PD of the DSP +**/ +typedef struct remote_rpc_effective_domain_id { + char *domain_name; /** @param[in]: Domain name of DSP */ + uint32_t domain_name_len; /** @param[in]: Domain name length, without NULL character */ + uint32_t session_id; /** @param[in]: Session ID of the reserved session. 0 can be used for Default session */ + uint32_t effective_domain_id; /** @param[out]: Effective Domain ID of session */ +} remote_rpc_effective_domain_id_t; + +/** + * Structure for remote_session_control, + * used with FASTRPC_GET_URI request ID + * to get the URI needed to load the module in the fastrpc user PD on the DSP +**/ +typedef struct remote_rpc_get_uri { + char *domain_name; /** @param[in]: Domain name of DSP */ + uint32_t domain_name_len; /** @param[in]: Domain name length, without NULL character */ + uint32_t session_id; /** @param[in]: Session ID of the reserved session. 0 can be used for Default session */ + char *module_uri ; /** @param[in]: URI of the module, found in the auto-generated header file*/ + uint32_t module_uri_len; /** @param[in]: Module URI length, without NULL character */ + char *uri ; /** @param[out]: URI containing module, domain and session. + * Memory for uri need to be pre-allocated with session_uri_len size. + * Typically session_uri_len is 30 characters more than Module URI length. + * If size of uri is beyond session_uri_len, remote_session_control fails with AEE_EBADSIZE + */ + uint32_t uri_len; /** @param[in]: URI length */ +} remote_rpc_get_uri_t; + +/** + * Request IDs for remote session control interface + **/ +enum session_control_req_id { + FASTRPC_RESERVED_1, /** Reserved */ + FASTRPC_THREAD_PARAMS, /** Set thread parameters like priority and stack size */ + DSPRPC_CONTROL_UNSIGNED_MODULE, /** Handle the unsigned module offload request, to be called before remote_handle_open() */ + FASTRPC_RESERVED_2, /** Reserved */ + FASTRPC_RELATIVE_THREAD_PRIORITY, /** To increase/decrease default thread priority */ + FASTRPC_RESERVED_3, /** Reserved */ + FASTRPC_REMOTE_PROCESS_KILL, /** Kill remote process */ + FASTRPC_SESSION_CLOSE, /** Close all open handles of requested domain */ + FASTRPC_CONTROL_PD_DUMP, /** Enable PD dump feature */ + FASTRPC_REMOTE_PROCESS_EXCEPTION, /** Trigger Exception in the remote process */ + FASTRPC_REMOTE_PROCESS_TYPE, /** Query type of process defined by enum fastrpc_process_type */ + FASTRPC_REGISTER_STATUS_NOTIFICATIONS, /** Enable DSP User process status notifications */ + FASTRPC_PD_INITMEM_SIZE, /** Set signed userpd initial memory size **/ + FASTRPC_RESERVE_NEW_SESSION, /** Reserve new FastRPC session **/ + FASTRPC_GET_EFFECTIVE_DOMAIN_ID, /** Get effective domain ID of a FastRPC session */ + FASTRPC_GET_URI /** Creates the URI needed to load a module in the DSP User PD */ +}; + + +/** + * Memory map control flags for using with remote_mem_map() and remote_mem_unmap() + **/ +enum remote_mem_map_flags { +/** + * Create static memory map on remote process with default cache configuration (writeback). + * Same remoteVirtAddr will be assigned on remote process when fastrpc call made with local virtual address. + * @Map lifetime + * Life time of this mapping is until user unmap using remote_mem_unmap or session close. + * No reference counts are used. Behavior of mapping multiple times without unmap is undefined. + * @Cache maintenance + * Driver clean caches when virtual address passed through RPC calls defined in IDL as a pointer. + * User is responsible for cleaning cache when remoteVirtAddr shared to DSP and accessed out of fastrpc method invocations on DSP. + * @recommended usage + * Map buffers which are reused for long time or until session close. This helps to reduce fastrpc latency. + * Memory shared with remote process and accessed only by DSP. + */ + REMOTE_MAP_MEM_STATIC, + +/** Update REMOTE_MAP_MAX_FLAG when adding new value to this enum **/ + }; + +/** + * @enum fastrpc_map_flags for fastrpc_mmap and fastrpc_munmap + * @brief Types of maps with cache maintenance + */ +enum fastrpc_map_flags { + /** + * Map memory pages with RW- permission and CACHE WRITEBACK. + * Driver will clean cache when buffer passed in a FastRPC call. + * Same remote virtual address will be assigned for subsequent + * FastRPC calls. + */ + FASTRPC_MAP_STATIC, + + /** Reserved for compatibility with deprecated flag */ + FASTRPC_MAP_RESERVED, + + /** + * Map memory pages with RW- permission and CACHE WRITEBACK. + * Mapping tagged with a file descriptor. User is responsible for + * maintenance of CPU and DSP caches for the buffer. Get virtual address + * of buffer on DSP using HAP_mmap_get() and HAP_mmap_put() functions. + */ + FASTRPC_MAP_FD, + + /** + * Mapping delayed until user calls HAP_mmap() and HAP_munmap() + * functions on DSP. User is responsible for maintenance of CPU and DSP + * caches for the buffer. Delayed mapping is useful for users to map + * buffer on DSP with other than default permissions and cache modes + * using HAP_mmap() and HAP_munmap() functions. + */ + FASTRPC_MAP_FD_DELAYED, + + /** Reserved for compatibility **/ + FASTRPC_MAP_RESERVED_4, + FASTRPC_MAP_RESERVED_5, + FASTRPC_MAP_RESERVED_6, + FASTRPC_MAP_RESERVED_7, + FASTRPC_MAP_RESERVED_8, + FASTRPC_MAP_RESERVED_9, + FASTRPC_MAP_RESERVED_10, + FASTRPC_MAP_RESERVED_11, + FASTRPC_MAP_RESERVED_12, + FASTRPC_MAP_RESERVED_13, + FASTRPC_MAP_RESERVED_14, + FASTRPC_MAP_RESERVED_15, + + /** + * This flag is used to skip CPU mapping, + * otherwise behaves similar to FASTRPC_MAP_FD_DELAYED flag. + */ + FASTRPC_MAP_FD_NOMAP, + + /** Update FASTRPC_MAP_MAX when adding new value to this enum **/ +}; + +/** + * Attributes for remote_register_buf_attr + **/ +#define FASTRPC_ATTR_NONE 0 /** No attribute to set.*/ +#define FASTRPC_ATTR_NON_COHERENT 2 /** Attribute to map a buffer as dma non-coherent, + Driver perform cache maintenance.*/ +#define FASTRPC_ATTR_COHERENT 4 /** Attribute to map a buffer as dma coherent, + Driver skips cache maintenenace + It will be ignored if a device is marked as dma-coherent in device tree.*/ +#define FASTRPC_ATTR_KEEP_MAP 8 /** Attribute to keep the buffer persistant + until unmap is called explicitly.*/ +#define FASTRPC_ATTR_NOMAP 16 /** Attribute for secure buffers to skip + smmu mapping in fastrpc driver*/ +#define FASTRPC_ATTR_FORCE_NOFLUSH 32 /** Attribute to map buffer such that flush by driver is skipped for that particular buffer + client has to perform cache maintenance*/ +#define FASTRPC_ATTR_FORCE_NOINVALIDATE 64 /** Attribute to map buffer such that invalidate by driver is skipped for that particular buffer + client has to perform cache maintenance */ +#define FASTRPC_ATTR_TRY_MAP_STATIC 128 /** Attribute for persistent mapping a buffer + to remote DSP process during buffer registration + with FastRPC driver. This buffer will be automatically + mapped during fastrpc session open and unmapped either + at unregister or session close. FastRPC library tries + to map buffers and ignore errors in case of failure. + pre-mapping a buffer reduces the FastRPC latency. + This flag is recommended only for buffers used with + latency critical rpc calls */ + + +/** + * REMOTE_MODE_PARALLEL used with remote_set_mode + * This is the default mode for the driver. While the driver is in parallel + * mode it will try to invalidate output buffers after it transfers control + * to the dsp. This allows the invalidate operations to overlap with the + * dsp processing the call. This mode should be used when output buffers + * are only read on the application processor and only written on the aDSP. + */ +#define REMOTE_MODE_PARALLEL 0 + +/** + * REMOTE_MODE_SERIAL used with remote_set_mode + * When operating in SERIAL mode the driver will invalidate output buffers + * before calling into the dsp. This mode should be used when output + * buffers have been written to somewhere besides the aDSP. + */ +#define REMOTE_MODE_SERIAL 1 + + +#ifdef _WIN32 +#include "remote_ext.h" /** For function pointers of remote APIs */ +#endif + + +/** + * remote_handle()_open + * Opens a remote_handle "name" + * returns 0 on success + **/ +__QAIC_REMOTE_EXPORT __QAIC_RETURN int __QAIC_REMOTE(remote_handle_open)(__QAIC_IN_CHAR const char* name, __QAIC_OUT remote_handle *ph) __QAIC_REMOTE_ATTRIBUTE; +__QAIC_REMOTE_EXPORT __QAIC_RETURN int __QAIC_REMOTE(remote_handle64_open)( __QAIC_IN_CHAR const char* name, __QAIC_OUT remote_handle64 *ph) __QAIC_REMOTE_ATTRIBUTE; + + +/** + * invokes the remote handle + * see retrive macro's on dwScalars format + * pra, contains the arguments in the following order, inbufs, outbufs, inhandles, outhandles. + * implementors should ignore and pass values asis that the transport doesn't understand. + */ +__QAIC_REMOTE_EXPORT __QAIC_RETURN int __QAIC_REMOTE(remote_handle_invoke)(__QAIC_IN remote_handle h, __QAIC_IN uint32_t dwScalars, __QAIC_IN remote_arg *pra) __QAIC_REMOTE_ATTRIBUTE; +__QAIC_REMOTE_EXPORT __QAIC_RETURN int __QAIC_REMOTE(remote_handle64_invoke)(__QAIC_IN remote_handle64 h, __QAIC_IN uint32_t dwScalars, __QAIC_IN remote_arg *pra) __QAIC_REMOTE_ATTRIBUTE; + + +/** + * remote_handle()_close + * closes the remote handle + */ +__QAIC_REMOTE_EXPORT __QAIC_RETURN int __QAIC_REMOTE(remote_handle_close)(__QAIC_IN remote_handle h) __QAIC_REMOTE_ATTRIBUTE; +__QAIC_REMOTE_EXPORT __QAIC_RETURN int __QAIC_REMOTE(remote_handle64_close)(__QAIC_IN remote_handle64 h) __QAIC_REMOTE_ATTRIBUTE; + + +/** + * remote_handle_control + * Set remote handle control parameters + * + * @param req, request ID defined by handle_control_req_id + * @param data, address of structure with parameters + * @param datalen, length of data + * @retval, 0 on success + */ +__QAIC_REMOTE_EXPORT __QAIC_RETURN int __QAIC_REMOTE(remote_handle_control)(__QAIC_IN uint32_t req, __QAIC_IN_LEN(datalen) void* data, __QAIC_IN uint32_t datalen) __QAIC_REMOTE_ATTRIBUTE; +__QAIC_REMOTE_EXPORT __QAIC_RETURN int __QAIC_REMOTE(remote_handle64_control)(__QAIC_IN remote_handle64 h, __QAIC_IN uint32_t req, __QAIC_IN_LEN(datalen) void* data, __QAIC_IN uint32_t datalen) __QAIC_REMOTE_ATTRIBUTE; + + +/** + * remote_session_control + * Set remote session parameters + * + * @param req, request ID + * @param data, address of structure with parameters + * @param datalen, length of data + * @retval, 0 on success + * remote_session_control with FASTRPC_REMOTE_PROCESS_KILL req ID, possible error codes + * are AEE_ENOSUCH, AEE_EBADPARM, AEE_EINVALIDDOMAIN. Other than this errors codes treated as + * retuned from fastRPC framework. + */ +__QAIC_REMOTE_EXPORT __QAIC_RETURN int __QAIC_REMOTE(remote_session_control)(__QAIC_IN uint32_t req, __QAIC_IN_LEN(datalen) void *data, __QAIC_IN uint32_t datalen) __QAIC_REMOTE_ATTRIBUTE; + + +/** + * remote_handle()_invoke_async + * invokes the remote handle asynchronously + * + * desc, descriptor contains type of asyncjob. context and call back function(if any) + * see retrive macro's on dwScalars format + * pra, contains the arguments in the following order, inbufs, outbufs, inhandles, outhandles. + * all outbufs need to be either allocated using rpcmem_alloc or registered ION buffers using register_buf + * implementors should ignore and pass values as is that the transport doesn't understand. + */ +__QAIC_REMOTE_EXPORT __QAIC_RETURN int __QAIC_REMOTE(remote_handle_invoke_async)(__QAIC_IN remote_handle h, __QAIC_IN fastrpc_async_descriptor_t *desc, __QAIC_IN uint32_t dwScalars, __QAIC_IN remote_arg *pra) __QAIC_REMOTE_ATTRIBUTE; +__QAIC_REMOTE_EXPORT __QAIC_RETURN int __QAIC_REMOTE(remote_handle64_invoke_async)(__QAIC_IN remote_handle64 h, __QAIC_IN fastrpc_async_descriptor_t *desc, __QAIC_IN uint32_t dwScalars, __QAIC_IN remote_arg *pra) __QAIC_REMOTE_ATTRIBUTE; + + +/** + * fastrpc_async_get_status + * Get status of Async job. This can be used to query the status of a Async job + * + * @param jobid, jobid returned during Async job submission. + * @param timeout_us, timeout in micro seconds + * timeout = 0, returns immediately with status/result + * timeout > 0, waits for specified time and then returns with status/result + * timeout < 0. waits indefinetely until job completes + * @param result, integer pointer for the result of the job + * 0 on success + * error code on failure + * @retval, 0 on job completion and result of job is part of @param result + * AEE_EBUSY, if job status is pending and is not returned from DSP + * AEE_EBADPARM, if job id is invalid + * AEE_EFAILED, FastRPC internal error + * + */ +__QAIC_REMOTE_EXPORT __QAIC_RETURN int __QAIC_REMOTE(fastrpc_async_get_status)(__QAIC_IN fastrpc_async_jobid jobid,__QAIC_IN int timeout_us,__QAIC_OUT int *result); + + +/** + * fastrpc_release_async_job + * Release Async job after receiving status either through callback/poll + * + * @param jobid, jobid returned during Async job submission. + * @retval, 0 on success + * AEE_EBUSY, if job status is pending and is not returned from DSP + * AEE_EBADPARM, if job id is invalid + * + */ +__QAIC_REMOTE_EXPORT __QAIC_RETURN int __QAIC_REMOTE(fastrpc_release_async_job)(__QAIC_IN fastrpc_async_jobid jobid); + + +/** + * remote_mmap + * map memory to the remote domain + * + * @param fd, fd assosciated with this memory + * @param flags, flags to be used for the mapping + * @param vaddrin, input address + * @param size, size of buffer + * @param vaddrout, output address + * @retval, 0 on success + */ +__QAIC_REMOTE_EXPORT __QAIC_RETURN int __QAIC_REMOTE(remote_mmap)(__QAIC_IN int fd, __QAIC_IN uint32_t flags, __QAIC_IN uint32_t vaddrin, __QAIC_IN int size, __QAIC_OUT uint32_t* vaddrout) __QAIC_REMOTE_ATTRIBUTE; + + +/** + * remote_munmap + * unmap memory from the remote domain + * + * @param vaddrout, remote address mapped + * @param size, size to unmap. Unmapping a range partially may not be supported. + * @retval, 0 on success, may fail if memory is still mapped + */ +__QAIC_REMOTE_EXPORT __QAIC_RETURN int __QAIC_REMOTE(remote_munmap)(__QAIC_IN uint32_t vaddrout, __QAIC_IN int size) __QAIC_REMOTE_ATTRIBUTE; + + +/** + * remote_mem_map + * Map memory to the remote process on a selected DSP domain + * + * @domain: DSP domain ID. Use -1 for using default domain. + * Default domain is selected based on library lib(a/m/s/c)dsprpc.so library linked to application. + * @fd: file descriptor of memory + * @flags: enum remote_mem_map_flags type of flag + * @virtAddr: virtual address of buffer + * @size: buffer length + * @remoteVirtAddr[out]: remote process virtual address + * @retval, 0 on success + */ +__QAIC_REMOTE_EXPORT __QAIC_RETURN int __QAIC_REMOTE(remote_mem_map)(__QAIC_IN int domain, __QAIC_IN int fd, __QAIC_IN int flags, __QAIC_IN uint64_t virtAddr, __QAIC_IN size_t size, __QAIC_OUT uint64_t* remoteVirtAddr) __QAIC_REMOTE_ATTRIBUTE; + + +/** + * remote_mem_unmap + * Unmap memory to the remote process on a selected DSP domain + * + * @domain: DSP domain ID. Use -1 for using default domain. Get domain from multi-domain handle if required. + * @remoteVirtAddr: remote process virtual address received from remote_mem_map + * @size: buffer length + * @retval, 0 on success + */ +__QAIC_REMOTE_EXPORT __QAIC_RETURN int __QAIC_REMOTE(remote_mem_unmap)(__QAIC_IN int domain, __QAIC_IN uint64_t remoteVirtAddr, __QAIC_IN size_t size) __QAIC_REMOTE_ATTRIBUTE; + + +/** + * remote_mmap64 + * map memory to the remote domain + * + * @param fd, fd associated with this memory + * @param flags, flags to be used for the mapping + * @param vaddrin, input address + * @param size, size of buffer + * @param vaddrout, output address + * @retval, 0 on success + */ +__QAIC_REMOTE_EXPORT __QAIC_RETURN int __QAIC_REMOTE(remote_mmap64)(__QAIC_IN int fd, __QAIC_IN uint32_t flags, __QAIC_IN __QAIC_INT64PTR vaddrin, __QAIC_IN int64_t size, __QAIC_OUT __QAIC_INT64PTR *vaddrout) __QAIC_REMOTE_ATTRIBUTE; + + +/** + * remote_munmap64 + * unmap memory from the remote domain + * + * @param vaddrout, remote address mapped + * @param size, size to unmap. Unmapping a range partially may not be supported. + * @retval, 0 on success, may fail if memory is still mapped + */ +__QAIC_REMOTE_EXPORT __QAIC_RETURN int __QAIC_REMOTE(remote_munmap64)(__QAIC_IN __QAIC_INT64PTR vaddrout, __QAIC_IN int64_t size) __QAIC_REMOTE_ATTRIBUTE; + + +/** + * fastrpc_mmap + * Creates a mapping on remote process for an ION buffer with file descriptor. New fastrpc session + * will be opened if not already opened for the domain. + * + * @param domain, DSP domain ID of a fastrpc session + * @param fd, ION memory file descriptor + * @param addr, buffer virtual address on cpu + * @param offset, offset from the beginning of the buffer + * @param length, size of buffer in bytes + * @param flags, controls mapping functionality on DSP. Refer fastrpc_map_flags enum definition for more information. + * + * @return, 0 on success, error code on failure. + * AEE_EALREADY Buffer already mapped. Multiple mappings for the same buffer are not supported. + * AEE_EBADPARM Bad parameters + * AEE_EFAILED Failed to map buffer + * AEE_ENOMEMORY Out of memory (internal error) + * AEE_EUNSUPPORTED Unsupported API on the target + */ +__QAIC_REMOTE_EXPORT __QAIC_RETURN int __QAIC_REMOTE(fastrpc_mmap)(__QAIC_IN int domain, __QAIC_IN int fd, __QAIC_IN void *addr, __QAIC_IN int offset, __QAIC_IN size_t length, __QAIC_IN enum fastrpc_map_flags flags)__QAIC_REMOTE_ATTRIBUTE; + + +/** + * fastrpc_munmap + * Removes a mapping associated with file descriptor. + * + * @param domain, DSP domain ID of a fastrpc session + * @param fd, file descriptor + * @param addr, buffer virtual address used for mapping creation + * @param length, buffer length + * + * @return, 0 on success, error code on failure. + * AEE_EBADPARM Bad parameters + * AEE_EINVALIDFD Mapping not found for specified fd + * AEE_EFAILED Failed to map buffer + * AEE_EUNSUPPORTED Unsupported API on the target + */ +__QAIC_REMOTE_EXPORT __QAIC_RETURN int __QAIC_REMOTE(fastrpc_munmap)(__QAIC_IN int domain, __QAIC_IN int fd, __QAIC_IN void *addr, __QAIC_IN size_t length)__QAIC_REMOTE_ATTRIBUTE; + + +/** + * remote_register_buf/remote_register_buf_attr + * Register a file descriptor for a buffer. + * Users of fastrpc should register zero-copy buffer to enable + * sharing of that buffer to the dsp via the SMMU. The API is limited + * register buffers of sizes less than 2 GB only. Recommendation is to use + * remote_register_buf_attr2 instead. API remote_register_buf_attr2 + * can now accept can now accept 64-bit size values.. + * + * Some versions of libcdsprpc.so lack this + * function, so users should set this symbol as weak. + * + * #pragma weak remote_register_buf + * #pragma weak remote_register_buf_attr + * + * @param buf, virtual address of the buffer + * @param size, size of the buffer + * @fd, the file descriptor, callers can use -1 to deregister. + * @attr, map buffer as coherent or non-coherent + */ +__QAIC_REMOTE_EXPORT __QAIC_RETURN void __QAIC_REMOTE(remote_register_buf)(__QAIC_IN_LEN(size) void* buf, __QAIC_IN int size, __QAIC_IN int fd) __QAIC_REMOTE_ATTRIBUTE; +__QAIC_REMOTE_EXPORT __QAIC_RETURN void __QAIC_REMOTE(remote_register_buf_attr)(__QAIC_IN_LEN(size) void* buf, __QAIC_IN int size, __QAIC_IN int fd, __QAIC_IN int attr) __QAIC_REMOTE_ATTRIBUTE; + + +/** + * remote_register_buf_attr2 + * Register a file descriptor for a buffer. Users of fastrpc should + * register zero-copy buffer to enable sharing of that buffer to the + * dsp via the SMMU. + * + * Some older versions of libcdsprpc.so lack this + * function, so users should set this symbol as weak. + * + * #pragma weak remote_register_buf_attr2 + * + * @param buf, virtual address of the buffer + * @param size, size of the buffer + * @fd, the file descriptor, callers can use -1 to deregister. + * @attr, setting attribute for the mapped buffer + * refer to "Attributes for remote_register_buf_attr/remote_register_buf_attr2" + * to set the required attribute value. + */ +__QAIC_REMOTE_EXPORT __QAIC_RETURN void __QAIC_REMOTE(remote_register_buf_attr2)(__QAIC_IN_LEN(size) void* buf, __QAIC_IN size_t size, __QAIC_IN int fd, __QAIC_IN int attr) __QAIC_REMOTE_ATTRIBUTE; + + +/** + * remote_register_dma_handle/remote_register_dma_handle_attr + * Register a dma handle with fastrpc. + * This is only valid on Android with ION allocated memory. + * Users of fastrpc should register a file descriptor allocated with + * ION to enable sharing that memory to the dsp via the SMMU. + * + * Some versions of libadsprpc.so lack this function, + * so users should set this symbol as weak. + * + * #pragma weak remote_register_dma_handle + * #pragma weak remote_register_dma_handle_attr + * + * @fd, the file descriptor, callers can use -1 to deregister. + * @param len, size of the buffer + * @attr, map buffer as coherent or non-coherent or no-map + */ +__QAIC_REMOTE_EXPORT __QAIC_RETURN int __QAIC_REMOTE(remote_register_dma_handle)(__QAIC_IN int fd,__QAIC_IN uint32_t len) __QAIC_REMOTE_ATTRIBUTE; +__QAIC_REMOTE_EXPORT __QAIC_RETURN int __QAIC_REMOTE(remote_register_dma_handle_attr)(__QAIC_IN int fd,__QAIC_IN uint32_t len,__QAIC_IN uint32_t attr) __QAIC_REMOTE_ATTRIBUTE; + + +/** + * remote_register_fd + * Register a file descriptor. + * This can be used when users do not have a mapping to pass to the + * RPC layer. The generated address is a mapping with PROT_NONE, any + * access to this memory will fail, so it should only be used as an + * ID to identify this file descriptor to the RPC layer. This API is + * limited to buffer sizes less than 2 GB. Recommendation is to use + * remote_register_fd2 for buffers allocation of any size. + * + * To deregister use remote_register_buf(addr, size, -1). + * + * #pragma weak remote_register_fd + * + * @param fd, the file descriptor. + * @param size, size to of the buffer + * @retval, (void*)-1 on failure, address on success. + */ +__QAIC_REMOTE_EXPORT __QAIC_RETURN void *__QAIC_REMOTE(remote_register_fd)(__QAIC_IN int fd,__QAIC_IN int size) __QAIC_REMOTE_ATTRIBUTE; + +/** + * remote_register_fd2 + * Register a file descriptor. + * This can be used when users do not have a mapping to pass to + * the RPC layer. The generated address is a mapping with PROT_NONE, + * any access to this memory will fail, so it should only be used + * as an ID to identify this file descriptor to the RPC layer. + * + * To deregister use remote_register_buf(addr, size, -1). + * + * #pragma weak remote_register_fd2 + * + * @param fd, the file descriptor. + * @param size, size to of the buffer + * @retval, (void*)-1 on failure, address on success. + */ +__QAIC_REMOTE_EXPORT __QAIC_RETURN void *__QAIC_REMOTE(remote_register_fd2)(__QAIC_IN int fd,__QAIC_IN size_t size) __QAIC_REMOTE_ATTRIBUTE; + + +#ifdef __cplusplus +} +#endif + +#endif /// REMOTE_H diff --git a/inc/remote64.h b/inc/remote64.h new file mode 100644 index 0000000..056d7c9 --- /dev/null +++ b/inc/remote64.h @@ -0,0 +1,12 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef REMOTE64_H +#define REMOTE64_H + +#include "remote.h" + +/* +All the functions declared here are moved to remote.h, remote64.h will be deleted in future. +*/ +#endif // REMOTE64_H diff --git a/inc/remotectl.h b/inc/remotectl.h new file mode 100644 index 0000000..4afc7c8 --- /dev/null +++ b/inc/remotectl.h @@ -0,0 +1,52 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _REMOTECTL_H +#define _REMOTECTL_H +#include +#include + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE +#ifdef __cplusplus +extern "C" { +#endif +#if !defined(__QAIC_STRING1_OBJECT_DEFINED__) && !defined(__STRING1_OBJECT__) +#define __QAIC_STRING1_OBJECT_DEFINED__ +#define __STRING1_OBJECT__ +typedef struct _cstring1_s { + char* data; + int dataLen; +} _cstring1_t; + +#endif /* __QAIC_STRING1_OBJECT_DEFINED__ */ +#define _const_remotectl_handle 0 +__QAIC_HEADER_EXPORT int __QAIC_HEADER(remotectl_open)(const char* name, int* handle, char* dlerror, int dlerrorLen, int* nErr) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(remotectl_close)(int handle, char* dlerror, int dlerrorLen, int* nErr) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(remotectl_grow_heap)(uint32 phyAddr, uint32 nSize) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(remotectl_set_param)(int reqID, const uint32* params, int paramsLen) __QAIC_HEADER_ATTRIBUTE; +#ifdef __cplusplus +} +#endif +#endif //_REMOTECTL_H diff --git a/inc/remotectl1.h b/inc/remotectl1.h new file mode 100644 index 0000000..9723490 --- /dev/null +++ b/inc/remotectl1.h @@ -0,0 +1,273 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _REMOTECTL1_H +#define _REMOTECTL1_H +#include +#include +#include +#include + + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#include + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef _ATTRIBUTE_VISIBILITY + +#ifdef _WIN32 +#define _ATTRIBUTE_VISIBILITY +#else +#define _ATTRIBUTE_VISIBILITY __attribute__ ((visibility("default"))) +#endif + +#endif // _ATTRIBUTE_VISIBILITY + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i = 0; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#ifdef _WIN32 +#define _QAIC_FARF(level, msg, ...) (void)0 +#else +#define _QAIC_FARF(level, msg, ...) \ + do {\ + if(0 == (HAP_debug_v2) ) {\ + (void)0; \ + } else { \ + FARF(level, msg , ##__VA_ARGS__); \ + } \ + }while(0) +#endif //_WIN32 for _QAIC_FARF + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _TRY_FARF(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + goto ee##farf##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _CATCH_FARF(exception) exception##farf##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#endif + + +#endif // _QAIC_ENV_H + +#ifdef __cplusplus +extern "C" { +#endif +#if !defined(__QAIC_STRING1_OBJECT_DEFINED__) && !defined(__STRING1_OBJECT__) +#define __QAIC_STRING1_OBJECT_DEFINED__ +#define __STRING1_OBJECT__ +typedef struct _cstring1_s { + char* data; + int dataLen; +} _cstring1_t; + +#endif /* __QAIC_STRING1_OBJECT_DEFINED__ */ +#define _const_remotectl1_handle 8 +/** + * Opens the handle in the specified domain. If this is the first + * handle, this creates the session. Typically this means opening + * the device, aka open("/dev/adsprpc-smd"), then calling ioctl + * device APIs to create a PD on the DSP to execute our code in, + * then asking that PD to dlopen the .so and dlsym the skel function. + * + * @param uri, _URI"&_dom=aDSP" + * _URI is a QAIC generated uri, or + * "file:///?_skel_handle_invoke&_modver=1.0" + * If the _dom parameter is not present, _dom=DEFAULT is assumed + * but not forwarded. + * Reserved uri keys: + * [0]: first unamed argument is the skel invoke function + * _dom: execution domain name, _dom=mDSP/aDSP/DEFAULT + * _modver: module version, _modver=1.0 + * _*: any other key name starting with an _ is reserved + * Unknown uri keys/values are forwarded as is. + * @param h, resulting handle + * @retval, 0 on success + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(remotectl1_open)(const char* uri, remote_handle64* h) __QAIC_HEADER_ATTRIBUTE; +/** + * Closes a handle. If this is the last handle to close, the session + * is closed as well, releasing all the allocated resources. + + * @param h, the handle to close + * @retval, 0 on success, should always succeed + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(remotectl1_close)(remote_handle64 h) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(remotectl1_open1)(remote_handle64 _h, const char* name, int* handle, char* dlerror, int dlerrorLen, int* nErr) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(remotectl1_close1)(remote_handle64 _h, int handle, char* dlerror, int dlerrorLen, int* nErr) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(remotectl1_grow_heap)(remote_handle64 _h, uint32 phyAddr, uint32 nSize) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(remotectl1_set_param)(remote_handle64 _h, int reqID, const uint32* params, int paramsLen) __QAIC_HEADER_ATTRIBUTE; +#ifndef remotectl1_URI +#define remotectl1_URI "file:///libremotectl1_skel.so?remotectl1_skel_handle_invoke&_modver=1.0" +#endif /*remotectl1_URI*/ +#ifdef __cplusplus +} +#endif +#endif //_REMOTECTL1_H diff --git a/inc/rpcmem.h b/inc/rpcmem.h new file mode 100644 index 0000000..079e3f5 --- /dev/null +++ b/inc/rpcmem.h @@ -0,0 +1,221 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef RPCMEM_H +#define RPCMEM_H + +#include "AEEStdDef.h" +#include "stddef.h" + +/** + * @file rpcmem.h + * @brief APIs used to manage memory allocated by the application processor and shared with the DSP. + */ + +/** @defgroup rpcmem_const RPCMEM API macros and enumerations + * @{ + */ + +/** + * Allocate memory with the same properties as the ION_FLAG_CACHED flag. + */ +#ifdef ION_FLAG_CACHED +#define RPCMEM_DEFAULT_FLAGS ION_FLAG_CACHED +#else +#define RPCMEM_DEFAULT_FLAGS 1 +#endif + +/** + * The FastRPC library tries to map buffers allocated with this flag to the remote process of all current and new + * FastRPC sessions. In case of failure to map, the FastRPC library ignores the error and continues to open the session + * without pre-mapping the buffer. In case of success, buffers allocated with this flag will be pre-mapped to reduce + * the latency of upcoming FastRPC calls. This flag is recommended only for buffers that are used with latency-critical + * FastRPC methods. Pre-mapped buffers will be unmapped during either buffer free or session close. + */ +#define RPCMEM_TRY_MAP_STATIC 0x04000000 + +/** + * Supported RPCMEM heap IDs. + * + * If you are not using any of the RPCMEM-defined heap IDs, + * you are responsible for ensuring that you are passing + * a valid ION heap ID. + */ +enum rpc_heap_ids { +/** + * Memory for secure use cases only. + * * Secure heap is to be used only by clients migrating to CPZ + */ + RPCMEM_HEAP_ID_SECURE = 9, +/** + * Contiguous physical memory: + * * Very limited memory is available (< 8 MB) + * * Recommended for subsystems without SMMU (sDSP and mDSP) + * * Contiguous heap memory will be deprecated from archs after v73 + */ + RPCMEM_HEAP_ID_CONTIG = 22, +/** + * Non-contiguous system physical memory. + * * Recommended for all use cases that do not require using a specific heap + * * Used with subsystems with SMMU (cDSP and aDSP) + */ + RPCMEM_HEAP_ID_SYSTEM = 25, + }; + +/** + * Use uncached memory. + */ +#define RPCMEM_FLAG_UNCACHED 0 + +/** + * Use cached memory. + */ +#define RPCMEM_FLAG_CACHED RPCMEM_DEFAULT_FLAGS + +/** + * @} + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup rpcmem_api RPCMEM API functions + * @{ + */ + +/** + * Initialize the RPCMEM Library. + * + * Only call this function once before using the RPCMEM Library. + * + * This API is mandatory on pre-Lahaina targets IF the client has linked to the + * rpcmem.a static library. If the client has only linked libadsprpc.so, + * libcdsprpc.so, or libsdsprpc.so, then the rpcmem_init call is not required + * on any target and other rpcmem APIs such as rpcmem_alloc can be called + * directly. + * + * NOTE: This function is not thread safe. + */ +void rpcmem_init(void); + +/** + * Deinitialize the RPCMEM Library. + * + * Only call this function once when the RPCMEM Library is no longer required. + * + * This API is mandatory on pre-Lahaina targets IF the client has linked to the + * rpcmem.a static library. If the client has only linked libadsprpc.so, + * libcdsprpc.so, or libsdsprpc.so, then the rpcmem_deinit call is not required + * on any target. + * + * NOTE: This function is not thread safe. + */ +void rpcmem_deinit(void); + +/** + * Allocate a zero-copy buffer for size upto 2 GB with the FastRPC framework. + * Buffers larger than 2 GB must be allocated with rpcmem_alloc2 + * @param[in] heapid Heap ID to use for memory allocation. + * @param[in] flags ION flags to use for memory allocation. + * @param[in] size Buffer size to allocate. + * @return Pointer to the buffer on success; NULL on failure. + * + * Examples: + * + * * Default memory attributes, 2 KB + * @code + * rpcmem_alloc(RPCMEM_HEAP_ID_SYSTEM, RPCMEM_DEFAULT_FLAGS, 2048); + * @endcode + * Or + * @code + * rpcmem_alloc_def(2048); + * @endcode + * + * * Heap 22, uncached, 1 KB + * @code + * rpcmem_alloc(22, 0, 1024); + * @endcode + * Or + * @code + * rpcmem_alloc(22, RPCMEM_FLAG_UNCACHED, 1024); + * @endcode + * + * * Heap 21, cached, 2 KB + * @code + * rpcmem_alloc(21, RPCMEM_FLAG_CACHED, 2048); + * @endcode + * Or + * @code + * #include + * rpcmem_alloc(21, ION_FLAG_CACHED, 2048); + * @endcode + * + * * Default memory attributes but from heap 18, 4 KB + * @code + * rpcmem_alloc(18, RPCMEM_DEFAULT_FLAGS, 4096); + * @endcode + */ +void* rpcmem_alloc(int heapid, uint32 flags, int size); + +/** + * Allocate a zero-copy buffer with the FastRPC framework. + * @param[in] heapid Heap ID to use for memory allocation. + * @param[in] flags ION flags to use for memory allocation. + * @param[in] size Buffer size to allocate. + * @return Pointer to the buffer on success; NULL on failure. + * + * Examples: + * + * * The usage examples are same as rpcmem_alloc. + */ +void* rpcmem_alloc2(int heapid, uint32 flags, size_t size); + +/** + * Allocate a buffer with default settings. + * @param[in] size Size of the buffer to be allocated. + * @return Pointer to the allocated memory buffer. + */ + #if !defined(WINNT) && !defined (_WIN32_WINNT) +__attribute__((unused)) +#endif +static __inline void* rpcmem_alloc_def(int size) { + return rpcmem_alloc(RPCMEM_HEAP_ID_SYSTEM, RPCMEM_DEFAULT_FLAGS, size); +} + +/** + * Free a buffer and ignore invalid buffers. + */ +void rpcmem_free(void* po); + +/** + * Return an associated file descriptor. + * @param[in] po Data pointer for an RPCMEM-allocated buffer. + * @return Buffer file descriptor. + */ +int rpcmem_to_fd(void* po); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +//! @cond Doxygen_Suppress +/** These macros are deprecated. + */ +#define RPCMEM_DEFAULT_HEAP -1 +#define RPCMEM_HEAP_DEFAULT 0x80000000 +#define RPCMEM_HEAP_NOREG 0x40000000 +#define RPCMEM_HEAP_UNCACHED 0x20000000 +#define RPCMEM_HEAP_NOVA 0x10000000 +#define RPCMEM_HEAP_NONCOHERENT 0x08000000 +#define RPCMEM_FORCE_NOFLUSH 0x01000000 +#define RPCMEM_FORCE_NOINVALIDATE 0x02000000 +// Use macros from libion instead +#define ION_SECURE_FLAGS ((1 << 31) | (1 << 19)) +//! @endcond + +#endif //RPCMEM_H diff --git a/inc/rpcmem_internal.h b/inc/rpcmem_internal.h new file mode 100644 index 0000000..62e8afa --- /dev/null +++ b/inc/rpcmem_internal.h @@ -0,0 +1,23 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef __RPCMEM_INTERNAL_H__ +#define __RPCMEM_INTERNAL_H__ + +#include "rpcmem.h" + +/* + * returns an file descriptor associated with the address + */ +int rpcmem_to_fd_internal(void *po); +/* + * allocates dma memory of size, from specific heap mentioned in heapid. + * flags are not used for now + */ +void *rpcmem_alloc_internal(int heapid, uint32 flags, size_t size); +/* + * frees the allocated memory from dma + */ +void rpcmem_free_internal(void *po); + +#endif /*__RPCMEM_INTERNAL_H__*/ diff --git a/inc/sbuf.h b/inc/sbuf.h new file mode 100644 index 0000000..aed1174 --- /dev/null +++ b/inc/sbuf.h @@ -0,0 +1,151 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef SBUF_H +#define SBUF_H + +#include +#include +#include "AEEstd.h" + +/** + * lightweight serialize/deserialize buffer. + + For example + + struct sbuf; + //initialize empty buffer; + sbuf_init(&sbuf, 0, 0, 0); + + //fill it with data + sbuf_align(&sbuf, 8); + sbuf_write(&sbuf, ptr1, 10); + sbuf_align(&sbuf, 8); + sbuf_write(&sbuf, ptr2, 20); + + //allocate the memory needed + mem = malloc(sbuf_needed(&sbuf)); + + //initialize with the data + sbuf_init(&sbuf, 0, mem, sbuf_needed(&sbuf)); + + //fill it with data, since it has memory, it will actually copy + sbuf_align(&sbuf, 8); + sbuf_write(&sbuf, ptr1, 10); + sbuf_align(&sbuf, 8); + sbuf_write(&sbuf, ptr2, 20); + + See sbuf_q.c for more examples + */ + + +struct sbuf { + uintptr_t buf; //! start of valid memory + uintptr_t bufEnd; //! end of valid memory + uintptr_t bufStart; //! start with optinal offset from valid mem + uintptr_t bufCur; //! current position, could be outside of valid range +}; + +/** + * @param buf, the buffer structure instance + * @param offset, this value indicates how far ahead the data buffer is + * start = data - offset + * @param data, the valid memory + * @param dataLen, the length ov valid memory + */ +static __inline void sbuf_init(struct sbuf* buf, int offset, void* data, int dataLen) { + buf->buf = (uintptr_t)data; + buf->bufStart = buf->bufCur = (uintptr_t)data - offset; + buf->bufEnd = (uintptr_t)data + dataLen; +} + +//! move the current pointer by len +static __inline void sbuf_advance(struct sbuf* buf, int len) { + buf->bufCur += len; +} + +/** + * @retval, the amount of memory needed for everything from the start (with the offset) + * to the current position of the buffer + */ +static __inline int sbuf_needed(struct sbuf* buf) { + return buf->bufCur - buf->bufStart; +} +/** + * @retval, the space left in the buffer. A negative value indicates overflow. + * A positive value includes the offset. + */ +static __inline int sbuf_left(struct sbuf* buf) { + int result; + __builtin_sub_overflow(buf->bufEnd, buf->bufCur, &result); + return result; +} + +//! @retval the current head pointer +static __inline void* sbuf_head(struct sbuf* buf) { + return (void*)buf->bufCur; +} + +//! @retval true if the current pointer is valid +static __inline int sbuf_valid(struct sbuf* buf) { + return buf->bufCur >= buf->buf && buf->bufCur < buf->bufEnd; +} + +//! advance the head pointer so the "needed" is aligned to the align value +#define _SBUF_ALIGN(x, y) (((x) + ((y)-1)) & ~((y)-1)) +static __inline void sbuf_align(struct sbuf* buf, uint32_t align) { + sbuf_advance(buf, _SBUF_ALIGN(sbuf_needed(buf), align) - sbuf_needed(buf)); +} + +/** + * Write to the buffer. + * @param src, the memory to read from. Will write srcLen bytes to buf from src + * from the buf's current position. Only the valid portion of data will + * be written. + * @param srcLen, the length of src. The buffer will be advanced by srcLen. + */ +static __inline void sbuf_write(struct sbuf* buf, void *psrc, int srcLen) { + uintptr_t src = (uintptr_t)psrc; + if(buf->bufCur + srcLen > buf->buf) { + int writeLen; + if(buf->bufCur < buf->buf) { + int len = buf->buf - buf->bufCur; + srcLen -= len; + src += len; + sbuf_advance(buf, len); + } + writeLen = STD_MIN(srcLen, sbuf_left(buf)); + if(writeLen > 0) { + std_memsmove((void*)buf->bufCur, buf->bufEnd - buf->bufCur, (void*)src, writeLen); + } + } + sbuf_advance(buf, srcLen); +} + +/** + * Read from the buffer into dst. + * @param dst, the data to write to. Will write dstLen to dst from buf + * from the current position of buf. Only valid memory + * will be written to dst. Invalid overlapping memory will + * remain untouched. + * @param dstLen, the length of dst. buf will be advanced by dstLen + */ +static __inline void sbuf_read(struct sbuf* buf, void *pdst, int dstLen) { + uintptr_t dst = (uintptr_t)pdst; + if(buf->bufCur + dstLen > buf->buf) { + int readLen; + if(buf->bufCur < buf->buf) { + int len = buf->buf - buf->bufCur; + dstLen -= len; + dst += len; + sbuf_advance(buf, len); + } + readLen = STD_MIN(dstLen, sbuf_left(buf)); + if(readLen > 0) { + std_memsmove((void*)dst, dstLen, (void*)buf->bufCur, readLen); + } + } + sbuf_advance(buf, dstLen); +} + +#endif diff --git a/inc/sbuf_parser.h b/inc/sbuf_parser.h new file mode 100644 index 0000000..b01b33a --- /dev/null +++ b/inc/sbuf_parser.h @@ -0,0 +1,240 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef SBUF_PARSER_H +#define SBUF_PARSER_H + +#include "sbuf.h" + +/** + * Greedy Recursive Descent Parser in C + * + * Stop using strstr or regular expressions. This simple Recursive Descent Parser can be + * used to handle complex grammars. + * + * For example: + * parsing a query string form a uri + * input: "file:///foo/bar_far.so.1?_blah1&_bar=barval5&_barfar" + * expected output: + * parsed query: _blah1 = + * parsed query: _bar = barval5 + * parsed query: _barfar = + * + * static int qmark(struct sbuf *buf) { + * return sbuf_char(buf, '?'); + * } + * static int notandoreq(struct sbuf *buf) { + * return sbuf_notchars(buf, "&="); + * } + * static int notand(struct sbuf *buf) { + * return sbuf_notchar(buf, '&'); + * } + * + * const char *name; + * int nameLen; + * const char *value; + * int valueLen; + * const char *data = "file:///foo/bar_far.so.1?_blah1&_bar=barval5&_barfar"; + * + * //initialize + * sbuf_parser_init(&buf, data, strlen(data)); + * + * //parse until question mark + * assert(sbuf_until(&buf, sbuf_any, qmark)); + * + * //parse each query + * while(!sbuf_end(&buf)) { + * //record where the name starts + * name = sbuf_cur(&buf); + * + * //name is valid until '=' or '&' + * assert(sbuf_many1(&buf, notandoreq)); + * nameLen = sbuf_cur(&buf) - name; + * + * value = 0; + * valueLen = 0; + * //if the next char is a '=' then we also get a value + * if(sbuf_char(&buf, '=')) { + * value = sbuf_cur(&buf); + * + * //value is until the next query that starts with '&' + * assert(sbuf_many1(&buf, notand)); + * valueLen = sbuf_cur(&buf) - value; + * } + * //expect '&' or end + * sbuf_char(&buf, '&'); + * printf("parsed query: %.*s = %.*s\n", nameLen, name, valueLen, value); + * } + * + */ + +//! init +static __inline void sbuf_parser_init(struct sbuf* buf, const char *data, int dataLen) { + sbuf_init(buf, 0, (void*)data, dataLen); +} + +//! current postiion +static __inline char *sbuf_cur(struct sbuf* buf) { + return (char*)sbuf_head(buf); +} + +//! look at the next character if the buffer is still valid +static __inline int sbuf_peek(struct sbuf* buf, char* c) { + if(!sbuf_valid(buf)) { + return 0; + } + *c = *sbuf_cur(buf); + return 1; +} + +//! returns true if the buffer is ended +static __inline int sbuf_end(struct sbuf* buf) { + return sbuf_left(buf) == 0; +} + +//! consume 1 char if its in string chars +static __inline int sbuf_chars(struct sbuf *buf, const char *chars) { + int i = 0; + char c; + if(!sbuf_peek(buf, &c)) { + return 0; + } + for(i = 0; chars[i] != 0; ++i) { + if(c == chars[i]) { + sbuf_advance(buf, 1); + return 1; + } + } + return 0; +} + +//! consume 1 char only if its not in string chars +static __inline int sbuf_notchars(struct sbuf *buf, const char *chars) { + int i = 0; + char c; + if(!sbuf_peek(buf, &c)) { + return 0; + } + for(i = 0; chars[i] != 0; ++i) { + if(c == chars[i]) { + return 0; + } + } + sbuf_advance(buf, 1); + return 1; +} + +//! consume only char t +static __inline int sbuf_char(struct sbuf *buf, const char t) { + char str[2] = {t, 0}; + return sbuf_chars(buf, str); +} + +//! consume any char except for t +static __inline int sbuf_notchar(struct sbuf *buf, const char t) { + char str[2] = {t, 0}; + return sbuf_notchars(buf, str); +} + +/** + * consume any char + */ +static __inline int sbuf_any(struct sbuf* buf) { + return sbuf_notchars(buf, ""); +} + + +/** + * range is pairs of characters + * + * pairs are inclusive, start must be less then or equal then the end + * + * for example: AZaz09--.. + * matches uppercase and lowercase letters, numbers, dashes and dots + * + */ +static __inline int sbuf_range(struct sbuf *buf, const char *chars) { + int i, j; + char c; + if(!sbuf_peek(buf, &c)) { + return 0; + } + for(i = 0, j = 1; chars[i] != 0 && chars[j] != 0; i+=2,j+=2) { + if(c >= chars[i] && c <= chars[j]) { + sbuf_advance(buf, 1); + return 1; + } + } + return 0; +} + + +/** + * greedly consume and match the entire string + * empty string always succeeds without consuming any data + */ +static __inline int sbuf_string(struct sbuf *buf, const char *str) { + int i = 0; + for(i = 0; str[i] != 0; ++i) { + if(!sbuf_char(buf, str[i])) { + return 0; + } + } + return 1; +} + +/** + * consumes until fails + */ +static __inline int sbuf_many(struct sbuf *buf, + int(*consume)(struct sbuf *buf)) +{ + if(!sbuf_valid(buf)) { + return 0; + } + while(consume(buf)) {;} + return 1; +} +/** + * consumes until fails, must consume at least 1 + */ +static __inline int sbuf_many1(struct sbuf *buf, + int(*consume)(struct sbuf *buf)) +{ + if(!consume(buf)) { + return 0; + } + sbuf_many(buf, consume); + return 1; +} +/** + * runs 'consume' until 'stop' succeeds + * 'stop' must fail in such a way that it doesn't consume any data + */ +static __inline int sbuf_until(struct sbuf *buf, + int(*consume)(struct sbuf *buf), + int(*stop)(struct sbuf *buf)) +{ + while(!stop(buf)) { + if(!consume(buf)) { + return 0; + } + } + return 1; +} + +/** + * allows for backtracking, + * @param parser, runs parser and only consume if it succeeds + */ +static __inline int sbuf_try(struct sbuf *buf, int(*parser)(struct sbuf *buf)) +{ + struct sbuf tryp; + sbuf_parser_init(&tryp, sbuf_cur(buf), sbuf_left(buf)); + if(parser(&tryp)) { + sbuf_advance(buf, sbuf_cur(&tryp) - sbuf_cur(buf)); + return 1; + } + return 0; +} +#endif // SBUF_PARSER_H diff --git a/inc/shared.h b/inc/shared.h new file mode 100644 index 0000000..a6b5f42 --- /dev/null +++ b/inc/shared.h @@ -0,0 +1,55 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef SHARED_H +#define SHARED_H + +#if defined(__NIX) +// TODO these sections not supported? +//static __so_func *__autostart[] __attribute__((section (".CRT$XIU"))) = { (__so_func*)__so_ctor }; +//static __so_func *__autoexit[] __attribute__((section (".CRT$XPU"))) = { (__so_func*)__so_dtor }; + +#define SHARED_OBJECT_API_ENTRY(ctor, dtor) + +#elif defined(_WIN32) +#include + +typedef int __so_cb(void); +static __so_cb *__so_get_ctor(); +static __so_cb *__so_get_dtor(); + +typedef void __so_func(void); +static void __so_ctor() { + (void)(__so_get_ctor())(); +} + +static void __so_dtor() { + (void)(__so_get_dtor())(); +} + +#pragma data_seg(".CRT$XIU") + static __so_func *__autostart[] = { (__so_func*)__so_ctor }; +#pragma data_seg(".CRT$XPU") + static __so_func *__autoexit[] = { (__so_func*)__so_dtor }; +#pragma data_seg() + +#define SHARED_OBJECT_API_ENTRY(ctor, dtor)\ + static __so_cb *__so_get_ctor() { return (__so_cb*)ctor; }\ + static __so_cb *__so_get_dtor() { return (__so_cb*)dtor; } + +#else //better be gcc + +#define SHARED_OBJECT_API_ENTRY(ctor, dtor)\ +__attribute__((constructor)) \ +static void __ctor__##ctor(void) {\ + (void)ctor();\ +}\ +\ +__attribute__((destructor))\ +static void __dtor__##dtor(void) {\ + (void)dtor();\ +} + +#endif //ifdef _WIN32 + +#endif // SHARED_H diff --git a/inc/std_dtoa.h b/inc/std_dtoa.h new file mode 100644 index 0000000..5f680be --- /dev/null +++ b/inc/std_dtoa.h @@ -0,0 +1,111 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef STD_DTOA_H +#define STD_DTOA_H + +// +// Constant Definitions +// + +// For floating point numbers, the range of a double precision number is +// approximately +/- 10 ^ 308.25 as per the IEEE Standard 754. +// As such, the maximum size of the integer portion of the +// string is assumed to be 311 (309 + sign + \0). The maximum +// size of the fractional part is assumed to be 100. Thus, the +// maximum size of the string that would contain the number +// after conversion is safely assumed to be 420 (including any +// prefix, the null character and exponent specifiers 'e'). +// +// The buffers that contain the converted integer and the fraction parts of +// the float are safely assumed to be of size 310. +#define STD_DTOA_FORMAT_FLOAT_SIZE 420 +#define STD_DTOA_FORMAT_INTEGER_SIZE 311 +#define STD_DTOA_FORMAT_FRACTION_SIZE 100 + +// Constants for operations on the IEEE 754 representation of double +// precision floating point numbers. +#define STD_DTOA_DP_SIGN_SHIFT_COUNT 63 +#define STD_DTOA_DP_EXPONENT_SHIFT_COUNT 52 +#define STD_DTOA_DP_EXPONENT_MASK 0x7ff +#define STD_DTOA_DP_EXPONENT_BIAS 1023 +#define STD_DTOA_DP_MANTISSA_MASK ( ( (uint64)1 << 52 ) - 1 ) +#define STD_DTOA_DP_INFINITY_EXPONENT_ID 0x7FF +#define STD_DTOA_DP_MAX_EXPONENT 1023 +#define STD_DTOA_DP_MIN_EXPONENT_NORM -1022 +#define STD_DTOA_DP_MIN_EXPONENT_DENORM -1074 +#define STD_DTOA_DP_MAX_EXPONENT_DEC 308 +#define STD_DTOA_DP_MIN_EXPONENT_DEC_DENORM -323 + +#define STD_DTOA_PRECISION_ROUNDING_VALUE 4 +#define STD_DTOA_DEFAULT_FLOAT_PRECISION 6 + +#define STD_DTOA_NEGATIVE_INF_UPPER_CASE "-INF" +#define STD_DTOA_NEGATIVE_INF_LOWER_CASE "-inf" +#define STD_DTOA_POSITIVE_INF_UPPER_CASE "INF" +#define STD_DTOA_POSITIVE_INF_LOWER_CASE "inf" +#define STD_DTOA_NAN_UPPER_CASE "NAN" +#define STD_DTOA_NAN_LOWER_CASE "nan" +#define STD_DTOA_FP_POSITIVE_INF 0x7FF0000000000000uLL +#define STD_DTOA_FP_NEGATIVE_INF 0xFFF0000000000000uLL +#define STD_DTOA_FP_SNAN 0xFFF0000000000001uLL +#define STD_DTOA_FP_QNAN 0xFFFFFFFFFFFFFFFFuLL + +// +// Useful Macros +// + +#define MY_ISDIGIT(c) ( ( (c) >= '0' ) && ( (c) <= '9' ) ) +#define FP_EXPONENT(u) ( ( ( (u) >> STD_DTOA_DP_EXPONENT_SHIFT_COUNT ) \ + & STD_DTOA_DP_EXPONENT_MASK ) - STD_DTOA_DP_EXPONENT_BIAS ) +#define FP_EXPONENT_BIASED(u) ( ( (u) >> STD_DTOA_DP_EXPONENT_SHIFT_COUNT ) \ + & STD_DTOA_DP_EXPONENT_MASK ) +#define FP_MANTISSA_NORM(u) ( ( (u) & STD_DTOA_DP_MANTISSA_MASK ) | \ + ( (uint64)1 << STD_DTOA_DP_EXPONENT_SHIFT_COUNT ) ) +#define FP_MANTISSA_DENORM(u) ( (u) & STD_DTOA_DP_MANTISSA_MASK ) +#define FP_MANTISSA(u) ( FP_EXPONENT_BIASED(u) ? FP_MANTISSA_NORM(u) : \ + FP_MANTISSA_DENORM(u) ) +#define FP_SIGN(u) ( (u) >> STD_DTOA_DP_SIGN_SHIFT_COUNT ) +#define DOUBLE_TO_UINT64(d) ( *( (uint64*) &(d) ) ) +#define DOUBLE_TO_INT64(d) ( *( (int64*) &(d) ) ) +#define UINT64_TO_DOUBLE(u) ( *( (double*) &(u) ) ) + +// +// Type Definitions +// + +typedef enum +{ + FP_TYPE_UNKOWN = 0, + FP_TYPE_NEGATIVE_INF, + FP_TYPE_POSITIVE_INF, + FP_TYPE_NAN, + FP_TYPE_GENERAL, +} FloatingPointType; + +// +// Function Declarations +// + +#ifdef __cplusplus +extern "C" { +#endif // #ifdef __cplusplus + +double fp_pow_10( int nPow ); +double fp_round( double dNumber, int nPrecision ); +int fp_log_10( double dNumber ); +int fp_check_special_cases( double dNumber, FloatingPointType* pNumberType ); +int std_dtoa_decimal( double dNumber, int nPrecision, + char acIntegerPart[ STD_DTOA_FORMAT_INTEGER_SIZE ], + char acFractionPart[ STD_DTOA_FORMAT_FRACTION_SIZE ] ); +int std_dtoa_hex( double dNumber, int nPrecision, char cFormat, + char acIntegerPart[ STD_DTOA_FORMAT_INTEGER_SIZE ], + char acFractionPart[ STD_DTOA_FORMAT_FRACTION_SIZE ], + int* pnExponent ); + +#ifdef __cplusplus +} +#endif // #ifdef __cplusplus + +#endif // STD_DTOA_H + diff --git a/inc/uthash.h b/inc/uthash.h new file mode 100644 index 0000000..045e79a --- /dev/null +++ b/inc/uthash.h @@ -0,0 +1,920 @@ +/* +Copyright (c) 2003-2011, Troy D. Hanson http://uthash.sourceforge.net +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef UTHASH_H +#define UTHASH_H + +#include /* memcmp,strlen */ +#include /* ptrdiff_t */ +#include /* exit() */ + +/* These macros use decltype or the earlier __typeof GNU extension. + As decltype is only available in newer compilers (VS2010 or gcc 4.3+ + when compiling c++ source) this code uses whatever method is needed + or, for VS2008 where neither is available, uses casting workarounds. */ +#ifdef _MSC_VER /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#define DECLTYPE(x) (decltype(x)) +#else /* VS2008 or older (or VS2010 in C mode) */ +#define NO_DECLTYPE +#define DECLTYPE(x) +#endif +#else /* GNU, Sun and other compilers */ +#define DECLTYPE(x) (__typeof(x)) +#endif + +#ifdef NO_DECLTYPE +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + char **_da_dst = (char**)(&(dst)); \ + *_da_dst = (char*)(src); \ +} while(0) +#else +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + (dst) = DECLTYPE(dst)(src); \ +} while(0) +#endif + +/* a number of the hash function use uint32_t which isn't defined on win32 */ +#ifdef _MSC_VER +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#else +#include /* uint32_t */ +#endif + +#define UTHASH_VERSION 1.9.4 + +#ifndef UTHASH_MALLOC +#define UTHASH_MALLOC malloc +#endif + +#ifndef UTHASH_FREE +#define UTHASH_FREE free +#endif + +#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ +#define uthash_malloc(sz) UTHASH_MALLOC(sz) /* malloc fcn */ +#define uthash_free(ptr,sz) UTHASH_FREE(ptr) /* free fcn */ + +#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ +#define uthash_expand_fyi(tbl) /* can be defined to log expands */ + +/* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */ +#define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */ + +/* calculate the element whose hash handle address is hhe */ +#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) + +#define HASH_FIND(hh,head,keyptr,keylen,out) \ +do { \ + unsigned _hf_bkt,_hf_hashv; \ + out=NULL; \ + if (head) { \ + HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \ + if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \ + HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \ + keyptr,keylen,out); \ + } \ + } \ +} while (0) + +#ifdef HASH_BLOOM +#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM) +#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0) +#define HASH_BLOOM_MAKE(tbl) \ +do { \ + (tbl)->bloom_nbits = HASH_BLOOM; \ + (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ + if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \ + memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \ + (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ +} while (0); + +#define HASH_BLOOM_FREE(tbl) \ +do { \ + uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ +} while (0); + +#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8))) +#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8))) + +#define HASH_BLOOM_ADD(tbl,hashv) \ + HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) + +#define HASH_BLOOM_TEST(tbl,hashv) \ + HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) + +#else +#define HASH_BLOOM_MAKE(tbl) +#define HASH_BLOOM_FREE(tbl) +#define HASH_BLOOM_ADD(tbl,hashv) +#define HASH_BLOOM_TEST(tbl,hashv) (1) +#endif + +#define HASH_MAKE_TABLE(hh,head) \ +do { \ + (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \ + sizeof(UT_hash_table)); \ + if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ + memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \ + (head)->hh.tbl->tail = &((head)->hh); \ + (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ + (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ + (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ + (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \ + memset((head)->hh.tbl->buckets, 0, \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_MAKE((head)->hh.tbl); \ + (head)->hh.tbl->signature = HASH_SIGNATURE; \ +} while(0) + +#define HASH_ADD(hh,head,fieldname,keylen_in,add) \ + HASH_ADD_KEYPTR(hh,head,&add->fieldname,keylen_in,add) + +#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ +do { \ + unsigned _ha_bkt; \ + (add)->hh.next = NULL; \ + (add)->hh.key = (char*)keyptr; \ + (add)->hh.keylen = keylen_in; \ + if (!(head)) { \ + head = (add); \ + (head)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh,head); \ + } else { \ + (head)->hh.tbl->tail->next = (add); \ + (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ + (head)->hh.tbl->tail = &((add)->hh); \ + } \ + (head)->hh.tbl->num_items++; \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \ + (add)->hh.hashv, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \ + HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \ + HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \ + HASH_FSCK(hh,head); \ +} while(0) + +#define HASH_TO_BKT( hashv, num_bkts, bkt ) \ +do { \ + bkt = ((hashv) & ((num_bkts) - 1)); \ +} while(0) + +/* delete "delptr" from the hash table. + * "the usual" patch-up process for the app-order doubly-linked-list. + * The use of _hd_hh_del below deserves special explanation. + * These used to be expressed using (delptr) but that led to a bug + * if someone used the same symbol for the head and deletee, like + * HASH_DELETE(hh,users,users); + * We want that to work, but by changing the head (users) below + * we were forfeiting our ability to further refer to the deletee (users) + * in the patch-up process. Solution: use scratch space to + * copy the deletee pointer, then the latter references are via that + * scratch pointer rather than through the repointed (users) symbol. + */ +#define HASH_DELETE(hh,head,delptr) \ +do { \ + unsigned _hd_bkt; \ + struct UT_hash_handle *_hd_hh_del; \ + if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + head = NULL; \ + } else { \ + _hd_hh_del = &((delptr)->hh); \ + if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \ + (head)->hh.tbl->tail = \ + (UT_hash_handle*)((char*)((delptr)->hh.prev) + \ + (head)->hh.tbl->hho); \ + } \ + if ((delptr)->hh.prev) { \ + ((UT_hash_handle*)((char*)((delptr)->hh.prev) + \ + (head)->hh.tbl->hho))->next = (delptr)->hh.next; \ + } else { \ + DECLTYPE_ASSIGN(head,(delptr)->hh.next); \ + } \ + if (_hd_hh_del->next) { \ + ((UT_hash_handle*)((char*)_hd_hh_del->next + \ + (head)->hh.tbl->hho))->prev = \ + _hd_hh_del->prev; \ + } \ + HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ + (head)->hh.tbl->num_items--; \ + } \ + HASH_FSCK(hh,head); \ +} while (0) + +/* use this function to delete an item from a table only if its in that table */ +#define HASH_DELETE_IF(hh,group,ptr) \ +do {\ + if(ptr && group && ptr->hh.tbl) { \ + HASH_DELETE(hh,group,ptr); \ + ptr->hh.tbl = 0;\ + } \ +} while(0) + +/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ +#define HASH_FIND_STR(head,findstr,out) \ + HASH_FIND(hh,head,findstr,strlen(findstr),out) +#define HASH_ADD_STR(head,strfield,add) \ + HASH_ADD(hh,head,strfield,strlen(add->strfield),add) +#define HASH_FIND_INT(head,findint,out) \ + HASH_FIND(hh,head,findint,sizeof(int),out) +#define HASH_ADD_INT(head,intfield,add) \ + HASH_ADD(hh,head,intfield,sizeof(int),add) +#define HASH_FIND_PTR(head,findptr,out) \ + HASH_FIND(hh,head,findptr,sizeof(void *),out) +#define HASH_ADD_PTR(head,ptrfield,add) \ + HASH_ADD(hh,head,ptrfield,sizeof(void *),add) +#define HASH_DEL(head,delptr) \ + HASH_DELETE(hh,head,delptr) + +/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. + * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. + */ +#ifdef HASH_DEBUG +#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) +#define HASH_FSCK(hh,head) \ +do { \ + unsigned _bkt_i; \ + unsigned _count, _bkt_count; \ + char *_prev; \ + struct UT_hash_handle *_thh; \ + if (head) { \ + _count = 0; \ + for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \ + _bkt_count = 0; \ + _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ + _prev = NULL; \ + while (_thh) { \ + if (_prev != (char*)(_thh->hh_prev)) { \ + HASH_OOPS("invalid hh_prev %p, actual %p\n", \ + _thh->hh_prev, _prev ); \ + } \ + _bkt_count++; \ + _prev = (char*)(_thh); \ + _thh = _thh->hh_next; \ + } \ + _count += _bkt_count; \ + if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ + HASH_OOPS("invalid bucket count %d, actual %d\n", \ + (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ + } \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("invalid hh item count %d, actual %d\n", \ + (head)->hh.tbl->num_items, _count ); \ + } \ + /* traverse hh in app order; check next/prev integrity, count */ \ + _count = 0; \ + _prev = NULL; \ + _thh = &(head)->hh; \ + while (_thh) { \ + _count++; \ + if (_prev !=(char*)(_thh->prev)) { \ + HASH_OOPS("invalid prev %p, actual %p\n", \ + _thh->prev, _prev ); \ + } \ + _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ + _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \ + (head)->hh.tbl->hho) : NULL ); \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("invalid app item count %d, actual %d\n", \ + (head)->hh.tbl->num_items, _count ); \ + } \ + } \ +} while (0) +#else +#define HASH_FSCK(hh,head) +#endif + +/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to + * the descriptor to which this macro is defined for tuning the hash function. + * The app can #include to get the prototype for write(2). */ +#ifdef HASH_EMIT_KEYS +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ +do { \ + unsigned _klen = fieldlen; \ + write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ + write(HASH_EMIT_KEYS, keyptr, fieldlen); \ +} while (0) +#else +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) +#endif + +/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ +#ifdef HASH_FUNCTION +#define HASH_FCN HASH_FUNCTION +#else +#define HASH_FCN HASH_JEN +#endif + +/* The Bernstein hash function, used in Perl prior to v5.6 */ +#define HASH_BER(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _hb_keylen=keylen; \ + char *_hb_key=(char*)(key); \ + (hashv) = 0; \ + while (_hb_keylen--) { (hashv) = ((hashv) * 33) + *_hb_key++; } \ + bkt = (hashv) & (num_bkts-1); \ +} while (0) + + +/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at + * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ +#define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _sx_i; \ + char *_hs_key=(char*)(key); \ + hashv = 0; \ + for(_sx_i=0; _sx_i < keylen; _sx_i++) \ + hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ + bkt = hashv & (num_bkts-1); \ +} while (0) + +#define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _fn_i; \ + char *_hf_key=(char*)(key); \ + hashv = 2166136261UL; \ + for(_fn_i=0; _fn_i < keylen; _fn_i++) \ + hashv = (hashv * 16777619) ^ _hf_key[_fn_i]; \ + bkt = hashv & (num_bkts-1); \ +} while(0); + +#define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _ho_i; \ + char *_ho_key=(char*)(key); \ + hashv = 0; \ + for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ + hashv += _ho_key[_ho_i]; \ + hashv += (hashv << 10); \ + hashv ^= (hashv >> 6); \ + } \ + hashv += (hashv << 3); \ + hashv ^= (hashv >> 11); \ + hashv += (hashv << 15); \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +#define HASH_JEN_MIX(a,b,c) \ +do { \ + __builtin_sub_overflow(a, b, &a); __builtin_sub_overflow(a, c, &a); a ^= ( c >> 13 ); \ + __builtin_sub_overflow(b, c, &b); __builtin_sub_overflow(b, a, &b); b ^= ( a << 8 ); \ + __builtin_sub_overflow(c, a, &c); __builtin_sub_overflow(c, b, &c); c ^= ( b >> 13 ); \ + __builtin_sub_overflow(a, b, &a); __builtin_sub_overflow(a, c, &a); a ^= ( c >> 12 ); \ + __builtin_sub_overflow(b, c, &b); __builtin_sub_overflow(b, a, &b); b ^= ( a << 16 ); \ + __builtin_sub_overflow(c, a, &c); __builtin_sub_overflow(c, b, &c); c ^= ( b >> 5 ); \ + __builtin_sub_overflow(a, b, &a); __builtin_sub_overflow(a, c, &a); a ^= ( c >> 3 ); \ + __builtin_sub_overflow(b, c, &b); __builtin_sub_overflow(b, a, &b); b ^= ( a << 10 ); \ + __builtin_sub_overflow(c, a, &c); __builtin_sub_overflow(c, b, &c); c ^= ( b >> 15 ); \ +} while (0) + +#define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _hj_i,_hj_j,_hj_k; \ + char *_hj_key=(char*)(key); \ + hashv = 0xfeedbeef; \ + _hj_i = _hj_j = 0x9e3779b9; \ + _hj_k = keylen; \ + while (_hj_k >= 12) { \ + _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ + + ( (unsigned)_hj_key[2] << 16 ) ); \ + __builtin_add_overflow(_hj_i, ( (unsigned)_hj_key[3] << 24 ), &_hj_i); \ + _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ + + ( (unsigned)_hj_key[6] << 16 ) ); \ + __builtin_add_overflow(_hj_j, ( (unsigned)_hj_key[7] << 24 ), &_hj_j); \ + hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ + + ( (unsigned)_hj_key[10] << 16 ) ); \ + __builtin_add_overflow(hashv, ( (unsigned)_hj_key[11] << 24 ), &hashv); \ + \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + \ + _hj_key += 12; \ + _hj_k -= 12; \ + } \ + hashv += keylen; \ + switch ( _hj_k ) { \ + case 11: __builtin_add_overflow(hashv, ( (unsigned)_hj_key[10] << 24 ), &hashv); \ + case 10: __builtin_add_overflow(hashv, ( (unsigned)_hj_key[9] << 16 ), &hashv); \ + case 9: __builtin_add_overflow(hashv, ( (unsigned)_hj_key[8] << 8 ), &hashv); \ + case 8: __builtin_add_overflow(_hj_j, ( (unsigned)_hj_key[7] << 24 ), &_hj_j); \ + case 7: __builtin_add_overflow(_hj_j, ( (unsigned)_hj_key[6] << 16 ), &_hj_j); \ + case 6: __builtin_add_overflow(_hj_j, ( (unsigned)_hj_key[5] << 8 ), &_hj_j); \ + case 5: __builtin_add_overflow(_hj_j, _hj_key[4], &_hj_j); \ + case 4: __builtin_add_overflow(_hj_i, ( (unsigned)_hj_key[3] << 24 ), &_hj_i); \ + case 3: __builtin_add_overflow(_hj_i, ( (unsigned)_hj_key[2] << 16 ), &_hj_i); \ + case 2: __builtin_add_overflow(_hj_i, ( (unsigned)_hj_key[1] << 8 ), &_hj_i); \ + case 1: __builtin_add_overflow(_hj_i, _hj_key[0], &_hj_i); \ + } \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +/* The Paul Hsieh hash function */ +#undef get16bits +#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ + || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) +#define get16bits(d) (*((const uint16_t *) (d))) +#endif + +#if !defined (get16bits) +#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ + +(uint32_t)(((const uint8_t *)(d))[0]) ) +#endif +#define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \ +do { \ + char *_sfh_key=(char*)(key); \ + uint32_t _sfh_tmp, _sfh_len = keylen; \ + \ + int _sfh_rem = _sfh_len & 3; \ + _sfh_len >>= 2; \ + hashv = 0xcafebabe; \ + \ + /* Main loop */ \ + for (;_sfh_len > 0; _sfh_len--) { \ + hashv += get16bits (_sfh_key); \ + _sfh_tmp = (get16bits (_sfh_key+2) << 11) ^ hashv; \ + hashv = (hashv << 16) ^ _sfh_tmp; \ + _sfh_key += 2*sizeof (uint16_t); \ + hashv += hashv >> 11; \ + } \ + \ + /* Handle end cases */ \ + switch (_sfh_rem) { \ + case 3: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 16; \ + hashv ^= _sfh_key[sizeof (uint16_t)] << 18; \ + hashv += hashv >> 11; \ + break; \ + case 2: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 11; \ + hashv += hashv >> 17; \ + break; \ + case 1: hashv += *_sfh_key; \ + hashv ^= hashv << 10; \ + hashv += hashv >> 1; \ + } \ + \ + /* Force "avalanching" of final 127 bits */ \ + hashv ^= hashv << 3; \ + hashv += hashv >> 5; \ + hashv ^= hashv << 4; \ + hashv += hashv >> 17; \ + hashv ^= hashv << 25; \ + hashv += hashv >> 6; \ + bkt = hashv & (num_bkts-1); \ +} while(0); + +#ifdef HASH_USING_NO_STRICT_ALIASING +/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads. + * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. + * MurmurHash uses the faster approach only on CPU's where we know it's safe. + * + * Note the preprocessor built-in defines can be emitted using: + * + * gcc -m64 -dM -E - < /dev/null (on gcc) + * cc -## a.c (where a.c is a simple test file) (Sun Studio) + */ +#if (defined(__i386__) || defined(__x86_64__)) +#define MUR_GETBLOCK(p,i) p[i] +#else /* non intel */ +#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 0x3) == 0) +#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 0x3) == 1) +#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 0x3) == 2) +#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 0x3) == 3) +#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL)) +#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__)) +#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8)) +#else /* assume little endian non-intel */ +#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8)) +#endif +#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \ + (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \ + (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \ + MUR_ONE_THREE(p)))) +#endif +#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) +#define MUR_FMIX(_h) \ +do { \ + _h ^= _h >> 16; \ + _h *= 0x85ebca6b; \ + _h ^= _h >> 13; \ + _h *= 0xc2b2ae35l; \ + _h ^= _h >> 16; \ +} while(0) + +#define HASH_MUR(key,keylen,num_bkts,hashv,bkt) \ +do { \ + const uint8_t *_mur_data = (const uint8_t*)(key); \ + const int _mur_nblocks = (keylen) / 4; \ + uint32_t _mur_h1 = 0xf88D5353; \ + uint32_t _mur_c1 = 0xcc9e2d51; \ + uint32_t _mur_c2 = 0x1b873593; \ + const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+_mur_nblocks*4); \ + int _mur_i; \ + for(_mur_i = -_mur_nblocks; _mur_i; _mur_i++) { \ + uint32_t _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + \ + _mur_h1 ^= _mur_k1; \ + _mur_h1 = MUR_ROTL32(_mur_h1,13); \ + _mur_h1 = _mur_h1*5+0xe6546b64; \ + } \ + const uint8_t *_mur_tail = (const uint8_t*)(_mur_data + _mur_nblocks*4); \ + uint32_t _mur_k1=0; \ + switch((keylen) & 3) { \ + case 3: _mur_k1 ^= _mur_tail[2] << 16; \ + case 2: _mur_k1 ^= _mur_tail[1] << 8; \ + case 1: _mur_k1 ^= _mur_tail[0]; \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + _mur_h1 ^= _mur_k1; \ + } \ + _mur_h1 ^= (keylen); \ + MUR_FMIX(_mur_h1); \ + hashv = _mur_h1; \ + bkt = hashv & (num_bkts-1); \ +} while(0) +#endif /* HASH_USING_NO_STRICT_ALIASING */ + +/* key comparison function; return 0 if keys equal */ +#define HASH_KEYCMP(a,b,len) memcmp(a,b,len) + +/* iterate over items in a known bucket to find desired item */ +#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \ +do { \ + if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \ + else out=NULL; \ + while (out) { \ + if (out->hh.keylen == keylen_in) { \ + if ((HASH_KEYCMP(out->hh.key,keyptr,keylen_in)) == 0) break; \ + } \ + if (out->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,out->hh.hh_next)); \ + else out = NULL; \ + } \ +} while(0) + +/* add an item to a bucket */ +#define HASH_ADD_TO_BKT(head,addhh) \ +do { \ + head.count++; \ + (addhh)->hh_next = head.hh_head; \ + (addhh)->hh_prev = NULL; \ + if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \ + (head).hh_head=addhh; \ + if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \ + && (addhh)->tbl->noexpand != 1) { \ + HASH_EXPAND_BUCKETS((addhh)->tbl); \ + } \ +} while(0) + +/* remove an item from a given bucket */ +#define HASH_DEL_IN_BKT(hh,head,hh_del) \ + (head).count--; \ + if ((head).hh_head == hh_del) { \ + (head).hh_head = hh_del->hh_next; \ + } \ + if (hh_del->hh_prev) { \ + hh_del->hh_prev->hh_next = hh_del->hh_next; \ + } \ + if (hh_del->hh_next) { \ + hh_del->hh_next->hh_prev = hh_del->hh_prev; \ + } + +/* Bucket expansion has the effect of doubling the number of buckets + * and redistributing the items into the new buckets. Ideally the + * items will distribute more or less evenly into the new buckets + * (the extent to which this is true is a measure of the quality of + * the hash function as it applies to the key domain). + * + * With the items distributed into more buckets, the chain length + * (item count) in each bucket is reduced. Thus by expanding buckets + * the hash keeps a bound on the chain length. This bounded chain + * length is the essence of how a hash provides constant time lookup. + * + * The calculation of tbl->ideal_chain_maxlen below deserves some + * explanation. First, keep in mind that we're calculating the ideal + * maximum chain length based on the *new* (doubled) bucket count. + * In fractions this is just n/b (n=number of items,b=new num buckets). + * Since the ideal chain length is an integer, we want to calculate + * ceil(n/b). We don't depend on floating point arithmetic in this + * hash, so to calculate ceil(n/b) with integers we could write + * + * ceil(n/b) = (n/b) + ((n%b)?1:0) + * + * and in fact a previous version of this hash did just that. + * But now we have improved things a bit by recognizing that b is + * always a power of two. We keep its base 2 log handy (call it lb), + * so now we can write this with a bit shift and logical AND: + * + * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) + * + */ +#define HASH_EXPAND_BUCKETS(tbl) \ +do { \ + unsigned _he_bkt; \ + unsigned _he_bkt_i; \ + struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ + UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ + _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ + 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ + memset(_he_new_buckets, 0, \ + 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + tbl->ideal_chain_maxlen = \ + (tbl->num_items >> (tbl->log2_num_buckets+1)) + \ + ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \ + tbl->nonideal_items = 0; \ + for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ + { \ + _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ + while (_he_thh) { \ + _he_hh_nxt = _he_thh->hh_next; \ + HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \ + _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ + if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ + tbl->nonideal_items++; \ + _he_newbkt->expand_mult = _he_newbkt->count / \ + tbl->ideal_chain_maxlen; \ + } \ + _he_thh->hh_prev = NULL; \ + _he_thh->hh_next = _he_newbkt->hh_head; \ + if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \ + _he_thh; \ + _he_newbkt->hh_head = _he_thh; \ + _he_thh = _he_hh_nxt; \ + } \ + } \ + uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ + tbl->num_buckets *= 2; \ + tbl->log2_num_buckets++; \ + tbl->buckets = _he_new_buckets; \ + tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ + (tbl->ineff_expands+1) : 0; \ + if (tbl->ineff_expands > 1) { \ + tbl->noexpand=1; \ + uthash_noexpand_fyi(tbl); \ + } \ + uthash_expand_fyi(tbl); \ +} while(0) + + +/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ +/* Note that HASH_SORT assumes the hash handle name to be hh. + * HASH_SRT was added to allow the hash handle name to be passed in. */ +#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) +#define HASH_SRT(hh,head,cmpfcn) \ +do { \ + unsigned _hs_i; \ + unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ + struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ + if (head) { \ + _hs_insize = 1; \ + _hs_looping = 1; \ + _hs_list = &((head)->hh); \ + while (_hs_looping) { \ + _hs_p = _hs_list; \ + _hs_list = NULL; \ + _hs_tail = NULL; \ + _hs_nmerges = 0; \ + while (_hs_p) { \ + _hs_nmerges++; \ + _hs_q = _hs_p; \ + _hs_psize = 0; \ + for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ + _hs_psize++; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + if (! (_hs_q) ) break; \ + } \ + _hs_qsize = _hs_insize; \ + while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \ + if (_hs_psize == 0) { \ + _hs_e = _hs_q; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_qsize--; \ + } else if ( (_hs_qsize == 0) || !(_hs_q) ) { \ + _hs_e = _hs_p; \ + _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ + ((void*)((char*)(_hs_p->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_psize--; \ + } else if (( \ + cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ + ) <= 0) { \ + _hs_e = _hs_p; \ + _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ + ((void*)((char*)(_hs_p->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_psize--; \ + } else { \ + _hs_e = _hs_q; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_qsize--; \ + } \ + if ( _hs_tail ) { \ + _hs_tail->next = ((_hs_e) ? \ + ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ + } else { \ + _hs_list = _hs_e; \ + } \ + _hs_e->prev = ((_hs_tail) ? \ + ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ + _hs_tail = _hs_e; \ + } \ + _hs_p = _hs_q; \ + } \ + _hs_tail->next = NULL; \ + if ( _hs_nmerges <= 1 ) { \ + _hs_looping=0; \ + (head)->hh.tbl->tail = _hs_tail; \ + DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ + } \ + _hs_insize *= 2; \ + } \ + HASH_FSCK(hh,head); \ + } \ +} while (0) + +/* This function selects items from one hash into another hash. + * The end result is that the selected items have dual presence + * in both hashes. There is no copy of the items made; rather + * they are added into the new hash through a secondary hash + * hash handle that must be present in the structure. */ +#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ +do { \ + unsigned _src_bkt, _dst_bkt; \ + void *_last_elt=NULL, *_elt; \ + UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ + ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ + if (src) { \ + for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ + for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ + _src_hh; \ + _src_hh = _src_hh->hh_next) { \ + _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ + if (cond(_elt)) { \ + _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ + _dst_hh->key = _src_hh->key; \ + _dst_hh->keylen = _src_hh->keylen; \ + _dst_hh->hashv = _src_hh->hashv; \ + _dst_hh->prev = _last_elt; \ + _dst_hh->next = NULL; \ + if (_last_elt_hh) { _last_elt_hh->next = _elt; } \ + if (!dst) { \ + DECLTYPE_ASSIGN(dst,_elt); \ + HASH_MAKE_TABLE(hh_dst,dst); \ + } else { \ + _dst_hh->tbl = (dst)->hh_dst.tbl; \ + } \ + HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ + HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ + (dst)->hh_dst.tbl->num_items++; \ + _last_elt = _elt; \ + _last_elt_hh = _dst_hh; \ + } \ + } \ + } \ + } \ + HASH_FSCK(hh_dst,dst); \ +} while (0) + +#define HASH_CLEAR(hh,head) \ +do { \ + if (head) { \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head)=NULL; \ + } \ +} while(0) + +#ifdef NO_DECLTYPE +#define HASH_ITER(hh,head,el,tmp) \ +for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \ + el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL)) +#else +#define HASH_ITER(hh,head,el,tmp) \ +for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \ + el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL)) +#endif + +/* obtain a count of items in the hash */ +#define HASH_COUNT(head) HASH_CNT(hh,head) +#define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0) + +typedef struct UT_hash_bucket { + struct UT_hash_handle *hh_head; + unsigned count; + + /* expand_mult is normally set to 0. In this situation, the max chain length + * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If + * the bucket's chain exceeds this length, bucket expansion is triggered). + * However, setting expand_mult to a non-zero value delays bucket expansion + * (that would be triggered by additions to this particular bucket) + * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. + * (The multiplier is simply expand_mult+1). The whole idea of this + * multiplier is to reduce bucket expansions, since they are expensive, in + * situations where we know that a particular bucket tends to be overused. + * It is better to let its chain length grow to a longer yet-still-bounded + * value, than to do an O(n) bucket expansion too often. + */ + unsigned expand_mult; + +} UT_hash_bucket; + +/* random signature used only to find hash tables in external analysis */ +#define HASH_SIGNATURE 0xa0111fe1 +#define HASH_BLOOM_SIGNATURE 0xb12220f2 + +typedef struct UT_hash_table { + UT_hash_bucket *buckets; + unsigned num_buckets, log2_num_buckets; + unsigned num_items; + struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ + ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ + + /* in an ideal situation (all buckets used equally), no bucket would have + * more than ceil(#items/#buckets) items. that's the ideal chain length. */ + unsigned ideal_chain_maxlen; + + /* nonideal_items is the number of items in the hash whose chain position + * exceeds the ideal chain maxlen. these items pay the penalty for an uneven + * hash distribution; reaching them in a chain traversal takes >ideal steps */ + unsigned nonideal_items; + + /* ineffective expands occur when a bucket doubling was performed, but + * afterward, more than half the items in the hash had nonideal chain + * positions. If this happens on two consecutive expansions we inhibit any + * further expansion, as it's not helping; this happens when the hash + * function isn't a good fit for the key domain. When expansion is inhibited + * the hash will still work, albeit no longer in constant time. */ + unsigned ineff_expands, noexpand; + + uint32_t signature; /* used only to find hash tables in external analysis */ +#ifdef HASH_BLOOM + uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ + uint8_t *bloom_bv; + char bloom_nbits; +#endif + +} UT_hash_table; + +typedef struct UT_hash_handle { + struct UT_hash_table *tbl; + void *prev; /* prev element in app order */ + void *next; /* next element in app order */ + struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ + struct UT_hash_handle *hh_next; /* next hh in bucket order */ + void *key; /* ptr to enclosing struct's key */ + unsigned keylen; /* enclosing struct's key len */ + unsigned hashv; /* result of hash-fcn(key) */ +} UT_hash_handle; + +#endif /* UTHASH_H */ diff --git a/inc/verify.h b/inc/verify.h new file mode 100644 index 0000000..9b784b8 --- /dev/null +++ b/inc/verify.h @@ -0,0 +1,167 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef VERIFY_H +#define VERIFY_H + + +extern const char *__progname; + +#ifndef _WIN32 +#define C_ASSERT(test) \ + switch(0) {\ + case 0:\ + case test:;\ + } +#endif // _WIN32 + +#ifndef __V_STR__ + #define __V_STR__(x) #x ":" +#endif //__STR__ +#ifndef __V_TOSTR__ + #define __V_TOSTR__(x) __V_STR__(x) +#endif // __TOSTR__ +#ifndef __V_FILE_LINE__ + #define __V_FILE_LINE__ __FILE__ ":" __V_TOSTR__(__LINE__) +#endif /*__FILE_LINE__*/ + + +#ifdef __ANDROID__ +/*android */ + +#if (defined VERIFY_PRINT_INFO) || (defined VERIFY_PRINT_ERROR) || (defined VERIFY_PRINT_ERROR_ALWAYS) || (defined VERIFY_PRINT_WARN) +#include +#endif + +#ifdef VERIFY_PRINT_INFO +#define VERIFY_IPRINTF(format, ...) __android_log_print(ANDROID_LOG_DEBUG , __progname, __V_FILE_LINE__ format, ##__VA_ARGS__) +#endif + +#ifdef VERIFY_PRINT_ERROR +#define VERIFY_EPRINTF(format, ...) __android_log_print(ANDROID_LOG_ERROR , __progname, __V_FILE_LINE__ format, ##__VA_ARGS__) +#endif + +#define VERIFY_EPRINTF_ALWAYS(format, ...) __android_log_print(ANDROID_LOG_ERROR , __progname, __V_FILE_LINE__ format, ##__VA_ARGS__) + +#ifdef VERIFY_PRINT_WARN +#define VERIFY_WPRINTF(format, ...) __android_log_print(ANDROID_LOG_WARN , __progname, __V_FILE_LINE__ format, ##__VA_ARGS__) +#endif + +/* end android */ +#elif (defined __hexagon__) || (defined __qdsp6__) +/* q6 */ + +#ifdef VERIFY_PRINT_INFO + #define FARF_VERIFY_LOW 1 + #define FARF_VERIFY_LOW_LEVEL HAP_LEVEL_LOW + #define VERIFY_IPRINTF(args...) FARF(VERIFY_LOW, args) +#endif + +#ifdef VERIFY_PRINT_ERROR + #define FARF_VERIFY_ERROR 1 + #define FARF_VERIFY_ERROR_LEVEL HAP_LEVEL_ERROR + #define VERIFY_EPRINTF(args...) FARF(VERIFY_ERROR, args) +#endif + +#if (defined VERIFY_PRINT_INFO) || (defined VERIFY_PRINT_ERROR) + #include "HAP_farf.h" +#endif + +/* end q6 */ +#elif (defined USE_SYSLOG) +/* syslog */ +#if (defined VERIFY_PRINT_INFO) || (defined VERIFY_PRINT_ERROR) || (defined VERIFY_PRINT_ERROR_ALWAYS) || (defined VERIFY_PRINT_WARN) +#include +#endif + +#ifdef VERIFY_PRINT_INFO +#define VERIFY_IPRINTF(format, ...) syslog(LOG_USER|LOG_INFO, __V_FILE_LINE__ format, ##__VA_ARGS__) +#endif + +#ifdef VERIFY_PRINT_ERROR +#define VERIFY_EPRINTF(format, ...) syslog(LOG_USER|LOG_ERR, __V_FILE_LINE__ format, ##__VA_ARGS__) +#endif + +#define VERIFY_EPRINTF_ALWAYS(format, ...) syslog(LOG_ERR , __V_FILE_LINE__ format, ##__VA_ARGS__) + +#ifdef VERIFY_PRINT_WARN +#define VERIFY_WPRINTF(format, ...) syslog(LOG_USER|LOG_ERR, __V_FILE_LINE__ format, ##__VA_ARGS__) +#endif + +/* end syslog */ +#else +/* generic */ + +#if (defined VERIFY_PRINT_INFO) || (defined VERIFY_PRINT_ERROR) || (defined VERIFY_PRINT_ERROR_ALWAYS) || (defined VERIFY_PRINT_WARN) +#include +#endif + +#ifdef VERIFY_PRINT_INFO +#define VERIFY_IPRINTF(format, ...) printf(__V_FILE_LINE__ format "\n", ##__VA_ARGS__) +#endif + +#ifdef VERIFY_PRINT_ERROR +#define VERIFY_EPRINTF(format, ...) printf(__V_FILE_LINE__ format "\n", ##__VA_ARGS__) +#endif + +#define VERIFY_EPRINTF_ALWAYS(format, ...) printf(__V_FILE_LINE__ format, ##__VA_ARGS__) + +#ifdef VERIFY_PRINT_WARN +#define VERIFY_WPRINTF(format, ...) printf(__V_FILE_LINE__ format "\n", ##__VA_ARGS__) +#endif + +/* end generic */ +#endif + +#ifndef VERIFY_PRINT_INFO +#define VERIFY_IPRINTF(format, ...) (void)0 +#endif + +#ifndef VERIFY_PRINT_ERROR +#define VERIFY_EPRINTF(format, ...) (void)0 +#endif + +#ifndef VERIFYC + #define VERIFYC(val,err_code) \ + do {\ + VERIFY_IPRINTF(":info: calling: %s", #val);\ + if(0 == (val)) {\ + nErr = err_code;\ + VERIFY_EPRINTF(":error: %d: %s", nErr, #val);\ + goto bail;\ + } else {\ + VERIFY_IPRINTF(":info: passed: %s", #val);\ + }\ + } while(0) +#endif //VERIFYC + +#ifndef VERIFY + #define VERIFY(val) \ + do {\ + VERIFY_IPRINTF(":info: calling: %s", #val);\ + if(0 == (val)) {\ + nErr = nErr == 0 ? -1 : nErr;\ + VERIFY_EPRINTF(":error: %d: %s", nErr, #val);\ + goto bail;\ + } else {\ + VERIFY_IPRINTF(":info: passed: %s", #val);\ + }\ + } while(0) +#endif //VERIFY + +#ifndef VERIFYM + #define VERIFYM(val,err_code,format, ...) \ + do {\ + VERIFY_IPRINTF(":info: calling: " #val "\n");\ + if(0 == (val)) {\ + nErr = err_code;\ + VERIFY_EPRINTF_ALWAYS(":Error: 0x%x: " #val "\n", nErr);\ + goto bail;\ + } else {\ + VERIFY_IPRINTF(":info: passed: " #val "\n");\ + }\ + } while(0) +#endif //VERIFYM + +#endif //VERIFY_H + diff --git a/inc/version.h b/inc/version.h new file mode 100644 index 0000000..893d6c7 --- /dev/null +++ b/inc/version.h @@ -0,0 +1,100 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef VERSION_H +#define VERSION_H +/*=========================================================================== + +FILE: version.h + +GENERAL DESCRIPTION: + Definitions for versioning +===========================================================================*/ +#if !defined(VERSION_CL) +#define VERSION_CL "?" +#endif + +#if !defined(VERSION_PROD) +#define VERSION_PROD "unknown" +#endif + +#if !defined(VERSION_BRANCH) +#define VERSION_BRANCH "?" +#endif + +#if !defined(VERSION_NUM) +#define VERSION_NUM "?.?.?.?" +#endif + +#define VERSION_STRING \ + VERSION_PROD " " \ + VERSION_NUM " " \ + "(br=" VERSION_BRANCH "; cl=" VERSION_CL ")" + +/* +======================================================================= +MACROS DOCUMENTATION +======================================================================= + +VERSION_MAJOR + +Description: + Defines the major release number of the version. + +Comments: + It has to be a valid numerical value +======================================================================= + +VERSION_MINOR + +Description: + Defines the minor release number of the version. + +Comments: + It has to be a valid numerical value +======================================================================= + +VERSION_MAINT + +Description: + Defines the maintenance release of the version. + +Comments: + It has to be a valid numerical value +======================================================================= + +VERSION_BUILD + +Description: + Defines the build ID of the version. + +Comments: + It has to be a valid numerical value +======================================================================= + +VERSION_STRING + +Description: + Defines the version string that specifies the version number. + +Definition: + + #define VERSION_STRING "a.b.c.d (name=value;name=value;...)" + where a=major release number + b=minor release number + c=maintenance release number + d=build number + + name=value pair provides additional information about the build. + Example: + patch/feature=comma separated list of features/patches that have been installed. + br=p4 branch that was used for the build + cl=p4 change list number + machine=hostname of the machine that was used for the build. + +Comments: + +======================================================================= +*/ + +#endif // VERSION_H diff --git a/src/BufBound.c b/src/BufBound.c new file mode 100644 index 0000000..a3d17e1 --- /dev/null +++ b/src/BufBound.c @@ -0,0 +1,200 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +/*============================================================================== + +FILE: AEEBufBound.c + +SERVICES: + AEEBufBound APIs + +GENERAL DESCRIPTION: + AEEBufBound provides a "bounded buffer" API that facilitates + measuring strings or character output. It's design accomodates + the implementation of functions that can have the same exact logic + for measuring and outputting char buffer content. + +REVISION HISTORY: + Sun Mar 06 11:23:10 2005 Created + +==============================================================================*/ +#include +#include "AEEBufBound.h" +#include "AEEstd.h" + +// Note on bounds-checking logic and saturation: +// +// Simple pointer comparisons are not adequate for bounds checking. pcBuf +// and pcEnd are assumed to be valid pointers in the address space. But +// pcWrite is not ... it is a theoretical value that can exceed pcEnd, and +// may in fact wrap around the end of the address space. In that case the +// test for (pcWrite < pcEnd) will yield TRUE, although pcWrite is outside +// the buffer. Use (pcEnd-pcWrite) > 0 to be accurate. +// +// In order to ensure this works in all cases, we need to avoid integer +// overflows. We do this by restricting pcWrite to the range +// [pcBuf..pcBuf+INT_MAX]. The ensures that pcWrite-pcBuf and pcWrite-pcBuf +// will always be valid integers. It also allows us to ensure that +// BufBound_Wrote() will not return wildly misleading results. +// +// PCSAT +// pcBuf pcEnd pcBuf+MAXINT +// |-------------------| . . . . . . . . . | +// ^ ^ +// pcWrite: (a) (b) +// + +#define PCSAT(me) ((me)->pcBuf + INT_MAX) + + +// Advance me->pcWrite, saturating. +// +// On entry: +// *pnLen = number of bytes to be written (non-negative) +// On exit: +// return value = where to write (pointer into the buffer) +// *pnLen = number of bytes to write +// +static char * +BufBound_ValidateWrite(BufBound *me, int *pnLen) +{ + int nLen = *pnLen; + char *pcWrite = me->pcWrite; + int nMaxCopy = me->pcEnd - pcWrite; // could be negative! + + if ( nMaxCopy < nLen ) { + // Must check PCSAT to validate advance + int nMaxAdvance = PCSAT(me) - pcWrite; // max amount to advance + + if (nLen > nMaxAdvance) { + nLen = nMaxAdvance; + } + if (nMaxCopy < 0) { + nMaxCopy = 0; + } + } else { + // Simple case: all fits in the buffer + nMaxCopy = nLen; + } + + *pnLen = nMaxCopy; + me->pcWrite = pcWrite + nLen; + return pcWrite; +} + +void BufBound_Write(BufBound *me, const char *pc, int nLen) +{ + if (nLen > 0) { + char *pcDest = BufBound_ValidateWrite(me, &nLen); + + while (--nLen >= 0) { + pcDest[nLen] = pc[nLen]; + } + } +} + +void BufBound_Putnc(BufBound *me, char c, int nLen) +{ + if (nLen > 0) { + char *pcDest = BufBound_ValidateWrite(me, &nLen); + + while (--nLen >= 0) { + pcDest[nLen] = c; + } + } +} + +void BufBound_Advance(BufBound *me, int nLen) +{ + uint32 uOffset = (uint32)((me->pcWrite - me->pcBuf) + nLen); + + if (uOffset > INT_MAX) { + uOffset = INT_MAX; + if (nLen < 0) { + uOffset = 0; + } + } + me->pcWrite = me->pcBuf + uOffset; +} + +void BufBound_Init(BufBound *me, char *pBuf, int nLen) +{ + if (nLen < 0) { + nLen = 0; + } + me->pcWrite = me->pcBuf = pBuf; + me->pcEnd = pBuf + nLen; +} + +void BufBound_Putc(BufBound *me, char c) +{ + if ( (me->pcEnd - me->pcWrite) > 0) { + *me->pcWrite++ = c; + } else if (me->pcWrite != PCSAT(me)) { + ++me->pcWrite; + } +} + +void BufBound_ForceNullTerm(BufBound *me) +{ + if ( (me->pcEnd - me->pcWrite) > 0) { + *me->pcWrite++ = '\0'; + } else { + if (me->pcWrite != PCSAT(me)) { + ++me->pcWrite; + } + // ensure null termination if non-empty buffer + if (me->pcEnd != me->pcBuf) { + me->pcEnd[-1] = '\0'; + } + } +} + +void BufBound_Puts(BufBound *me, const char* cpsz) +{ + BufBound_Write(me, cpsz, std_strlen(cpsz)); +} + +int BufBound_BufSize(BufBound* me) +{ + return me->pcEnd - me->pcBuf; +} + +int BufBound_Left(BufBound* me) +{ + return (me->pcEnd - me->pcWrite); +} + +int BufBound_ReallyWrote(BufBound* me) +{ + return STD_MIN(me->pcEnd - me->pcBuf, me->pcWrite - me->pcBuf); +} + +int BufBound_Wrote(BufBound* me) +{ + return (me->pcWrite - me->pcBuf); +} + +void BufBound_WriteLE(BufBound *me, + const void *pvSrc, int nSrcSize, + const char *pszFields) +{ + if (nSrcSize > 0) { + int nLen = nSrcSize; + char *pcDest = BufBound_ValidateWrite(me, &nLen); + + (void)std_CopyLE(pcDest, nLen, pvSrc, nSrcSize, pszFields); + } +} + +void BufBound_WriteBE(BufBound *me, + const void *pvSrc, int nSrcSize, + const char *pszFields) +{ + if (nSrcSize > 0) { + int nLen = nSrcSize; + char *pcDest = BufBound_ValidateWrite(me, &nLen); + + (void)std_CopyBE(pcDest, nLen, pvSrc, nSrcSize, pszFields); + } +} diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..217c0eb --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,128 @@ +lib_LTLIBRARIES = + +LIBDSPRPC_CFLAGS = -fno-short-enums -U_DEBUG -DARM_ARCH_7A -DLE_ENABLE -DNO_HAL -DENABLE_UPSTREAM_DRIVER_INTERFACE -DUSE_SYSLOG -I$(top_srcdir)/inc + +LIBDSPRPC_SOURCES = \ + fastrpc_apps_user.c \ + fastrpc_perf.c \ + fastrpc_pm.c \ + fastrpc_config.c \ + fastrpc_async.c \ + fastrpc_mem.c \ + fastrpc_notif.c \ + fastrpc_latency.c \ + fastrpc_ioctl.c \ + fastrpc_log.c \ + fastrpc_procbuf.c \ + fastrpc_cap.c \ + log_config.c \ + dspsignal.c \ + dspqueue\dspqueue_cpu \ + dspqueue\dspqueue_rpc_stub \ + listener_android.c \ + apps_std_imp.c \ + apps_mem_imp.c \ + apps_mem_skel.c \ + rpcmem_linux.c \ + adspmsgd.c \ + adspmsgd_printf.c \ + std.c \ + std_path.c \ + std_mem.c \ + std_dtoa.c \ + std_strlprintf.c \ + BufBound.c \ + std_SwapBytes.c \ + smath.c \ + atomic.c \ + cae.c \ + platform_libs.c \ + pl_list.c \ + gpls.c \ + remotectl_stub.c \ + remotectl1_stub.c \ + adspmsgd_apps_skel.c \ + adspmsgd_adsp_stub.c \ + adspmsgd_adsp1_stub.c \ + apps_remotectl_skel.c \ + adsp_current_process_stub.c \ + adsp_current_process1_stub.c \ + adsp_listener_stub.c \ + adsp_listener1_stub.c \ + apps_std_skel.c \ + adsp_perf_stub.c \ + adsp_perf1_stub.c \ + mod_table.c + +LIBDEFAULT_LISTENER_SOURCES = \ + adsp_default_listener.c \ + adsp_default_listener_stub.c \ + adsp_default_listener1_stub.c \ + std.c \ + std_mem.c + +ADSP_CFLAGS = $(LIBDSPRPC_CFLAGS) -DDEFAULT_DOMAIN_ID=0 + +lib_LTLIBRARIES += libadsprpc.la +libadsprpc_la_SOURCES = $(LIBDSPRPC_SOURCES) +libadsprpc_la_LDFLAGS = -ldl -lm -llog +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 -avoid-version -llog +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 = -ldl -lm -llog +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 -avoid-version -llog +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 = -ldl -lm -llog +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 -avoid-version -llog +libsdsp_default_listener_la_CFLAGS = $(SDSP_CFLAGS) -DUSE_SYSLOG + + +bin_PROGRAMS = adsprpcd cdsprpcd sdsprpcd + +adsprpcddir = $(libdir) +adsprpcd_SOURCES = adsprpcd.c +adsprpcd_DEPENDENCIES = libadsp_default_listener.la +adsprpcd_CFLAGS = -I$(top_srcdir)/inc -DDEFAULT_DOMAIN_ID=0 -DUSE_SYSLOG +adsprpcd_LDADD = -ldl -llog + + +cdsprpcddir = $(libdir) +cdsprpcd_SOURCES = cdsprpcd.c +cdsprpcd_DEPENDENCIES = libcdsp_default_listener.la +cdsprpcd_CFLAGS = -I$(top_srcdir)/inc -DDEFAULT_DOMAIN_ID=3 -DUSE_SYSLOG +cdsprpcd_LDADD = -ldl -llog + + +sdsprpcddir = $(libdir) +sdsprpcd_SOURCES = cdsprpcd.c +sdsprpcd_DEPENDENCIES = libsdsp_default_listener.la +sdsprpcd_CFLAGS = -I$(top_srcdir)/inc -DDEFAULT_DOMAIN_ID=2 -DUSE_SYSLOG +sdsprpcd_LDADD = -ldl -llog + + +otherincludedir = $(includedir)/fastrpc +otherinclude_HEADERS = $(top_srcdir)/inc/*.h diff --git a/src/adsp_current_process1_stub.c b/src/adsp_current_process1_stub.c new file mode 100644 index 0000000..31c9cc3 --- /dev/null +++ b/src/adsp_current_process1_stub.c @@ -0,0 +1,737 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _ADSP_CURRENT_PROCESS1_STUB_H +#define _ADSP_CURRENT_PROCESS1_STUB_H +#include "adsp_current_process1.h" +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#include + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef _ATTRIBUTE_VISIBILITY + +#ifdef _WIN32 +#define _ATTRIBUTE_VISIBILITY +#else +#define _ATTRIBUTE_VISIBILITY __attribute__ ((visibility("default"))) +#endif + +#endif // _ATTRIBUTE_VISIBILITY + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i = 0; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#endif + + +#endif // _QAIC_ENV_H + +#include +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include +#include + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc((size_t)size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + (size_t)size) < (uintptr_t)me->stack + (size_t)me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _ADSP_CURRENT_PROCESS1_SLIM_H +#define _ADSP_CURRENT_PROCESS1_SLIM_H +#include + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Type types[2]; +static const SequenceType sequenceTypes[1] = {{&(types[0]),0x0,0x4,0x4,0x0}}; +static const Type types[2] = {{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)0x0,0}}, 4,SLIM_IFPTR32(0x4,0x8)},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4}}; +static const Parameter parameters[8] = {{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)0x0,0}}, 4,SLIM_IFPTR32(0x4,0x8),0,0},{SLIM_IFPTR32(0x4,0x8),{{(const uintptr_t)0xdeadc0de,(const uintptr_t)0}}, 0,SLIM_IFPTR32(0x4,0x8),3,0},{SLIM_IFPTR32(0x4,0x8),{{(const uintptr_t)0xdeadc0de,(const uintptr_t)0}}, 0,SLIM_IFPTR32(0x4,0x8),0,0},{0x2,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x2,0,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(sequenceTypes[0]),0}}, 25,SLIM_IFPTR32(0x4,0x8),0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[1]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8),0,0}}; +static const Parameter* const parameterArrays[11] = {(&(parameters[6])),(&(parameters[6])),(&(parameters[6])),(&(parameters[4])),(&(parameters[3])),(&(parameters[4])),(&(parameters[0])),(&(parameters[1])),(&(parameters[7])),(&(parameters[5])),(&(parameters[2]))}; +static const Method methods[9] = {{REMOTE_SCALARS_MAKEX(0,0,0x2,0x0,0x0,0x1),0x4,0x0,2,2,(&(parameterArrays[6])),0x4,0x1},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x0,0x1,0x0),0x0,0x0,1,1,(&(parameterArrays[10])),0x1,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x0,0x0,0x0),0x0,0x0,0,0,0,0x0,0x0},{REMOTE_SCALARS_MAKEX(0,0,255,255,15,15),0x8,0x0,3,2,(&(parameterArrays[4])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x1,0x0,0x0),0x0,0x4,1,1,(&(parameterArrays[9])),0x1,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0x4,0x0,1,1,(&(parameterArrays[0])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,255,255,15,15),0x8,0x0,3,2,(&(parameterArrays[2])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0x8,0x0,2,2,(&(parameterArrays[0])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x2,0x0,0x0,0x0),0x4,0x0,2,1,(&(parameterArrays[8])),0x4,0x0}}; +static const Method* const methodArrays[12] = {&(methods[0]),&(methods[1]),&(methods[2]),&(methods[2]),&(methods[3]),&(methods[4]),&(methods[5]),&(methods[2]),&(methods[6]),&(methods[7]),&(methods[2]),&(methods[8])}; +static const char strings[185] = "enable_notifications\0set_logging_params2\0set_logging_params\0panic_err_codes\0thread_exit\0filesToLog\0poll_mode\0exception\0timeout\0latency\0getASID\0enable\0setQoS\0close\0asid\0mask\0open\0uri\0h\0"; +static const uint16_t methodStrings[24] = {99,143,119,21,168,88,41,168,88,173,178,182,60,66,150,127,135,163,157,182,0,109,76,83}; +static const uint16_t methodStringsArrays[12] = {9,18,23,22,6,16,14,21,3,0,20,12}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(adsp_current_process1_slim) = {12,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_ADSP_CURRENT_PROCESS1_SLIM_H + + +#ifdef __cplusplus +extern "C" { +#endif +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process1_open)(const char* uri, remote_handle64* h) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle64_open)(uri, h); +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process1_close)(remote_handle64 h) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle64_close)(h); +} +static __inline int _stub_method(remote_handle64 _handle, uint32_t _mid) { + remote_arg* _pra = 0; + int _nErr = 0; + _TRY(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 0, 0, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process1_exit)(remote_handle64 _handle) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 2; + return _stub_method(_handle, _mid); +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process1_thread_exit)(remote_handle64 _handle) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 3; + return _stub_method(_handle, _mid); +} +static __inline int _stub_unpack(_ATTRIBUTE_UNUSED remote_arg* _praROutPost, _ATTRIBUTE_UNUSED remote_arg* _ppraROutPost[1], _ATTRIBUTE_UNUSED void* _primROut, _ATTRIBUTE_UNUSED char* _in0[1], _ATTRIBUTE_UNUSED uint32_t _in0Len[1]) { + int _nErr = 0; + remote_arg* _praROutPostStart = _praROutPost; + remote_arg** _ppraROutPostStart = _ppraROutPost; + _ppraROutPost = &_praROutPost; + _ppraROutPostStart[0] += (_praROutPost - _praROutPostStart) +0; + return _nErr; +} +static __inline int _stub_pack(_ATTRIBUTE_UNUSED _allocator* _al, _ATTRIBUTE_UNUSED remote_arg* _praIn, _ATTRIBUTE_UNUSED remote_arg* _ppraIn[1], _ATTRIBUTE_UNUSED remote_arg* _praROut, _ATTRIBUTE_UNUSED remote_arg* _ppraROut[1], _ATTRIBUTE_UNUSED remote_arg* _praHIn, _ATTRIBUTE_UNUSED remote_arg* _ppraHIn[1], _ATTRIBUTE_UNUSED remote_arg* _praHROut, _ATTRIBUTE_UNUSED remote_arg* _ppraHROut[1], _ATTRIBUTE_UNUSED void* _primIn, _ATTRIBUTE_UNUSED void* _primROut, _ATTRIBUTE_UNUSED char* _in0[1], _ATTRIBUTE_UNUSED uint32_t _in0Len[1]) { + int _nErr = 0; + remote_arg* _praInStart = _praIn; + remote_arg** _ppraInStart = _ppraIn; + remote_arg* _praROutStart = _praROut; + remote_arg** _ppraROutStart = _ppraROut; + _ppraIn = &_praIn; + _ppraROut = &_praROut; + _in0Len[0] = (uint32_t)(1 + strlen(_in0[0])); + _COPY(_primIn, 0, _in0Len, 0, 4); + _praIn[0].buf.pv = (void*) _in0[0]; + _praIn[0].buf.nLen = (1 * _in0Len[0]); + _ppraInStart[0] += (_praIn - _praInStart) + 1; + _ppraROutStart[0] += (_praROut - _praROutStart) +0; + return _nErr; +} +static __inline void _count(int _numIn[1], int _numROut[1], int _numInH[1], int _numROutH[1]) { + _numIn[0] += 1; + _numROut[0] += 0; + _numInH[0] += 0; + _numROutH[0] += 0; +} +static __inline int _stub_method_1(remote_handle64 _handle, uint32_t _mid, uint16_t _in0[1], void* _in1[1], uint32_t _in1Len[1]) { + remote_arg* _pra = 0; + int _numIn[1] = {0}; + int _numROut[1] = {0}; + int _numInH[1] = {0}; + int _numROutH[1] = {0}; + char* _seq_nat1 = 0; + int _ii = 0; + _allocator _al[1] = {{0}}; + uint32_t _primIn[2]= {0}; + remote_arg* _praIn = 0; + remote_arg** _ppraIn = &_praIn; + remote_arg* _praROut = 0; + remote_arg** _ppraROut = &_praROut; + remote_arg* _praHIn = 0; + remote_arg** _ppraHIn = &_praHIn; + remote_arg* _praHROut = 0; + remote_arg** _ppraHROut = &_praHROut; + char* _seq_primIn1 = 0; + int _nErr = 0; + remote_arg* _praROutPost = 0; + remote_arg** _ppraROutPost = &_praROutPost; + _numIn[0] = 1; + _numROut[0] = 0; + _numInH[0] = 0; + _numROutH[0] = 0; + for(_ii = 0, _seq_nat1 = (char*)_in1[0];_ii < (int)_in1Len[0];++_ii, _seq_nat1 = (_seq_nat1 + SLIM_IFPTR32(8, 16))) + { + _count(_numIn, _numROut, _numInH, _numROutH); + } + if(_numIn[0]>=255) + { + printf("ERROR: Unsupported number of input buffers\n"); + return AEE_EUNSUPPORTED; + } + if(_numROut[0]>=255) + { + printf("ERROR: Unsupported number of output buffers\n"); + return AEE_EUNSUPPORTED; + } + _allocator_init(_al, 0, 0); + _ALLOCATE(_nErr, _al, ((((((((_numIn[0] + _numROut[0]) + _numInH[0]) + _numROutH[0]) + 1) + 0) + 0) + 0) * sizeof(_pra[0])), 4, _pra); + _ASSERT(_nErr, _pra); + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _COPY(_primIn, 0, _in0, 0, 2); + _COPY(_primIn, 4, _in1Len, 0, 4); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 0); + if(_praHIn == 0) + { + _praHIn = ((_praIn + _numIn[0]) + 0); + } + if(_praHROut == 0) + (_praHROut = _praHIn + _numInH[0] + 0); + _ALLOCATE(_nErr, _al, (_in1Len[0] * 4), 4, _praIn[0].buf.pv); + _praIn[0].buf.nLen = (4 * _in1Len[0]); + for(_ii = 0, _seq_primIn1 = (char*)_praIn[0].buf.pv, _seq_nat1 = (char*)_in1[0];_ii < (int)_in1Len[0];++_ii, _seq_primIn1 = (_seq_primIn1 + 4), _seq_nat1 = (_seq_nat1 + SLIM_IFPTR32(8, 16))) + { + _TRY(_nErr, _stub_pack(_al, (_praIn + 1), _ppraIn, (_praROut + 0), _ppraROut, _praHIn, _ppraHIn, _praHROut, _ppraHROut, _seq_primIn1, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat1)[0]), (char**)&(((uint64_t*)_seq_nat1)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat1)[1]), (uint32_t*)&(((uint32_t*)_seq_nat1)[2])))); + } + _ASSERT(_nErr, (_numInH[0] + 0) <= 15); + _ASSERT(_nErr, (_numROutH[0] + 0) <= 15); + _TRY(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, (_numIn[0] + 1), (_numROut[0] + 0), (_numInH[0] + 0), (_numROutH[0] + 0)), _pra)); + _praROutPost = _praROut; + for(_ii = 0, _seq_nat1 = (char*)_in1[0];_ii < (int)_in1Len[0];++_ii, _seq_nat1 = (_seq_nat1 + SLIM_IFPTR32(8, 16))) + { + _TRY(_nErr, _stub_unpack((_praROutPost + 0), _ppraROutPost, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat1)[0]), (char**)&(((uint64_t*)_seq_nat1)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat1)[1]), (uint32_t*)&(((uint32_t*)_seq_nat1)[2])))); + } + _CATCH(_nErr) {} + _allocator_deinit(_al); + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process1_set_logging_params)(remote_handle64 _handle, unsigned short mask, const _cstring1_t* filesToLog, int filesToLogLen) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 4; + return _stub_method_1(_handle, _mid, (uint16_t*)&mask, (void**)&filesToLog, (uint32_t*)&filesToLogLen); +} +static __inline int _stub_method_2(remote_handle64 _handle, uint32_t _mid, uint32_t _rout0[1]) { + int _numIn[1] = {0}; + remote_arg _pra[1] = {0}; + uint32_t _primROut[1]= {0}; + int _nErr = 0; + _numIn[0] = 0; + _pra[(_numIn[0] + 0)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 0)].buf.nLen = sizeof(_primROut); + _TRY(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 0, 1, 0, 0), _pra)); + _COPY(_rout0, 0, _primROut, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process1_getASID)(remote_handle64 _handle, unsigned int* asid) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 5; + return _stub_method_2(_handle, _mid, (uint32_t*)asid); +} +static __inline int _stub_method_3(remote_handle64 _handle, uint32_t _mid, uint32_t _in0[1]) { + remote_arg _pra[1] = {0}; + uint32_t _primIn[1]= {0}; + int _nErr = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _COPY(_primIn, 0, _in0, 0, 4); + _TRY(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 0, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process1_setQoS)(remote_handle64 _handle, unsigned int latency) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 6; + return _stub_method_3(_handle, _mid, (uint32_t*)&latency); +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process1_exception)(remote_handle64 _handle) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 7; + return _stub_method(_handle, _mid); +} +static __inline int _stub_method_4(remote_handle64 _handle, uint32_t _mid, uint32_t _in0[1], void* _in1[1], uint32_t _in1Len[1]) { + remote_arg* _pra = 0; + int _numIn[1] = {0}; + int _numROut[1] = {0}; + int _numInH[1] = {0}; + int _numROutH[1] = {0}; + char* _seq_nat1 = 0; + int _ii = 0; + _allocator _al[1] = {{0}}; + uint32_t _primIn[2]= {0}; + remote_arg* _praIn = 0; + remote_arg** _ppraIn = &_praIn; + remote_arg* _praROut = 0; + remote_arg** _ppraROut = &_praROut; + remote_arg* _praHIn = 0; + remote_arg** _ppraHIn = &_praHIn; + remote_arg* _praHROut = 0; + remote_arg** _ppraHROut = &_praHROut; + char* _seq_primIn1 = 0; + int _nErr = 0; + remote_arg* _praROutPost = 0; + remote_arg** _ppraROutPost = &_praROutPost; + _numIn[0] = 1; + _numROut[0] = 0; + _numInH[0] = 0; + _numROutH[0] = 0; + for(_ii = 0, _seq_nat1 = (char*)_in1[0];_ii < (int)_in1Len[0];++_ii, _seq_nat1 = (_seq_nat1 + SLIM_IFPTR32(8, 16))) + { + _count(_numIn, _numROut, _numInH, _numROutH); + } + if(_numIn[0]>=255) + { + printf("ERROR: Unsupported number of input buffers\n"); + return AEE_EUNSUPPORTED; + } + if(_numROut[0]>=255) + { + printf("ERROR: Unsupported number of output buffers\n"); + return AEE_EUNSUPPORTED; + } + _allocator_init(_al, 0, 0); + _ALLOCATE(_nErr, _al, ((((((((_numIn[0] + _numROut[0]) + _numInH[0]) + _numROutH[0]) + 1) + 0) + 0) + 0) * sizeof(_pra[0])), 4, _pra); + _ASSERT(_nErr, _pra); + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _in1Len, 0, 4); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 0); + if(_praHIn == 0) + { + _praHIn = ((_praIn + _numIn[0]) + 0); + } + if(_praHROut == 0) + (_praHROut = _praHIn + _numInH[0] + 0); + _ALLOCATE(_nErr, _al, (_in1Len[0] * 4), 4, _praIn[0].buf.pv); + _praIn[0].buf.nLen = (4 * _in1Len[0]); + for(_ii = 0, _seq_primIn1 = (char*)_praIn[0].buf.pv, _seq_nat1 = (char*)_in1[0];_ii < (int)_in1Len[0];++_ii, _seq_primIn1 = (_seq_primIn1 + 4), _seq_nat1 = (_seq_nat1 + SLIM_IFPTR32(8, 16))) + { + _TRY(_nErr, _stub_pack(_al, (_praIn + 1), _ppraIn, (_praROut + 0), _ppraROut, _praHIn, _ppraHIn, _praHROut, _ppraHROut, _seq_primIn1, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat1)[0]), (char**)&(((uint64_t*)_seq_nat1)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat1)[1]), (uint32_t*)&(((uint32_t*)_seq_nat1)[2])))); + } + _ASSERT(_nErr, (_numInH[0] + 0) <= 15); + _ASSERT(_nErr, (_numROutH[0] + 0) <= 15); + _TRY(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, (_numIn[0] + 1), (_numROut[0] + 0), (_numInH[0] + 0), (_numROutH[0] + 0)), _pra)); + _praROutPost = _praROut; + for(_ii = 0, _seq_nat1 = (char*)_in1[0];_ii < (int)_in1Len[0];++_ii, _seq_nat1 = (_seq_nat1 + SLIM_IFPTR32(8, 16))) + { + _TRY(_nErr, _stub_unpack((_praROutPost + 0), _ppraROutPost, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat1)[0]), (char**)&(((uint64_t*)_seq_nat1)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat1)[1]), (uint32_t*)&(((uint32_t*)_seq_nat1)[2])))); + } + _CATCH(_nErr) {} + _allocator_deinit(_al); + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process1_set_logging_params2)(remote_handle64 _handle, unsigned int mask, const _cstring1_t* filesToLog, int filesToLogLen) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 8; + return _stub_method_4(_handle, _mid, (uint32_t*)&mask, (void**)&filesToLog, (uint32_t*)&filesToLogLen); +} +static __inline int _stub_method_5(remote_handle64 _handle, uint32_t _mid, uint32_t _in0[1], uint32_t _in1[1]) { + remote_arg _pra[1] = {0}; + uint32_t _primIn[2]= {0}; + int _nErr = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _in1, 0, 4); + _TRY(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 0, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process1_poll_mode)(remote_handle64 _handle, unsigned int enable, unsigned int timeout) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 9; + return _stub_method_5(_handle, _mid, (uint32_t*)&enable, (uint32_t*)&timeout); +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process1_enable_notifications)(remote_handle64 _handle) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 10; + return _stub_method(_handle, _mid); +} +static __inline int _stub_method_6(remote_handle64 _handle, uint32_t _mid, char* _in0[1], uint32_t _in0Len[1]) { + remote_arg _pra[2] = {0}; + uint32_t _primIn[1]= {0}; + remote_arg* _praIn = 0; + int _nErr = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _COPY(_primIn, 0, _in0Len, 0, 4); + _praIn = (_pra + 1); + _praIn[0].buf.pv = (void*) _in0[0]; + _praIn[0].buf.nLen = (4 * _in0Len[0]); + _TRY(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 2, 0, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process1_panic_err_codes)(remote_handle64 _handle, const int* err_codes, int err_codesLen) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 11; + return _stub_method_6(_handle, _mid, (char**)&err_codes, (uint32_t*)&err_codesLen); +} +#ifdef __cplusplus +} +#endif +#endif //_ADSP_CURRENT_PROCESS1_STUB_H diff --git a/src/adsp_current_process_stub.c b/src/adsp_current_process_stub.c new file mode 100644 index 0000000..d7d6186 --- /dev/null +++ b/src/adsp_current_process_stub.c @@ -0,0 +1,873 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _ADSP_CURRENT_PROCESS_STUB_H +#define _ADSP_CURRENT_PROCESS_STUB_H +#include "adsp_current_process.h" +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#include + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef _ATTRIBUTE_VISIBILITY + +#ifdef _WIN32 +#define _ATTRIBUTE_VISIBILITY +#else +#define _ATTRIBUTE_VISIBILITY __attribute__ ((visibility("default"))) +#endif + +#endif // _ATTRIBUTE_VISIBILITY + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i = 0; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#endif + + +#endif // _QAIC_ENV_H + +#include +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include +#include + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc((size_t)size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + (size_t)size) < (uintptr_t)me->stack + (size_t)me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _ADSP_CURRENT_PROCESS_SLIM_H +#define _ADSP_CURRENT_PROCESS_SLIM_H +#include + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Type types[1]; +static const SequenceType sequenceTypes[1] = {{&(types[0]),0x0,0x4,0x4,0x0}}; +static const Type types[1] = {{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)0x0,0}}, 4,SLIM_IFPTR32(0x4,0x8)}}; +static const Parameter parameters[4] = {{0x2,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x2,0,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(sequenceTypes[0]),0}}, 25,SLIM_IFPTR32(0x4,0x8),0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0}}; +static const Parameter* const parameterArrays[7] = {(&(parameters[3])),(&(parameters[3])),(&(parameters[3])),(&(parameters[1])),(&(parameters[0])),(&(parameters[1])),(&(parameters[2]))}; +static const Method methods[6] = {{REMOTE_SCALARS_MAKEX(0,0,0x0,0x0,0x0,0x0),0x0,0x0,0,0,0,0x0,0x0},{REMOTE_SCALARS_MAKEX(0,0,255,255,15,15),0x8,0x0,3,2,(&(parameterArrays[4])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x1,0x0,0x0),0x0,0x4,1,1,(&(parameterArrays[6])),0x1,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0x4,0x0,1,1,(&(parameterArrays[0])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,255,255,15,15),0x8,0x0,3,2,(&(parameterArrays[2])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0x8,0x0,2,2,(&(parameterArrays[0])),0x4,0x0}}; +static const Method* const methodArrays[9] = {&(methods[0]),&(methods[0]),&(methods[1]),&(methods[2]),&(methods[3]),&(methods[0]),&(methods[4]),&(methods[5]),&(methods[0])}; +static const char strings[152] = "enable_notifications\0set_logging_params2\0set_logging_params\0thread_exit\0filesToLog\0poll_mode\0exception\0timeout\0latency\0getASID\0enable\0setQoS\0asid\0mask\0"; +static const uint16_t methodStrings[17] = {83,127,103,21,146,72,41,146,72,134,111,119,141,0,93,60,67}; +static const uint16_t methodStringsArrays[9] = {16,15,6,11,9,14,3,0,13}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(adsp_current_process_slim) = {9,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_ADSP_CURRENT_PROCESS_SLIM_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _const_adsp_current_process_handle +#define _const_adsp_current_process_handle ((remote_handle)-1) +#endif //_const_adsp_current_process_handle + +static void _adsp_current_process_pls_dtor(void* data) { + remote_handle* ph = (remote_handle*)data; + if(_const_adsp_current_process_handle != *ph) { + (void)__QAIC_REMOTE(remote_handle_close)(*ph); + *ph = _const_adsp_current_process_handle; + } +} + +static int _adsp_current_process_pls_ctor(void* ctx, void* data) { + remote_handle* ph = (remote_handle*)data; + *ph = _const_adsp_current_process_handle; + if(*ph == (remote_handle)-1) { + return __QAIC_REMOTE(remote_handle_open)((const char*)ctx, ph); + } + return 0; +} + +#if (defined __qdsp6__) || (defined __hexagon__) +#pragma weak adsp_pls_add_lookup +extern int adsp_pls_add_lookup(uint32_t type, uint32_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* ctx), void** ppo); +#pragma weak HAP_pls_add_lookup +extern int HAP_pls_add_lookup(uint32_t type, uint32_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* ctx), void** ppo); + +__QAIC_STUB_EXPORT remote_handle _adsp_current_process_handle(void) { + remote_handle* ph = 0; + if(adsp_pls_add_lookup) { + if(0 == adsp_pls_add_lookup((uint32_t)_adsp_current_process_handle, 0, sizeof(*ph), _adsp_current_process_pls_ctor, "adsp_current_process", _adsp_current_process_pls_dtor, (void**)&ph)) { + return *ph; + } + return (remote_handle)-1; + } else if(HAP_pls_add_lookup) { + if(0 == HAP_pls_add_lookup((uint32_t)_adsp_current_process_handle, 0, sizeof(*ph), _adsp_current_process_pls_ctor, "adsp_current_process", _adsp_current_process_pls_dtor, (void**)&ph)) { + return *ph; + } + return (remote_handle)-1; + } + return(remote_handle)-1; +} + +#else //__qdsp6__ || __hexagon__ + +uint32_t _adsp_current_process_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare); + +#ifdef _WIN32 +#ifdef _USRDLL +#include "Windows.h" +#else +#include "ntddk.h" +#endif //_USRDLL +uint32_t _adsp_current_process_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare) { + return (uint32_t)InterlockedCompareExchange((volatile LONG*)puDest, (LONG)uExchange, (LONG)uCompare); +} +#elif __GNUC__ +uint32_t _adsp_current_process_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare) { + return __sync_val_compare_and_swap(puDest, uCompare, uExchange); +} +#endif //_WIN32 + + +__QAIC_STUB_EXPORT remote_handle _adsp_current_process_handle(void) { + static remote_handle handle = _const_adsp_current_process_handle; + if((remote_handle)-1 != handle) { + return handle; + } else { + remote_handle tmp; + int nErr = _adsp_current_process_pls_ctor("adsp_current_process", (void*)&tmp); + if(nErr) { + return (remote_handle)-1; + } + if(((remote_handle)-1 != handle) || ((remote_handle)-1 != (remote_handle)_adsp_current_process_atomic_CompareAndExchange((uint32_t*)&handle, (uint32_t)tmp, (uint32_t)-1))) { + _adsp_current_process_pls_dtor(&tmp); + } + return handle; + } +} + +#endif //__qdsp6__ + +#ifdef __cplusplus +} +#endif + + +#ifdef __cplusplus +extern "C" { +#endif +static __inline int _stub_method(remote_handle _handle, uint32_t _mid) { + remote_arg* _pra = 0; + int _nErr = 0; + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 0, 0, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process_exit)(void) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 0; + remote_handle _handle = _adsp_current_process_handle(); + if (_handle != (remote_handle)-1) + { + return _stub_method(_handle, _mid); + } + else + { + return AEE_EINVHANDLE; + } +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process_thread_exit)(void) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 1; + remote_handle _handle = _adsp_current_process_handle(); + if (_handle != (remote_handle)-1) + { + return _stub_method(_handle, _mid); + } + else + { + return AEE_EINVHANDLE; + } +} +static __inline int _stub_unpack(_ATTRIBUTE_UNUSED remote_arg* _praROutPost, _ATTRIBUTE_UNUSED remote_arg* _ppraROutPost[1], _ATTRIBUTE_UNUSED void* _primROut, _ATTRIBUTE_UNUSED char* _in0[1], _ATTRIBUTE_UNUSED uint32_t _in0Len[1]) { + int _nErr = 0; + remote_arg* _praROutPostStart = _praROutPost; + remote_arg** _ppraROutPostStart = _ppraROutPost; + _ppraROutPost = &_praROutPost; + _ppraROutPostStart[0] += (_praROutPost - _praROutPostStart) +0; + return _nErr; +} +static __inline int _stub_pack(_ATTRIBUTE_UNUSED _allocator* _al, _ATTRIBUTE_UNUSED remote_arg* _praIn, _ATTRIBUTE_UNUSED remote_arg* _ppraIn[1], _ATTRIBUTE_UNUSED remote_arg* _praROut, _ATTRIBUTE_UNUSED remote_arg* _ppraROut[1], _ATTRIBUTE_UNUSED remote_arg* _praHIn, _ATTRIBUTE_UNUSED remote_arg* _ppraHIn[1], _ATTRIBUTE_UNUSED remote_arg* _praHROut, _ATTRIBUTE_UNUSED remote_arg* _ppraHROut[1], _ATTRIBUTE_UNUSED void* _primIn, _ATTRIBUTE_UNUSED void* _primROut, _ATTRIBUTE_UNUSED char* _in0[1], _ATTRIBUTE_UNUSED uint32_t _in0Len[1]) { + int _nErr = 0; + remote_arg* _praInStart = _praIn; + remote_arg** _ppraInStart = _ppraIn; + remote_arg* _praROutStart = _praROut; + remote_arg** _ppraROutStart = _ppraROut; + _ppraIn = &_praIn; + _ppraROut = &_praROut; + _in0Len[0] = (uint32_t)(1 + strlen(_in0[0])); + _COPY(_primIn, 0, _in0Len, 0, 4); + _praIn[0].buf.pv = (void*) _in0[0]; + _praIn[0].buf.nLen = (1 * _in0Len[0]); + _ppraInStart[0] += (_praIn - _praInStart) + 1; + _ppraROutStart[0] += (_praROut - _praROutStart) +0; + return _nErr; +} +static __inline void _count(int _numIn[1], int _numROut[1], int _numInH[1], int _numROutH[1]) { + _numIn[0] += 1; + _numROut[0] += 0; + _numInH[0] += 0; + _numROutH[0] += 0; +} +static __inline int _stub_method_1(remote_handle _handle, uint32_t _mid, uint16_t _in0[1], void* _in1[1], uint32_t _in1Len[1]) { + remote_arg* _pra = 0; + int _numIn[1] = {0}; + int _numROut[1] = {0}; + int _numInH[1] = {0}; + int _numROutH[1] = {0}; + char* _seq_nat1 = 0; + int _ii = 0; + _allocator _al[1] = {{0}}; + uint32_t _primIn[2]= {0}; + remote_arg* _praIn = 0; + remote_arg** _ppraIn = &_praIn; + remote_arg* _praROut = 0; + remote_arg** _ppraROut = &_praROut; + remote_arg* _praHIn = 0; + remote_arg** _ppraHIn = &_praHIn; + remote_arg* _praHROut = 0; + remote_arg** _ppraHROut = &_praHROut; + char* _seq_primIn1 = 0; + int _nErr = 0; + remote_arg* _praROutPost = 0; + remote_arg** _ppraROutPost = &_praROutPost; + _numIn[0] = 1; + _numROut[0] = 0; + _numInH[0] = 0; + _numROutH[0] = 0; + for(_ii = 0, _seq_nat1 = (char*)_in1[0];_ii < (int)_in1Len[0];++_ii, _seq_nat1 = (_seq_nat1 + SLIM_IFPTR32(8, 16))) + { + _count(_numIn, _numROut, _numInH, _numROutH); + } + if(_numIn[0]>=255) + { + printf("ERROR: Unsupported number of input buffers\n"); + return AEE_EUNSUPPORTED; + } + if(_numROut[0]>=255) + { + printf("ERROR: Unsupported number of output buffers\n"); + return AEE_EUNSUPPORTED; + } + _allocator_init(_al, 0, 0); + _ALLOCATE(_nErr, _al, ((((((((_numIn[0] + _numROut[0]) + _numInH[0]) + _numROutH[0]) + 1) + 0) + 0) + 0) * sizeof(_pra[0])), 4, _pra); + _ASSERT(_nErr, _pra); + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _COPY(_primIn, 0, _in0, 0, 2); + _COPY(_primIn, 4, _in1Len, 0, 4); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 0); + if(_praHIn == 0) + { + _praHIn = ((_praIn + _numIn[0]) + 0); + } + if(_praHROut == 0) + (_praHROut = _praHIn + _numInH[0] + 0); + _ALLOCATE(_nErr, _al, (_in1Len[0] * 4), 4, _praIn[0].buf.pv); + _praIn[0].buf.nLen = (4 * _in1Len[0]); + for(_ii = 0, _seq_primIn1 = (char*)_praIn[0].buf.pv, _seq_nat1 = (char*)_in1[0];_ii < (int)_in1Len[0];++_ii, _seq_primIn1 = (_seq_primIn1 + 4), _seq_nat1 = (_seq_nat1 + SLIM_IFPTR32(8, 16))) + { + _TRY(_nErr, _stub_pack(_al, (_praIn + 1), _ppraIn, (_praROut + 0), _ppraROut, _praHIn, _ppraHIn, _praHROut, _ppraHROut, _seq_primIn1, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat1)[0]), (char**)&(((uint64_t*)_seq_nat1)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat1)[1]), (uint32_t*)&(((uint32_t*)_seq_nat1)[2])))); + } + _ASSERT(_nErr, (_numInH[0] + 0) <= 15); + _ASSERT(_nErr, (_numROutH[0] + 0) <= 15); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, (_numIn[0] + 1), (_numROut[0] + 0), (_numInH[0] + 0), (_numROutH[0] + 0)), _pra)); + _praROutPost = _praROut; + for(_ii = 0, _seq_nat1 = (char*)_in1[0];_ii < (int)_in1Len[0];++_ii, _seq_nat1 = (_seq_nat1 + SLIM_IFPTR32(8, 16))) + { + _TRY(_nErr, _stub_unpack((_praROutPost + 0), _ppraROutPost, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat1)[0]), (char**)&(((uint64_t*)_seq_nat1)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat1)[1]), (uint32_t*)&(((uint32_t*)_seq_nat1)[2])))); + } + _CATCH(_nErr) {} + _allocator_deinit(_al); + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process_set_logging_params)(unsigned short mask, const _cstring1_t* filesToLog, int filesToLogLen) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 2; + remote_handle _handle = _adsp_current_process_handle(); + if (_handle != (remote_handle)-1) + { + return _stub_method_1(_handle, _mid, (uint16_t*)&mask, (void**)&filesToLog, (uint32_t*)&filesToLogLen); + } + else + { + return AEE_EINVHANDLE; + } +} +static __inline int _stub_method_2(remote_handle _handle, uint32_t _mid, uint32_t _rout0[1]) { + int _numIn[1] = {0}; + remote_arg _pra[1] = {0}; + uint32_t _primROut[1]= {0}; + int _nErr = 0; + _numIn[0] = 0; + _pra[(_numIn[0] + 0)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 0)].buf.nLen = sizeof(_primROut); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 0, 1, 0, 0), _pra)); + _COPY(_rout0, 0, _primROut, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process_getASID)(unsigned int* asid) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 3; + remote_handle _handle = _adsp_current_process_handle(); + if (_handle != (remote_handle)-1) + { + return _stub_method_2(_handle, _mid, (uint32_t*)asid); + } + else + { + return AEE_EINVHANDLE; + } +} +static __inline int _stub_method_3(remote_handle _handle, uint32_t _mid, uint32_t _in0[1]) { + remote_arg _pra[1] = {0}; + uint32_t _primIn[1]= {0}; + int _nErr = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _COPY(_primIn, 0, _in0, 0, 4); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 0, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process_setQoS)(unsigned int latency) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 4; + remote_handle _handle = _adsp_current_process_handle(); + if (_handle != (remote_handle)-1) + { + return _stub_method_3(_handle, _mid, (uint32_t*)&latency); + } + else + { + return AEE_EINVHANDLE; + } +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process_exception)(void) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 5; + remote_handle _handle = _adsp_current_process_handle(); + if (_handle != (remote_handle)-1) + { + return _stub_method(_handle, _mid); + } + else + { + return AEE_EINVHANDLE; + } +} +static __inline int _stub_method_4(remote_handle _handle, uint32_t _mid, uint32_t _in0[1], void* _in1[1], uint32_t _in1Len[1]) { + remote_arg* _pra = 0; + int _numIn[1] = {0}; + int _numROut[1] = {0}; + int _numInH[1] = {0}; + int _numROutH[1] = {0}; + char* _seq_nat1 = 0; + int _ii = 0; + _allocator _al[1] = {{0}}; + uint32_t _primIn[2]= {0}; + remote_arg* _praIn = 0; + remote_arg** _ppraIn = &_praIn; + remote_arg* _praROut = 0; + remote_arg** _ppraROut = &_praROut; + remote_arg* _praHIn = 0; + remote_arg** _ppraHIn = &_praHIn; + remote_arg* _praHROut = 0; + remote_arg** _ppraHROut = &_praHROut; + char* _seq_primIn1 = 0; + int _nErr = 0; + remote_arg* _praROutPost = 0; + remote_arg** _ppraROutPost = &_praROutPost; + _numIn[0] = 1; + _numROut[0] = 0; + _numInH[0] = 0; + _numROutH[0] = 0; + for(_ii = 0, _seq_nat1 = (char*)_in1[0];_ii < (int)_in1Len[0];++_ii, _seq_nat1 = (_seq_nat1 + SLIM_IFPTR32(8, 16))) + { + _count(_numIn, _numROut, _numInH, _numROutH); + } + if(_numIn[0]>=255) + { + printf("ERROR: Unsupported number of input buffers\n"); + return AEE_EUNSUPPORTED; + } + if(_numROut[0]>=255) + { + printf("ERROR: Unsupported number of output buffers\n"); + return AEE_EUNSUPPORTED; + } + _allocator_init(_al, 0, 0); + _ALLOCATE(_nErr, _al, ((((((((_numIn[0] + _numROut[0]) + _numInH[0]) + _numROutH[0]) + 1) + 0) + 0) + 0) * sizeof(_pra[0])), 4, _pra); + _ASSERT(_nErr, _pra); + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _in1Len, 0, 4); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 0); + if(_praHIn == 0) + { + _praHIn = ((_praIn + _numIn[0]) + 0); + } + if(_praHROut == 0) + (_praHROut = _praHIn + _numInH[0] + 0); + _ALLOCATE(_nErr, _al, (_in1Len[0] * 4), 4, _praIn[0].buf.pv); + _praIn[0].buf.nLen = (4 * _in1Len[0]); + for(_ii = 0, _seq_primIn1 = (char*)_praIn[0].buf.pv, _seq_nat1 = (char*)_in1[0];_ii < (int)_in1Len[0];++_ii, _seq_primIn1 = (_seq_primIn1 + 4), _seq_nat1 = (_seq_nat1 + SLIM_IFPTR32(8, 16))) + { + _TRY(_nErr, _stub_pack(_al, (_praIn + 1), _ppraIn, (_praROut + 0), _ppraROut, _praHIn, _ppraHIn, _praHROut, _ppraHROut, _seq_primIn1, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat1)[0]), (char**)&(((uint64_t*)_seq_nat1)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat1)[1]), (uint32_t*)&(((uint32_t*)_seq_nat1)[2])))); + } + _ASSERT(_nErr, (_numInH[0] + 0) <= 15); + _ASSERT(_nErr, (_numROutH[0] + 0) <= 15); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, (_numIn[0] + 1), (_numROut[0] + 0), (_numInH[0] + 0), (_numROutH[0] + 0)), _pra)); + _praROutPost = _praROut; + for(_ii = 0, _seq_nat1 = (char*)_in1[0];_ii < (int)_in1Len[0];++_ii, _seq_nat1 = (_seq_nat1 + SLIM_IFPTR32(8, 16))) + { + _TRY(_nErr, _stub_unpack((_praROutPost + 0), _ppraROutPost, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat1)[0]), (char**)&(((uint64_t*)_seq_nat1)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat1)[1]), (uint32_t*)&(((uint32_t*)_seq_nat1)[2])))); + } + _CATCH(_nErr) {} + _allocator_deinit(_al); + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process_set_logging_params2)(unsigned int mask, const _cstring1_t* filesToLog, int filesToLogLen) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 6; + remote_handle _handle = _adsp_current_process_handle(); + if (_handle != (remote_handle)-1) + { + return _stub_method_4(_handle, _mid, (uint32_t*)&mask, (void**)&filesToLog, (uint32_t*)&filesToLogLen); + } + else + { + return AEE_EINVHANDLE; + } +} +static __inline int _stub_method_5(remote_handle _handle, uint32_t _mid, uint32_t _in0[1], uint32_t _in1[1]) { + remote_arg _pra[1] = {0}; + uint32_t _primIn[2]= {0}; + int _nErr = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _in1, 0, 4); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 0, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process_poll_mode)(unsigned int enable, unsigned int timeout) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 7; + remote_handle _handle = _adsp_current_process_handle(); + if (_handle != (remote_handle)-1) + { + return _stub_method_5(_handle, _mid, (uint32_t*)&enable, (uint32_t*)&timeout); + } + else + { + return AEE_EINVHANDLE; + } +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_current_process_enable_notifications)(void) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 8; + remote_handle _handle = _adsp_current_process_handle(); + if (_handle != (remote_handle)-1) + { + return _stub_method(_handle, _mid); + } + else + { + return AEE_EINVHANDLE; + } +} +#ifdef __cplusplus +} +#endif +#endif //_ADSP_CURRENT_PROCESS_STUB_H diff --git a/src/adsp_def_symbols.lst b/src/adsp_def_symbols.lst new file mode 100644 index 0000000..d8a26b3 --- /dev/null +++ b/src/adsp_def_symbols.lst @@ -0,0 +1,11 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +{ + global: + adsp_default_listener_start; + adsp_default_listener1_open; + adsp_default_listener1_close; + adsp_default_listener1_register; + local: *; +}; diff --git a/src/adsp_default_listener.c b/src/adsp_default_listener.c new file mode 100644 index 0000000..ca1ec22 --- /dev/null +++ b/src/adsp_default_listener.c @@ -0,0 +1,249 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +// Need to always define in order to use VERIFY_EPRINTF +#ifndef VERIFY_PRINT_ERROR +#define VERIFY_PRINT_ERROR +#endif + +#define FARF_ERROR 1 + +#include "adsp_default_listener.h" +#include "AEEStdErr.h" +#include "AEEstd.h" +#include "HAP_farf.h" +#include "adsp_default_listener1.h" +#include "fastrpc_common.h" +#include "fastrpc_internal.h" +#include "remote.h" +#include "verify.h" +#include +#include +#include +#include +#include +#include + +#define MAX_DOMAIN_URI_SIZE 12 +#define ROOTPD_NAME "rootpd" +#define ATTACH_GUESTOS "attachguestos" +#define CREATE_STATICPD "createstaticpd:" + +// Array of supported domain names and its corresponding ID's. +static domain_t supported_domains[] = {{ADSP_DOMAIN_ID, ADSP_DOMAIN}, + {MDSP_DOMAIN_ID, MDSP_DOMAIN}, + {SDSP_DOMAIN_ID, SDSP_DOMAIN}, + {CDSP_DOMAIN_ID, CDSP_DOMAIN}}; + +// Get domain name for the domain id. +static domain_t *get_domain_uri(int domain_id) { + int i = 0; + int size = sizeof(supported_domains) / sizeof(domain_t); + + for (i = 0; i < size; i++) { + if (supported_domains[i].id == domain_id) + return &supported_domains[i]; + } + + return NULL; +} + +int adsp_default_listener_start(int argc, char *argv[]) { + struct pollfd pfd; + eventfd_t event = 0; + remote_handle64 event_fd = INVALID_HANDLE; + remote_handle64 fd = INVALID_HANDLE; + remote_handle64 listener_fd = INVALID_HANDLE; + int nErr = AEE_SUCCESS, domain_id = INVALID_DOMAIN_ID; + char *name = NULL; + char *adsp_default_listener1_URI_domain = NULL; + int adsp_default_listener1_URI_domain_len = + strlen(adsp_default_listener1_URI) + MAX_DOMAIN_URI_SIZE; + domain_t *dsp_domain = NULL; + int namelen = 0; + char *eventfd_domain = NULL; + int eventfdlen = 0; + (void)argc; + (void)argv; + + if (argc > 2) { + /* Two arguments are passed in below format + * Example: ./adsprpcd audiopd adsp + * Get domain name from arguments and use domains API. + */ + VERIFY_IPRINTF("%s started with arguments %s and %s\n", __func__, argv[1], + argv[2]); + VERIFYC(INVALID_DOMAIN_ID != (domain_id = get_domain_from_name( + argv[2], DOMAIN_NAME_STAND_ALONE)), + AEE_EINVALIDDOMAIN); + VERIFYC(NULL != (dsp_domain = get_domain_uri(domain_id)), + AEE_EINVALIDDOMAIN); + + // Allocate memory for URI. Example: "ITRANSPORT_PREFIX + // createstaticpd:audiopd&dom=adsp" + namelen = strlen(ITRANSPORT_PREFIX CREATE_STATICPD) + strlen(argv[1]) + + strlen(ADSP_DOMAIN); + VERIFYC(NULL != (name = (char *)malloc((namelen + 1) * sizeof(char))), + AEE_ENOMEMORY); + + // Copy URI to allocated memory + if (!std_strncmp(argv[1], ROOTPD_NAME, std_strlen(argv[1]))) { + std_strlcpy(name, ITRANSPORT_PREFIX ATTACH_GUESTOS, + strlen(ITRANSPORT_PREFIX ATTACH_GUESTOS) + 1); + } else { + std_strlcpy(name, ITRANSPORT_PREFIX CREATE_STATICPD, + strlen(ITRANSPORT_PREFIX CREATE_STATICPD) + 1); + std_strlcat(name, argv[1], + strlen(ITRANSPORT_PREFIX CREATE_STATICPD) + strlen(argv[1]) + + 1); + } + + // Concatenate domain to the URI + std_strlcat(name, dsp_domain->uri, namelen + 1); + + // Open static process handle + VERIFY(AEE_SUCCESS == (nErr = remote_handle64_open(name, &fd))); + goto start_listener; + } else if (argc > 1) { + /* One arguments is passed in below format + * Example: ./adsprpcd "createstaticpd:audiopd&dom=adsp" (or) ./adsprpcd + * audiopd Get domain name from arguments and use domains API. + */ + VERIFY_IPRINTF("%s started with arguments %s\n", __func__, argv[1]); + domain_id = get_domain_from_name(argv[1], DOMAIN_NAME_IN_URI); + + // If domain name part of arguments, use domains API + if (domain_id != INVALID_DOMAIN_ID) { + VERIFY(AEE_SUCCESS == (nErr = remote_handle64_open(argv[1], &fd))); + goto start_listener; + } + + // Allocate memory for URI. Example: "ITRANSPORT_PREFIX + // createstaticpd:audiopd" + namelen = strlen(ITRANSPORT_PREFIX CREATE_STATICPD) + strlen(argv[1]); + VERIFYC(NULL != (name = (char *)malloc((namelen + 1) * sizeof(char))), + AEE_ENOMEMORY); + + // Copy URI to allocated memory + std_strlcpy(name, ITRANSPORT_PREFIX CREATE_STATICPD, + strlen(ITRANSPORT_PREFIX CREATE_STATICPD) + 1); + std_strlcat(name, argv[1], namelen + 1); + } else { + // If no arguments passed, default/rootpd daemon of remote subsystem + namelen = strlen(ITRANSPORT_PREFIX ATTACH_GUESTOS); + VERIFYC(NULL != (name = (char *)malloc((namelen + 1) * sizeof(char))), + AEE_ENOMEMORY); + std_strlcpy(name, ITRANSPORT_PREFIX ATTACH_GUESTOS, + strlen(ITRANSPORT_PREFIX ATTACH_GUESTOS) + 1); + } + + // Default case: Open non-domain static process handle + VERIFY_IPRINTF("%s started with arguments %s\n", __func__, name); + VERIFY(AEE_SUCCESS == (nErr = remote_handle_open(name, (remote_handle *)&fd))); +start_listener: + VERIFYC(!setenv("ADSP_LISTENER_MEM_CACHE_SIZE", "1048576", 0), AEE_ESETENV); + + // If domain name part of arguments, use domains API + if (domain_id != INVALID_DOMAIN_ID) { + // Allocate memory and copy adsp_default_listener1 URI Example: + // "adsp_default_listener1_URI&dom=adsp" + VERIFYC(NULL != + (adsp_default_listener1_URI_domain = (char *)malloc( + (adsp_default_listener1_URI_domain_len) * sizeof(char))), + AEE_ENOMEMORY); + VERIFYC(NULL != (dsp_domain = get_domain_uri(domain_id)), + AEE_EINVALIDDOMAIN); + nErr = snprintf(adsp_default_listener1_URI_domain, + adsp_default_listener1_URI_domain_len, "%s%s", + adsp_default_listener1_URI, dsp_domain->uri); + if (nErr < 0) { + VERIFY_EPRINTF("ERROR: %s: %d returned from snprintf\n", __func__, nErr); + nErr = AEE_EFAILED; + goto bail; + } + + // Open default listener handle + nErr = adsp_default_listener1_open(adsp_default_listener1_URI_domain, + &listener_fd); + + // Register daemon as default listener to static process + if (nErr == AEE_SUCCESS) { + VERIFY(0 == (nErr = adsp_default_listener1_register(listener_fd))); + goto start_poll; + } + } + + // Default case: Register non-domain default listener + VERIFY_IPRINTF("%s domains support is not available for " + "adsp_default_listener1, using non-domain API\n", + __func__); + VERIFY(0 == + (nErr = remote_handle_open("adsp_default_listener", (remote_handle *)&listener_fd))); + VERIFY(0 == (nErr = adsp_default_listener_register())); +start_poll: + // If domain name part of arguments, use domains API + if (domain_id != INVALID_DOMAIN_ID) { + // Allocate memory and copy geteventfd URI Example: "ITRANSPORT_PREFIX + // geteventfd&dom=adsp" + eventfdlen = strlen(ITRANSPORT_PREFIX "geteventfd") + MAX_DOMAIN_URI_SIZE; + VERIFYC(NULL != + (eventfd_domain = (char *)malloc((eventfdlen) * sizeof(char))), + AEE_ENOMEMORY); + nErr = snprintf(eventfd_domain, eventfdlen, "%s%s", + ITRANSPORT_PREFIX "geteventfd", dsp_domain->uri); + if (nErr < 0) { + VERIFY_EPRINTF("ERROR: %s: %d returned from snprintf\n", __func__, nErr); + nErr = AEE_EFAILED; + goto bail; + } + + // Get even FD to poll on listener thread + VERIFY(0 == (nErr = remote_handle64_open(eventfd_domain, &event_fd))); + pfd.fd = (remote_handle)event_fd; + } else { + VERIFY(0 == (nErr = remote_handle_open(ITRANSPORT_PREFIX "geteventfd", + (remote_handle *)&pfd.fd))); + } + if (name != NULL) { + free(name); + name = NULL; + } + if (eventfd_domain != NULL) { + free(eventfd_domain); + eventfd_domain = NULL; + } + if (adsp_default_listener1_URI_domain != NULL) { + free(adsp_default_listener1_URI_domain); + adsp_default_listener1_URI_domain = NULL; + } + // Poll on listener thread + pfd.events = POLLIN; + pfd.revents = 0; + while (1) { + VERIFYC(0 < poll(&pfd, 1, -1), AEE_EPOLL); + VERIFYC(0 == eventfd_read(pfd.fd, &event), AEE_EEVENTREAD); + if (event) { + break; + } + } +bail: + if (listener_fd != INVALID_HANDLE) { + adsp_default_listener1_close(listener_fd); + } + if (nErr != AEE_SUCCESS) { + if (name != NULL) { + free(name); + name = NULL; + } + if (eventfd_domain != NULL) { + free(eventfd_domain); + eventfd_domain = NULL; + } + if (adsp_default_listener1_URI_domain != NULL) { + free(adsp_default_listener1_URI_domain); + adsp_default_listener1_URI_domain = NULL; + } + VERIFY_EPRINTF("Error 0x%x: %s exiting\n", nErr, __func__); + } + return nErr; +} diff --git a/src/adsp_default_listener1_stub.c b/src/adsp_default_listener1_stub.c new file mode 100644 index 0000000..d511c35 --- /dev/null +++ b/src/adsp_default_listener1_stub.c @@ -0,0 +1,314 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _ADSP_DEFAULT_LISTENER1_STUB_H +#define _ADSP_DEFAULT_LISTENER1_STUB_H +#include "adsp_default_listener1.h" +#include +#ifndef _WIN32 +#include "HAP_farf.h" +#endif //_WIN32 for HAP_farf +#include +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include +#include + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc((size_t)size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + (size_t)size) < (uintptr_t)me->stack + (size_t)me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _ADSP_DEFAULT_LISTENER1_SLIM_H +#define _ADSP_DEFAULT_LISTENER1_SLIM_H +#include + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Parameter parameters[3] = {{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)0x0,0}}, 4,SLIM_IFPTR32(0x4,0x8),0,0},{SLIM_IFPTR32(0x4,0x8),{{(const uintptr_t)0xdeadc0de,(const uintptr_t)0}}, 0,SLIM_IFPTR32(0x4,0x8),3,0},{SLIM_IFPTR32(0x4,0x8),{{(const uintptr_t)0xdeadc0de,(const uintptr_t)0}}, 0,SLIM_IFPTR32(0x4,0x8),0,0}}; +static const Parameter* const parameterArrays[3] = {(&(parameters[0])),(&(parameters[1])),(&(parameters[2]))}; +static const Method methods[3] = {{REMOTE_SCALARS_MAKEX(0,0,0x2,0x0,0x0,0x1),0x4,0x0,2,2,(&(parameterArrays[0])),0x4,0x1},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x0,0x1,0x0),0x0,0x0,1,1,(&(parameterArrays[2])),0x1,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x0,0x0,0x0),0x0,0x0,0,0,0,0x0,0x0}}; +static const Method* const methodArrays[3] = {&(methods[0]),&(methods[1]),&(methods[2])}; +static const char strings[27] = "register\0close\0open\0uri\0h\0"; +static const uint16_t methodStrings[6] = {15,20,24,9,24,0}; +static const uint16_t methodStringsArrays[3] = {0,3,5}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(adsp_default_listener1_slim) = {3,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_ADSP_DEFAULT_LISTENER1_SLIM_H + + +#ifdef __cplusplus +extern "C" { +#endif +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_default_listener1_open)(const char* uri, remote_handle64* h) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle64_open)(uri, h); +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_default_listener1_close)(remote_handle64 h) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle64_close)(h); +} +static __inline int _stub_method(remote_handle64 _handle, uint32_t _mid) { + remote_arg* _pra = 0; + int _nErr = 0; + _TRY_FARF(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 0, 0, 0, 0), _pra)); + _CATCH_FARF(_nErr) { + _QAIC_FARF(RUNTIME_ERROR, "ERROR 0x%x: handle=0x%"PRIx64", scalar=0x%x, method ID=%d: %s failed\n", _nErr , _handle, REMOTE_SCALARS_MAKEX(0, _mid, 0, 0, 0, 0), _mid, __func__); + } + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_default_listener1_register)(remote_handle64 _handle) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 2; + return _stub_method(_handle, _mid); +} +#ifdef __cplusplus +} +#endif +#endif //_ADSP_DEFAULT_LISTENER1_STUB_H diff --git a/src/adsp_default_listener_stub.c b/src/adsp_default_listener_stub.c new file mode 100644 index 0000000..92a8710 --- /dev/null +++ b/src/adsp_default_listener_stub.c @@ -0,0 +1,559 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _ADSP_DEFAULT_LISTENER_STUB_H +#define _ADSP_DEFAULT_LISTENER_STUB_H +#include "adsp_default_listener.h" +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#include + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef _ATTRIBUTE_VISIBILITY + +#ifdef _WIN32 +#define _ATTRIBUTE_VISIBILITY +#else +#define _ATTRIBUTE_VISIBILITY __attribute__ ((visibility("default"))) +#endif + +#endif // _ATTRIBUTE_VISIBILITY + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i = 0; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#endif + + +#endif // _QAIC_ENV_H + +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include +#include + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc((size_t)size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + (size_t)size) < (uintptr_t)me->stack + (size_t)me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _ADSP_DEFAULT_LISTENER_SLIM_H +#define _ADSP_DEFAULT_LISTENER_SLIM_H +#include + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Method methods[1] = {{REMOTE_SCALARS_MAKEX(0,0,0x0,0x0,0x0,0x0),0x0,0x0,0,0,0,0x0,0x0}}; +static const Method* const methodArrays[1] = {&(methods[0])}; +static const char strings[10] = "register\0"; +static const uint16_t methodStrings[1] = {0}; +static const uint16_t methodStringsArrays[1] = {0}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(adsp_default_listener_slim) = {1,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_ADSP_DEFAULT_LISTENER_SLIM_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _const_adsp_default_listener_handle +#define _const_adsp_default_listener_handle ((remote_handle)-1) +#endif //_const_adsp_default_listener_handle + +static void _adsp_default_listener_pls_dtor(void* data) { + remote_handle* ph = (remote_handle*)data; + if(_const_adsp_default_listener_handle != *ph) { + (void)__QAIC_REMOTE(remote_handle_close)(*ph); + *ph = _const_adsp_default_listener_handle; + } +} + +static int _adsp_default_listener_pls_ctor(void* ctx, void* data) { + remote_handle* ph = (remote_handle*)data; + *ph = _const_adsp_default_listener_handle; + if(*ph == (remote_handle)-1) { + return __QAIC_REMOTE(remote_handle_open)((const char*)ctx, ph); + } + return 0; +} + +#if (defined __qdsp6__) || (defined __hexagon__) +#pragma weak adsp_pls_add_lookup +extern int adsp_pls_add_lookup(uint32_t type, uint32_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* ctx), void** ppo); +#pragma weak HAP_pls_add_lookup +extern int HAP_pls_add_lookup(uint32_t type, uint32_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* ctx), void** ppo); + +__QAIC_STUB_EXPORT remote_handle _adsp_default_listener_handle(void) { + remote_handle* ph = 0; + if(adsp_pls_add_lookup) { + if(0 == adsp_pls_add_lookup((uint32_t)_adsp_default_listener_handle, 0, sizeof(*ph), _adsp_default_listener_pls_ctor, "adsp_default_listener", _adsp_default_listener_pls_dtor, (void**)&ph)) { + return *ph; + } + return (remote_handle)-1; + } else if(HAP_pls_add_lookup) { + if(0 == HAP_pls_add_lookup((uint32_t)_adsp_default_listener_handle, 0, sizeof(*ph), _adsp_default_listener_pls_ctor, "adsp_default_listener", _adsp_default_listener_pls_dtor, (void**)&ph)) { + return *ph; + } + return (remote_handle)-1; + } + return(remote_handle)-1; +} + +#else //__qdsp6__ || __hexagon__ + +uint32_t _adsp_default_listener_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare); + +#ifdef _WIN32 +#ifdef _USRDLL +#include "Windows.h" +#else +#include "ntddk.h" +#endif //_USRDLL +uint32_t _adsp_default_listener_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare) { + return (uint32_t)InterlockedCompareExchange((volatile LONG*)puDest, (LONG)uExchange, (LONG)uCompare); +} +#elif __GNUC__ +uint32_t _adsp_default_listener_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare) { + return __sync_val_compare_and_swap(puDest, uCompare, uExchange); +} +#endif //_WIN32 + + +__QAIC_STUB_EXPORT remote_handle _adsp_default_listener_handle(void) { + static remote_handle handle = _const_adsp_default_listener_handle; + if((remote_handle)-1 != handle) { + return handle; + } else { + remote_handle tmp; + int nErr = _adsp_default_listener_pls_ctor("adsp_default_listener", (void*)&tmp); + if(nErr) { + return (remote_handle)-1; + } + if(((remote_handle)-1 != handle) || ((remote_handle)-1 != (remote_handle)_adsp_default_listener_atomic_CompareAndExchange((uint32_t*)&handle, (uint32_t)tmp, (uint32_t)-1))) { + _adsp_default_listener_pls_dtor(&tmp); + } + return handle; + } +} + +#endif //__qdsp6__ + +#ifdef __cplusplus +} +#endif + + +#ifdef __cplusplus +extern "C" { +#endif +static __inline int _stub_method(remote_handle _handle, uint32_t _mid) { + remote_arg* _pra = 0; + int _nErr = 0; + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 0, 0, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_default_listener_register)(void) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 0; + remote_handle _handle = _adsp_default_listener_handle(); + if (_handle != (remote_handle)-1) + { + return _stub_method(_handle, _mid); + } + else + { + return AEE_EINVHANDLE; + } +} +#ifdef __cplusplus +} +#endif +#endif //_ADSP_DEFAULT_LISTENER_STUB_H diff --git a/src/adsp_listener1_stub.c b/src/adsp_listener1_stub.c new file mode 100644 index 0000000..89a47a6 --- /dev/null +++ b/src/adsp_listener1_stub.c @@ -0,0 +1,647 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _ADSP_LISTENER1_STUB_H +#define _ADSP_LISTENER1_STUB_H +#include "adsp_listener1.h" +#include +#ifndef _WIN32 +#include "HAP_farf.h" +#endif //_WIN32 for HAP_farf +#include +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include +#include + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc((size_t)size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + (size_t)size) < (uintptr_t)me->stack + (size_t)me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _ADSP_LISTENER1_SLIM_H +#define _ADSP_LISTENER1_SLIM_H +#include + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Type types[3]; +static const SequenceType sequenceTypes[1] = {{&(types[0]),0x0,0x4,0x4,0x0}}; +static const Type types[3] = {{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[1]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8)},{0x1,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x1},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4}}; +static const Parameter parameters[14] = {{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)0x0,0}}, 4,SLIM_IFPTR32(0x4,0x8),0,0},{SLIM_IFPTR32(0x4,0x8),{{(const uintptr_t)0xdeadc0de,(const uintptr_t)0}}, 0,SLIM_IFPTR32(0x4,0x8),3,0},{SLIM_IFPTR32(0x4,0x8),{{(const uintptr_t)0xdeadc0de,(const uintptr_t)0}}, 0,SLIM_IFPTR32(0x4,0x8),0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(sequenceTypes[0]),0}}, 25,SLIM_IFPTR32(0x4,0x8),0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(sequenceTypes[0]),0}}, 25,SLIM_IFPTR32(0x4,0x8),3,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[2]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8),3,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[1]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8),0,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[1]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8),3,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0}}; +static const Parameter* const parameterArrays[26] = {(&(parameters[3])),(&(parameters[4])),(&(parameters[5])),(&(parameters[6])),(&(parameters[7])),(&(parameters[8])),(&(parameters[9])),(&(parameters[10])),(&(parameters[10])),(&(parameters[3])),(&(parameters[4])),(&(parameters[11])),(&(parameters[6])),(&(parameters[7])),(&(parameters[8])),(&(parameters[12])),(&(parameters[13])),(&(parameters[3])),(&(parameters[4])),(&(parameters[12])),(&(parameters[13])),(&(parameters[3])),(&(parameters[9])),(&(parameters[0])),(&(parameters[1])),(&(parameters[2]))}; +static const Method methods[7] = {{REMOTE_SCALARS_MAKEX(0,0,0x2,0x0,0x0,0x1),0x4,0x0,2,2,(&(parameterArrays[23])),0x4,0x1},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x0,0x1,0x0),0x0,0x0,1,1,(&(parameterArrays[25])),0x1,0x0},{REMOTE_SCALARS_MAKEX(0,0,255,255,15,15),0x18,0xc,16,9,(&(parameterArrays[0])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,255,255,15,15),0x8,0x0,4,2,(&(parameterArrays[21])),0x4,0x1},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x0,0x0,0x0),0x0,0x0,0,0,0,0x0,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x2,0x2,0x0,0x0),0x10,0x10,11,8,(&(parameterArrays[9])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x2,0x0,0x0),0xc,0x4,6,4,(&(parameterArrays[17])),0x4,0x4}}; +static const Method* const methodArrays[8] = {&(methods[0]),&(methods[1]),&(methods[2]),&(methods[3]),&(methods[4]),&(methods[4]),&(methods[5]),&(methods[6])}; +static const char strings[183] = "invoke_get_in_bufs\0routBufLenReq\0get_in_bufs2\0inBufLenReq\0next_invoke\0bufsLenReq\0prevResult\0inBuffers\0prevbufs\0outBufs\0prevCtx\0offset\0handle\0next2\0init2\0close\0init\0open\0ctx\0uri\0sc\0h\0"; +static const uint16_t methodStrings[34] = {58,119,81,111,169,134,177,92,46,19,141,119,81,102,169,134,177,14,70,33,169,127,14,70,0,169,92,164,173,180,153,180,147,159}; +static const uint16_t methodStringsArrays[8] = {27,30,0,24,33,32,10,19}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(adsp_listener1_slim) = {8,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_ADSP_LISTENER1_SLIM_H + + +#ifdef __cplusplus +extern "C" { +#endif +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_listener1_open)(const char* uri, remote_handle64* h) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle64_open)(uri, h); +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_listener1_close)(remote_handle64 h) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle64_close)(h); +} +static __inline int _stub_unpack(_ATTRIBUTE_UNUSED remote_arg* _praROutPost, _ATTRIBUTE_UNUSED remote_arg* _ppraROutPost[1], _ATTRIBUTE_UNUSED void* _primROut, _ATTRIBUTE_UNUSED char* _rout0[1], _ATTRIBUTE_UNUSED uint32_t _rout0Len[1]) { + int _nErr = 0; + remote_arg* _praROutPostStart = _praROutPost; + remote_arg** _ppraROutPostStart = _ppraROutPost; + _ppraROutPost = &_praROutPost; + _ppraROutPostStart[0] += (_praROutPost - _praROutPostStart) +1; + return _nErr; +} +static __inline int _stub_unpack_1(_ATTRIBUTE_UNUSED remote_arg* _praROutPost, _ATTRIBUTE_UNUSED remote_arg* _ppraROutPost[1], _ATTRIBUTE_UNUSED void* _primROut, _ATTRIBUTE_UNUSED char* _in0[1], _ATTRIBUTE_UNUSED uint32_t _in0Len[1]) { + int _nErr = 0; + remote_arg* _praROutPostStart = _praROutPost; + remote_arg** _ppraROutPostStart = _ppraROutPost; + _ppraROutPost = &_praROutPost; + _ppraROutPostStart[0] += (_praROutPost - _praROutPostStart) +0; + return _nErr; +} +static __inline int _stub_pack(_ATTRIBUTE_UNUSED _allocator* _al, _ATTRIBUTE_UNUSED remote_arg* _praIn, _ATTRIBUTE_UNUSED remote_arg* _ppraIn[1], _ATTRIBUTE_UNUSED remote_arg* _praROut, _ATTRIBUTE_UNUSED remote_arg* _ppraROut[1], _ATTRIBUTE_UNUSED remote_arg* _praHIn, _ATTRIBUTE_UNUSED remote_arg* _ppraHIn[1], _ATTRIBUTE_UNUSED remote_arg* _praHROut, _ATTRIBUTE_UNUSED remote_arg* _ppraHROut[1], _ATTRIBUTE_UNUSED void* _primIn, _ATTRIBUTE_UNUSED void* _primROut, _ATTRIBUTE_UNUSED char* _rout0[1], _ATTRIBUTE_UNUSED uint32_t _rout0Len[1]) { + int _nErr = 0; + remote_arg* _praInStart = _praIn; + remote_arg** _ppraInStart = _ppraIn; + remote_arg* _praROutStart = _praROut; + remote_arg** _ppraROutStart = _ppraROut; + _ppraIn = &_praIn; + _ppraROut = &_praROut; + _COPY(_primIn, 0, _rout0Len, 0, 4); + _praROut[0].buf.pv = _rout0[0]; + _praROut[0].buf.nLen = (1 * _rout0Len[0]); + _ppraInStart[0] += (_praIn - _praInStart) + 0; + _ppraROutStart[0] += (_praROut - _praROutStart) +1; + return _nErr; +} +static __inline int _stub_pack_1(_ATTRIBUTE_UNUSED _allocator* _al, _ATTRIBUTE_UNUSED remote_arg* _praIn, _ATTRIBUTE_UNUSED remote_arg* _ppraIn[1], _ATTRIBUTE_UNUSED remote_arg* _praROut, _ATTRIBUTE_UNUSED remote_arg* _ppraROut[1], _ATTRIBUTE_UNUSED remote_arg* _praHIn, _ATTRIBUTE_UNUSED remote_arg* _ppraHIn[1], _ATTRIBUTE_UNUSED remote_arg* _praHROut, _ATTRIBUTE_UNUSED remote_arg* _ppraHROut[1], _ATTRIBUTE_UNUSED void* _primIn, _ATTRIBUTE_UNUSED void* _primROut, _ATTRIBUTE_UNUSED char* _in0[1], _ATTRIBUTE_UNUSED uint32_t _in0Len[1]) { + int _nErr = 0; + remote_arg* _praInStart = _praIn; + remote_arg** _ppraInStart = _ppraIn; + remote_arg* _praROutStart = _praROut; + remote_arg** _ppraROutStart = _ppraROut; + _ppraIn = &_praIn; + _ppraROut = &_praROut; + _COPY(_primIn, 0, _in0Len, 0, 4); + _praIn[0].buf.pv = (void*) _in0[0]; + _praIn[0].buf.nLen = (1 * _in0Len[0]); + _ppraInStart[0] += (_praIn - _praInStart) + 1; + _ppraROutStart[0] += (_praROut - _praROutStart) +0; + return _nErr; +} +static __inline void _count(int _numIn[1], int _numROut[1], int _numInH[1], int _numROutH[1], _ATTRIBUTE_UNUSED char* _rout0[1], _ATTRIBUTE_UNUSED uint32_t _rout0Len[1]) { + _numIn[0] += 0; + _numROut[0] += 1; + _numInH[0] += 0; + _numROutH[0] += 0; +} +static __inline void _count_1(int _numIn[1], int _numROut[1], int _numInH[1], int _numROutH[1], _ATTRIBUTE_UNUSED char* _in0[1], _ATTRIBUTE_UNUSED uint32_t _in0Len[1]) { + _numIn[0] += 1; + _numROut[0] += 0; + _numInH[0] += 0; + _numROutH[0] += 0; +} +static __inline int _stub_method(remote_handle64 _handle, uint32_t _mid, uint32_t _in0[1], uint32_t _in1[1], void* _in2[1], uint32_t _in2Len[1], uint32_t _rout3[1], uint32_t _rout4[1], uint32_t _rout5[1], void* _rout6[1], uint32_t _rout6Len[1], char* _rout7[1], uint32_t _rout7Len[1], char* _rout8[1], uint32_t _rout8Len[1]) { + remote_arg* _pra = 0; + int _numIn[1] = {0}; + int _numROut[1] = {0}; + int _numInH[1] = {0}; + int _numROutH[1] = {0}; + char* _seq_nat2 = 0; + int _ii = 0; + char* _seq_nat6 = 0; + _allocator _al[1] = {{0}}; + uint32_t _primIn[6]= {0}; + uint32_t _primROut[3]= {0}; + remote_arg* _praIn = 0; + remote_arg* _praROut = 0; + remote_arg* _praROutPost = 0; + remote_arg** _ppraROutPost = &_praROutPost; + remote_arg** _ppraIn = &_praIn; + remote_arg** _ppraROut = &_praROut; + remote_arg* _praHIn = 0; + remote_arg** _ppraHIn = &_praHIn; + remote_arg* _praHROut = 0; + remote_arg** _ppraHROut = &_praHROut; + char* _seq_primIn2 = 0; + int _nErr = 0; + char* _seq_primIn6 = 0; + _numIn[0] = 2; + _numROut[0] = 2; + _numInH[0] = 0; + _numROutH[0] = 0; + for(_ii = 0, _seq_nat2 = (char*)_in2[0];_ii < (int)_in2Len[0];++_ii, _seq_nat2 = (_seq_nat2 + SLIM_IFPTR32(8, 16))){ + _count_1(_numIn, _numROut, _numInH, _numROutH, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat2)[0]), (char**)&(((uint64_t*)_seq_nat2)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat2)[1]), (uint32_t*)&(((uint32_t*)_seq_nat2)[2]))); + } + for(_ii = 0, _seq_nat6 = (char*)_rout6[0];_ii < (int)_rout6Len[0];++_ii, _seq_nat6 = (_seq_nat6 + SLIM_IFPTR32(8, 16))){ + _count(_numIn, _numROut, _numInH, _numROutH, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat6)[0]), (char**)&(((uint64_t*)_seq_nat6)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat6)[1]), (uint32_t*)&(((uint32_t*)_seq_nat6)[2]))); + } + if(_numIn[0]>=255){ + _QAIC_FARF(RUNTIME_ERROR, "ERROR: Unsupported number of input buffers\n"); + return AEE_EUNSUPPORTED; + } + if(_numROut[0]>=255){ + _QAIC_FARF(RUNTIME_ERROR, "ERROR: Unsupported number of output buffers\n"); + return AEE_EUNSUPPORTED; + } + _allocator_init(_al, 0, 0); + _ALLOCATE(_nErr, _al, ((((((((_numIn[0] + _numROut[0]) + _numInH[0]) + _numROutH[0]) + 1) + 1) + 0) + 0) * sizeof(_pra[0])), 4, _pra); + _ASSERT(_nErr, _pra); + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _pra[(_numIn[0] + 1)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 1)].buf.nLen = sizeof(_primROut); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 1); + _praROutPost = _praROut; + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _in1, 0, 4); + _COPY(_primIn, 8, _in2Len, 0, 4); + if(_praHIn == 0) + { + _praHIn = ((_praROut + _numROut[0]) + 1); + } + if(_praHROut == 0) + (_praHROut = _praHIn + _numInH[0] + 0); + _ALLOCATE(_nErr, _al, (_in2Len[0] * 4), 4, _praIn[0].buf.pv); + _praIn[0].buf.nLen = (4 * _in2Len[0]); + for(_ii = 0, _seq_primIn2 = (char*)_praIn[0].buf.pv, _seq_nat2 = (char*)_in2[0];_ii < (int)_in2Len[0];++_ii, _seq_primIn2 = (_seq_primIn2 + 4), _seq_nat2 = (_seq_nat2 + SLIM_IFPTR32(8, 16))){ + _TRY(_nErr, _stub_pack_1(_al, (_praIn + 1), _ppraIn, (_praROut + 0), _ppraROut, _praHIn, _ppraHIn, _praHROut, _ppraHROut, _seq_primIn2, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat2)[0]), (char**)&(((uint64_t*)_seq_nat2)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat2)[1]), (uint32_t*)&(((uint32_t*)_seq_nat2)[2])))); + } + _COPY(_primIn, 12, _rout6Len, 0, 4); + _ALLOCATE(_nErr, _al, (_rout6Len[0] * 4), 4, _praIn[1].buf.pv); + _praIn[1].buf.nLen = (4 * _rout6Len[0]); + for(_ii = 0, _seq_primIn6 = (char*)_praIn[1].buf.pv, _seq_nat6 = (char*)_rout6[0];_ii < (int)_rout6Len[0];++_ii, _seq_primIn6 = (_seq_primIn6 + 4), _seq_nat6 = (_seq_nat6 + SLIM_IFPTR32(8, 16))){ + _TRY(_nErr, _stub_pack(_al, (_praIn + 2), _ppraIn, (_praROut + 0), _ppraROut, _praHIn, _ppraHIn, _praHROut, _ppraHROut, _seq_primIn6, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat6)[0]), (char**)&(((uint64_t*)_seq_nat6)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat6)[1]), (uint32_t*)&(((uint32_t*)_seq_nat6)[2])))); + } + _COPY(_primIn, 16, _rout7Len, 0, 4); + _praROut[0].buf.pv = _rout7[0]; + _praROut[0].buf.nLen = (4 * _rout7Len[0]); + _COPY(_primIn, 20, _rout8Len, 0, 4); + _praROut[1].buf.pv = _rout8[0]; + _praROut[1].buf.nLen = (4 * _rout8Len[0]); + _ASSERT(_nErr, (_numInH[0] + 0) <= 15); + _ASSERT(_nErr, (_numROutH[0] + 0) <= 15); + _TRY_FARF(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, (_numIn[0] + 1), (_numROut[0] + 1), (_numInH[0] + 0), (_numROutH[0] + 0)), _pra)); + for(_ii = 0, _seq_nat2 = (char*)_in2[0];_ii < (int)_in2Len[0];++_ii, _seq_nat2 = (_seq_nat2 + SLIM_IFPTR32(8, 16))){ + _TRY(_nErr, _stub_unpack_1((_praROutPost + 0), _ppraROutPost, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat2)[0]), (char**)&(((uint64_t*)_seq_nat2)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat2)[1]), (uint32_t*)&(((uint32_t*)_seq_nat2)[2])))); + } + _COPY(_rout3, 0, _primROut, 0, 4); + _COPY(_rout4, 0, _primROut, 4, 4); + _COPY(_rout5, 0, _primROut, 8, 4); + for(_ii = 0, _seq_nat6 = (char*)_rout6[0];_ii < (int)_rout6Len[0];++_ii, _seq_nat6 = (_seq_nat6 + SLIM_IFPTR32(8, 16))){ + _TRY(_nErr, _stub_unpack((_praROutPost + 0), _ppraROutPost, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat6)[0]), (char**)&(((uint64_t*)_seq_nat6)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat6)[1]), (uint32_t*)&(((uint32_t*)_seq_nat6)[2])))); + } + _CATCH(_nErr) {} + _allocator_deinit(_al); + _CATCH_FARF(_nErr) { + _QAIC_FARF(RUNTIME_ERROR, "ERROR 0x%x: handle=0x%"PRIx64", scalar=0x%x, method ID=%d: %s failed\n", _nErr , _handle, REMOTE_SCALARS_MAKEX(0, _mid, (_numIn[0] + 1), (_numROut[0] + 1), (_numInH[0] + 0), (_numROutH[0] + 0)), _mid, __func__); + } + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_listener1_next_invoke)(remote_handle64 _handle, adsp_listener1_invoke_ctx prevCtx, int prevResult, const adsp_listener1_buffer* outBufs, int outBufsLen, adsp_listener1_invoke_ctx* ctx, adsp_listener1_remote_handle* handle, uint32* sc, adsp_listener1_buffer* inBuffers, int inBuffersLen, int* inBufLenReq, int inBufLenReqLen, int* routBufLenReq, int routBufLenReqLen) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 2; + return _stub_method(_handle, _mid, (uint32_t*)&prevCtx, (uint32_t*)&prevResult, (void**)&outBufs, (uint32_t*)&outBufsLen, (uint32_t*)ctx, (uint32_t*)handle, (uint32_t*)sc, (void**)&inBuffers, (uint32_t*)&inBuffersLen, (char**)&inBufLenReq, (uint32_t*)&inBufLenReqLen, (char**)&routBufLenReq, (uint32_t*)&routBufLenReqLen); +} +static __inline int _stub_unpack_2(_ATTRIBUTE_UNUSED remote_arg* _praROutPost, _ATTRIBUTE_UNUSED remote_arg* _ppraROutPost[1], _ATTRIBUTE_UNUSED void* _primROut, _ATTRIBUTE_UNUSED char* _rout0[1], _ATTRIBUTE_UNUSED uint32_t _rout0Len[1]) { + int _nErr = 0; + remote_arg* _praROutPostStart = _praROutPost; + remote_arg** _ppraROutPostStart = _ppraROutPost; + _ppraROutPost = &_praROutPost; + _ppraROutPostStart[0] += (_praROutPost - _praROutPostStart) +1; + return _nErr; +} +static __inline int _stub_pack_2(_ATTRIBUTE_UNUSED _allocator* _al, _ATTRIBUTE_UNUSED remote_arg* _praIn, _ATTRIBUTE_UNUSED remote_arg* _ppraIn[1], _ATTRIBUTE_UNUSED remote_arg* _praROut, _ATTRIBUTE_UNUSED remote_arg* _ppraROut[1], _ATTRIBUTE_UNUSED remote_arg* _praHIn, _ATTRIBUTE_UNUSED remote_arg* _ppraHIn[1], _ATTRIBUTE_UNUSED remote_arg* _praHROut, _ATTRIBUTE_UNUSED remote_arg* _ppraHROut[1], _ATTRIBUTE_UNUSED void* _primIn, _ATTRIBUTE_UNUSED void* _primROut, _ATTRIBUTE_UNUSED char* _rout0[1], _ATTRIBUTE_UNUSED uint32_t _rout0Len[1]) { + int _nErr = 0; + remote_arg* _praInStart = _praIn; + remote_arg** _ppraInStart = _ppraIn; + remote_arg* _praROutStart = _praROut; + remote_arg** _ppraROutStart = _ppraROut; + _ppraIn = &_praIn; + _ppraROut = &_praROut; + _COPY(_primIn, 0, _rout0Len, 0, 4); + _praROut[0].buf.pv = _rout0[0]; + _praROut[0].buf.nLen = (1 * _rout0Len[0]); + _ppraInStart[0] += (_praIn - _praInStart) + 0; + _ppraROutStart[0] += (_praROut - _praROutStart) +1; + return _nErr; +} +static __inline int _stub_method_1(remote_handle64 _handle, uint32_t _mid, uint32_t _in0[1], void* _rout1[1], uint32_t _rout1Len[1]) { + remote_arg* _pra = 0; + int _numIn[1] = {0}; + int _numROut[1] = {0}; + int _numInH[1] = {0}; + int _numROutH[1] = {0}; + char* _seq_nat1 = 0; + int _ii = 0; + _allocator _al[1] = {{0}}; + uint32_t _primIn[2]= {0}; + remote_arg* _praIn = 0; + remote_arg* _praROut = 0; + remote_arg* _praROutPost = 0; + remote_arg** _ppraROutPost = &_praROutPost; + remote_arg** _ppraIn = &_praIn; + remote_arg** _ppraROut = &_praROut; + remote_arg* _praHIn = 0; + remote_arg** _ppraHIn = &_praHIn; + remote_arg* _praHROut = 0; + remote_arg** _ppraHROut = &_praHROut; + char* _seq_primIn1 = 0; + int _nErr = 0; + _numIn[0] = 1; + _numROut[0] = 0; + _numInH[0] = 0; + _numROutH[0] = 0; + for(_ii = 0, _seq_nat1 = (char*)_rout1[0];_ii < (int)_rout1Len[0];++_ii, _seq_nat1 = (_seq_nat1 + SLIM_IFPTR32(8, 16))){ + _count(_numIn, _numROut, _numInH, _numROutH, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat1)[0]), (char**)&(((uint64_t*)_seq_nat1)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat1)[1]), (uint32_t*)&(((uint32_t*)_seq_nat1)[2]))); + } + if(_numIn[0]>=255){ + _QAIC_FARF(RUNTIME_ERROR, "ERROR: Unsupported number of input buffers\n"); + return AEE_EUNSUPPORTED; + } + if(_numROut[0]>=255){ + _QAIC_FARF(RUNTIME_ERROR, "ERROR: Unsupported number of output buffers\n"); + return AEE_EUNSUPPORTED; + } + _allocator_init(_al, 0, 0); + _ALLOCATE(_nErr, _al, ((((((((_numIn[0] + _numROut[0]) + _numInH[0]) + _numROutH[0]) + 1) + 0) + 0) + 0) * sizeof(_pra[0])), 4, _pra); + _ASSERT(_nErr, _pra); + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 0); + _praROutPost = _praROut; + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _rout1Len, 0, 4); + if(_praHIn == 0) + { + _praHIn = ((_praROut + _numROut[0]) + 0); + } + if(_praHROut == 0) + (_praHROut = _praHIn + _numInH[0] + 0); + _ALLOCATE(_nErr, _al, (_rout1Len[0] * 4), 4, _praIn[0].buf.pv); + _praIn[0].buf.nLen = (4 * _rout1Len[0]); + for(_ii = 0, _seq_primIn1 = (char*)_praIn[0].buf.pv, _seq_nat1 = (char*)_rout1[0];_ii < (int)_rout1Len[0];++_ii, _seq_primIn1 = (_seq_primIn1 + 4), _seq_nat1 = (_seq_nat1 + SLIM_IFPTR32(8, 16))){ + _TRY(_nErr, _stub_pack_2(_al, (_praIn + 1), _ppraIn, (_praROut + 0), _ppraROut, _praHIn, _ppraHIn, _praHROut, _ppraHROut, _seq_primIn1, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat1)[0]), (char**)&(((uint64_t*)_seq_nat1)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat1)[1]), (uint32_t*)&(((uint32_t*)_seq_nat1)[2])))); + } + _ASSERT(_nErr, (_numInH[0] + 0) <= 15); + _ASSERT(_nErr, (_numROutH[0] + 0) <= 15); + _TRY_FARF(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, (_numIn[0] + 1), (_numROut[0] + 0), (_numInH[0] + 0), (_numROutH[0] + 0)), _pra)); + for(_ii = 0, _seq_nat1 = (char*)_rout1[0];_ii < (int)_rout1Len[0];++_ii, _seq_nat1 = (_seq_nat1 + SLIM_IFPTR32(8, 16))){ + _TRY(_nErr, _stub_unpack_2((_praROutPost + 0), _ppraROutPost, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat1)[0]), (char**)&(((uint64_t*)_seq_nat1)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat1)[1]), (uint32_t*)&(((uint32_t*)_seq_nat1)[2])))); + } + _CATCH(_nErr) {} + _allocator_deinit(_al); + _CATCH_FARF(_nErr) { + _QAIC_FARF(RUNTIME_ERROR, "ERROR 0x%x: handle=0x%"PRIx64", scalar=0x%x, method ID=%d: %s failed\n", _nErr , _handle, REMOTE_SCALARS_MAKEX(0, _mid, (_numIn[0] + 1), (_numROut[0] + 0), (_numInH[0] + 0), (_numROutH[0] + 0)), _mid, __func__); + } + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_listener1_invoke_get_in_bufs)(remote_handle64 _handle, adsp_listener1_invoke_ctx ctx, adsp_listener1_buffer* inBuffers, int inBuffersLen) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 3; + return _stub_method_1(_handle, _mid, (uint32_t*)&ctx, (void**)&inBuffers, (uint32_t*)&inBuffersLen); +} +static __inline int _stub_method_2(remote_handle64 _handle, uint32_t _mid) { + remote_arg* _pra = 0; + int _nErr = 0; + _TRY_FARF(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 0, 0, 0, 0), _pra)); + _CATCH_FARF(_nErr) { + _QAIC_FARF(RUNTIME_ERROR, "ERROR 0x%x: handle=0x%"PRIx64", scalar=0x%x, method ID=%d: %s failed\n", _nErr , _handle, REMOTE_SCALARS_MAKEX(0, _mid, 0, 0, 0, 0), _mid, __func__); + } + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_listener1_init)(remote_handle64 _handle) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 4; + return _stub_method_2(_handle, _mid); +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_listener1_init2)(remote_handle64 _handle) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 5; + return _stub_method_2(_handle, _mid); +} +static __inline int _stub_method_3(remote_handle64 _handle, uint32_t _mid, uint32_t _in0[1], uint32_t _in1[1], char* _in2[1], uint32_t _in2Len[1], uint32_t _rout3[1], uint32_t _rout4[1], uint32_t _rout5[1], char* _rout6[1], uint32_t _rout6Len[1], uint32_t _rout7[1]) { + int _numIn[1] = {0}; + remote_arg _pra[4] = {0}; + uint32_t _primIn[4]= {0}; + uint32_t _primROut[4]= {0}; + remote_arg* _praIn = 0; + remote_arg* _praROut = 0; + int _nErr = 0; + _numIn[0] = 1; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _pra[(_numIn[0] + 1)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 1)].buf.nLen = sizeof(_primROut); + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _in1, 0, 4); + _COPY(_primIn, 8, _in2Len, 0, 4); + _praIn = (_pra + 1); + _praIn[0].buf.pv = (void*) _in2[0]; + _praIn[0].buf.nLen = (1 * _in2Len[0]); + _COPY(_primIn, 12, _rout6Len, 0, 4); + _praROut = (_praIn + _numIn[0] + 1); + _praROut[0].buf.pv = _rout6[0]; + _praROut[0].buf.nLen = (1 * _rout6Len[0]); + _TRY_FARF(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 2, 2, 0, 0), _pra)); + _COPY(_rout3, 0, _primROut, 0, 4); + _COPY(_rout4, 0, _primROut, 4, 4); + _COPY(_rout5, 0, _primROut, 8, 4); + _COPY(_rout7, 0, _primROut, 12, 4); + _CATCH_FARF(_nErr) { + _QAIC_FARF(RUNTIME_ERROR, "ERROR 0x%x: handle=0x%"PRIx64", scalar=0x%x, method ID=%d: %s failed\n", _nErr , _handle, REMOTE_SCALARS_MAKEX(0, _mid, 2, 2, 0, 0), _mid, __func__); + } + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_listener1_next2)(remote_handle64 _handle, adsp_listener1_invoke_ctx prevCtx, int prevResult, const uint8* prevbufs, int prevbufsLen, adsp_listener1_invoke_ctx* ctx, adsp_listener1_remote_handle* handle, uint32* sc, uint8* bufs, int bufsLen, int* bufsLenReq) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 6; + return _stub_method_3(_handle, _mid, (uint32_t*)&prevCtx, (uint32_t*)&prevResult, (char**)&prevbufs, (uint32_t*)&prevbufsLen, (uint32_t*)ctx, (uint32_t*)handle, (uint32_t*)sc, (char**)&bufs, (uint32_t*)&bufsLen, (uint32_t*)bufsLenReq); +} +static __inline int _stub_method_4(remote_handle64 _handle, uint32_t _mid, uint32_t _in0[1], uint32_t _in1[1], char* _rout2[1], uint32_t _rout2Len[1], uint32_t _rout3[1]) { + int _numIn[1] = {0}; + remote_arg _pra[3] = {0}; + uint32_t _primIn[3]= {0}; + uint32_t _primROut[1]= {0}; + remote_arg* _praIn = 0; + remote_arg* _praROut = 0; + int _nErr = 0; + _numIn[0] = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _pra[(_numIn[0] + 1)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 1)].buf.nLen = sizeof(_primROut); + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _in1, 0, 4); + _COPY(_primIn, 8, _rout2Len, 0, 4); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 1); + _praROut[0].buf.pv = _rout2[0]; + _praROut[0].buf.nLen = (1 * _rout2Len[0]); + _TRY_FARF(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 2, 0, 0), _pra)); + _COPY(_rout3, 0, _primROut, 0, 4); + _CATCH_FARF(_nErr) { + _QAIC_FARF(RUNTIME_ERROR, "ERROR 0x%x: handle=0x%"PRIx64", scalar=0x%x, method ID=%d: %s failed\n", _nErr , _handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 2, 0, 0), _mid, __func__); + } + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_listener1_get_in_bufs2)(remote_handle64 _handle, adsp_listener1_invoke_ctx ctx, int offset, uint8* bufs, int bufsLen, int* bufsLenReq) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 7; + return _stub_method_4(_handle, _mid, (uint32_t*)&ctx, (uint32_t*)&offset, (char**)&bufs, (uint32_t*)&bufsLen, (uint32_t*)bufsLenReq); +} +#ifdef __cplusplus +} +#endif +#endif //_ADSP_LISTENER1_STUB_H diff --git a/src/adsp_listener_stub.c b/src/adsp_listener_stub.c new file mode 100644 index 0000000..c9e4252 --- /dev/null +++ b/src/adsp_listener_stub.c @@ -0,0 +1,937 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _ADSP_LISTENER_STUB_H +#define _ADSP_LISTENER_STUB_H +#include "adsp_listener.h" +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#include + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef _ATTRIBUTE_VISIBILITY + +#ifdef _WIN32 +#define _ATTRIBUTE_VISIBILITY +#else +#define _ATTRIBUTE_VISIBILITY __attribute__ ((visibility("default"))) +#endif + +#endif // _ATTRIBUTE_VISIBILITY + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i = 0; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#endif + + +#endif // _QAIC_ENV_H + +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include +#include + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc((size_t)size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + (size_t)size) < (uintptr_t)me->stack + (size_t)me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _ADSP_LISTENER_SLIM_H +#define _ADSP_LISTENER_SLIM_H +#include + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Type types[3]; +static const SequenceType sequenceTypes[1] = {{&(types[0]),0x0,0x4,0x4,0x0}}; +static const Type types[3] = {{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[1]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8)},{0x1,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x1},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4}}; +static const Parameter parameters[11] = {{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(sequenceTypes[0]),0}}, 25,SLIM_IFPTR32(0x4,0x8),0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(sequenceTypes[0]),0}}, 25,SLIM_IFPTR32(0x4,0x8),3,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[2]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8),3,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[1]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8),0,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[1]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8),3,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0}}; +static const Parameter* const parameterArrays[23] = {(&(parameters[0])),(&(parameters[1])),(&(parameters[2])),(&(parameters[3])),(&(parameters[4])),(&(parameters[5])),(&(parameters[6])),(&(parameters[7])),(&(parameters[7])),(&(parameters[0])),(&(parameters[1])),(&(parameters[8])),(&(parameters[3])),(&(parameters[4])),(&(parameters[5])),(&(parameters[9])),(&(parameters[10])),(&(parameters[0])),(&(parameters[1])),(&(parameters[9])),(&(parameters[10])),(&(parameters[0])),(&(parameters[6]))}; +static const Method methods[5] = {{REMOTE_SCALARS_MAKEX(0,0,255,255,15,15),0x18,0xc,16,9,(&(parameterArrays[0])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,255,255,15,15),0x8,0x0,4,2,(&(parameterArrays[21])),0x4,0x1},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x0,0x0,0x0),0x0,0x0,0,0,0,0x0,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x2,0x2,0x0,0x0),0x10,0x10,11,8,(&(parameterArrays[9])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x2,0x0,0x0),0xc,0x4,6,4,(&(parameterArrays[17])),0x4,0x4}}; +static const Method* const methodArrays[6] = {&(methods[0]),&(methods[1]),&(methods[2]),&(methods[2]),&(methods[3]),&(methods[4])}; +static const char strings[166] = "invoke_get_in_bufs\0routBufLenReq\0get_in_bufs2\0inBufLenReq\0next_invoke\0bufsLenReq\0prevResult\0inBuffers\0prevbufs\0outBufs\0prevCtx\0offset\0handle\0next2\0init2\0init\0ctx\0sc\0"; +static const uint16_t methodStrings[29] = {58,119,81,111,158,134,162,92,46,19,141,119,81,102,158,134,162,14,70,33,158,127,14,70,0,158,92,147,153}; +static const uint16_t methodStringsArrays[6] = {0,24,28,27,10,19}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(adsp_listener_slim) = {6,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_ADSP_LISTENER_SLIM_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _const_adsp_listener_handle +#define _const_adsp_listener_handle ((remote_handle)-1) +#endif //_const_adsp_listener_handle + +static void _adsp_listener_pls_dtor(void* data) { + remote_handle* ph = (remote_handle*)data; + if(_const_adsp_listener_handle != *ph) { + (void)__QAIC_REMOTE(remote_handle_close)(*ph); + *ph = _const_adsp_listener_handle; + } +} + +static int _adsp_listener_pls_ctor(void* ctx, void* data) { + remote_handle* ph = (remote_handle*)data; + *ph = _const_adsp_listener_handle; + if(*ph == (remote_handle)-1) { + return __QAIC_REMOTE(remote_handle_open)((const char*)ctx, ph); + } + return 0; +} + +#if (defined __qdsp6__) || (defined __hexagon__) +#pragma weak adsp_pls_add_lookup +extern int adsp_pls_add_lookup(uint32_t type, uint32_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* ctx), void** ppo); +#pragma weak HAP_pls_add_lookup +extern int HAP_pls_add_lookup(uint32_t type, uint32_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* ctx), void** ppo); + +__QAIC_STUB_EXPORT remote_handle _adsp_listener_handle(void) { + remote_handle* ph = 0; + if(adsp_pls_add_lookup) { + if(0 == adsp_pls_add_lookup((uint32_t)_adsp_listener_handle, 0, sizeof(*ph), _adsp_listener_pls_ctor, "adsp_listener", _adsp_listener_pls_dtor, (void**)&ph)) { + return *ph; + } + return (remote_handle)-1; + } else if(HAP_pls_add_lookup) { + if(0 == HAP_pls_add_lookup((uint32_t)_adsp_listener_handle, 0, sizeof(*ph), _adsp_listener_pls_ctor, "adsp_listener", _adsp_listener_pls_dtor, (void**)&ph)) { + return *ph; + } + return (remote_handle)-1; + } + return(remote_handle)-1; +} + +#else //__qdsp6__ || __hexagon__ + +uint32_t _adsp_listener_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare); + +#ifdef _WIN32 +#ifdef _USRDLL +#include "Windows.h" +#else +#include "ntddk.h" +#endif //_USRDLL +uint32_t _adsp_listener_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare) { + return (uint32_t)InterlockedCompareExchange((volatile LONG*)puDest, (LONG)uExchange, (LONG)uCompare); +} +#elif __GNUC__ +uint32_t _adsp_listener_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare) { + return __sync_val_compare_and_swap(puDest, uCompare, uExchange); +} +#endif //_WIN32 + + +__QAIC_STUB_EXPORT remote_handle _adsp_listener_handle(void) { + static remote_handle handle = _const_adsp_listener_handle; + if((remote_handle)-1 != handle) { + return handle; + } else { + remote_handle tmp; + int nErr = _adsp_listener_pls_ctor("adsp_listener", (void*)&tmp); + if(nErr) { + return (remote_handle)-1; + } + if(((remote_handle)-1 != handle) || ((remote_handle)-1 != (remote_handle)_adsp_listener_atomic_CompareAndExchange((uint32_t*)&handle, (uint32_t)tmp, (uint32_t)-1))) { + _adsp_listener_pls_dtor(&tmp); + } + return handle; + } +} + +#endif //__qdsp6__ + +#ifdef __cplusplus +} +#endif + + +#ifdef __cplusplus +extern "C" { +#endif +static __inline int _stub_unpack(_ATTRIBUTE_UNUSED remote_arg* _praROutPost, _ATTRIBUTE_UNUSED remote_arg* _ppraROutPost[1], _ATTRIBUTE_UNUSED void* _primROut, _ATTRIBUTE_UNUSED char* _rout0[1], _ATTRIBUTE_UNUSED uint32_t _rout0Len[1]) { + int _nErr = 0; + remote_arg* _praROutPostStart = _praROutPost; + remote_arg** _ppraROutPostStart = _ppraROutPost; + _ppraROutPost = &_praROutPost; + _ppraROutPostStart[0] += (_praROutPost - _praROutPostStart) +1; + return _nErr; +} +static __inline int _stub_unpack_1(_ATTRIBUTE_UNUSED remote_arg* _praROutPost, _ATTRIBUTE_UNUSED remote_arg* _ppraROutPost[1], _ATTRIBUTE_UNUSED void* _primROut, _ATTRIBUTE_UNUSED char* _in0[1], _ATTRIBUTE_UNUSED uint32_t _in0Len[1]) { + int _nErr = 0; + remote_arg* _praROutPostStart = _praROutPost; + remote_arg** _ppraROutPostStart = _ppraROutPost; + _ppraROutPost = &_praROutPost; + _ppraROutPostStart[0] += (_praROutPost - _praROutPostStart) +0; + return _nErr; +} +static __inline int _stub_pack(_ATTRIBUTE_UNUSED _allocator* _al, _ATTRIBUTE_UNUSED remote_arg* _praIn, _ATTRIBUTE_UNUSED remote_arg* _ppraIn[1], _ATTRIBUTE_UNUSED remote_arg* _praROut, _ATTRIBUTE_UNUSED remote_arg* _ppraROut[1], _ATTRIBUTE_UNUSED remote_arg* _praHIn, _ATTRIBUTE_UNUSED remote_arg* _ppraHIn[1], _ATTRIBUTE_UNUSED remote_arg* _praHROut, _ATTRIBUTE_UNUSED remote_arg* _ppraHROut[1], _ATTRIBUTE_UNUSED void* _primIn, _ATTRIBUTE_UNUSED void* _primROut, _ATTRIBUTE_UNUSED char* _rout0[1], _ATTRIBUTE_UNUSED uint32_t _rout0Len[1]) { + int _nErr = 0; + remote_arg* _praInStart = _praIn; + remote_arg** _ppraInStart = _ppraIn; + remote_arg* _praROutStart = _praROut; + remote_arg** _ppraROutStart = _ppraROut; + _ppraIn = &_praIn; + _ppraROut = &_praROut; + _COPY(_primIn, 0, _rout0Len, 0, 4); + _praROut[0].buf.pv = _rout0[0]; + _praROut[0].buf.nLen = (1 * _rout0Len[0]); + _ppraInStart[0] += (_praIn - _praInStart) + 0; + _ppraROutStart[0] += (_praROut - _praROutStart) +1; + return _nErr; +} +static __inline int _stub_pack_1(_ATTRIBUTE_UNUSED _allocator* _al, _ATTRIBUTE_UNUSED remote_arg* _praIn, _ATTRIBUTE_UNUSED remote_arg* _ppraIn[1], _ATTRIBUTE_UNUSED remote_arg* _praROut, _ATTRIBUTE_UNUSED remote_arg* _ppraROut[1], _ATTRIBUTE_UNUSED remote_arg* _praHIn, _ATTRIBUTE_UNUSED remote_arg* _ppraHIn[1], _ATTRIBUTE_UNUSED remote_arg* _praHROut, _ATTRIBUTE_UNUSED remote_arg* _ppraHROut[1], _ATTRIBUTE_UNUSED void* _primIn, _ATTRIBUTE_UNUSED void* _primROut, _ATTRIBUTE_UNUSED char* _in0[1], _ATTRIBUTE_UNUSED uint32_t _in0Len[1]) { + int _nErr = 0; + remote_arg* _praInStart = _praIn; + remote_arg** _ppraInStart = _ppraIn; + remote_arg* _praROutStart = _praROut; + remote_arg** _ppraROutStart = _ppraROut; + _ppraIn = &_praIn; + _ppraROut = &_praROut; + _COPY(_primIn, 0, _in0Len, 0, 4); + _praIn[0].buf.pv = (void*) _in0[0]; + _praIn[0].buf.nLen = (1 * _in0Len[0]); + _ppraInStart[0] += (_praIn - _praInStart) + 1; + _ppraROutStart[0] += (_praROut - _praROutStart) +0; + return _nErr; +} +static __inline void _count(int _numIn[1], int _numROut[1], int _numInH[1], int _numROutH[1]) { + _numIn[0] += 0; + _numROut[0] += 1; + _numInH[0] += 0; + _numROutH[0] += 0; +} +static __inline void _count_1(int _numIn[1], int _numROut[1], int _numInH[1], int _numROutH[1]) { + _numIn[0] += 1; + _numROut[0] += 0; + _numInH[0] += 0; + _numROutH[0] += 0; +} +static __inline int _stub_method(remote_handle _handle, uint32_t _mid, uint32_t _in0[1], uint32_t _in1[1], void* _in2[1], uint32_t _in2Len[1], uint32_t _rout3[1], uint32_t _rout4[1], uint32_t _rout5[1], void* _rout6[1], uint32_t _rout6Len[1], char* _rout7[1], uint32_t _rout7Len[1], char* _rout8[1], uint32_t _rout8Len[1]) { + remote_arg* _pra = 0; + int _numIn[1] = {0}; + int _numROut[1] = {0}; + int _numInH[1] = {0}; + int _numROutH[1] = {0}; + char* _seq_nat2 = 0; + int _ii = 0; + char* _seq_nat6 = 0; + _allocator _al[1] = {{0}}; + uint32_t _primIn[6]= {0}; + uint32_t _primROut[3]= {0}; + remote_arg* _praIn = 0; + remote_arg* _praROut = 0; + remote_arg* _praROutPost = 0; + remote_arg** _ppraROutPost = &_praROutPost; + remote_arg** _ppraIn = &_praIn; + remote_arg** _ppraROut = &_praROut; + remote_arg* _praHIn = 0; + remote_arg** _ppraHIn = &_praHIn; + remote_arg* _praHROut = 0; + remote_arg** _ppraHROut = &_praHROut; + char* _seq_primIn2 = 0; + int _nErr = 0; + char* _seq_primIn6 = 0; + _numIn[0] = 2; + _numROut[0] = 2; + _numInH[0] = 0; + _numROutH[0] = 0; + for(_ii = 0, _seq_nat2 = (char*)_in2[0];_ii < (int)_in2Len[0];++_ii, _seq_nat2 = (_seq_nat2 + SLIM_IFPTR32(8, 16))) + { + _count_1(_numIn, _numROut, _numInH, _numROutH); + } + for(_ii = 0, _seq_nat6 = (char*)_rout6[0];_ii < (int)_rout6Len[0];++_ii, _seq_nat6 = (_seq_nat6 + SLIM_IFPTR32(8, 16))) + { + _count(_numIn, _numROut, _numInH, _numROutH); + } + if(_numIn[0]>=255) + { + printf("ERROR: Unsupported number of input buffers\n"); + return AEE_EUNSUPPORTED; + } + if(_numROut[0]>=255) + { + printf("ERROR: Unsupported number of output buffers\n"); + return AEE_EUNSUPPORTED; + } + _allocator_init(_al, 0, 0); + _ALLOCATE(_nErr, _al, ((((((((_numIn[0] + _numROut[0]) + _numInH[0]) + _numROutH[0]) + 1) + 1) + 0) + 0) * sizeof(_pra[0])), 4, _pra); + _ASSERT(_nErr, _pra); + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _pra[(_numIn[0] + 1)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 1)].buf.nLen = sizeof(_primROut); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 1); + _praROutPost = _praROut; + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _in1, 0, 4); + _COPY(_primIn, 8, _in2Len, 0, 4); + if(_praHIn == 0) + { + _praHIn = ((_praROut + _numROut[0]) + 1); + } + if(_praHROut == 0) + (_praHROut = _praHIn + _numInH[0] + 0); + _ALLOCATE(_nErr, _al, (_in2Len[0] * 4), 4, _praIn[0].buf.pv); + _praIn[0].buf.nLen = (4 * _in2Len[0]); + for(_ii = 0, _seq_primIn2 = (char*)_praIn[0].buf.pv, _seq_nat2 = (char*)_in2[0];_ii < (int)_in2Len[0];++_ii, _seq_primIn2 = (_seq_primIn2 + 4), _seq_nat2 = (_seq_nat2 + SLIM_IFPTR32(8, 16))) + { + _TRY(_nErr, _stub_pack_1(_al, (_praIn + 1), _ppraIn, (_praROut + 0), _ppraROut, _praHIn, _ppraHIn, _praHROut, _ppraHROut, _seq_primIn2, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat2)[0]), (char**)&(((uint64_t*)_seq_nat2)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat2)[1]), (uint32_t*)&(((uint32_t*)_seq_nat2)[2])))); + } + _COPY(_primIn, 12, _rout6Len, 0, 4); + _ALLOCATE(_nErr, _al, (_rout6Len[0] * 4), 4, _praIn[1].buf.pv); + _praIn[1].buf.nLen = (4 * _rout6Len[0]); + for(_ii = 0, _seq_primIn6 = (char*)_praIn[1].buf.pv, _seq_nat6 = (char*)_rout6[0];_ii < (int)_rout6Len[0];++_ii, _seq_primIn6 = (_seq_primIn6 + 4), _seq_nat6 = (_seq_nat6 + SLIM_IFPTR32(8, 16))) + { + _TRY(_nErr, _stub_pack(_al, (_praIn + 2), _ppraIn, (_praROut + 0), _ppraROut, _praHIn, _ppraHIn, _praHROut, _ppraHROut, _seq_primIn6, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat6)[0]), (char**)&(((uint64_t*)_seq_nat6)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat6)[1]), (uint32_t*)&(((uint32_t*)_seq_nat6)[2])))); + } + _COPY(_primIn, 16, _rout7Len, 0, 4); + _praROut[0].buf.pv = _rout7[0]; + _praROut[0].buf.nLen = (4 * _rout7Len[0]); + _COPY(_primIn, 20, _rout8Len, 0, 4); + _praROut[1].buf.pv = _rout8[0]; + _praROut[1].buf.nLen = (4 * _rout8Len[0]); + _ASSERT(_nErr, (_numInH[0] + 0) <= 15); + _ASSERT(_nErr, (_numROutH[0] + 0) <= 15); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, (_numIn[0] + 1), (_numROut[0] + 1), (_numInH[0] + 0), (_numROutH[0] + 0)), _pra)); + for(_ii = 0, _seq_nat2 = (char*)_in2[0];_ii < (int)_in2Len[0];++_ii, _seq_nat2 = (_seq_nat2 + SLIM_IFPTR32(8, 16))) + { + _TRY(_nErr, _stub_unpack_1((_praROutPost + 0), _ppraROutPost, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat2)[0]), (char**)&(((uint64_t*)_seq_nat2)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat2)[1]), (uint32_t*)&(((uint32_t*)_seq_nat2)[2])))); + } + _COPY(_rout3, 0, _primROut, 0, 4); + _COPY(_rout4, 0, _primROut, 4, 4); + _COPY(_rout5, 0, _primROut, 8, 4); + for(_ii = 0, _seq_nat6 = (char*)_rout6[0];_ii < (int)_rout6Len[0];++_ii, _seq_nat6 = (_seq_nat6 + SLIM_IFPTR32(8, 16))) + { + _TRY(_nErr, _stub_unpack((_praROutPost + 0), _ppraROutPost, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat6)[0]), (char**)&(((uint64_t*)_seq_nat6)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat6)[1]), (uint32_t*)&(((uint32_t*)_seq_nat6)[2])))); + } + _CATCH(_nErr) {} + _allocator_deinit(_al); + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_listener_next_invoke)(adsp_listener_invoke_ctx prevCtx, int prevResult, const adsp_listener_buffer* outBufs, int outBufsLen, adsp_listener_invoke_ctx* ctx, adsp_listener_remote_handle* handle, uint32* sc, adsp_listener_buffer* inBuffers, int inBuffersLen, int* inBufLenReq, int inBufLenReqLen, int* routBufLenReq, int routBufLenReqLen) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 0; + remote_handle _handle = _adsp_listener_handle(); + if (_handle != (remote_handle)-1) + { + return _stub_method(_handle, _mid, (uint32_t*)&prevCtx, (uint32_t*)&prevResult, (void**)&outBufs, (uint32_t*)&outBufsLen, (uint32_t*)ctx, (uint32_t*)handle, (uint32_t*)sc, (void**)&inBuffers, (uint32_t*)&inBuffersLen, (char**)&inBufLenReq, (uint32_t*)&inBufLenReqLen, (char**)&routBufLenReq, (uint32_t*)&routBufLenReqLen); + } + else + { + return AEE_EINVHANDLE; + } +} +static __inline int _stub_unpack_2(_ATTRIBUTE_UNUSED remote_arg* _praROutPost, _ATTRIBUTE_UNUSED remote_arg* _ppraROutPost[1], _ATTRIBUTE_UNUSED void* _primROut, _ATTRIBUTE_UNUSED char* _rout0[1], _ATTRIBUTE_UNUSED uint32_t _rout0Len[1]) { + int _nErr = 0; + remote_arg* _praROutPostStart = _praROutPost; + remote_arg** _ppraROutPostStart = _ppraROutPost; + _ppraROutPost = &_praROutPost; + _ppraROutPostStart[0] += (_praROutPost - _praROutPostStart) +1; + return _nErr; +} +static __inline int _stub_pack_2(_ATTRIBUTE_UNUSED _allocator* _al, _ATTRIBUTE_UNUSED remote_arg* _praIn, _ATTRIBUTE_UNUSED remote_arg* _ppraIn[1], _ATTRIBUTE_UNUSED remote_arg* _praROut, _ATTRIBUTE_UNUSED remote_arg* _ppraROut[1], _ATTRIBUTE_UNUSED remote_arg* _praHIn, _ATTRIBUTE_UNUSED remote_arg* _ppraHIn[1], _ATTRIBUTE_UNUSED remote_arg* _praHROut, _ATTRIBUTE_UNUSED remote_arg* _ppraHROut[1], _ATTRIBUTE_UNUSED void* _primIn, _ATTRIBUTE_UNUSED void* _primROut, _ATTRIBUTE_UNUSED char* _rout0[1], _ATTRIBUTE_UNUSED uint32_t _rout0Len[1]) { + int _nErr = 0; + remote_arg* _praInStart = _praIn; + remote_arg** _ppraInStart = _ppraIn; + remote_arg* _praROutStart = _praROut; + remote_arg** _ppraROutStart = _ppraROut; + _ppraIn = &_praIn; + _ppraROut = &_praROut; + _COPY(_primIn, 0, _rout0Len, 0, 4); + _praROut[0].buf.pv = _rout0[0]; + _praROut[0].buf.nLen = (1 * _rout0Len[0]); + _ppraInStart[0] += (_praIn - _praInStart) + 0; + _ppraROutStart[0] += (_praROut - _praROutStart) +1; + return _nErr; +} +static __inline int _stub_method_1(remote_handle _handle, uint32_t _mid, uint32_t _in0[1], void* _rout1[1], uint32_t _rout1Len[1]) { + remote_arg* _pra = 0; + int _numIn[1] = {0}; + int _numROut[1] = {0}; + int _numInH[1] = {0}; + int _numROutH[1] = {0}; + char* _seq_nat1 = 0; + int _ii = 0; + _allocator _al[1] = {{0}}; + uint32_t _primIn[2]= {0}; + remote_arg* _praIn = 0; + remote_arg* _praROut = 0; + remote_arg* _praROutPost = 0; + remote_arg** _ppraROutPost = &_praROutPost; + remote_arg** _ppraIn = &_praIn; + remote_arg** _ppraROut = &_praROut; + remote_arg* _praHIn = 0; + remote_arg** _ppraHIn = &_praHIn; + remote_arg* _praHROut = 0; + remote_arg** _ppraHROut = &_praHROut; + char* _seq_primIn1 = 0; + int _nErr = 0; + _numIn[0] = 1; + _numROut[0] = 0; + _numInH[0] = 0; + _numROutH[0] = 0; + for(_ii = 0, _seq_nat1 = (char*)_rout1[0];_ii < (int)_rout1Len[0];++_ii, _seq_nat1 = (_seq_nat1 + SLIM_IFPTR32(8, 16))) + { + _count(_numIn, _numROut, _numInH, _numROutH); + } + if(_numIn[0]>=255) + { + printf("ERROR: Unsupported number of input buffers\n"); + return AEE_EUNSUPPORTED; + } + if(_numROut[0]>=255) + { + printf("ERROR: Unsupported number of output buffers\n"); + return AEE_EUNSUPPORTED; + } + _allocator_init(_al, 0, 0); + _ALLOCATE(_nErr, _al, ((((((((_numIn[0] + _numROut[0]) + _numInH[0]) + _numROutH[0]) + 1) + 0) + 0) + 0) * sizeof(_pra[0])), 4, _pra); + _ASSERT(_nErr, _pra); + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 0); + _praROutPost = _praROut; + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _rout1Len, 0, 4); + if(_praHIn == 0) + { + _praHIn = ((_praROut + _numROut[0]) + 0); + } + if(_praHROut == 0) + (_praHROut = _praHIn + _numInH[0] + 0); + _ALLOCATE(_nErr, _al, (_rout1Len[0] * 4), 4, _praIn[0].buf.pv); + _praIn[0].buf.nLen = (4 * _rout1Len[0]); + for(_ii = 0, _seq_primIn1 = (char*)_praIn[0].buf.pv, _seq_nat1 = (char*)_rout1[0];_ii < (int)_rout1Len[0];++_ii, _seq_primIn1 = (_seq_primIn1 + 4), _seq_nat1 = (_seq_nat1 + SLIM_IFPTR32(8, 16))) + { + _TRY(_nErr, _stub_pack_2(_al, (_praIn + 1), _ppraIn, (_praROut + 0), _ppraROut, _praHIn, _ppraHIn, _praHROut, _ppraHROut, _seq_primIn1, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat1)[0]), (char**)&(((uint64_t*)_seq_nat1)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat1)[1]), (uint32_t*)&(((uint32_t*)_seq_nat1)[2])))); + } + _ASSERT(_nErr, (_numInH[0] + 0) <= 15); + _ASSERT(_nErr, (_numROutH[0] + 0) <= 15); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, (_numIn[0] + 1), (_numROut[0] + 0), (_numInH[0] + 0), (_numROutH[0] + 0)), _pra)); + for(_ii = 0, _seq_nat1 = (char*)_rout1[0];_ii < (int)_rout1Len[0];++_ii, _seq_nat1 = (_seq_nat1 + SLIM_IFPTR32(8, 16))) + { + _TRY(_nErr, _stub_unpack_2((_praROutPost + 0), _ppraROutPost, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat1)[0]), (char**)&(((uint64_t*)_seq_nat1)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat1)[1]), (uint32_t*)&(((uint32_t*)_seq_nat1)[2])))); + } + _CATCH(_nErr) {} + _allocator_deinit(_al); + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_listener_invoke_get_in_bufs)(adsp_listener_invoke_ctx ctx, adsp_listener_buffer* inBuffers, int inBuffersLen) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 1; + remote_handle _handle = _adsp_listener_handle(); + if (_handle != (remote_handle)-1) + { + return _stub_method_1(_handle, _mid, (uint32_t*)&ctx, (void**)&inBuffers, (uint32_t*)&inBuffersLen); + } + else + { + return AEE_EINVHANDLE; + } +} +static __inline int _stub_method_2(remote_handle _handle, uint32_t _mid) { + remote_arg* _pra = 0; + int _nErr = 0; + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 0, 0, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_listener_init)(void) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 2; + remote_handle _handle = _adsp_listener_handle(); + if (_handle != (remote_handle)-1) + { + return _stub_method_2(_handle, _mid); + } + else + { + return AEE_EINVHANDLE; + } +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_listener_init2)(void) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 3; + remote_handle _handle = _adsp_listener_handle(); + if (_handle != (remote_handle)-1) + { + return _stub_method_2(_handle, _mid); + } + else + { + return AEE_EINVHANDLE; + } +} +static __inline int _stub_method_3(remote_handle _handle, uint32_t _mid, uint32_t _in0[1], uint32_t _in1[1], char* _in2[1], uint32_t _in2Len[1], uint32_t _rout3[1], uint32_t _rout4[1], uint32_t _rout5[1], char* _rout6[1], uint32_t _rout6Len[1], uint32_t _rout7[1]) { + int _numIn[1] = {0}; + remote_arg _pra[4] = {0}; + uint32_t _primIn[4]= {0}; + uint32_t _primROut[4]= {0}; + remote_arg* _praIn = 0; + remote_arg* _praROut = 0; + int _nErr = 0; + _numIn[0] = 1; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _pra[(_numIn[0] + 1)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 1)].buf.nLen = sizeof(_primROut); + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _in1, 0, 4); + _COPY(_primIn, 8, _in2Len, 0, 4); + _praIn = (_pra + 1); + _praIn[0].buf.pv = (void*) _in2[0]; + _praIn[0].buf.nLen = (1 * _in2Len[0]); + _COPY(_primIn, 12, _rout6Len, 0, 4); + _praROut = (_praIn + _numIn[0] + 1); + _praROut[0].buf.pv = _rout6[0]; + _praROut[0].buf.nLen = (1 * _rout6Len[0]); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 2, 2, 0, 0), _pra)); + _COPY(_rout3, 0, _primROut, 0, 4); + _COPY(_rout4, 0, _primROut, 4, 4); + _COPY(_rout5, 0, _primROut, 8, 4); + _COPY(_rout7, 0, _primROut, 12, 4); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_listener_next2)(adsp_listener_invoke_ctx prevCtx, int prevResult, const uint8* prevbufs, int prevbufsLen, adsp_listener_invoke_ctx* ctx, adsp_listener_remote_handle* handle, uint32* sc, uint8* bufs, int bufsLen, int* bufsLenReq) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 4; + remote_handle _handle = _adsp_listener_handle(); + if (_handle != (remote_handle)-1) + { + return _stub_method_3(_handle, _mid, (uint32_t*)&prevCtx, (uint32_t*)&prevResult, (char**)&prevbufs, (uint32_t*)&prevbufsLen, (uint32_t*)ctx, (uint32_t*)handle, (uint32_t*)sc, (char**)&bufs, (uint32_t*)&bufsLen, (uint32_t*)bufsLenReq); + } + else + { + return AEE_EINVHANDLE; + } +} +static __inline int _stub_method_4(remote_handle _handle, uint32_t _mid, uint32_t _in0[1], uint32_t _in1[1], char* _rout2[1], uint32_t _rout2Len[1], uint32_t _rout3[1]) { + int _numIn[1] = {0}; + remote_arg _pra[3] = {0}; + uint32_t _primIn[3]= {0}; + uint32_t _primROut[1]= {0}; + remote_arg* _praIn = 0; + remote_arg* _praROut = 0; + int _nErr = 0; + _numIn[0] = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _pra[(_numIn[0] + 1)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 1)].buf.nLen = sizeof(_primROut); + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _in1, 0, 4); + _COPY(_primIn, 8, _rout2Len, 0, 4); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 1); + _praROut[0].buf.pv = _rout2[0]; + _praROut[0].buf.nLen = (1 * _rout2Len[0]); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 2, 0, 0), _pra)); + _COPY(_rout3, 0, _primROut, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_listener_get_in_bufs2)(adsp_listener_invoke_ctx ctx, int offset, uint8* bufs, int bufsLen, int* bufsLenReq) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 5; + remote_handle _handle = _adsp_listener_handle(); + if (_handle != (remote_handle)-1) + { + return _stub_method_4(_handle, _mid, (uint32_t*)&ctx, (uint32_t*)&offset, (char**)&bufs, (uint32_t*)&bufsLen, (uint32_t*)bufsLenReq); + } + else + { + return AEE_EINVHANDLE; + } +} +#ifdef __cplusplus +} +#endif +#endif //_ADSP_LISTENER_STUB_H diff --git a/src/adsp_perf1_stub.c b/src/adsp_perf1_stub.c new file mode 100644 index 0000000..19e83ee --- /dev/null +++ b/src/adsp_perf1_stub.c @@ -0,0 +1,375 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _ADSP_PERF1_STUB_H +#define _ADSP_PERF1_STUB_H +#include "adsp_perf1.h" +#include +#ifndef _WIN32 +#include "HAP_farf.h" +#endif //_WIN32 for HAP_farf +#include +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include +#include + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc((size_t)size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + (size_t)size) < (uintptr_t)me->stack + (size_t)me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _ADSP_PERF1_SLIM_H +#define _ADSP_PERF1_SLIM_H +#include + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Type types[2]; +static const Type types[2] = {{0x8,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x8},{0x1,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x1}}; +static const Parameter parameters[7] = {{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)0x0,0}}, 4,SLIM_IFPTR32(0x4,0x8),0,0},{SLIM_IFPTR32(0x4,0x8),{{(const uintptr_t)0xdeadc0de,(const uintptr_t)0}}, 0,SLIM_IFPTR32(0x4,0x8),3,0},{SLIM_IFPTR32(0x4,0x8),{{(const uintptr_t)0xdeadc0de,(const uintptr_t)0}}, 0,SLIM_IFPTR32(0x4,0x8),0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[0]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8),3,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[1]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8),3,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0}}; +static const Parameter* const parameterArrays[8] = {(&(parameters[5])),(&(parameters[6])),(&(parameters[6])),(&(parameters[0])),(&(parameters[1])),(&(parameters[4])),(&(parameters[3])),(&(parameters[2]))}; +static const Method methods[5] = {{REMOTE_SCALARS_MAKEX(0,0,0x2,0x0,0x0,0x1),0x4,0x0,2,2,(&(parameterArrays[3])),0x4,0x1},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x0,0x1,0x0),0x0,0x0,1,1,(&(parameterArrays[7])),0x1,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0x4,0x0,1,1,(&(parameterArrays[6])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x1,0x0,0x0),0x4,0x0,3,1,(&(parameterArrays[5])),0x4,0x1},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x2,0x0,0x0),0x4,0x8,5,3,(&(parameterArrays[0])),0x4,0x4}}; +static const Method* const methodArrays[5] = {&(methods[0]),&(methods[1]),&(methods[2]),&(methods[3]),&(methods[4])}; +static const char strings[66] = "get_usecs\0get_keys\0numKeys\0maxLen\0enable\0close\0open\0dst\0uri\0ix\0h\0"; +static const uint16_t methodStrings[13] = {10,14,27,19,47,56,63,0,52,34,60,41,63}; +static const uint16_t methodStringsArrays[5] = {4,11,9,7,0}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(adsp_perf1_slim) = {5,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_ADSP_PERF1_SLIM_H + + +#ifdef __cplusplus +extern "C" { +#endif +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_perf1_open)(const char* uri, remote_handle64* h) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle64_open)(uri, h); +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_perf1_close)(remote_handle64 h) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle64_close)(h); +} +static __inline int _stub_method(remote_handle64 _handle, uint32_t _mid, uint32_t _in0[1]) { + remote_arg _pra[1] = {0}; + uint32_t _primIn[1]= {0}; + int _nErr = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _COPY(_primIn, 0, _in0, 0, 4); + _TRY_FARF(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 0, 0, 0), _pra)); + _CATCH_FARF(_nErr) { + _QAIC_FARF(RUNTIME_ERROR, "ERROR 0x%x: handle=0x%"PRIx64", scalar=0x%x, method ID=%d: %s failed\n", _nErr , _handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 0, 0, 0), _mid, __func__); + } + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_perf1_enable)(remote_handle64 _handle, int ix) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 2; + return _stub_method(_handle, _mid, (uint32_t*)&ix); +} +static __inline int _stub_method_1(remote_handle64 _handle, uint32_t _mid, char* _rout0[1], uint32_t _rout0Len[1]) { + int _numIn[1] = {0}; + remote_arg _pra[2] = {0}; + uint32_t _primIn[1]= {0}; + remote_arg* _praIn = 0; + remote_arg* _praROut = 0; + int _nErr = 0; + _numIn[0] = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _COPY(_primIn, 0, _rout0Len, 0, 4); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 0); + _praROut[0].buf.pv = _rout0[0]; + _praROut[0].buf.nLen = (8 * _rout0Len[0]); + _TRY_FARF(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 1, 0, 0), _pra)); + _CATCH_FARF(_nErr) { + _QAIC_FARF(RUNTIME_ERROR, "ERROR 0x%x: handle=0x%"PRIx64", scalar=0x%x, method ID=%d: %s failed\n", _nErr , _handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 1, 0, 0), _mid, __func__); + } + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_perf1_get_usecs)(remote_handle64 _handle, int64* dst, int dstLen) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 3; + return _stub_method_1(_handle, _mid, (char**)&dst, (uint32_t*)&dstLen); +} +static __inline int _stub_method_2(remote_handle64 _handle, uint32_t _mid, char* _rout0[1], uint32_t _rout0Len[1], uint32_t _rout1[1], uint32_t _rout2[1]) { + int _numIn[1] = {0}; + remote_arg _pra[3] = {0}; + uint32_t _primIn[1]= {0}; + uint32_t _primROut[2]= {0}; + remote_arg* _praIn = 0; + remote_arg* _praROut = 0; + int _nErr = 0; + _numIn[0] = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _pra[(_numIn[0] + 1)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 1)].buf.nLen = sizeof(_primROut); + _COPY(_primIn, 0, _rout0Len, 0, 4); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 1); + _praROut[0].buf.pv = _rout0[0]; + _praROut[0].buf.nLen = (1 * _rout0Len[0]); + _TRY_FARF(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 2, 0, 0), _pra)); + _COPY(_rout1, 0, _primROut, 0, 4); + _COPY(_rout2, 0, _primROut, 4, 4); + _CATCH_FARF(_nErr) { + _QAIC_FARF(RUNTIME_ERROR, "ERROR 0x%x: handle=0x%"PRIx64", scalar=0x%x, method ID=%d: %s failed\n", _nErr , _handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 2, 0, 0), _mid, __func__); + } + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_perf1_get_keys)(remote_handle64 _handle, char* keys, int keysLen, int* maxLen, int* numKeys) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 4; + return _stub_method_2(_handle, _mid, (char**)&keys, (uint32_t*)&keysLen, (uint32_t*)maxLen, (uint32_t*)numKeys); +} +#ifdef __cplusplus +} +#endif +#endif //_ADSP_PERF1_STUB_H diff --git a/src/adsp_perf_stub.c b/src/adsp_perf_stub.c new file mode 100644 index 0000000..4f2f2c9 --- /dev/null +++ b/src/adsp_perf_stub.c @@ -0,0 +1,634 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _ADSP_PERF_STUB_H +#define _ADSP_PERF_STUB_H +#include "adsp_perf.h" +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#include + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef _ATTRIBUTE_VISIBILITY + +#ifdef _WIN32 +#define _ATTRIBUTE_VISIBILITY +#else +#define _ATTRIBUTE_VISIBILITY __attribute__ ((visibility("default"))) +#endif + +#endif // _ATTRIBUTE_VISIBILITY + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i = 0; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#endif + + +#endif // _QAIC_ENV_H + +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include +#include + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc((size_t)size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + (size_t)size) < (uintptr_t)me->stack + (size_t)me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _ADSP_PERF_SLIM_H +#define _ADSP_PERF_SLIM_H +#include + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Type types[2]; +static const Type types[2] = {{0x8,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x8},{0x1,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x1}}; +static const Parameter parameters[4] = {{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[0]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8),3,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[1]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8),3,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0}}; +static const Parameter* const parameterArrays[5] = {(&(parameters[2])),(&(parameters[3])),(&(parameters[3])),(&(parameters[1])),(&(parameters[0]))}; +static const Method methods[3] = {{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0x4,0x0,1,1,(&(parameterArrays[4])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x1,0x0,0x0),0x4,0x0,3,1,(&(parameterArrays[3])),0x4,0x1},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x2,0x0,0x0),0x4,0x8,5,3,(&(parameterArrays[0])),0x4,0x4}}; +static const Method* const methodArrays[3] = {&(methods[0]),&(methods[1]),&(methods[2])}; +static const char strings[49] = "get_usecs\0get_keys\0numKeys\0maxLen\0enable\0dst\0ix\0"; +static const uint16_t methodStrings[8] = {10,14,27,19,0,41,34,45}; +static const uint16_t methodStringsArrays[3] = {6,4,0}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(adsp_perf_slim) = {3,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_ADSP_PERF_SLIM_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _const_adsp_perf_handle +#define _const_adsp_perf_handle ((remote_handle)-1) +#endif //_const_adsp_perf_handle + +static void _adsp_perf_pls_dtor(void* data) { + remote_handle* ph = (remote_handle*)data; + if(_const_adsp_perf_handle != *ph) { + (void)__QAIC_REMOTE(remote_handle_close)(*ph); + *ph = _const_adsp_perf_handle; + } +} + +static int _adsp_perf_pls_ctor(void* ctx, void* data) { + remote_handle* ph = (remote_handle*)data; + *ph = _const_adsp_perf_handle; + if(*ph == (remote_handle)-1) { + return __QAIC_REMOTE(remote_handle_open)((const char*)ctx, ph); + } + return 0; +} + +#if (defined __qdsp6__) || (defined __hexagon__) +#pragma weak adsp_pls_add_lookup +extern int adsp_pls_add_lookup(uint32_t type, uint32_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* ctx), void** ppo); +#pragma weak HAP_pls_add_lookup +extern int HAP_pls_add_lookup(uint32_t type, uint32_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* ctx), void** ppo); + +__QAIC_STUB_EXPORT remote_handle _adsp_perf_handle(void) { + remote_handle* ph = 0; + if(adsp_pls_add_lookup) { + if(0 == adsp_pls_add_lookup((uint32_t)_adsp_perf_handle, 0, sizeof(*ph), _adsp_perf_pls_ctor, "adsp_perf", _adsp_perf_pls_dtor, (void**)&ph)) { + return *ph; + } + return (remote_handle)-1; + } else if(HAP_pls_add_lookup) { + if(0 == HAP_pls_add_lookup((uint32_t)_adsp_perf_handle, 0, sizeof(*ph), _adsp_perf_pls_ctor, "adsp_perf", _adsp_perf_pls_dtor, (void**)&ph)) { + return *ph; + } + return (remote_handle)-1; + } + return(remote_handle)-1; +} + +#else //__qdsp6__ || __hexagon__ + +uint32_t _adsp_perf_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare); + +#ifdef _WIN32 +#ifdef _USRDLL +#include "Windows.h" +#else +#include "ntddk.h" +#endif //_USRDLL +uint32_t _adsp_perf_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare) { + return (uint32_t)InterlockedCompareExchange((volatile LONG*)puDest, (LONG)uExchange, (LONG)uCompare); +} +#elif __GNUC__ +uint32_t _adsp_perf_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare) { + return __sync_val_compare_and_swap(puDest, uCompare, uExchange); +} +#endif //_WIN32 + + +__QAIC_STUB_EXPORT remote_handle _adsp_perf_handle(void) { + static remote_handle handle = _const_adsp_perf_handle; + if((remote_handle)-1 != handle) { + return handle; + } else { + remote_handle tmp; + int nErr = _adsp_perf_pls_ctor("adsp_perf", (void*)&tmp); + if(nErr) { + return (remote_handle)-1; + } + if(((remote_handle)-1 != handle) || ((remote_handle)-1 != (remote_handle)_adsp_perf_atomic_CompareAndExchange((uint32_t*)&handle, (uint32_t)tmp, (uint32_t)-1))) { + _adsp_perf_pls_dtor(&tmp); + } + return handle; + } +} + +#endif //__qdsp6__ + +#ifdef __cplusplus +} +#endif + + +#ifdef __cplusplus +extern "C" { +#endif +static __inline int _stub_method(remote_handle _handle, uint32_t _mid, uint32_t _in0[1]) { + remote_arg _pra[1] = {0}; + uint32_t _primIn[1]= {0}; + int _nErr = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _COPY(_primIn, 0, _in0, 0, 4); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 0, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_perf_enable)(int ix) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 0; + remote_handle _handle = _adsp_perf_handle(); + if (_handle != (remote_handle)-1) + { + return _stub_method(_handle, _mid, (uint32_t*)&ix); + } + else + { + return AEE_EINVHANDLE; + } +} +static __inline int _stub_method_1(remote_handle _handle, uint32_t _mid, char* _rout0[1], uint32_t _rout0Len[1]) { + int _numIn[1] = {0}; + remote_arg _pra[2] = {0}; + uint32_t _primIn[1]= {0}; + remote_arg* _praIn = 0; + remote_arg* _praROut = 0; + int _nErr = 0; + _numIn[0] = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _COPY(_primIn, 0, _rout0Len, 0, 4); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 0); + _praROut[0].buf.pv = _rout0[0]; + _praROut[0].buf.nLen = (8 * _rout0Len[0]); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 1, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_perf_get_usecs)(int64* dst, int dstLen) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 1; + remote_handle _handle = _adsp_perf_handle(); + if (_handle != (remote_handle)-1) + { + return _stub_method_1(_handle, _mid, (char**)&dst, (uint32_t*)&dstLen); + } + else + { + return AEE_EINVHANDLE; + } +} +static __inline int _stub_method_2(remote_handle _handle, uint32_t _mid, char* _rout0[1], uint32_t _rout0Len[1], uint32_t _rout1[1], uint32_t _rout2[1]) { + int _numIn[1] = {0}; + remote_arg _pra[3] = {0}; + uint32_t _primIn[1]= {0}; + uint32_t _primROut[2]= {0}; + remote_arg* _praIn = 0; + remote_arg* _praROut = 0; + int _nErr = 0; + _numIn[0] = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _pra[(_numIn[0] + 1)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 1)].buf.nLen = sizeof(_primROut); + _COPY(_primIn, 0, _rout0Len, 0, 4); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 1); + _praROut[0].buf.pv = _rout0[0]; + _praROut[0].buf.nLen = (1 * _rout0Len[0]); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 2, 0, 0), _pra)); + _COPY(_rout1, 0, _primROut, 0, 4); + _COPY(_rout2, 0, _primROut, 4, 4); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adsp_perf_get_keys)(char* keys, int keysLen, int* maxLen, int* numKeys) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 2; + remote_handle _handle = _adsp_perf_handle(); + if (_handle != (remote_handle)-1) + { + return _stub_method_2(_handle, _mid, (char**)&keys, (uint32_t*)&keysLen, (uint32_t*)maxLen, (uint32_t*)numKeys); + } + else + { + return AEE_EINVHANDLE; + } +} +#ifdef __cplusplus +} +#endif +#endif //_ADSP_PERF_STUB_H diff --git a/src/adspmsgd.c b/src/adspmsgd.c new file mode 100644 index 0000000..7b64ed6 --- /dev/null +++ b/src/adspmsgd.c @@ -0,0 +1,176 @@ +// 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 + +#include +#include +#include +#include + +#include "AEEStdErr.h" +#include "HAP_farf.h" +#include "adspmsgd_adsp1.h" +#include "adspmsgd_internal.h" +#include "fastrpc_internal.h" +#include "rpcmem.h" +#include "verify.h" + + +#define BUFFER_SIZE 256 +#define DEFAULT_MEMORY_SIZE 256 * 1024 +#include "fastrpc_common.h" + + +extern char *fastrpc_config_get_runtime_farf_file(void); + +msgd androidmsgd_handle[NUM_DOMAINS_EXTEND]; + +void readMessage(int domain) { + int index = 0; + msgd *msgd_handle = &androidmsgd_handle[domain]; + unsigned long long lreadIndex = msgd_handle->readIndex; + memset(msgd_handle->message, 0, BUFFER_SIZE); + if (msgd_handle->readIndex >= msgd_handle->bufferSize) { + lreadIndex = msgd_handle->readIndex = 0; + } + while ((lreadIndex != *(msgd_handle->currentIndex)) && + (msgd_handle->headPtr[lreadIndex] == '\0')) { + lreadIndex++; + if (lreadIndex >= msgd_handle->bufferSize) { + lreadIndex = 0; + } + } + while (msgd_handle->headPtr[lreadIndex] != '\0') { + *(msgd_handle->message + index) = msgd_handle->headPtr[lreadIndex]; + index++; + lreadIndex++; + if (lreadIndex >= msgd_handle->bufferSize) { + lreadIndex = 0; + } + if (index >= BUFFER_SIZE) { + break; + } + } + if (*(msgd_handle->message + 0) != '\0') { + if (msgd_handle->log_file_fd != NULL) { + fputs(msgd_handle->message, msgd_handle->log_file_fd); + fputs("\n", msgd_handle->log_file_fd); + } + adspmsgd_log_message("%s", msgd_handle->message); + msgd_handle->readIndex = lreadIndex + 1; + } +} +// function to flush messages to logcat +static void *adspmsgd_reader(void *arg) { + remote_handle64 handle = (remote_handle64)arg; + int domain = DEFAULT_DOMAIN_ID; + int nErr = AEE_SUCCESS; + unsigned long long bytesToRead = 0; + msgd *msgd_handle; + + FARF(RUNTIME_RPC_HIGH, "%s thread starting for domain %d\n", __func__, + domain); + VERIFY(AEE_SUCCESS == (nErr = get_domain_from_handle(handle, &domain))); + msgd_handle = &androidmsgd_handle[domain]; + msgd_handle->threadStop = 0; + while (!(msgd_handle->threadStop)) { + if (*(msgd_handle->currentIndex) == msgd_handle->readIndex) { + // wait till messages are ready from DSP + adspmsgd_adsp1_wait(handle, &bytesToRead); + } + readMessage(domain); + } + while (*(msgd_handle->currentIndex) != msgd_handle->readIndex) { + readMessage(domain); + } + msgd_handle->threadStop = -1; +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error 0x%x: %s thread of domain %d for handle 0x%lx " + "exiting (errno %s)\n", + nErr, __func__, domain, handle, strerror(errno)); + } else { + FARF(ALWAYS, "%s thread exiting for domain %d\n", __func__, domain); + } + return (void *)(uintptr_t)nErr; +} +// function to create msgd shared buffer and logger thread to flush messages to +// logcat +int adspmsgd_init(remote_handle64 handle, int filter) { + int nErr = AEE_SUCCESS; + int domain = DEFAULT_DOMAIN_ID; + unsigned long long vapps = 0; + errno = 0; + char *filename = NULL; + msgd *msgd_handle = &androidmsgd_handle[DEFAULT_DOMAIN_ID]; + VERIFY(AEE_SUCCESS == (nErr = get_domain_from_handle(handle, &domain))); + msgd_handle = &androidmsgd_handle[domain]; + if (msgd_handle->thread_running) { + androidmsgd_handle[domain].threadStop = 1; + adspmsgd_adsp1_deinit(handle); + adspmsgd_stop(domain); + } + msgd_handle->message = NULL; + // If daemon already running, adspmsgd_adsp1_init3 already happened, vapps + // return NULL + VERIFY(AEE_SUCCESS == + (nErr = adspmsgd_adsp1_init3(handle, 0, RPCMEM_HEAP_DEFAULT, filter, + DEFAULT_MEMORY_SIZE, &vapps))); + VERIFYC(vapps, AEE_EBADITEM); + msgd_handle->headPtr = (char *)vapps; + msgd_handle->bufferSize = + DEFAULT_MEMORY_SIZE - sizeof(*(msgd_handle->currentIndex)); + msgd_handle->readIndex = 0; + msgd_handle->currentIndex = (unsigned int *)(vapps + msgd_handle->bufferSize); + VERIFYC(0 != (msgd_handle->message = calloc(1, BUFFER_SIZE)), AEE_ENOMEMORY); + VERIFY(AEE_SUCCESS == + (nErr = pthread_create(&(msgd_handle->msgreader_thread), NULL, + adspmsgd_reader, (void *)handle))); + msgd_handle->thread_running = true; + filename = fastrpc_config_get_runtime_farf_file(); + if (filename) { // Check "Runtime farf logs collection into a file" is enabled + msgd_handle->log_file_fd = fopen(filename, "w"); + if (msgd_handle->log_file_fd == NULL) { + VERIFY_EPRINTF("Error 0x%x: %s failed to collect runtime farf logs into " + "file %s with errno %s\n", + nErr, __func__, filename, strerror(errno)); + } + } +bail: + if ((nErr != AEE_SUCCESS) && + (nErr != (int)(AEE_EUNSUPPORTED + DSP_AEE_EOFFSET))) { + VERIFY_EPRINTF( + "Error 0x%x: %s failed for handle 0x%lx filter %d with errno %s\n", + nErr, __func__, handle, filter, strerror(errno)); + if (msgd_handle->message) { + free(msgd_handle->message); + msgd_handle->message = NULL; + } + adspmsgd_adsp1_deinit(handle); + } + return nErr; +} + +// function to stop logger thread +void adspmsgd_stop(int dom) { + if (!androidmsgd_handle[dom].thread_running) + return; + if (androidmsgd_handle[dom].threadStop == 0) { + androidmsgd_handle[dom].threadStop = 1; + while (androidmsgd_handle[dom].threadStop != -1) + ; + pthread_join(androidmsgd_handle[dom].msgreader_thread, NULL); + androidmsgd_handle[dom].msgreader_thread = 0; + androidmsgd_handle[dom].thread_running = false; + if (androidmsgd_handle[dom].message) { + free(androidmsgd_handle[dom].message); + androidmsgd_handle[dom].message = NULL; + } + if (androidmsgd_handle[dom].log_file_fd) { + fclose(androidmsgd_handle[dom].log_file_fd); + } + } +} diff --git a/src/adspmsgd_adsp1_stub.c b/src/adspmsgd_adsp1_stub.c new file mode 100644 index 0000000..0387efb --- /dev/null +++ b/src/adspmsgd_adsp1_stub.c @@ -0,0 +1,516 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _ADSPMSGD_ADSP1_STUB_H +#define _ADSPMSGD_ADSP1_STUB_H +#include "adspmsgd_adsp1.h" +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#include + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef _ATTRIBUTE_VISIBILITY + +#ifdef _WIN32 +#define _ATTRIBUTE_VISIBILITY +#else +#define _ATTRIBUTE_VISIBILITY __attribute__ ((visibility("default"))) +#endif + +#endif // _ATTRIBUTE_VISIBILITY + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i = 0; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#endif + + +#endif // _QAIC_ENV_H + +#include +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include +#include + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc((size_t)size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + (size_t)size) < (uintptr_t)me->stack + (size_t)me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _ADSPMSGD_ADSP1_SLIM_H +#define _ADSPMSGD_ADSP1_SLIM_H +#include + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Parameter parameters[7] = {{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)0x0,0}}, 4,SLIM_IFPTR32(0x4,0x8),0,0},{SLIM_IFPTR32(0x4,0x8),{{(const uintptr_t)0xdeadc0de,(const uintptr_t)0}}, 0,SLIM_IFPTR32(0x4,0x8),3,0},{SLIM_IFPTR32(0x4,0x8),{{(const uintptr_t)0xdeadc0de,(const uintptr_t)0}}, 0,SLIM_IFPTR32(0x4,0x8),0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{0x8,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x8,0,0},{0x8,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x8,3,0}}; +static const Parameter* const parameterArrays[8] = {(&(parameters[3])),(&(parameters[4])),(&(parameters[4])),(&(parameters[5])),(&(parameters[6])),(&(parameters[0])),(&(parameters[1])),(&(parameters[2]))}; +static const Method methods[5] = {{REMOTE_SCALARS_MAKEX(0,0,0x2,0x0,0x0,0x1),0x4,0x0,2,2,(&(parameterArrays[5])),0x4,0x1},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x0,0x1,0x0),0x0,0x0,1,1,(&(parameterArrays[7])),0x1,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x0,0x0,0x0),0x0,0x0,0,0,0,0x0,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x1,0x0,0x0),0x18,0x8,7,5,(&(parameterArrays[0])),0x8,0x8},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x1,0x0,0x0),0x0,0x8,1,1,(&(parameterArrays[4])),0x1,0x8}}; +static const Method* const methodArrays[6] = {&(methods[0]),&(methods[1]),&(methods[2]),&(methods[2]),&(methods[3]),&(methods[4])}; +static const char strings[99] = "bytes_to_read\0buff_addr\0ion_flags\0buf_size\0filter\0heapid\0deinit\0init3\0init2\0close\0wait\0open\0uri\0h\0"; +static const uint16_t methodStrings[15] = {64,50,24,43,34,14,87,92,96,82,0,76,96,57,70}; +static const uint16_t methodStringsArrays[6] = {6,11,14,13,0,9}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(adspmsgd_adsp1_slim) = {6,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_ADSPMSGD_ADSP1_SLIM_H + + +#ifdef __cplusplus +extern "C" { +#endif +__QAIC_STUB_EXPORT int __QAIC_STUB(adspmsgd_adsp1_open)(const char* uri, remote_handle64* h) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle64_open)(uri, h); +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adspmsgd_adsp1_close)(remote_handle64 h) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle64_close)(h); +} +static __inline int _stub_method(remote_handle64 _handle, uint32_t _mid) { + remote_arg* _pra = 0; + int _nErr = 0; + _TRY(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 0, 0, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adspmsgd_adsp1_init2)(remote_handle64 _handle) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 2; + return _stub_method(_handle, _mid); +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adspmsgd_adsp1_deinit)(remote_handle64 _handle) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 3; + return _stub_method(_handle, _mid); +} +static __inline int _stub_method_1(remote_handle64 _handle, uint32_t _mid, uint32_t _in0[1], uint32_t _in1[1], uint32_t _in2[1], uint64_t _in3[1], uint64_t _rout4[1]) { + int _numIn[1] = {0}; + remote_arg _pra[2] = {0}; + uint64_t _primIn[3]= {0}; + uint64_t _primROut[1]= {0}; + int _nErr = 0; + _numIn[0] = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _pra[(_numIn[0] + 1)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 1)].buf.nLen = sizeof(_primROut); + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _in1, 0, 4); + _COPY(_primIn, 8, _in2, 0, 4); + _COPY(_primIn, 16, _in3, 0, 8); + _TRY(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 1, 0, 0), _pra)); + _COPY(_rout4, 0, _primROut, 0, 8); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adspmsgd_adsp1_init3)(remote_handle64 _handle, int heapid, uint32 ion_flags, uint32 filter, uint64 buf_size, uint64* buff_addr) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 4; + return _stub_method_1(_handle, _mid, (uint32_t*)&heapid, (uint32_t*)&ion_flags, (uint32_t*)&filter, (uint64_t*)&buf_size, (uint64_t*)buff_addr); +} +static __inline int _stub_method_2(remote_handle64 _handle, uint32_t _mid, uint64_t _rout0[1]) { + int _numIn[1] = {0}; + remote_arg _pra[1] = {0}; + uint64_t _primROut[1]= {0}; + int _nErr = 0; + _numIn[0] = 0; + _pra[(_numIn[0] + 0)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 0)].buf.nLen = sizeof(_primROut); + _TRY(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 0, 1, 0, 0), _pra)); + _COPY(_rout0, 0, _primROut, 0, 8); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adspmsgd_adsp1_wait)(remote_handle64 _handle, uint64* bytes_to_read) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 5; + return _stub_method_2(_handle, _mid, (uint64_t*)bytes_to_read); +} +#ifdef __cplusplus +} +#endif +#endif //_ADSPMSGD_ADSP1_STUB_H diff --git a/src/adspmsgd_adsp_stub.c b/src/adspmsgd_adsp_stub.c new file mode 100644 index 0000000..94eb105 --- /dev/null +++ b/src/adspmsgd_adsp_stub.c @@ -0,0 +1,605 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _ADSPMSGD_ADSP_STUB_H +#define _ADSPMSGD_ADSP_STUB_H +#include "adspmsgd_adsp.h" +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#include + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef _ATTRIBUTE_VISIBILITY + +#ifdef _WIN32 +#define _ATTRIBUTE_VISIBILITY +#else +#define _ATTRIBUTE_VISIBILITY __attribute__ ((visibility("default"))) +#endif + +#endif // _ATTRIBUTE_VISIBILITY + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i = 0; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#endif + + +#endif // _QAIC_ENV_H + +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include +#include + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc((size_t)size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + (size_t)size) < (uintptr_t)me->stack + (size_t)me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _ADSPMSGD_ADSP_SLIM_H +#define _ADSPMSGD_ADSP_SLIM_H +#include + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Parameter parameters[3] = {{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0}}; +static const Parameter* const parameterArrays[5] = {(&(parameters[0])),(&(parameters[1])),(&(parameters[1])),(&(parameters[1])),(&(parameters[2]))}; +static const Method methods[2] = {{REMOTE_SCALARS_MAKEX(0,0,0x1,0x1,0x0,0x0),0x10,0x4,5,5,(&(parameterArrays[0])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x0,0x0,0x0),0x0,0x0,0,0,0,0x0,0x0}}; +static const Method* const methodArrays[3] = {&(methods[0]),&(methods[1]),&(methods[1])}; +static const char strings[57] = "buff_addr\0ion_flags\0buf_size\0deinit\0filter\0heapid\0init2\0"; +static const uint16_t methodStrings[8] = {31,43,10,36,20,0,29,50}; +static const uint16_t methodStringsArrays[3] = {0,7,6}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(adspmsgd_adsp_slim) = {3,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_ADSPMSGD_ADSP_SLIM_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _const_adspmsgd_adsp_handle +#define _const_adspmsgd_adsp_handle ((remote_handle)-1) +#endif //_const_adspmsgd_adsp_handle + +static void _adspmsgd_adsp_pls_dtor(void* data) { + remote_handle* ph = (remote_handle*)data; + if(_const_adspmsgd_adsp_handle != *ph) { + (void)__QAIC_REMOTE(remote_handle_close)(*ph); + *ph = _const_adspmsgd_adsp_handle; + } +} + +static int _adspmsgd_adsp_pls_ctor(void* ctx, void* data) { + remote_handle* ph = (remote_handle*)data; + *ph = _const_adspmsgd_adsp_handle; + if(*ph == (remote_handle)-1) { + return __QAIC_REMOTE(remote_handle_open)((const char*)ctx, ph); + } + return 0; +} + +#if (defined __qdsp6__) || (defined __hexagon__) +#pragma weak adsp_pls_add_lookup +extern int adsp_pls_add_lookup(uint32_t type, uint32_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* ctx), void** ppo); +#pragma weak HAP_pls_add_lookup +extern int HAP_pls_add_lookup(uint32_t type, uint32_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* ctx), void** ppo); + +__QAIC_STUB_EXPORT remote_handle _adspmsgd_adsp_handle(void) { + remote_handle* ph = 0; + if(adsp_pls_add_lookup) { + if(0 == adsp_pls_add_lookup((uint32_t)_adspmsgd_adsp_handle, 0, sizeof(*ph), _adspmsgd_adsp_pls_ctor, "adspmsgd_adsp", _adspmsgd_adsp_pls_dtor, (void**)&ph)) { + return *ph; + } + return (remote_handle)-1; + } else if(HAP_pls_add_lookup) { + if(0 == HAP_pls_add_lookup((uint32_t)_adspmsgd_adsp_handle, 0, sizeof(*ph), _adspmsgd_adsp_pls_ctor, "adspmsgd_adsp", _adspmsgd_adsp_pls_dtor, (void**)&ph)) { + return *ph; + } + return (remote_handle)-1; + } + return(remote_handle)-1; +} + +#else //__qdsp6__ || __hexagon__ + +uint32_t _adspmsgd_adsp_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare); + +#ifdef _WIN32 +#ifdef _USRDLL +#include "Windows.h" +#else +#include "ntddk.h" +#endif //_USRDLL +uint32_t _adspmsgd_adsp_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare) { + return (uint32_t)InterlockedCompareExchange((volatile LONG*)puDest, (LONG)uExchange, (LONG)uCompare); +} +#elif __GNUC__ +uint32_t _adspmsgd_adsp_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare) { + return __sync_val_compare_and_swap(puDest, uCompare, uExchange); +} +#endif //_WIN32 + + +__QAIC_STUB_EXPORT remote_handle _adspmsgd_adsp_handle(void) { + static remote_handle handle = _const_adspmsgd_adsp_handle; + if((remote_handle)-1 != handle) { + return handle; + } else { + remote_handle tmp; + int nErr = _adspmsgd_adsp_pls_ctor("adspmsgd_adsp", (void*)&tmp); + if(nErr) { + return (remote_handle)-1; + } + if(((remote_handle)-1 != handle) || ((remote_handle)-1 != (remote_handle)_adspmsgd_adsp_atomic_CompareAndExchange((uint32_t*)&handle, (uint32_t)tmp, (uint32_t)-1))) { + _adspmsgd_adsp_pls_dtor(&tmp); + } + return handle; + } +} + +#endif //__qdsp6__ + +#ifdef __cplusplus +} +#endif + + +#ifdef __cplusplus +extern "C" { +#endif +static __inline int _stub_method(remote_handle _handle, uint32_t _mid, uint32_t _in0[1], uint32_t _in1[1], uint32_t _in2[1], uint32_t _in3[1], uint32_t _rout4[1]) { + int _numIn[1] = {0}; + remote_arg _pra[2] = {0}; + uint32_t _primIn[4]= {0}; + uint32_t _primROut[1]= {0}; + int _nErr = 0; + _numIn[0] = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _pra[(_numIn[0] + 1)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 1)].buf.nLen = sizeof(_primROut); + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _in1, 0, 4); + _COPY(_primIn, 8, _in2, 0, 4); + _COPY(_primIn, 12, _in3, 0, 4); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 1, 0, 0), _pra)); + _COPY(_rout4, 0, _primROut, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adspmsgd_adsp_init)(int heapid, uint32 ion_flags, uint32 filter, uint32 buf_size, int* buff_addr) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 0; + remote_handle _handle = _adspmsgd_adsp_handle(); + if (_handle != (remote_handle)-1) + { + return _stub_method(_handle, _mid, (uint32_t*)&heapid, (uint32_t*)&ion_flags, (uint32_t*)&filter, (uint32_t*)&buf_size, (uint32_t*)buff_addr); + } + else + { + return AEE_EINVHANDLE; + } +} +static __inline int _stub_method_1(remote_handle _handle, uint32_t _mid) { + remote_arg* _pra = 0; + int _nErr = 0; + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 0, 0, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adspmsgd_adsp_init2)(void) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 1; + remote_handle _handle = _adspmsgd_adsp_handle(); + if (_handle != (remote_handle)-1) + { + return _stub_method_1(_handle, _mid); + } + else + { + return AEE_EINVHANDLE; + } +} +__QAIC_STUB_EXPORT int __QAIC_STUB(adspmsgd_adsp_deinit)(void) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 2; + remote_handle _handle = _adspmsgd_adsp_handle(); + if (_handle != (remote_handle)-1) + { + return _stub_method_1(_handle, _mid); + } + else + { + return AEE_EINVHANDLE; + } +} +#ifdef __cplusplus +} +#endif +#endif //_ADSPMSGD_ADSP_STUB_H diff --git a/src/adspmsgd_apps_skel.c b/src/adspmsgd_apps_skel.c new file mode 100644 index 0000000..682cdcf --- /dev/null +++ b/src/adspmsgd_apps_skel.c @@ -0,0 +1,487 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _ADSPMSGD_APPS_SKEL_H +#define _ADSPMSGD_APPS_SKEL_H +#include "adspmsgd_apps.h" + +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#include + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef _ATTRIBUTE_VISIBILITY + +#ifdef _WIN32 +#define _ATTRIBUTE_VISIBILITY +#else +#define _ATTRIBUTE_VISIBILITY __attribute__ ((visibility("default"))) +#endif + +#endif // _ATTRIBUTE_VISIBILITY + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i = 0; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#endif + + +#endif // _QAIC_ENV_H + +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include +#include + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc((size_t)size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + (size_t)size) < (uintptr_t)me->stack + (size_t)me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _ADSPMSGD_APPS_SLIM_H +#define _ADSPMSGD_APPS_SLIM_H +#include + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Type types[1]; +static const Type types[1] = {{0x1,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x1}}; +static const Parameter parameters[1] = {{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[0]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8),0,0}}; +static const Parameter* const parameterArrays[1] = {(&(parameters[0]))}; +static const Method methods[1] = {{REMOTE_SCALARS_MAKEX(0,0,0x2,0x0,0x0,0x0),0x4,0x0,2,1,(&(parameterArrays[0])),0x4,0x0}}; +static const Method* const methodArrays[1] = {&(methods[0])}; +static const char strings[24] = "log_message_buffer\0log\0"; +static const uint16_t methodStrings[2] = {19,0}; +static const uint16_t methodStringsArrays[1] = {0}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(adspmsgd_apps_slim) = {1,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_ADSPMSGD_APPS_SLIM_H +extern int adsp_mmap_fd_getinfo(int, uint32_t *); +#ifdef __cplusplus +extern "C" { +#endif +_ATTRIBUTE_VISIBILITY uint32_t adspmsgd_apps_skel_invoke_qaic_version = 10042; +static __inline int _skel_method(int (*_pfn)(const unsigned char*, int), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + char* _in0[1] = {0}; + uint32_t _in0Len[1] = {0}; + uint32_t* _primIn= 0; + remote_arg* _praIn = 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==2); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((2 + 0) + (((0 + 0) + 0) + 0))) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 4); + _primIn = _pra[0].buf.pv; + _COPY(_in0Len, 0, _primIn, 0, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, ((_praIn[0].buf.nLen / 1)) >= (size_t)(_in0Len[0])); + _in0[0] = _praIn[0].buf.pv; + _TRY(_nErr, _pfn((const unsigned char*)*_in0, (int)*_in0Len)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_SKEL_EXPORT int __QAIC_SKEL(adspmsgd_apps_skel_invoke)(uint32_t _sc, remote_arg* _pra) __QAIC_SKEL_ATTRIBUTE { + switch(REMOTE_SCALARS_METHOD(_sc)) + { + case 0: + return _skel_method(__QAIC_IMPL(adspmsgd_apps_log), _sc, _pra); + } + return AEE_EUNSUPPORTED; +} +#ifdef __cplusplus +} +#endif +#endif //_ADSPMSGD_APPS_SKEL_H diff --git a/src/adspmsgd_printf.c b/src/adspmsgd_printf.c new file mode 100644 index 0000000..787d9c1 --- /dev/null +++ b/src/adspmsgd_printf.c @@ -0,0 +1,58 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#include "adspmsgd_apps.h" +#include "remote.h" + +#include + +#define LOG_NODE_SIZE 256 +#define LOG_FILENAME_SIZE 30 +#define LOG_MSG_SIZE \ + LOG_NODE_SIZE - LOG_FILENAME_SIZE - sizeof(enum adspmsgd_apps_Level) - \ + (2 * sizeof(unsigned short)) + +typedef struct __attribute__((packed)) { + enum adspmsgd_apps_Level level; + unsigned short line; + unsigned short thread_id; + char str[LOG_MSG_SIZE]; + char file[LOG_FILENAME_SIZE]; +} LogNode; + +#if 0 +static inline android_LogPriority convert_level_to_android_priority( + enum adspmsgd_apps_Level level) +{ + switch (level) { + case LOW: + return LOW; + case MEDIUM: + return MEDIUM; + case HIGH: + return HIGH; + case ERROR: + return ERROR; + case FATAL: + return FATAL; + default: + return 0; + } +} +#endif + +int adspmsgd_apps_log(const unsigned char *log_message_buffer, + int log_message_bufferLen) { + LogNode *logMessage = (LogNode *)log_message_buffer; + while ((log_message_bufferLen > 0) && (logMessage != NULL)) { + printf("adsprpc: %s:%d:0x%x:%s", logMessage->file, logMessage->line, + logMessage->thread_id, logMessage->str); + logMessage++; + log_message_bufferLen -= sizeof(LogNode); + }; + + return 0; +} +void adspmsgd_log_message(char *format, char *msg) { + printf("adsprpc:dsp: %s\n", msg); +} diff --git a/src/adsprpc_blacklist.txt b/src/adsprpc_blacklist.txt new file mode 100644 index 0000000..c716b38 --- /dev/null +++ b/src/adsprpc_blacklist.txt @@ -0,0 +1,4 @@ +src:*/adspmsgd_apps_skel.c +src:*/apps_mem_skel.c +src:*/apps_remotectl_skel.c +src:*/apps_std_skel.c \ No newline at end of file diff --git a/src/adsprpcd.c b/src/adsprpcd.c new file mode 100644 index 0000000..452c645 --- /dev/null +++ b/src/adsprpcd.c @@ -0,0 +1,67 @@ +// 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 +#define VERIFY_PRINT_INFO 0 + +#include +#include +#include +#include "verify.h" +#include "HAP_farf.h" +#include "AEEStdErr.h" + + +#ifndef ADSP_DEFAULT_LISTENER_NAME +#define ADSP_DEFAULT_LISTENER_NAME "libadsp_default_listener.so" +#endif +#ifndef ADSP_LIBHIDL_NAME +#define ADSP_LIBHIDL_NAME "libhidlbase.so" +#endif + +typedef int (*adsp_default_listener_start_t)(int argc, char *argv[]); + +int main(int argc, char *argv[]) { + + int nErr = 0; + void *adsphandler = NULL; +#ifndef NO_HAL + void *libhidlbaseHandler = NULL; +#endif + adsp_default_listener_start_t listener_start; + + VERIFY_EPRINTF("adsp daemon starting"); +#ifndef NO_HAL + if(NULL != (libhidlbaseHandler = dlopen(ADSP_LIBHIDL_NAME, RTLD_NOW))) { +#endif + while (1) { + if(NULL != (adsphandler = dlopen(ADSP_DEFAULT_LISTENER_NAME, RTLD_NOW))) { + if(NULL != (listener_start = + (adsp_default_listener_start_t)dlsym(adsphandler, "adsp_default_listener_start"))) { + VERIFY_IPRINTF("adsp_default_listener_start called"); + nErr = listener_start(argc, argv); + } + if(0 != dlclose(adsphandler)) { + VERIFY_EPRINTF("dlclose failed"); + } + } else { + VERIFY_EPRINTF("adsp daemon error %s", dlerror()); + } + if (nErr == AEE_ECONNREFUSED) { + VERIFY_EPRINTF("fastRPC device driver is disabled, retrying..."); + } + VERIFY_EPRINTF("adsp daemon will restart after 25ms..."); + usleep(25000); + } +#ifndef NO_HAL + if(0 != dlclose(libhidlbaseHandler)) { + VERIFY_EPRINTF("libhidlbase dlclose failed"); + } + } +#endif + VERIFY_EPRINTF("adsp daemon exiting %x", nErr); + + return nErr; +} diff --git a/src/apps_mem_imp.c b/src/apps_mem_imp.c new file mode 100644 index 0000000..77e00e1 --- /dev/null +++ b/src/apps_mem_imp.c @@ -0,0 +1,351 @@ +// 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 */ + +#include "AEEQList.h" +#include "AEEStdErr.h" +#include "AEEstd.h" +#include "apps_mem.h" +#include "fastrpc_cap.h" +#include "fastrpc_common.h" +#include "fastrpc_apps_user.h" +#include "fastrpc_mem.h" +#include "fastrpc_trace.h" +#include "remote64.h" +#include "rpcmem_internal.h" +#include "verify.h" +#include +#include +#include +#include +#include + +#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 */ + +static QList memlst[NUM_DOMAINS_EXTEND]; +static pthread_mutex_t memmt[NUM_DOMAINS_EXTEND]; +int mem_init_flag[NUM_DOMAINS_EXTEND]; + +struct mem_info { + QNode qn; + uint64 vapps; + uint64 vadsp; + int32 size; + int32 mapped; + uint32 rflags; +}; + +/* +These should be called in some static constructor of the .so that +uses rpcmem. + +I moved them into fastrpc_apps_user.c because there is no gurantee in +the order of when constructors are called. +*/ + +int apps_mem_init(int domain) { + QList_Ctor(&memlst[domain]); + pthread_mutex_init(&memmt[domain], 0); + mem_init_flag[domain] = 1; + return AEE_SUCCESS; +} + +void apps_mem_deinit(int domain) { + QNode *pn; + if (mem_init_flag[domain]) { + while ((pn = QList_PopZ(&memlst[domain])) != NULL) { + struct mem_info *mfree = STD_RECOVER_REC(struct mem_info, qn, pn); + if (mfree->vapps) { + if (mfree->mapped) { + munmap((void *)(uintptr_t)mfree->vapps, mfree->size); + } else { + rpcmem_free_internal((void *)(uintptr_t)mfree->vapps); + } + } + free(mfree); + mfree = NULL; + } + pthread_mutex_destroy(&memmt[domain]); + mem_init_flag[domain] = 0; + } +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_mem_request_map64)(int heapid, uint32 lflags, uint32 rflags, + uint64 vin, int64 len, uint64 *vapps, + uint64 *vadsp) __QAIC_IMPL_ATTRIBUTE { + struct mem_info *minfo = 0; + int nErr = 0, unsigned_module = 0, ualloc_support = 0; + void *buf = 0; + uint64_t pbuf; + int fd = -1; + int domain = get_current_domain(); + + 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", + __func__, rflags, lflags, len, heapid, + unsigned_module); + if (unsigned_module) { + ualloc_support = is_userspace_allocation_supported(); + } + (void)vin; + VERIFYC(len >= 0, AEE_EBADPARM); + VERIFYC(NULL != (minfo = malloc(sizeof(*minfo))), AEE_ENOMEMORY); + QNode_CtorZ(&minfo->qn); + *vadsp = 0; + if (rflags == ADSP_MMAP_HEAP_ADDR || rflags == ADSP_MMAP_REMOTE_HEAP_ADDR) { + VERIFY(AEE_SUCCESS == (nErr = remote_mmap64_internal(-1, rflags, 0, len, + (uint64_t *)vadsp))); + *vapps = 0; + minfo->vapps = 0; + } else if (rflags == FASTRPC_ALLOC_HLOS_FD) { + VERIFYC(NULL != (buf = rpcmem_alloc_internal(heapid, lflags, len)), + AEE_ENORPCMEMORY); + VERIFYC(0 < (fd = rpcmem_to_fd_internal(buf)), AEE_EBADFD); + + /* 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, + FASTRPC_MAP_FD_DELAYED))); + pbuf = (uint64_t)buf; + *vapps = pbuf; + minfo->vapps = *vapps; + + /* HLOS fd will be used to map memory on DSP later if required. + * fd here will act as the unique key between the memory mapped + * on HLOS and DSP. + */ + *vadsp = (uint64)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)) && + (!is_kernel_alloc_supported(-1, -1) || + (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 = remote_mmap64_internal(fd, rflags, (uint64_t)buf, len, + (uint64_t *)vadsp))); + pbuf = (uint64_t)buf; + *vapps = pbuf; + minfo->vapps = *vapps; + } + minfo->vadsp = *vadsp; + minfo->size = len; + minfo->mapped = 0; + minfo->rflags = rflags; + pthread_mutex_lock(&memmt[domain]); + QList_AppendNode(&memlst[domain], &minfo->qn); + pthread_mutex_unlock(&memmt[domain]); +bail: + if (nErr) { + if (buf) { + rpcmem_free_internal(buf); + buf = NULL; + } + if (minfo) { + free(minfo); + 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", + nErr, fd, len, lflags, rflags); + } + FASTRPC_ATRACE_END(); + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_mem_request_map)(int heapid, uint32 lflags, uint32 rflags, + uint32 vin, int32 len, uint32 *vapps, + uint32 *vadsp) __QAIC_IMPL_ATTRIBUTE { + uint64 vin1, vapps1, vadsp1; + int64 len1; + int nErr = AEE_SUCCESS; + vin1 = (uint64)vin; + len1 = (int64)len; + nErr = apps_mem_request_map64(heapid, lflags, rflags, vin1, len1, &vapps1, + &vadsp1); + *vapps = (uint32)vapps1; + *vadsp = (uint32)vadsp1; + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_mem_request_unmap64)(uint64 vadsp, + int64 len) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS, fd = -1; + struct mem_info *minfo, *mfree = 0; + QNode *pn, *pnn; + int domain = get_current_domain(); + + FASTRPC_ATRACE_BEGIN_L("%s called with vadsp 0x%llx, len 0x%llx", __func__, + vadsp, len); + pthread_mutex_lock(&memmt[domain]); + QLIST_NEXTSAFE_FOR_ALL(&memlst[domain], pn, pnn) { + minfo = STD_RECOVER_REC(struct mem_info, qn, pn); + if (minfo->vadsp == vadsp) { + mfree = minfo; + break; + } + } + pthread_mutex_unlock(&memmt[domain]); + VERIFYC(mfree, AEE_ENOSUCHMAP); + + /* If apps_mem_request_map64 was called with flag FASTRPC_ALLOC_HLOS_FD, + * use fastrpc_munmap else use remote_munmap64 to unmap. + */ + if (mfree->rflags == FASTRPC_ALLOC_HLOS_FD) { + fd = (int)vadsp; + VERIFY(AEE_SUCCESS == (nErr = fastrpc_munmap(domain, fd, 0, len))); + } else { + VERIFY(AEE_SUCCESS == (nErr = remote_munmap64((uint64_t)vadsp, len))); + } + + /* Dequeue done after unmap to prevent leaks in case unmap fails */ + pthread_mutex_lock(&memmt[domain]); + QNode_Dequeue(&mfree->qn); + pthread_mutex_unlock(&memmt[domain]); + + if (mfree->mapped) { + munmap((void *)(uintptr_t)mfree->vapps, mfree->size); + } else { + if (mfree->vapps) + rpcmem_free_internal((void *)(uintptr_t)mfree->vapps); + } + free(mfree); + mfree = NULL; +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error 0x%x: apps_mem_request_unmap64 failed for size %lld " + "(vadsp 0x%llx)\n", + nErr, len, vadsp); + } + FASTRPC_ATRACE_END(); + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_mem_request_unmap)(uint32 vadsp, + int32 len) __QAIC_IMPL_ATTRIBUTE { + uint64 vadsp1 = (uint64)vadsp; + int64 len1 = (int64)len; + int nErr = apps_mem_request_unmap64(vadsp1, len1); + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_mem_share_map)(int fd, int size, uint64 *vapps, + uint64 *vadsp) __QAIC_IMPL_ATTRIBUTE { + struct mem_info *minfo = 0; + int nErr = AEE_SUCCESS; + void *buf = 0; + uint64_t pbuf; + int domain = get_current_domain(); + + VERIFYC(fd > 0, AEE_EBADPARM); + VERIFYC(0 != (minfo = malloc(sizeof(*minfo))), AEE_ENOMEMORY); + QNode_CtorZ(&minfo->qn); + *vadsp = 0; + VERIFYC(MAP_FAILED != (buf = (void *)mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0)), + AEE_ERPC); + VERIFY(AEE_SUCCESS == (nErr = remote_mmap64_internal( + fd, 0, (uint64_t)buf, size, (uint64_t *)vadsp))); + pbuf = (uint64_t)buf; + *vapps = pbuf; + minfo->vapps = *vapps; + minfo->vadsp = *vadsp; + minfo->size = size; + minfo->mapped = 1; + pthread_mutex_lock(&memmt[domain]); + QList_AppendNode(&memlst[domain], &minfo->qn); + pthread_mutex_unlock(&memmt[domain]); +bail: + if (nErr) { + if (buf) { + munmap(buf, size); + } + if (minfo) { + free(minfo); + minfo = NULL; + } + VERIFY_EPRINTF( + "Error 0x%x: apps_mem_share_map failed for fd 0x%x of size %d\n", nErr, + fd, size); + } + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_mem_share_unmap)(uint64 vadsp, int size) + __QAIC_IMPL_ATTRIBUTE { + int64 len1 = (int64)size; + int nErr = AEE_SUCCESS; + 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", + nErr, size, vadsp); + } + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_mem_dma_handle_map)(int fd, int offset, + int size) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + uint32_t len = 0, attr = 0; + int flags = FASTRPC_MAP_FD_DELAYED; + int domain = get_current_domain(); + + VERIFYC(fd > 0 && size > 0, AEE_EBADPARM); + unregister_dma_handle(fd, &len, &attr); + // If attr is FASTRPC_ATTR_NOMAP, use flags FASTRPC_MAP_FD_NOMAP to skip CPU + // mapping + if (attr == FASTRPC_ATTR_NOMAP) { + VERIFYC(size <= (int)len, AEE_EBADPARM); + flags = FASTRPC_MAP_FD_NOMAP; + } + VERIFY(AEE_SUCCESS == + (nErr = fastrpc_mmap(domain, fd, 0, offset, size, flags))); +bail: + if (nErr) { + VERIFY_EPRINTF("Error 0x%x: %s failed for fd 0x%x of size %d\n", nErr, + __func__, fd, size); + } + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_mem_dma_handle_unmap)(int fd, int size) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + int domain = get_current_domain(); + + VERIFYC(fd > 0 && size > 0, AEE_EBADPARM); + VERIFY(AEE_SUCCESS == (nErr = fastrpc_munmap(domain, fd, 0, size))); +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error 0x%x: %s failed for fd 0x%x of size %d\n", nErr, + __func__, fd, size); + } + return nErr; +} diff --git a/src/apps_mem_skel.c b/src/apps_mem_skel.c new file mode 100644 index 0000000..1d5f3df --- /dev/null +++ b/src/apps_mem_skel.c @@ -0,0 +1,677 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _APPS_MEM_SKEL_H +#define _APPS_MEM_SKEL_H +#include "apps_mem.h" + +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#include + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef _ATTRIBUTE_VISIBILITY + +#ifdef _WIN32 +#define _ATTRIBUTE_VISIBILITY +#else +#define _ATTRIBUTE_VISIBILITY __attribute__ ((visibility("default"))) +#endif + +#endif // _ATTRIBUTE_VISIBILITY + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i = 0; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#endif + + +#endif // _QAIC_ENV_H + +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include +#include + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc((size_t)size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + (size_t)size) < (uintptr_t)me->stack + (size_t)me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _APPS_MEM_SLIM_H +#define _APPS_MEM_SLIM_H +#include + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Parameter parameters[7] = {{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0},{0x8,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x8,0,0},{0x8,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x8,0,0},{0x8,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x8,3,0}}; +static const Parameter* const parameterArrays[23] = {(&(parameters[0])),(&(parameters[1])),(&(parameters[1])),(&(parameters[4])),(&(parameters[5])),(&(parameters[6])),(&(parameters[6])),(&(parameters[0])),(&(parameters[1])),(&(parameters[1])),(&(parameters[1])),(&(parameters[2])),(&(parameters[3])),(&(parameters[3])),(&(parameters[0])),(&(parameters[0])),(&(parameters[6])),(&(parameters[6])),(&(parameters[0])),(&(parameters[0])),(&(parameters[0])),(&(parameters[4])),(&(parameters[0]))}; +static const Method methods[8] = {{REMOTE_SCALARS_MAKEX(0,0,0x1,0x1,0x0,0x0),0x14,0x8,7,7,(&(parameterArrays[7])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0x8,0x0,2,2,(&(parameterArrays[10])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x1,0x0,0x0),0x20,0x10,11,7,(&(parameterArrays[0])),0x8,0x8},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0x10,0x0,6,2,(&(parameterArrays[3])),0x8,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x1,0x0,0x0),0x8,0x10,4,4,(&(parameterArrays[14])),0x4,0x8},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0xc,0x0,4,2,(&(parameterArrays[21])),0x8,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0xc,0x0,3,3,(&(parameterArrays[18])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0x8,0x0,2,2,(&(parameterArrays[14])),0x4,0x0}}; +static const Method* const methodArrays[8] = {&(methods[0]),&(methods[1]),&(methods[2]),&(methods[3]),&(methods[4]),&(methods[5]),&(methods[6]),&(methods[7])}; +static const char strings[170] = "dma_handle_unmap\0request_unmap64\0dma_handle_map\0request_map64\0request_unmap\0share_unmap\0request_map\0share_map\0ion_flags\0offset\0rflags\0heapid\0vadsp\0vapps\0size\0len\0vin\0fd\0"; +static const uint16_t methodStrings[37] = {48,134,110,127,162,158,147,141,88,134,110,127,162,158,147,141,100,166,153,147,141,33,166,120,153,0,166,153,76,141,153,17,141,158,62,141,158}; +static const uint16_t methodStringsArrays[8] = {8,34,0,31,16,28,21,25}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(apps_mem_slim) = {8,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_APPS_MEM_SLIM_H +extern int adsp_mmap_fd_getinfo(int, uint32_t *); +#ifdef __cplusplus +extern "C" { +#endif +_ATTRIBUTE_VISIBILITY uint32_t apps_mem_skel_invoke_qaic_version = 10042; +static __inline int _skel_method(int (*_pfn)(int, int), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + uint32_t _in0[1] = {0}; + uint32_t _in1[1] = {0}; + uint32_t* _primIn= 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((1 + 0) + (((0 + 0) + 0) + 0))) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_in1, 0, _primIn, 4, 4); + _TRY(_nErr, _pfn((int)*_in0, (int)*_in1)); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_1(int (*_pfn)(int, int, int), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + uint32_t _in0[1] = {0}; + uint32_t _in1[1] = {0}; + uint32_t _in2[1] = {0}; + uint32_t* _primIn= 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((1 + 0) + (((0 + 0) + 0) + 0))) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 12); + _primIn = _pra[0].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_in1, 0, _primIn, 4, 4); + _COPY(_in2, 0, _primIn, 8, 4); + _TRY(_nErr, _pfn((int)*_in0, (int)*_in1, (int)*_in2)); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_2(int (*_pfn)(uint64, int), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + uint64_t _in0[1] = {0}; + uint32_t _in1[1] = {0}; + uint64_t* _primIn= 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((1 + 0) + (((0 + 0) + 0) + 0))) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 12); + _primIn = _pra[0].buf.pv; + _COPY(_in0, 0, _primIn, 0, 8); + _COPY(_in1, 0, _primIn, 8, 4); + _TRY(_nErr, _pfn((uint64)*_in0, (int)*_in1)); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_3(int (*_pfn)(int, int, uint64*, uint64*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + uint32_t _in0[1] = {0}; + uint32_t _in1[1] = {0}; + uint64_t _rout2[1] = {0}; + uint64_t _rout3[1] = {0}; + uint32_t* _primIn= 0; + int _numIn[1] = {0}; + uint64_t* _primROut= 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((1 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 16); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_in1, 0, _primIn, 4, 4); + _TRY(_nErr, _pfn((int)*_in0, (int)*_in1, (uint64*)_rout2, (uint64*)_rout3)); + _COPY(_primROut, 0, _rout2, 0, 8); + _COPY(_primROut, 8, _rout3, 0, 8); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_4(int (*_pfn)(uint64, int64), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + uint64_t _in0[1] = {0}; + uint64_t _in1[1] = {0}; + uint64_t* _primIn= 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((1 + 0) + (((0 + 0) + 0) + 0))) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 16); + _primIn = _pra[0].buf.pv; + _COPY(_in0, 0, _primIn, 0, 8); + _COPY(_in1, 0, _primIn, 8, 8); + _TRY(_nErr, _pfn((uint64)*_in0, (int64)*_in1)); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_5(int (*_pfn)(int, uint32, uint32, uint64, int64, uint64*, uint64*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + uint32_t _in0[1] = {0}; + uint32_t _in1[1] = {0}; + uint32_t _in2[1] = {0}; + uint64_t _in3[1] = {0}; + uint64_t _in4[1] = {0}; + uint64_t _rout5[1] = {0}; + uint64_t _rout6[1] = {0}; + uint64_t* _primIn= 0; + int _numIn[1] = {0}; + uint64_t* _primROut= 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((1 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 32); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 16); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_in1, 0, _primIn, 4, 4); + _COPY(_in2, 0, _primIn, 8, 4); + _COPY(_in3, 0, _primIn, 16, 8); + _COPY(_in4, 0, _primIn, 24, 8); + _TRY(_nErr, _pfn((int)*_in0, (uint32)*_in1, (uint32)*_in2, (uint64)*_in3, (int64)*_in4, (uint64*)_rout5, (uint64*)_rout6)); + _COPY(_primROut, 0, _rout5, 0, 8); + _COPY(_primROut, 8, _rout6, 0, 8); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_6(int (*_pfn)(uint32, int32), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + uint32_t _in0[1] = {0}; + uint32_t _in1[1] = {0}; + uint32_t* _primIn= 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((1 + 0) + (((0 + 0) + 0) + 0))) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_in1, 0, _primIn, 4, 4); + _TRY(_nErr, _pfn((uint32)*_in0, (int32)*_in1)); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_7(int (*_pfn)(int, uint32, uint32, uint32, int32, uint32*, uint32*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + uint32_t _in0[1] = {0}; + uint32_t _in1[1] = {0}; + uint32_t _in2[1] = {0}; + uint32_t _in3[1] = {0}; + uint32_t _in4[1] = {0}; + uint32_t _rout5[1] = {0}; + uint32_t _rout6[1] = {0}; + uint32_t* _primIn= 0; + int _numIn[1] = {0}; + uint32_t* _primROut= 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((1 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 20); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 8); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_in1, 0, _primIn, 4, 4); + _COPY(_in2, 0, _primIn, 8, 4); + _COPY(_in3, 0, _primIn, 12, 4); + _COPY(_in4, 0, _primIn, 16, 4); + _TRY(_nErr, _pfn((int)*_in0, (uint32)*_in1, (uint32)*_in2, (uint32)*_in3, (int32)*_in4, (uint32*)_rout5, (uint32*)_rout6)); + _COPY(_primROut, 0, _rout5, 0, 4); + _COPY(_primROut, 4, _rout6, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_SKEL_EXPORT int __QAIC_SKEL(apps_mem_skel_invoke)(uint32_t _sc, remote_arg* _pra) __QAIC_SKEL_ATTRIBUTE { + switch(REMOTE_SCALARS_METHOD(_sc)) + { + case 0: + return _skel_method_7(__QAIC_IMPL(apps_mem_request_map), _sc, _pra); + case 1: + return _skel_method_6(__QAIC_IMPL(apps_mem_request_unmap), _sc, _pra); + case 2: + return _skel_method_5(__QAIC_IMPL(apps_mem_request_map64), _sc, _pra); + case 3: + return _skel_method_4(__QAIC_IMPL(apps_mem_request_unmap64), _sc, _pra); + case 4: + return _skel_method_3(__QAIC_IMPL(apps_mem_share_map), _sc, _pra); + case 5: + return _skel_method_2(__QAIC_IMPL(apps_mem_share_unmap), _sc, _pra); + case 6: + return _skel_method_1(__QAIC_IMPL(apps_mem_dma_handle_map), _sc, _pra); + case 7: + return _skel_method(__QAIC_IMPL(apps_mem_dma_handle_unmap), _sc, _pra); + } + return AEE_EUNSUPPORTED; +} +#ifdef __cplusplus +} +#endif +#endif //_APPS_MEM_SKEL_H diff --git a/src/apps_remotectl_skel.c b/src/apps_remotectl_skel.c new file mode 100644 index 0000000..0b62ae4 --- /dev/null +++ b/src/apps_remotectl_skel.c @@ -0,0 +1,541 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _APPS_REMOTECTL_SKEL_H +#define _APPS_REMOTECTL_SKEL_H +#include "apps_remotectl.h" + +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#include + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef _ATTRIBUTE_VISIBILITY + +#ifdef _WIN32 +#define _ATTRIBUTE_VISIBILITY +#else +#define _ATTRIBUTE_VISIBILITY __attribute__ ((visibility("default"))) +#endif + +#endif // _ATTRIBUTE_VISIBILITY + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i = 0; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#endif + + +#endif // _QAIC_ENV_H + +#include +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include +#include + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc((size_t)size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + (size_t)size) < (uintptr_t)me->stack + (size_t)me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _APPS_REMOTECTL_SLIM_H +#define _APPS_REMOTECTL_SLIM_H +#include + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Type types[1]; +static const Type types[1] = {{0x1,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x1}}; +static const Parameter parameters[4] = {{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)0x0,0}}, 4,SLIM_IFPTR32(0x4,0x8),0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[0]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8),3,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0}}; +static const Parameter* const parameterArrays[7] = {(&(parameters[0])),(&(parameters[1])),(&(parameters[2])),(&(parameters[1])),(&(parameters[3])),(&(parameters[2])),(&(parameters[1]))}; +static const Method methods[2] = {{REMOTE_SCALARS_MAKEX(0,0,0x2,0x2,0x0,0x0),0x8,0x8,6,4,(&(parameterArrays[0])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x2,0x0,0x0),0x8,0x4,5,3,(&(parameterArrays[4])),0x4,0x4}}; +static const Method* const methodArrays[2] = {&(methods[0]),&(methods[1])}; +static const char strings[37] = "dlerror\0handle\0close\0nErr\0name\0open\0"; +static const uint16_t methodStrings[9] = {31,26,8,0,21,15,8,0,21}; +static const uint16_t methodStringsArrays[2] = {0,5}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(apps_remotectl_slim) = {2,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_APPS_REMOTECTL_SLIM_H +extern int adsp_mmap_fd_getinfo(int, uint32_t *); +#ifdef __cplusplus +extern "C" { +#endif +_ATTRIBUTE_VISIBILITY uint32_t apps_remotectl_skel_invoke_qaic_version = 10042; +static __inline int _skel_method(int (*_pfn)(int, char*, int, int*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + uint32_t _in0[1] = {0}; + char* _rout1[1] = {0}; + uint32_t _rout1Len[1] = {0}; + uint32_t _rout2[1] = {0}; + uint32_t* _primIn= 0; + int _numIn[1] = {0}; + uint32_t* _primROut= 0; + remote_arg* _praIn = 0; + remote_arg* _praROut = 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==2); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((1 + 2) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 4); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_rout1Len, 0, _primIn, 4, 4); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 1); + _ASSERT(_nErr, ((_praROut[0].buf.nLen / 1)) >= (size_t)(_rout1Len[0])); + _rout1[0] = _praROut[0].buf.pv; + _TRY(_nErr, _pfn((int)*_in0, (char*)*_rout1, (int)*_rout1Len, (int*)_rout2)); + _COPY(_primROut, 0, _rout2, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_1(int (*_pfn)(const char*, int*, char*, int, int*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + char* _in0[1] = {0}; + uint32_t _in0Len[1] = {0}; + uint32_t _rout1[1] = {0}; + char* _rout2[1] = {0}; + uint32_t _rout2Len[1] = {0}; + uint32_t _rout3[1] = {0}; + uint32_t* _primIn= 0; + int _numIn[1] = {0}; + uint32_t* _primROut= 0; + remote_arg* _praIn = 0; + remote_arg* _praROut = 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==2); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==2); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((2 + 2) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 8); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0Len, 0, _primIn, 0, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, ((_praIn[0].buf.nLen / 1)) >= (size_t)(_in0Len[0])); + _in0[0] = _praIn[0].buf.pv; + _ASSERT(_nErr, (_in0Len[0] > 0) && (_in0[0][(_in0Len[0] - 1)] == 0)); + _COPY(_rout2Len, 0, _primIn, 4, 4); + _praROut = (_praIn + _numIn[0] + 1); + _ASSERT(_nErr, ((_praROut[0].buf.nLen / 1)) >= (size_t)(_rout2Len[0])); + _rout2[0] = _praROut[0].buf.pv; + _TRY(_nErr, _pfn((const char*)*_in0, (int*)_rout1, (char*)*_rout2, (int)*_rout2Len, (int*)_rout3)); + _COPY(_primROut, 0, _rout1, 0, 4); + _COPY(_primROut, 4, _rout3, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_SKEL_EXPORT int __QAIC_SKEL(apps_remotectl_skel_invoke)(uint32_t _sc, remote_arg* _pra) __QAIC_SKEL_ATTRIBUTE { + switch(REMOTE_SCALARS_METHOD(_sc)) + { + case 0: + return _skel_method_1(__QAIC_IMPL(apps_remotectl_open), _sc, _pra); + case 1: + return _skel_method(__QAIC_IMPL(apps_remotectl_close), _sc, _pra); + } + return AEE_EUNSUPPORTED; +} +#ifdef __cplusplus +} +#endif +#endif //_APPS_REMOTECTL_SKEL_H diff --git a/src/apps_std_imp.c b/src/apps_std_imp.c new file mode 100644 index 0000000..4a8c01f --- /dev/null +++ b/src/apps_std_imp.c @@ -0,0 +1,1759 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifdef _WIN32 +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif // _CRT_SECURE_NO_WARNINGS + +#pragma warning(disable : 4996) +#define strtok_r strtok_s +#define S_ISDIR(mode) (mode & S_IFDIR) +#endif //_WIN32 + +#ifndef VERIFY_PRINT_ERROR +#define VERIFY_PRINT_ERROR +#endif // VERIFY_PRINT_ERROR +#ifndef VERIFY_PRINT_ERROR_ALWAYS +#define VERIFY_PRINT_ERROR_ALWAYS +#endif // VERIFY_PRINT_ERROR_ALWAYS +#define FARF_ERROR 1 +#define FARF_LOW 1 + +#ifndef VERIFY_PRINT_WARN +#define VERIFY_PRINT_WARN +#endif // VERIFY_PRINT_WARN + +#define FARF_CRITICAL 1 + +#include "AEEQList.h" +#include "AEEStdErr.h" +#include "AEEatomic.h" +#include "AEEstd.h" +#include "HAP_farf.h" +#include "apps_std.h" +#include "apps_std_internal.h" +#include "fastrpc_common.h" +#include "fastrpc_trace.h" +#include "platform_libs.h" +#include "remote.h" +#include "rpcmem_internal.h" +#include "verify.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef _WIN32 +#include +#endif // _WiN32 + +#ifndef C_ASSERT +#define C_ASSERT(test) \ + switch (0) { \ + case 0: \ + case test:; \ + } +#endif // C_ASSERT + +#define APPS_FD_BASE 100 +#define ERRNO (errno ? errno : nErr ? nErr : -1) +#define APPS_STD_STREAM_FILE 1 +#define APPS_STD_STREAM_BUF 2 + +#define ION_HEAP_ID_QSEECOM 27 + +#define OEM_CONFIG_FILE_NAME "oemconfig.so" +#define TESTSIG_FILE_NAME "testsig" +#define RPC_VERSION_FILE_NAME "librpcversion_skel.so" + +#define FREEIF(pv) \ + do { \ + if (pv) { \ + void *tmp = (void *)pv; \ + pv = 0; \ + free(tmp); \ + tmp = 0; \ + } \ + } while (0) + +struct apps_std_buf_info { + char *fbuf; + int flen; + int pos; +}; + +struct apps_std_info { + QNode qn; + int type; + union { + FILE *stream; + struct apps_std_buf_info binfo; + } u; + apps_std_FILE fd; +}; + +/* + * Member of the linked list of valid directory handles + */ +struct apps_std_dir_info { + QNode qn; + uint64 handle; +}; + +static QList apps_std_qlst; + +/* Linked list that tracks list of all valid dir handles */ +static QList apps_std_dirlist; +static pthread_mutex_t apps_std_mt; +extern const char *SUBSYSTEM_NAME[]; +struct mem_io_to_fd { + QNode qn; + int size; + int fd; + int fdfile; + FILE *stream; + void *buf; +}; + +struct mem_io_fd_list { + QList ql; + pthread_mutex_t mut; +}; + +static struct mem_io_fd_list fdlist; + +int setenv(const char *name, const char *value, int overwrite); +int unsetenv(const char *name); + +int apps_std_get_dirinfo(const apps_std_DIR *dir, + struct apps_std_dir_info **pDirinfo) { + int nErr = AEE_SUCCESS; + QNode *pn = NULL, *pnn = NULL; + struct apps_std_dir_info *dirinfo = 0; + boolean match = FALSE; + + pthread_mutex_lock(&apps_std_mt); + QLIST_NEXTSAFE_FOR_ALL(&apps_std_dirlist, pn, pnn) { + dirinfo = STD_RECOVER_REC(struct apps_std_dir_info, qn, pn); + if (dirinfo && dirinfo->handle == dir->handle) { + match = TRUE; + break; + } + } + pthread_mutex_unlock(&apps_std_mt); + + if (match) { + *pDirinfo = dirinfo; + } else { + nErr = ESTALE; + VERIFY_EPRINTF( + "Error 0x%x: %s: stale directory handle 0x%llx passed by DSP\n", nErr, + __func__, dir->handle); + goto bail; + } +bail: + return nErr; +} + +int apps_std_init(void) { + QList_Ctor(&apps_std_qlst); + QList_Ctor(&apps_std_dirlist); + pthread_mutex_init(&apps_std_mt, 0); + pthread_mutex_init(&fdlist.mut, 0); + QList_Ctor(&fdlist.ql); + return AEE_SUCCESS; +} + +void apps_std_deinit(void) { + pthread_mutex_destroy(&apps_std_mt); + pthread_mutex_destroy(&fdlist.mut); +} + +PL_DEFINE(apps_std, apps_std_init, apps_std_deinit); + +static void apps_std_FILE_free(struct apps_std_info *sfree) { + + FARF(RUNTIME_RPC_LOW, "Entering %s", __func__); + pthread_mutex_lock(&apps_std_mt); + QNode_Dequeue(&sfree->qn); + pthread_mutex_unlock(&apps_std_mt); + + FREEIF(sfree); + FARF(RUNTIME_RPC_LOW, "Exiting %s", __func__); + return; +} + +static int apps_std_FILE_alloc(FILE *stream, apps_std_FILE *fd) { + struct apps_std_info *sinfo = 0, *info; + QNode *pn = 0; + apps_std_FILE prevfd = APPS_FD_BASE - 1; + int nErr = AEE_SUCCESS; + + FARF(RUNTIME_RPC_LOW, "Entering %s", __func__); + VERIFYC(0 != (sinfo = calloc(1, sizeof(*sinfo))), ENOMEM); + QNode_CtorZ(&sinfo->qn); + sinfo->type = APPS_STD_STREAM_FILE; + pthread_mutex_lock(&apps_std_mt); + pn = QList_GetFirst(&apps_std_qlst); + if (pn) { + info = STD_RECOVER_REC(struct apps_std_info, qn, pn); + prevfd = info->fd; + QLIST_FOR_REST(&apps_std_qlst, pn) { + info = STD_RECOVER_REC(struct apps_std_info, qn, pn); + if (info->fd != prevfd + 1) { + sinfo->fd = prevfd + 1; + QNode_InsPrev(pn, &sinfo->qn); + break; + } + prevfd = info->fd; + } + } + if (!QNode_IsQueuedZ(&sinfo->qn)) { + sinfo->fd = prevfd + 1; + QList_AppendNode(&apps_std_qlst, &sinfo->qn); + } + pthread_mutex_unlock(&apps_std_mt); + + sinfo->u.stream = stream; + *fd = sinfo->fd; + +bail: + if (nErr) { + FREEIF(sinfo); + VERIFY_EPRINTF("Error 0x%x: apps_std_FILE_alloc failed, errno %s \n", nErr, + strerror(nErr)); + } + FARF(RUNTIME_RPC_LOW, "Exiting %s fd 0x%x err %d", __func__, *fd, nErr); + return nErr; +} + +static int apps_std_FILE_get(apps_std_FILE fd, struct apps_std_info **info) { + struct apps_std_info *sinfo = 0; + QNode *pn, *pnn; + int nErr = EBADF; + + FARF(RUNTIME_RPC_LOW, "Entering %s", __func__); + pthread_mutex_lock(&apps_std_mt); + QLIST_NEXTSAFE_FOR_ALL(&apps_std_qlst, pn, pnn) { + sinfo = STD_RECOVER_REC(struct apps_std_info, qn, pn); + if (sinfo->fd == fd) { + *info = sinfo; + nErr = AEE_SUCCESS; + break; + } + } + pthread_mutex_unlock(&apps_std_mt); + if (nErr) { + VERIFY_EPRINTF( + "Error 0x%x: apps_std_FILE_get failed for fd 0x%x, errno %s \n", nErr, + fd, strerror(nErr)); + } + FARF(RUNTIME_RPC_LOW, "Exiting %s fd 0x%x err %d", __func__, fd, nErr); + return nErr; +} + +static void apps_std_FILE_set_buffer_stream(struct apps_std_info *sinfo, + char *fbuf, int flen, int pos) { + pthread_mutex_lock(&apps_std_mt); + fclose(sinfo->u.stream); + sinfo->type = APPS_STD_STREAM_BUF; + sinfo->u.binfo.fbuf = fbuf; + sinfo->u.binfo.flen = flen; + sinfo->u.binfo.pos = pos; + pthread_mutex_unlock(&apps_std_mt); +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_std_fopen)(const char *name, const char *mode, + apps_std_FILE *psout) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + FILE *stream = NULL; + uint64_t tdiff = 0; + + if (name) { + FASTRPC_ATRACE_BEGIN_L("%s for %s in %s mode", __func__, name, mode); + } + FARF(RUNTIME_RPC_LOW, "Entering %s", __func__); + errno = 0; + VERIFYC(name != NULL, AEE_EBADPARM); + PROFILE(&tdiff, stream = fopen(name, mode);); + if (stream) { + FASTRPC_ATRACE_END_L("%s done, fopen for %s in mode %s done in %" PRIu64 + " us", + __func__, name, mode, tdiff); + return apps_std_FILE_alloc(stream, psout); + } else { + nErr = ERRNO; + } +bail: + if (nErr != AEE_SUCCESS) { + // Ignoring this error, as fopen happens on all ADSP_LIBRARY_PATHs + VERIFY_IPRINTF("Error 0x%x: %s failed for %s (%s)\n", nErr, __func__, name, + strerror(ERRNO)); + } + FARF(RUNTIME_RPC_LOW, "Exiting %s name %s mode %s err %d", __func__, name, + mode, nErr); + FASTRPC_ATRACE_END(); + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_std_fopen_fd)(const char *name, const char *mode, int *fd, + int *len) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct stat statbuf; + void *source = NULL; + int sz = 0, fdfile = 0; + struct mem_io_to_fd *tofd = 0; + int domain = get_current_domain(); + FILE *stream = NULL; + boolean fopen_fail = FALSE, mmap_pass = FALSE; + uint64_t fopen_time = 0, read_time = 0, rpc_alloc_time = 0, mmap_time = 0; + + FASTRPC_ATRACE_BEGIN_L("%s for %s in %s mode", __func__, name, mode); + FARF(RUNTIME_RPC_LOW, "Entering %s", __func__); + errno = 0; + VERIFYC(name != NULL, AEE_EBADPARM); + PROFILE_ALWAYS(&fopen_time, stream = fopen(name, mode);); + if (!stream) { + fopen_fail = TRUE; + nErr = ERRNO; + goto bail; + } + VERIFYC(-1 != (fdfile = fileno(stream)), ERRNO); + VERIFYC(0 == fstat(fdfile, &statbuf), ERRNO); + PROFILE_ALWAYS( + &rpc_alloc_time, + source = rpcmem_alloc_internal(0, RPCMEM_HEAP_DEFAULT, statbuf.st_size);); + VERIFYC(0 != source, AEE_ENORPCMEMORY); + PROFILE_ALWAYS(&read_time, sz = read(fdfile, source, statbuf.st_size);); + if (sz < 0) { + nErr = AEE_EFILE; + goto bail; + } + *fd = rpcmem_to_fd(source); + *len = statbuf.st_size; + PROFILE_ALWAYS(&mmap_time, nErr = fastrpc_mmap(domain, *fd, source, 0, *len, + FASTRPC_MAP_FD)); + VERIFY(AEE_SUCCESS == nErr); + VERIFYC(NULL != (tofd = calloc(1, sizeof(*tofd))), AEE_ENOMEMORY); + QNode_CtorZ(&tofd->qn); + tofd->size = *len; + tofd->fd = *fd; + tofd->fdfile = fdfile; + tofd->stream = stream; + tofd->buf = source; + pthread_mutex_lock(&fdlist.mut); + QList_AppendNode(&fdlist.ql, &tofd->qn); + pthread_mutex_unlock(&fdlist.mut); +bail: + if (nErr != AEE_SUCCESS) { + if (stream) { + fclose(stream); + } + // Ignore fopen error, as fopen happens on all ADSP_LIBRARY_PATHs + if (!fopen_fail) { + FARF(ERROR, "Error 0x%x: %s failed for %s (%s)\n", nErr, __func__, name, + strerror(ERRNO)); + } + if (mmap_pass) { + fastrpc_munmap(domain, *fd, source, *len); + } + FREEIF(tofd); + if (source) { + rpcmem_free_internal(source); + source = NULL; + } + } + FARF(RUNTIME_RPC_LOW, "Exiting %s name %s mode %s err %d", __func__, name, + mode, nErr); + FASTRPC_ATRACE_END_L("%s: done for %s with fopen:%" PRIu64 "us, read:%" PRIu64 + "us, rpc_alloc:%" PRIu64 "us, mmap:%" PRIu64 "us", + __func__, name, fopen_time, read_time, rpc_alloc_time, + mmap_time); + FARF(CRITICAL, + "%s: done for %s with fopen:%" PRIu64 "us, read:%" PRIu64 + "us, rpc_alloc:%" PRIu64 "us, mmap:%" PRIu64 "us", + __func__, name, fopen_time, read_time, rpc_alloc_time, mmap_time); + return nErr; +} +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_std_freopen)(apps_std_FILE sin, const char *name, + const char *mode, + apps_std_FILE *psout) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct apps_std_info *sinfo = 0; + FILE *stream; + + if (name) { + FASTRPC_ATRACE_BEGIN_L("%s for %s (fd 0x%x) in %s mode", __func__, name, + sin, mode); + } + FARF(RUNTIME_RPC_LOW, "Entering %s", __func__); + errno = 0; + VERIFYC(name != NULL, AEE_EBADPARM); + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + VERIFYC(sinfo->type == APPS_STD_STREAM_FILE, EBADF); + stream = freopen(name, mode, sinfo->u.stream); + if (stream) { + FARF(RUNTIME_RPC_HIGH, "freopen success: %s %x\n", name, stream); + return apps_std_FILE_alloc(stream, psout); + } else { + nErr = ERRNO; + } +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF( + "Error 0x%x: freopen for %s mode %s sin %x failed. errno: %s\n", nErr, + name, mode, sin, strerror(nErr)); + } + FARF(RUNTIME_RPC_LOW, "Exiting %s name %s mode %s sin %x err %d", __func__, + name, mode, sin, nErr); + FASTRPC_ATRACE_END(); + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_std_fflush)(apps_std_FILE sin) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct apps_std_info *sinfo = 0; + + FASTRPC_ATRACE_BEGIN_L("%s for file with fd 0x%x", __func__, sin); + FARF(RUNTIME_RPC_LOW, "Entering %s", __func__); + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if (sinfo->type == APPS_STD_STREAM_FILE) { + VERIFYC(0 == fflush(sinfo->u.stream), ERRNO); + } +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error 0x%x: fflush for %x failed. errno: %s\n", nErr, sin, + strerror(nErr)); + } + FARF(RUNTIME_RPC_LOW, "Exiting %s sin %x err %d", __func__, sin, nErr); + FASTRPC_ATRACE_END(); + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_std_fclose)(apps_std_FILE sin) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct apps_std_info *sinfo = 0; + + FASTRPC_ATRACE_BEGIN_L("%s for file with fd 0x%x", __func__, sin); + FARF(RUNTIME_RPC_LOW, "Entering %s", __func__); + errno = 0; + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if (sinfo->type == APPS_STD_STREAM_FILE) { + VERIFYC(0 == fclose(sinfo->u.stream), ERRNO); + } else { + if (sinfo->u.binfo.fbuf) { + rpcmem_free_internal(sinfo->u.binfo.fbuf); + sinfo->u.binfo.fbuf = NULL; + } + } + apps_std_FILE_free(sinfo); +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error 0x%x: freopen for %x failed. errno: %s\n", nErr, sin, + strerror(nErr)); + } + FARF(RUNTIME_RPC_LOW, "Exiting %s sin %x err %d", __func__, sin, nErr); + FASTRPC_ATRACE_END(); + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_std_fclose_fd)(int fd) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + int domain = get_current_domain(); + + FASTRPC_ATRACE_BEGIN_L("%s for file with fd 0x%x", __func__, fd); + FARF(RUNTIME_RPC_LOW, "Entering %s", __func__); + errno = 0; + QNode *pn, *pnn; + struct mem_io_to_fd *freefd = NULL; + pthread_mutex_lock(&fdlist.mut); + QLIST_NEXTSAFE_FOR_ALL(&fdlist.ql, pn, pnn) { + struct mem_io_to_fd *tofd = STD_RECOVER_REC(struct mem_io_to_fd, qn, pn); + if (tofd->fd == fd) { + QNode_DequeueZ(&tofd->qn); + freefd = tofd; + tofd = NULL; + break; + } + } + pthread_mutex_unlock(&fdlist.mut); + if (freefd) { + VERIFY(AEE_SUCCESS == + (nErr = fastrpc_munmap(domain, fd, freefd->buf, freefd->size))); + if (freefd->buf) { + rpcmem_free_internal(freefd->buf); + freefd->buf = NULL; + } + VERIFYC(0 == fclose(freefd->stream), ERRNO); + } +bail: + FREEIF(freefd); + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error 0x%x: %s for %x failed. errno: %s\n", nErr, __func__, + fd, strerror(nErr)); + } + FARF(RUNTIME_RPC_LOW, "Exiting %s fd %x err %d", __func__, fd, nErr); + FASTRPC_ATRACE_END(); + return nErr; +} +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_std_fread)(apps_std_FILE sin, byte *buf, int bufLen, + int *bytesRead, int *bEOF) __QAIC_IMPL_ATTRIBUTE { + int out = 0, nErr = AEE_SUCCESS; + struct apps_std_info *sinfo = 0; + uint64_t tdiff = 0; + + FASTRPC_ATRACE_BEGIN_L("%s requested for %d bytes with fd 0x%x", __func__, + bufLen, sin); + FARF(RUNTIME_RPC_LOW, "Entering %s", __func__); + errno = 0; + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if (sinfo->type == APPS_STD_STREAM_FILE) { + PROFILE(&tdiff, out = fread(buf, 1, bufLen, sinfo->u.stream);); + *bEOF = FALSE; + if (out <= bufLen) { + int err; + if (0 == out && (0 != (err = ferror(sinfo->u.stream)))) { + nErr = ERRNO; + VERIFY_EPRINTF("Error 0x%x: fread returning %d bytes, requested was %d " + "bytes, errno is %x\n", + nErr, out, bufLen, err); + return nErr; + } + *bEOF = feof(sinfo->u.stream); + clearerr(sinfo->u.stream); + } + *bytesRead = out; + } else { + *bytesRead = + std_memscpy(buf, bufLen, sinfo->u.binfo.fbuf + sinfo->u.binfo.pos, + sinfo->u.binfo.flen - sinfo->u.binfo.pos); + sinfo->u.binfo.pos += *bytesRead; + *bEOF = sinfo->u.binfo.pos == sinfo->u.binfo.flen ? TRUE : FALSE; + } + FARF(RUNTIME_RPC_HIGH, "fread returning %d %d\n", out, bufLen); +bail: + FARF(RUNTIME_RPC_LOW, + "Exiting %s returning %d bytes, requested was %d bytes for %x, err 0x%x", + __func__, out, bufLen, sin, nErr); + FASTRPC_ATRACE_END_L("%s done, read %d bytes in %" PRIu64 + " us, requested %d bytes for fd 0x%x, err 0x%x", + __func__, out, tdiff, bufLen, sin, nErr); + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_std_fwrite)(apps_std_FILE sin, const byte *buf, int bufLen, + int *bytesRead, int *bEOF) __QAIC_IMPL_ATTRIBUTE { + int out = 0, nErr = AEE_SUCCESS; + struct apps_std_info *sinfo = 0; + + FASTRPC_ATRACE_BEGIN_L("%s requested for %d bytes with fd 0x%x", __func__, + bufLen, sin); + FARF(RUNTIME_RPC_LOW, "Entering %s", __func__); + errno = 0; + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if (sinfo->type == APPS_STD_STREAM_FILE) { + out = fwrite(buf, 1, bufLen, sinfo->u.stream); + *bEOF = FALSE; + if (out <= bufLen) { + int err; + if (0 == out && (0 != (err = ferror(sinfo->u.stream)))) { + nErr = ERRNO; + VERIFY_EPRINTF("Error 0x%x: fwrite returning %d bytes, requested was " + "%d bytes, errno is %x\n", + nErr, out, bufLen, err); + return nErr; + } + *bEOF = feof(sinfo->u.stream); + clearerr(sinfo->u.stream); + } + *bytesRead = out; + } else { + nErr = AEE_EFILE; + } +bail: + FARF(RUNTIME_RPC_LOW, + "Exiting %s returning %d bytes, requested was %d bytes for %x, err %d", + __func__, out, bufLen, sin, nErr); + FASTRPC_ATRACE_END(); + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_std_fgetpos)(apps_std_FILE sin, byte *pos, int posLen, + int *posLenReq) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + fpos_t fpos; + struct apps_std_info *sinfo = 0; + + FASTRPC_ATRACE_BEGIN_L("%s for file with fd 0x%x with posLen %d", __func__, + sin, posLen); + FARF(RUNTIME_RPC_LOW, "Entering %s", __func__); + errno = 0; + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if (sinfo->type == APPS_STD_STREAM_FILE) { + if (0 == fgetpos(sinfo->u.stream, &fpos)) { + std_memmove(pos, &fpos, STD_MIN((int)sizeof(fpos), posLen)); + *posLenReq = sizeof(fpos); + } else { + nErr = ERRNO; + } + } else { + nErr = EBADF; + } +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error 0x%x: fgetpos failed for %x, errno is %s\n", nErr, + sin, strerror(nErr)); + } + FARF(RUNTIME_RPC_LOW, "Exiting %s for %x, err %d", __func__, sin, nErr); + FASTRPC_ATRACE_END(); + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_std_fsetpos)(apps_std_FILE sin, const byte *pos, + int posLen) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + fpos_t fpos; + struct apps_std_info *sinfo = 0; + + FASTRPC_ATRACE_BEGIN_L("%s for file with fd 0x%x with posLen %d", __func__, + sin, posLen); + FARF(RUNTIME_RPC_LOW, "Entering %s", __func__); + errno = 0; + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if (sinfo->type == APPS_STD_STREAM_FILE) { + if (sizeof(fpos) != posLen) { + nErr = EBADF; + goto bail; + } + std_memmove(&fpos, pos, sizeof(fpos)); + VERIFYC(0 == fsetpos(sinfo->u.stream, &fpos), ERRNO); + } else { + nErr = EBADF; + } +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error 0x%x: fsetpos failed for %x, errno is %s\n", nErr, + sin, strerror(nErr)); + } + FARF(RUNTIME_RPC_LOW, "Exiting %s for %x, err %d", __func__, sin, nErr); + FASTRPC_ATRACE_END(); + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_std_ftell)(apps_std_FILE sin, int *pos) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct apps_std_info *sinfo = 0; + + FASTRPC_ATRACE_BEGIN_L("%s for file with fd 0x%x", __func__, sin); + FARF(RUNTIME_RPC_LOW, "Entering %s", __func__); + errno = 0; + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if (sinfo->type == APPS_STD_STREAM_FILE) { + VERIFYC((*pos = ftell(sinfo->u.stream)) >= 0, ERRNO); + } else { + *pos = sinfo->u.binfo.pos; + } +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error 0x%x: ftell failed for %x, errno is %s\n", nErr, sin, + strerror(nErr)); + } + FARF(RUNTIME_RPC_LOW, "Exiting %s for %x, err %d", __func__, sin, nErr); + FASTRPC_ATRACE_END(); + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_std_fseek)(apps_std_FILE sin, int offset, + apps_std_SEEK whence) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + int op = (int)whence; + struct apps_std_info *sinfo = 0; + uint64_t tdiff = 0; + + FASTRPC_ATRACE_BEGIN_L("%s for file with fd 0x%x for op %d on offset %d", + __func__, sin, whence, offset); + FARF(RUNTIME_RPC_LOW, "Entering %s op %d", __func__, op); + errno = 0; + C_ASSERT(APPS_STD_SEEK_SET == SEEK_SET); + C_ASSERT(APPS_STD_SEEK_CUR == SEEK_CUR); + C_ASSERT(APPS_STD_SEEK_END == SEEK_END); + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if (sinfo->type == APPS_STD_STREAM_FILE) { + PROFILE(&tdiff, + VERIFYC(0 == fseek(sinfo->u.stream, offset, whence), ERRNO);); + } else { + switch (op) { + case APPS_STD_SEEK_SET: + VERIFYC(offset <= sinfo->u.binfo.flen, AEE_EFILE); + sinfo->u.binfo.pos = offset; + break; + case APPS_STD_SEEK_CUR: + VERIFYC(offset + sinfo->u.binfo.pos <= sinfo->u.binfo.flen, AEE_EFILE); + sinfo->u.binfo.pos += offset; + break; + case APPS_STD_SEEK_END: + VERIFYC(offset + sinfo->u.binfo.flen <= sinfo->u.binfo.flen, AEE_EFILE); + sinfo->u.binfo.pos += offset + sinfo->u.binfo.flen; + break; + } + } +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error 0x%x: fseek failed for %x, errno is %s\n", nErr, sin, + strerror(nErr)); + } + FARF(RUNTIME_RPC_LOW, "Exiting %s for %x offset %d, err %d", __func__, sin, + offset, nErr); + FASTRPC_ATRACE_END_L("%s done for fd 0x%x, op %d on offset %d, time %" PRIu64 + " us, err %d", + __func__, sin, whence, offset, tdiff, nErr); + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_std_rewind)(apps_std_FILE sin) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct apps_std_info *sinfo = 0; + + FASTRPC_ATRACE_BEGIN_L("%s for file with fd 0x%x", __func__, sin); + FARF(RUNTIME_RPC_LOW, "Entering %s", __func__); + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if (sinfo->type == APPS_STD_STREAM_FILE) { + rewind(sinfo->u.stream); + } else { + sinfo->u.binfo.pos = 0; + } + if (errno != 0) + nErr = ERRNO; +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error 0x%x: rewind failed for %x, errno is %s\n", nErr, sin, + strerror(nErr)); + } + FARF(RUNTIME_RPC_LOW, "Exiting %s for %x, err %d", __func__, sin, nErr); + FASTRPC_ATRACE_END(); + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_std_feof)(apps_std_FILE sin, int *bEOF) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct apps_std_info *sinfo = 0; + + FASTRPC_ATRACE_BEGIN_L("%s for file with fd 0x%x", __func__, sin); + FARF(RUNTIME_RPC_LOW, "Entering %s", __func__); + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if (sinfo->type == APPS_STD_STREAM_FILE) { + *bEOF = feof(sinfo->u.stream); + clearerr(sinfo->u.stream); + } else { + nErr = EBADF; + } +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error 0x%x: feof failed for %x, errno is %s\n", nErr, sin, + strerror(nErr)); + } + FARF(RUNTIME_RPC_LOW, "Exiting %s for %x, err %d", __func__, sin, nErr); + FASTRPC_ATRACE_END(); + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_ferror)(apps_std_FILE sin, int *err) + __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct apps_std_info *sinfo = 0; + + FASTRPC_ATRACE_BEGIN_L("%s for file with fd 0x%x", __func__, sin); + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if (sinfo->type == APPS_STD_STREAM_FILE) { + *err = ferror(sinfo->u.stream); + } else { + nErr = EBADF; + } +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error 0x%x: ferror failed for %x, errno is %s\n", nErr, sin, + strerror(nErr)); + } + FASTRPC_ATRACE_END(); + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_std_clearerr)(apps_std_FILE sin) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct apps_std_info *sinfo = 0; + + FASTRPC_ATRACE_BEGIN_L("%s for file with fd 0x%x", __func__, sin); + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if (sinfo->type == APPS_STD_STREAM_FILE) { + clearerr(sinfo->u.stream); + } else { + nErr = EBADF; + } +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error 0x%x: clearerr failed for %x, errno is %s\n", nErr, + sin, strerror(nErr)); + } + FASTRPC_ATRACE_END(); + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_std_flen)(apps_std_FILE sin, + uint64 *len) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct apps_std_info *sinfo = 0; + + FASTRPC_ATRACE_BEGIN_L("%s for file with fd 0x%x", __func__, sin); + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if (sinfo->type == APPS_STD_STREAM_FILE) { + struct stat st_buf; + errno = 0; + int fd = fileno(sinfo->u.stream); + C_ASSERT(sizeof(st_buf.st_size) <= sizeof(*len)); + if (fd == -1) { + nErr = ERRNO; + VERIFY_EPRINTF("Error 0x%x: flen failed for %x, errno is %s\n", nErr, sin, + strerror(ERRNO)); + return nErr; + } + errno = 0; + if (0 != fstat(fd, &st_buf)) { + nErr = ERRNO; + VERIFY_EPRINTF("Error 0x%x: flen failed for %x, errno is %s\n", nErr, sin, + strerror(ERRNO)); + return nErr; + } + *len = st_buf.st_size; + } else { + *len = sinfo->u.binfo.flen; + } +bail: + FASTRPC_ATRACE_END(); + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_std_print_string)(const char *str) __QAIC_IMPL_ATTRIBUTE { + printf("%s\n", str); + return AEE_SUCCESS; +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_std_getenv)(const char *name, char *val, int valLen, + int *valLenReq) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + errno = 0; + char *vv = getenv(name); + if (vv) { + *valLenReq = std_strlen(vv) + 1; + std_strlcpy(val, vv, STD_MIN(valLen, *valLenReq)); + return AEE_SUCCESS; + } + nErr = ERRNO; + FARF(RUNTIME_RPC_HIGH, "Error 0x%x: apps_std getenv failed: %s %s\n", nErr, + name, strerror(ERRNO)); + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_std_setenv)(const char *name, const char *val, + int override) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + errno = 0; +#ifdef _WIN32 + return AEE_EUNSUPPORTED; +#else //_WIN32 + if (0 != setenv(name, val, override)) { + nErr = ERRNO; + VERIFY_EPRINTF("Error 0x%x: setenv failed for %s, errno is %s\n", nErr, + name, strerror(ERRNO)); + return nErr; + } + return AEE_SUCCESS; +#endif //_WIN32 +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_std_unsetenv)(const char *name) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + errno = 0; +#ifdef _WIN32 + return AEE_EUNSUPPORTED; +#else //_WIN32 + if (0 != unsetenv(name)) { + nErr = ERRNO; + VERIFY_EPRINTF("Error 0x%x: unsetenv failed for %s, errno is %s\n", nErr, + name, strerror(ERRNO)); + return nErr; + } + return AEE_SUCCESS; +#endif //_WIN32 +} + +#define EMTPY_STR "" +#define ENV_LEN_GUESS 256 + +static int get_dirlist_from_env(const char *envvarname, char **ppDirList) { + char *envList = NULL; + char *envListBuf = NULL; + char *dirList = NULL; + char *dirListBuf = NULL; + char *srcStr = NULL; + int nErr = AEE_SUCCESS; + int envListLen = 0; + int envListPrependLen = 0; + int listLen = 0; + int envLenGuess = STD_MAX(ENV_LEN_GUESS, 1 + std_strlen(DSP_SEARCH_PATH)); + + FARF(RUNTIME_RPC_LOW, "Entering %s", __func__); + VERIFYC(NULL != ppDirList, AEE_ERPC); + + VERIFYC(envListBuf = (char *)malloc(sizeof(char) * envLenGuess), + AEE_ENOMEMORY); + envList = envListBuf; + *envList = '\0'; + if (0 == apps_std_getenv(envvarname, envList, envLenGuess, &envListLen)) { + if (std_strncmp(envvarname, ADSP_LIBRARY_PATH, + std_strlen(ADSP_LIBRARY_PATH)) == 0 || + std_strncmp(envvarname, DSP_LIBRARY_PATH, + std_strlen(DSP_LIBRARY_PATH)) == 0) { + // Calculate total length of env and DSP_SEARCH_PATH + envListPrependLen = envListLen + std_strlen(DSP_SEARCH_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))); + } + // Append default DSP_SEARCH_PATH to user defined env + std_strlcat(envList, DSP_SEARCH_PATH, envListPrependLen); + envListLen = envListPrependLen; + } else if (std_strncmp(envvarname, ADSP_AVS_PATH, + std_strlen(ADSP_AVS_PATH)) == 0) { + envListPrependLen = envListLen + std_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))); + } + std_strlcat(envList, ADSP_AVS_CFG_PATH, envListPrependLen); + envListLen = envListPrependLen; + } else { + envListLen = listLen; + } + } else if (std_strncmp(envvarname, ADSP_LIBRARY_PATH, + std_strlen(ADSP_LIBRARY_PATH)) == 0 || + std_strncmp(envvarname, DSP_LIBRARY_PATH, + std_strlen(DSP_LIBRARY_PATH)) == 0) { + envListLen = listLen = + 1 + std_strlcpy(envListBuf, DSP_SEARCH_PATH, envLenGuess); + } else if (std_strncmp(envvarname, ADSP_AVS_PATH, + std_strlen(ADSP_AVS_PATH)) == 0) { + envListLen = listLen = + 1 + std_strlcpy(envListBuf, ADSP_AVS_CFG_PATH, envLenGuess); + } + + /* + * Allocate mem. to copy envvarname. + */ + if ('\0' != *envList) { + srcStr = envList; + } else { + envListLen = std_strlen(EMTPY_STR) + 1; + } + VERIFYC(dirListBuf = (char *)malloc(sizeof(char) * envListLen), + AEE_ENOMEMORY); + dirList = dirListBuf; + VERIFYC(srcStr != NULL, AEE_EBADPARM); + std_strlcpy(dirList, srcStr, envListLen); + *ppDirList = dirListBuf; +bail: + FREEIF(envListBuf); + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error 0x%x: get dirlist from env failed for %s\n", nErr, + envvarname); + } + FARF(RUNTIME_RPC_LOW, "Exiting %s for %s, err %d", __func__, envvarname, + nErr); + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_fopen_with_env)( + const char *envvarname, const char *delim, const char *name, + const char *mode, apps_std_FILE *psout) __QAIC_IMPL_ATTRIBUTE { + + int nErr = AEE_SUCCESS; + char *dirName = NULL; + char *pos = NULL; + char *dirListBuf = NULL; + char *dirList = NULL; + char *absName = NULL; + const char *envVar = NULL; + uint16 absNameLen = 0; + int domain = get_current_domain() & DOMAIN_ID_MASK; + + FARF(LOW, "Entering %s", __func__); + VERIFYC(NULL != mode, AEE_EBADPARM); + VERIFYC(NULL != delim, AEE_EBADPARM); + VERIFYC(NULL != name, AEE_EBADPARM); + VERIFYC(NULL != envvarname, AEE_EBADPARM); + FASTRPC_ATRACE_BEGIN_L("%s for %s in %s mode from path in environment " + "variable %s delimited with %s", + __func__, name, mode, envvarname, delim); + if (std_strncmp(envvarname, ADSP_LIBRARY_PATH, + std_strlen(ADSP_LIBRARY_PATH)) == 0) { + if (getenv(DSP_LIBRARY_PATH)) { + envVar = DSP_LIBRARY_PATH; + } else { + envVar = ADSP_LIBRARY_PATH; + } + } else { + envVar = envvarname; + } + + VERIFY(0 == (nErr = get_dirlist_from_env(envVar, &dirListBuf))); + VERIFYC(NULL != (dirList = dirListBuf), AEE_EBADPARM); + FARF(RUNTIME_RPC_HIGH, "%s dirList %s", __func__, dirList); + + while (dirList) { + pos = strstr(dirList, delim); + dirName = dirList; + if (pos) { + *pos = '\0'; + dirList = pos + std_strlen(delim); + } else { + dirList = 0; + } + + // Append domain to path + absNameLen = + std_strlen(dirName) + std_strlen(name) + 2 + std_strlen("adsp") + 1; + VERIFYC(NULL != (absName = (char *)malloc(sizeof(char) * absNameLen)), + AEE_ENOMEMORY); + if ('\0' != *dirName) { + std_strlcpy(absName, dirName, absNameLen); + std_strlcat(absName, "/", absNameLen); + std_strlcat(absName, SUBSYSTEM_NAME[domain], absNameLen); + std_strlcat(absName, "/", absNameLen); + std_strlcat(absName, name, absNameLen); + } else { + std_strlcpy(absName, name, absNameLen); + } + + nErr = apps_std_fopen(absName, mode, psout); + if (AEE_SUCCESS == nErr) { + // Success + FARF(ALWAYS, "Successfully opened file %s", absName); + goto bail; + } + FREEIF(absName); + + // fallback: If not found in domain path /vendor/dsp/adsp try in /vendor/dsp + absNameLen = std_strlen(dirName) + std_strlen(name) + 2; + VERIFYC(NULL != (absName = (char *)malloc(sizeof(char) * absNameLen)), + AEE_ENOMEMORY); + if ('\0' != *dirName) { + std_strlcpy(absName, dirName, absNameLen); + std_strlcat(absName, "/", absNameLen); + std_strlcat(absName, name, absNameLen); + } else { + std_strlcpy(absName, name, absNameLen); + } + + nErr = apps_std_fopen(absName, mode, psout); + if (AEE_SUCCESS == nErr) { + // Success + if (name != NULL && + (std_strncmp(name, OEM_CONFIG_FILE_NAME, + std_strlen(OEM_CONFIG_FILE_NAME)) != 0) && + (std_strncmp(name, TESTSIG_FILE_NAME, + std_strlen(TESTSIG_FILE_NAME)) != 0)) + FARF(ALWAYS, "Successfully opened file %s", name); + goto bail; + } + FREEIF(absName); + } +bail: + FREEIF(absName); + FREEIF(dirListBuf); + if (nErr != AEE_SUCCESS) { + if (ERRNO != ENOENT || + (name != NULL && + std_strncmp(name, OEM_CONFIG_FILE_NAME, + std_strlen(OEM_CONFIG_FILE_NAME)) != 0 && + std_strncmp(name, RPC_VERSION_FILE_NAME, + std_strlen(RPC_VERSION_FILE_NAME)) != 0 && + std_strncmp(name, TESTSIG_FILE_NAME, std_strlen(TESTSIG_FILE_NAME)) != + 0)) + VERIFY_WPRINTF(" Warning: %s failed with 0x%x for %s (%s)", __func__, + nErr, name, strerror(ERRNO)); + } + FARF(RUNTIME_RPC_LOW, + "Exiting %s for %s envvarname %s mode %s delim %s, err %d", __func__, + name, envvarname, mode, delim, nErr); + if (name && mode && envvarname && delim) { + FASTRPC_ATRACE_END(); + } + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_fopen_with_env_fd)( + const char *envvarname, const char *delim, const char *name, + const char *mode, int *fd, int *len) __QAIC_IMPL_ATTRIBUTE { + + int nErr = ENOENT, err = ENOENT; + char *dirName = NULL; + char *pos = NULL; + char *dirListBuf = NULL; + char *dirList = NULL; + char *absName = NULL; + char *errabsName = NULL; + const char *envVar = NULL; + uint16 absNameLen = 0; + int domain = get_current_domain() & DOMAIN_ID_MASK; + + FARF(RUNTIME_RPC_LOW, "Entering %s", __func__); + VERIFYC(NULL != mode, AEE_EBADPARM); + VERIFYC(NULL != delim, AEE_EBADPARM); + VERIFYC(NULL != name, AEE_EBADPARM); + VERIFYC(NULL != envvarname, AEE_EBADPARM); +#if 0 //TODO: Bharath + char *tempName = name; + tempName += 2; + if (tempName[0] == '\0') { + nErr = AEE_EBADPARM; + goto bail; + } +#endif + FASTRPC_ATRACE_BEGIN_L("%s for %s in %s mode from path in environment " + "variable %s delimited with %s", + __func__, name, mode, envvarname, delim); + if (std_strncmp(envvarname, ADSP_LIBRARY_PATH, + std_strlen(ADSP_LIBRARY_PATH)) == 0) { + if (getenv(DSP_LIBRARY_PATH)) { + envVar = DSP_LIBRARY_PATH; + } else { + envVar = ADSP_LIBRARY_PATH; + } + } else { + envVar = envvarname; + } + + VERIFY(0 == (nErr = get_dirlist_from_env(envVar, &dirListBuf))); + VERIFYC(NULL != (dirList = dirListBuf), AEE_EBADPARM); + + while (dirList) { + pos = strstr(dirList, delim); + dirName = dirList; + if (pos) { + *pos = '\0'; + dirList = pos + std_strlen(delim); + } else { + dirList = 0; + } + + // Append domain to path + absNameLen = + std_strlen(dirName) + std_strlen(name) + 2 + std_strlen("adsp") + 1; + VERIFYC(NULL != (absName = (char *)malloc(sizeof(char) * absNameLen)), + AEE_ENOMEMORY); + if ('\0' != *dirName) { + std_strlcpy(absName, dirName, absNameLen); + std_strlcat(absName, "/", absNameLen); + std_strlcat(absName, SUBSYSTEM_NAME[domain], absNameLen); + std_strlcat(absName, "/", absNameLen); + std_strlcat(absName, name, absNameLen); + } else { + std_strlcpy(absName, name, absNameLen); + } + + err = apps_std_fopen_fd(absName, mode, fd, len); + if (AEE_SUCCESS == err) { + // Success + FARF(ALWAYS, "Successfully opened file %s", absName); + goto bail; + } + /* Do not Update nErr if error is no such file, as it may not be + * genuine error until we find in all path's. + */ + if (err != ENOENT && (nErr == ENOENT || nErr == AEE_SUCCESS)) { + nErr = err; + errabsName = absName; + absName = NULL; + } + FREEIF(absName); + + // fallback: If not found in domain path /vendor/dsp/adsp try in /vendor/dsp + absNameLen = std_strlen(dirName) + std_strlen(name) + 2; + VERIFYC(NULL != (absName = (char *)malloc(sizeof(char) * absNameLen)), + AEE_ENOMEMORY); + if ('\0' != *dirName) { + std_strlcpy(absName, dirName, absNameLen); + std_strlcat(absName, "/", absNameLen); + std_strlcat(absName, name, absNameLen); + } else { + std_strlcpy(absName, name, absNameLen); + } + + err = apps_std_fopen_fd(absName, mode, fd, len); + if (AEE_SUCCESS == err) { + // Success + FARF(ALWAYS, "Successfully opened file %s", absName); + nErr = err; + goto bail; + } + /* Do not Update nErr if error is no such file, as it may not be + * genuine error until we find in all path's. + */ + if (err != ENOENT && (nErr == ENOENT || nErr == AEE_SUCCESS)) { + nErr = err; + errabsName = absName; + absName = NULL; + } + FREEIF(absName); + } + /* In case if file is not present in any path update + * error code to no such file. + */ + if (err == ENOENT && (nErr == ENOENT || nErr == AEE_SUCCESS)) + nErr = err; +bail: + if (nErr != AEE_SUCCESS) { + if (ERRNO != ENOENT || + (name != NULL && + std_strncmp(name, OEM_CONFIG_FILE_NAME, + std_strlen(OEM_CONFIG_FILE_NAME)) != 0 && + std_strncmp(name, RPC_VERSION_FILE_NAME, + std_strlen(RPC_VERSION_FILE_NAME)) != 0 && + std_strncmp(name, TESTSIG_FILE_NAME, std_strlen(TESTSIG_FILE_NAME)) != + 0)) { + if (errabsName) { + VERIFY_WPRINTF(" Warning: %s failed with 0x%x for path %s name %s (%s)", + __func__, nErr, errabsName, name, strerror(ERRNO)); + } else { + VERIFY_WPRINTF(" Warning: %s failed with 0x%x for %s (%s)", __func__, + nErr, name, strerror(ERRNO)); + } + } + } + + FREEIF(errabsName); + FREEIF(absName); + FREEIF(dirListBuf); + FARF(RUNTIME_RPC_LOW, + "Exiting %s for %s envvarname %s mode %s delim %s, err %d", __func__, + name, envvarname, mode, delim, nErr); + if (name && mode && envvarname && delim) { + FASTRPC_ATRACE_END(); + } + return nErr; +} + +__QAIC_HEADER_EXPORT int __QAIC_IMPL(apps_std_get_search_paths_with_env)( + const char *envvarname, const char *delim, _cstring1_t *paths, int pathsLen, + uint32 *numPaths, uint16 *maxPathLen) __QAIC_IMPL_ATTRIBUTE { + + char *path = NULL; + char *pathDomain = NULL; + int pathDomainLen = 0; + int nErr = AEE_SUCCESS; + char *dirListBuf = NULL; + int i = 0; + char *saveptr = NULL; + const char *envVar = NULL; + struct stat st; + int domain = get_current_domain() & DOMAIN_ID_MASK; + + FARF(RUNTIME_RPC_LOW, "Entering %s", __func__); + VERIFYC(NULL != numPaths, AEE_EBADPARM); + VERIFYC(NULL != delim, AEE_EBADPARM); + VERIFYC(NULL != maxPathLen, AEE_EBADPARM); + + if (std_strncmp(envvarname, ADSP_LIBRARY_PATH, + std_strlen(ADSP_LIBRARY_PATH)) == 0) { + if (getenv(DSP_LIBRARY_PATH)) { + envVar = DSP_LIBRARY_PATH; + } else { + envVar = ADSP_LIBRARY_PATH; + } + } else { + envVar = envvarname; + } + + VERIFY(AEE_SUCCESS == (nErr = get_dirlist_from_env(envVar, &dirListBuf))); + + *numPaths = 0; + *maxPathLen = 0; + + // Get the number of folders + path = strtok_r(dirListBuf, delim, &saveptr); + while (path != NULL) { + pathDomainLen = std_strlen(path) + 1 + std_strlen("adsp") + 1; + VERIFYC(pathDomain = (char *)malloc(sizeof(char) * (pathDomainLen)), + AEE_ENOMEMORY); + std_strlcpy(pathDomain, path, pathDomainLen); + std_strlcat(pathDomain, "/", pathDomainLen); + std_strlcat(pathDomain, SUBSYSTEM_NAME[domain], pathDomainLen); + // If the path exists, add it to the return + if ((stat(pathDomain, &st) == 0) && (S_ISDIR(st.st_mode))) { + *maxPathLen = STD_MAX(*maxPathLen, std_strlen(pathDomain) + 1); + if (paths && i < pathsLen && paths[i].data && + paths[i].dataLen >= (int)std_strlen(path)) { + std_strlcpy(paths[i].data, pathDomain, paths[i].dataLen); + } + i++; + } + if ((stat(path, &st) == 0) && (S_ISDIR(st.st_mode))) { + *maxPathLen = STD_MAX(*maxPathLen, std_strlen(path) + 1); + if (paths && i < pathsLen && paths[i].data && + paths[i].dataLen >= (int)std_strlen(path)) { + std_strlcpy(paths[i].data, path, paths[i].dataLen); + } + i++; + } + path = strtok_r(NULL, delim, &saveptr); + FREEIF(pathDomain); + } + *numPaths = i; + +bail: + FREEIF(dirListBuf); + FREEIF(pathDomain); + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error 0x%x: apps_std_get_search_paths_with_env failed\n", + nErr); + } + FARF(RUNTIME_RPC_LOW, "Exiting %s for envvarname %s delim %s, err %d", + __func__, envvarname, delim, nErr); + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_std_fgets)(apps_std_FILE sin, byte *buf, int bufLen, + int *bEOF) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct apps_std_info *sinfo = 0; + + FASTRPC_ATRACE_BEGIN_L("%s for file with fd 0x%x for buflen %d", __func__, + sin, bufLen); + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if (sinfo->type == APPS_STD_STREAM_FILE) { + char *out = fgets((char *)buf, bufLen, sinfo->u.stream); + *bEOF = FALSE; + if (!out) { + int err = 0; + if (0 != (err = ferror(sinfo->u.stream))) { + nErr = ERRNO; + VERIFY_EPRINTF("Error 0x%x: fgets failed for %x, errno is %s\n", nErr, + sin, strerror(ERRNO)); + goto bail; + } + *bEOF = feof(sinfo->u.stream); + } + } else { + nErr = EBADF; + } +bail: + FASTRPC_ATRACE_END(); + return nErr; +} + +__QAIC_HEADER_EXPORT int +__QAIC_HEADER(apps_std_fileExists)(const char *path, + boolean *exists) __QAIC_HEADER_ATTRIBUTE { + int nErr = AEE_SUCCESS, err = 0; + struct stat buffer; + + VERIFYC(path != NULL, AEE_EBADPARM); + VERIFYC(exists != NULL, AEE_EBADPARM); + + errno = 0; + *exists = (stat(path, &buffer) == 0); + err = errno; +bail: + if (nErr != AEE_SUCCESS || err) { + FARF(RUNTIME_RPC_HIGH, + "Warniing 0x%x: fileExists failed for path %s, errno is %s\n", nErr, + path, strerror(err)); + } + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_std_fsync)(apps_std_FILE sin) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct apps_std_info *sinfo = 0; + + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if (sinfo->type == APPS_STD_STREAM_FILE) { + // This flushes the given sin file stream to user-space buffer. + // NOTE: this does NOT ensure data is physically sotred on disk + nErr = fflush(sinfo->u.stream); + if (nErr != AEE_SUCCESS) { + nErr = ERRNO; + VERIFY_EPRINTF("Error 0x%x: apps_std fsync failed,errno is %s\n", nErr, + strerror(ERRNO)); + } + } else { + nErr = EBADF; + } + +bail: + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_std_fremove)(const char *name) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + + if (NULL == name) { + return EINVAL; + } + FASTRPC_ATRACE_BEGIN_L("%s for file %s", __func__, name); + nErr = remove(name); + if (nErr != AEE_SUCCESS) { + nErr = ERRNO; + VERIFY_EPRINTF("Error 0x%x: failed to remove file %s,errno is %s\n", nErr, + name, strerror(ERRNO)); + } + FASTRPC_ATRACE_END(); + return nErr; +} + +static int decrypt_int(char *fbuf, int size) { + int nErr = 0, fd; + void *handle = 0; + int32_t (*l_init)(void); + int32_t (*l_deinit)(void); + int32_t (*l_decrypt)(int32_t, int32_t); + + VERIFYC(NULL != (handle = dlopen("liblmclient.so", RTLD_NOW)), + AEE_EINVHANDLE); + VERIFYM(NULL != (l_init = dlsym(handle, "license_manager_init")), AEE_ERPC, + "Error: %s failed symbol license_manager_init not found err 0x%x " + "errno is %s", + __func__, nErr, strerror(ERRNO)); + VERIFYM(NULL != (l_deinit = dlsym(handle, "license_manager_deinit")), + AEE_ERPC, + "Error: %s failed symbol license_manager_deinit not found err 0x%x " + "errno is %s", + __func__, nErr, strerror(ERRNO)); + VERIFYM(NULL != (l_decrypt = dlsym(handle, "license_manager_decrypt")), + AEE_ERPC, + "Error: %s failed symbol license_manager_decrypt not found err 0x%x " + "errno is %s", + __func__, nErr, strerror(ERRNO)); + VERIFY(0 == (nErr = l_init())); + VERIFYC(-1 != (fd = rpcmem_to_fd_internal(fbuf)), AEE_ERPC); + VERIFY(0 == (nErr = l_decrypt(fd, size))); + VERIFY(0 == (nErr = l_deinit())); +bail: + if (nErr) { + VERIFY_EPRINTF("Error 0x%x: dlopen for licmgr failed. errno: %s\n", nErr, + dlerror()); + } + if (handle) { + dlclose(handle); + } + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_fdopen_decrypt)( + apps_std_FILE sin, apps_std_FILE *psout) __QAIC_IMPL_ATTRIBUTE { + int fd, nErr = AEE_SUCCESS; + struct stat st_buf; + struct apps_std_info *sinfo = 0; + int sz, pos; + char *fbuf = 0; + + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + if (sinfo->type == APPS_STD_STREAM_FILE) { + pos = ftell(sinfo->u.stream); + VERIFYM(-1 != (fd = fileno(sinfo->u.stream)), AEE_EFILE, + "Error: %s failed file len is not proper err 0x%x errno is %s", + __func__, nErr, strerror(ERRNO)); + VERIFYM(0 == fstat(fd, &st_buf), AEE_EFILE, + "Error: %s failed file len is not proper err 0x%x errno is %s", + __func__, nErr, strerror(ERRNO)); + sz = (int)st_buf.st_size; + VERIFYC( + 0 != (fbuf = rpcmem_alloc_internal(ION_HEAP_ID_QSEECOM, 1, (size_t)sz)), + AEE_ENORPCMEMORY); + VERIFYM(0 == fseek(sinfo->u.stream, 0, SEEK_SET), AEE_EFILE, + "Error: %s failed as fseek failed err 0x%x errno is %s", __func__, + nErr, strerror(ERRNO)); + VERIFYM(sz == (int)fread(fbuf, 1, sz, sinfo->u.stream), AEE_EFILE, + "Error: %s failed as fread failed err 0x%x errno is %s", __func__, + nErr, strerror(ERRNO)); + VERIFY(0 == (nErr = decrypt_int(fbuf, sz))); + apps_std_FILE_set_buffer_stream(sinfo, fbuf, sz, pos); + *psout = sin; + } else { + nErr = EBADF; + } +bail: + if (nErr) { + if (fbuf) { + rpcmem_free_internal(fbuf); + fbuf = NULL; + } + } + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_HEADER(apps_std_opendir)(const char *name, + apps_std_DIR *dir) __QAIC_IMPL_ATTRIBUTE { + int nErr = 0; + DIR *odir; + struct apps_std_dir_info *dirinfo = 0; + + if (NULL == dir) { + return EINVAL; + } + if (name == NULL) + return AEE_EBADPARM; + errno = 0; + odir = opendir(name); + if (odir != NULL) { + dir->handle = (uint64)odir; + dirinfo = + (struct apps_std_dir_info *)calloc(1, sizeof(struct apps_std_dir_info)); + VERIFYC(dirinfo != NULL, ENOMEM); + dirinfo->handle = dir->handle; + pthread_mutex_lock(&apps_std_mt); + QList_AppendNode(&apps_std_dirlist, &dirinfo->qn); + pthread_mutex_unlock(&apps_std_mt); + } else { + nErr = ERRNO; + } +bail: + if (nErr) { + VERIFY_EPRINTF("Error 0x%x: failed to opendir %s,errno is %s\n", nErr, name, + strerror(ERRNO)); + } + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_HEADER(apps_std_closedir)(const apps_std_DIR *dir) + __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct apps_std_dir_info *dirinfo = 0; + + if ((NULL == dir) || (0 == dir->handle)) { + return EINVAL; + } + + errno = 0; + VERIFY(AEE_SUCCESS == (nErr = apps_std_get_dirinfo(dir, &dirinfo))); + + nErr = closedir((DIR *)dir->handle); + if (nErr != AEE_SUCCESS) { + nErr = ERRNO; + goto bail; + } else { + pthread_mutex_lock(&apps_std_mt); + QNode_Dequeue(&dirinfo->qn); + pthread_mutex_unlock(&apps_std_mt); + free(dirinfo); + dirinfo = NULL; + } +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error 0x%x: failed to closedir, errno is %s\n", nErr, + strerror(ERRNO)); + } + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_HEADER(apps_std_readdir)(const apps_std_DIR *dir, + apps_std_DIRENT *dirent, + int *bEOF) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + struct apps_std_dir_info *dirinfo = 0; + struct dirent *odirent; + + if ((NULL == dir) || (0 == dir->handle)) { + return EINVAL; + } + + errno = 0; + VERIFY(AEE_SUCCESS == (nErr = apps_std_get_dirinfo(dir, &dirinfo))); + *bEOF = 0; + odirent = readdir((DIR *)dir->handle); + if (odirent != NULL) { + dirent->ino = (int)odirent->d_ino; + std_strlcpy(dirent->name, odirent->d_name, sizeof(dirent->name)); + } else { + if (errno == 0) { + *bEOF = 1; + } else { + nErr = ERRNO; + goto bail; + } + } +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error 0x%x: failed to readdir,errno is %s\n", nErr, + strerror(ERRNO)); + } + return nErr; +} + +__QAIC_IMPL_EXPORT int __QAIC_HEADER(apps_std_mkdir)(const char *name, int mode) + __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + + if (NULL == name) { + return EINVAL; + } + errno = 0; + nErr = mkdir(name, mode); + if (nErr != AEE_SUCCESS) { + nErr = ERRNO; + VERIFY_EPRINTF("Error 0x%x: failed to mkdir %s,errno is %s\n", nErr, name, + strerror(ERRNO)); + } + + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_HEADER(apps_std_rmdir)(const char *name) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + + if (NULL == name) { + return EINVAL; + } + errno = 0; + nErr = rmdir(name); + if (nErr != AEE_SUCCESS) { + nErr = ERRNO; + VERIFY_EPRINTF("Error 0x%x: failed to rmdir %s,errno is %s\n", nErr, name, + strerror(ERRNO)); + } + + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_HEADER(apps_std_stat)(const char *name, + apps_std_STAT *ist) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS, nOpenErr = AEE_SUCCESS, fd = -1; + apps_std_FILE ps; + struct apps_std_info *sinfo = 0; + struct stat st; + + if ((NULL == name) || (NULL == ist)) { + return EINVAL; + } + FASTRPC_ATRACE_BEGIN_L("%s for file %s", __func__, name); + errno = 0; + VERIFYM(0 == (nOpenErr = apps_std_fopen_with_env(ADSP_LIBRARY_PATH, ";", name, + "r", &ps)), + AEE_EFILE, "Error: %s failed as fopen failed err 0x%x", __func__, + nErr); + VERIFY(0 == (nErr = apps_std_FILE_get(ps, &sinfo))); + VERIFYC(-1 != (fd = fileno(sinfo->u.stream)), ERRNO); + VERIFYC(0 == fstat(fd, &st), ERRNO); + ist->dev = st.st_dev; + ist->ino = st.st_ino; + ist->mode = st.st_mode; + ist->nlink = st.st_nlink; + ist->rdev = st.st_rdev; + ist->size = st.st_size; + ist->atime = (int64)st.st_atim.tv_sec; + ist->atimensec = (int64)st.st_atim.tv_nsec; + ist->mtime = (int64)st.st_mtim.tv_sec; + ist->mtimensec = (int64)st.st_mtim.tv_nsec; + ist->ctime = (int64)st.st_ctim.tv_nsec; + ist->ctimensec = (int64)st.st_ctim.tv_nsec; +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF( + "Error 0x%x: %s: failed to stat %s, file open returned 0x%x (%s)\n", + nErr, __func__, name, nOpenErr, strerror(ERRNO)); + nErr = ERRNO; + } + if (nOpenErr == AEE_SUCCESS) { + apps_std_fclose(ps); + sinfo = 0; + } + if (sinfo) { + apps_std_FILE_free(sinfo); + } + FASTRPC_ATRACE_END(); + return nErr; +} + +__QAIC_HEADER_EXPORT int +__QAIC_HEADER(apps_std_ftrunc)(apps_std_FILE sin, + int offset) __QAIC_HEADER_ATTRIBUTE { + int nErr = 0, fd = -1; + struct apps_std_info *sinfo = 0; + + FASTRPC_ATRACE_BEGIN_L("%s for file with fd 0x%x for length %d", __func__, + sin, offset); + VERIFY(0 == (nErr = apps_std_FILE_get(sin, &sinfo))); + errno = 0; + VERIFYC(-1 != (fd = fileno(sinfo->u.stream)), ERRNO); + + VERIFYC(0 == ftruncate(fd, offset), ERRNO); +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error 0x%x: failed to ftrunc file, errno is %s\n", nErr, + strerror(ERRNO)); + } + FASTRPC_ATRACE_END(); + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_std_frename)(const char *oldname, + const char *newname) __QAIC_IMPL_ATTRIBUTE { + int nErr = AEE_SUCCESS; + + if (NULL == oldname || NULL == newname) + return EINVAL; + FASTRPC_ATRACE_BEGIN_L("%s for file with oldname %s to new name %s", __func__, + oldname, newname); + nErr = rename(oldname, newname); + if (nErr != AEE_SUCCESS) { + nErr = ERRNO; + VERIFY_EPRINTF("Error 0x%x: failed to rename file, errno is %s\n", nErr, + strerror(ERRNO)); + } + FASTRPC_ATRACE_END(); + return nErr; +} diff --git a/src/apps_std_skel.c b/src/apps_std_skel.c new file mode 100644 index 0000000..f82d1fb --- /dev/null +++ b/src/apps_std_skel.c @@ -0,0 +1,1453 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _APPS_STD_SKEL_H +#define _APPS_STD_SKEL_H +#include "apps_std.h" + +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#include + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef _ATTRIBUTE_VISIBILITY + +#ifdef _WIN32 +#define _ATTRIBUTE_VISIBILITY +#else +#define _ATTRIBUTE_VISIBILITY __attribute__ ((visibility("default"))) +#endif + +#endif // _ATTRIBUTE_VISIBILITY + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i = 0; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#endif + + +#endif // _QAIC_ENV_H + +#include +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include +#include + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc((size_t)size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + (size_t)size) < (uintptr_t)me->stack + (size_t)me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _APPS_STD_SLIM_H +#define _APPS_STD_SLIM_H +#include + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Type types[8]; +static const Type* const typeArrays[15] = {&(types[2]),&(types[2]),&(types[2]),&(types[6]),&(types[6]),&(types[2]),&(types[2]),&(types[7]),&(types[7]),&(types[7]),&(types[7]),&(types[7]),&(types[7]),&(types[3]),&(types[4])}; +static const StructType structTypes[3] = {{0x1,&(typeArrays[0]),0x8,0x0,0x8,0x8,0x1,0x8},{0x2,&(typeArrays[13]),0x104,0x0,0x104,0x4,0x1,0x4},{0xd,&(typeArrays[0]),0x60,0x0,0x60,0x8,0x1,0x8}}; +static const SequenceType sequenceTypes[1] = {{&(types[1]),0x0,0x4,0x4,0x0}}; +static const Type types[8] = {{0x1,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x1},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)0x0,0}}, 4,SLIM_IFPTR32(0x4,0x8)},{0x8,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x8},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4},{0xff,{{(const uintptr_t)&(types[5]),(const uintptr_t)0xff}}, 8,0x1},{0x1,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x1},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4},{0x8,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x8}}; +static const Parameter parameters[18] = {{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)0x0,0}}, 4,SLIM_IFPTR32(0x4,0x8),0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[0]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8),3,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[0]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8),0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{0x4,{{0,0}}, 3,0x4,0,0},{0x8,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x8,3,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)0x0,0}}, 4,SLIM_IFPTR32(0x4,0x8),3,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(sequenceTypes[0]),0}}, 25,SLIM_IFPTR32(0x4,0x8),3,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0},{0x2,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x2,3,0},{0x1,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x1,3,0},{0x8,{{(const uintptr_t)&(structTypes[0]),0}}, 6,0x8,3,0},{0x8,{{(const uintptr_t)&(structTypes[0]),0}}, 6,0x8,0,0},{0x104,{{(const uintptr_t)&(structTypes[1]),0}}, 6,0x4,3,0},{0x60,{{(const uintptr_t)&(structTypes[2]),0}}, 6,0x8,3,0}}; +static const Parameter* const parameterArrays[52] = {(&(parameters[0])),(&(parameters[0])),(&(parameters[0])),(&(parameters[0])),(&(parameters[4])),(&(parameters[4])),(&(parameters[0])),(&(parameters[0])),(&(parameters[10])),(&(parameters[11])),(&(parameters[12])),(&(parameters[0])),(&(parameters[0])),(&(parameters[0])),(&(parameters[0])),(&(parameters[1])),(&(parameters[2])),(&(parameters[5])),(&(parameters[4])),(&(parameters[4])),(&(parameters[2])),(&(parameters[3])),(&(parameters[4])),(&(parameters[4])),(&(parameters[2])),(&(parameters[0])),(&(parameters[0])),(&(parameters[1])),(&(parameters[15])),(&(parameters[16])),(&(parameters[4])),(&(parameters[0])),(&(parameters[0])),(&(parameters[6])),(&(parameters[0])),(&(parameters[9])),(&(parameters[4])),(&(parameters[2])),(&(parameters[6])),(&(parameters[7])),(&(parameters[0])),(&(parameters[17])),(&(parameters[0])),(&(parameters[14])),(&(parameters[2])),(&(parameters[1])),(&(parameters[0])),(&(parameters[13])),(&(parameters[2])),(&(parameters[8])),(&(parameters[2])),(&(parameters[4]))}; +static const Method methods[27] = {{REMOTE_SCALARS_MAKEX(0,0,0x3,0x1,0x0,0x0),0x8,0x4,3,3,(&(parameterArrays[13])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x3,0x1,0x0,0x0),0xc,0x4,4,4,(&(parameterArrays[24])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0x4,0x0,1,1,(&(parameterArrays[16])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x2,0x0,0x0),0x8,0x8,6,4,(&(parameterArrays[20])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x2,0x1,0x0,0x0),0x8,0x8,5,4,(&(parameterArrays[16])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x2,0x0,0x0),0x8,0x4,5,3,(&(parameterArrays[20])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x2,0x0,0x0,0x0),0x8,0x0,3,2,(&(parameterArrays[16])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x1,0x0,0x0),0x4,0x4,2,2,(&(parameterArrays[50])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0xc,0x0,3,3,(&(parameterArrays[37])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x1,0x0,0x0),0x4,0x8,2,2,(&(parameterArrays[48])),0x4,0x8},{REMOTE_SCALARS_MAKEX(0,0,0x2,0x0,0x0,0x0),0x4,0x0,1,1,(&(parameterArrays[0])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x2,0x2,0x0,0x0),0x8,0x4,5,3,(&(parameterArrays[34])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x3,0x0,0x0,0x0),0xc,0x0,3,3,(&(parameterArrays[31])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x5,0x1,0x0,0x0),0x10,0x4,5,5,(&(parameterArrays[11])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,255,255,15,15),0xc,0x6,7,5,(&(parameterArrays[6])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x2,0x1,0x0,0x0),0x4,0x1,2,2,(&(parameterArrays[46])),0x4,0x1},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x1,0x0,0x0),0x4,0x4,2,2,(&(parameterArrays[44])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x2,0x1,0x0,0x0),0x4,0x8,2,2,(&(parameterArrays[42])),0x4,0x8},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0x8,0x0,1,1,(&(parameterArrays[28])),0x8,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x1,0x0,0x0),0x8,0x108,3,3,(&(parameterArrays[28])),0x8,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x2,0x0,0x0,0x0),0x8,0x0,2,2,(&(parameterArrays[32])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x2,0x1,0x0,0x0),0x4,0x60,2,2,(&(parameterArrays[40])),0x4,0x8},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0x8,0x0,2,2,(&(parameterArrays[37])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x3,0x0,0x0,0x0),0x8,0x0,2,2,(&(parameterArrays[0])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x3,0x1,0x0,0x0),0x8,0x8,4,4,(&(parameterArrays[2])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0x4,0x0,1,1,(&(parameterArrays[33])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x5,0x1,0x0,0x0),0x10,0x8,6,6,(&(parameterArrays[0])),0x4,0x4}}; +static const Method* const methodArrays[37] = {&(methods[0]),&(methods[1]),&(methods[2]),&(methods[2]),&(methods[3]),&(methods[4]),&(methods[5]),&(methods[6]),&(methods[7]),&(methods[8]),&(methods[9]),&(methods[2]),&(methods[7]),&(methods[7]),&(methods[2]),&(methods[10]),&(methods[11]),&(methods[12]),&(methods[10]),&(methods[13]),&(methods[5]),&(methods[14]),&(methods[15]),&(methods[2]),&(methods[10]),&(methods[16]),&(methods[17]),&(methods[18]),&(methods[19]),&(methods[20]),&(methods[10]),&(methods[21]),&(methods[22]),&(methods[23]),&(methods[24]),&(methods[25]),&(methods[26])}; +static const char strings[568] = "get_search_paths_with_env\0fopen_with_env_fd\0fdopen_decrypt\0fopen_with_env\0print_string\0bytesWritten\0fileExists\0maxPathLen\0envvarname\0fclose_fd\0ctimensec\0mtimensec\0atimensec\0valLenReq\0posLenReq\0bytesRead\0fopen_fd\0closedir\0numPaths\0unsetenv\0override\0clearerr\0newname\0oldname\0frename\0readdir\0opendir\0fremove\0fsetpos\0fgetpos\0freopen\0ftrunc\0dirent\0handle\0exists\0getenv\0ferror\0rewind\0whence\0offset\0fwrite\0fclose\0fflush\0ctime\0mtime\0atime\0nlink\0rmdir\0mkdir\0fsync\0paths\0fgets\0delim\0fseek\0ftell\0fread\0psout\0fopen\0size\0rdev\0stat\0path\0feof\0flen\0bEOF\0mode\0tsz\0ino\0val\0str\0buf\0sin\0"; +static const uint16_t methodStrings[143] = {513,128,513,543,509,547,538,431,508,503,425,163,419,153,413,143,26,122,467,128,538,41,529,281,217,343,336,547,128,533,0,122,467,455,221,111,59,122,467,128,538,491,203,128,538,41,529,392,563,559,87,533,485,563,559,193,533,321,563,128,538,491,289,128,217,343,461,563,559,533,232,128,551,239,357,128,551,173,473,563,385,378,313,563,309,183,497,128,538,491,273,265,257,329,563,385,443,128,538,212,217,343,44,563,491,100,518,350,364,563,253,523,563,533,528,563,529,479,563,309,305,563,309,133,41,437,128,297,128,449,563,230,128,74,555,248,563,371,563,399,563,406,563}; +static const uint16_t methodStringsArrays[37] = {86,57,141,139,52,47,82,120,117,78,114,137,111,108,135,133,74,70,131,36,66,30,105,129,127,102,62,99,23,96,125,0,93,90,42,123,16}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(apps_std_slim) = {37,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_APPS_STD_SLIM_H +extern int adsp_mmap_fd_getinfo(int, uint32_t *); +#ifdef __cplusplus +extern "C" { +#endif +_ATTRIBUTE_VISIBILITY uint32_t apps_std_skel_invoke_qaic_version = 10042; +static __inline int _skel_method(int (*_pfn)(const char*, const char*, const char*, const char*, int*, int*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + uint32_t _in0[1] = {0}; + char* _in1[1] = {0}; + uint32_t _in1Len[1] = {0}; + char* _in2[1] = {0}; + uint32_t _in2Len[1] = {0}; + char* _in3[1] = {0}; + uint32_t _in3Len[1] = {0}; + char* _in4[1] = {0}; + uint32_t _in4Len[1] = {0}; + uint32_t _rout5[1] = {0}; + uint32_t _rout6[1] = {0}; + uint32_t* _primIn= 0; + int _numIn[1] = {0}; + uint32_t* _primROut= 0; + remote_arg* _praIn = 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==5); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((5 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 20); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 8); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_in1Len, 0, _primIn, 4, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, ((_praIn[0].buf.nLen / 1)) >= (size_t)(_in1Len[0])); + _in1[0] = _praIn[0].buf.pv; + _ASSERT(_nErr, (_in1Len[0] > 0) && (_in1[0][(_in1Len[0] - 1)] == 0)); + _COPY(_in2Len, 0, _primIn, 8, 4); + _ASSERT(_nErr, ((_praIn[1].buf.nLen / 1)) >= (size_t)(_in2Len[0])); + _in2[0] = _praIn[1].buf.pv; + _ASSERT(_nErr, (_in2Len[0] > 0) && (_in2[0][(_in2Len[0] - 1)] == 0)); + _COPY(_in3Len, 0, _primIn, 12, 4); + _ASSERT(_nErr, ((_praIn[2].buf.nLen / 1)) >= (size_t)(_in3Len[0])); + _in3[0] = _praIn[2].buf.pv; + _ASSERT(_nErr, (_in3Len[0] > 0) && (_in3[0][(_in3Len[0] - 1)] == 0)); + _COPY(_in4Len, 0, _primIn, 16, 4); + _ASSERT(_nErr, ((_praIn[3].buf.nLen / 1)) >= (size_t)(_in4Len[0])); + _in4[0] = _praIn[3].buf.pv; + _ASSERT(_nErr, (_in4Len[0] > 0) && (_in4[0][(_in4Len[0] - 1)] == 0)); + _TRY(_nErr, _pfn((const char*)*_in1, (const char*)*_in2, (const char*)*_in3, (const char*)*_in4, (int*)_rout5, (int*)_rout6)); + _COPY(_primROut, 0, _rout5, 0, 4); + _COPY(_primROut, 4, _rout6, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_1(int (*_pfn)(int), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + uint32_t _in0[1] = {0}; + uint32_t _in1[1] = {0}; + uint32_t* _primIn= 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((1 + 0) + (((0 + 0) + 0) + 0))) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_in1, 0, _primIn, 4, 4); + _TRY(_nErr, _pfn((int)*_in1)); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_2(int (*_pfn)(const char*, const char*, int*, int*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + uint32_t _in0[1] = {0}; + char* _in1[1] = {0}; + uint32_t _in1Len[1] = {0}; + char* _in2[1] = {0}; + uint32_t _in2Len[1] = {0}; + uint32_t _rout3[1] = {0}; + uint32_t _rout4[1] = {0}; + uint32_t* _primIn= 0; + int _numIn[1] = {0}; + uint32_t* _primROut= 0; + remote_arg* _praIn = 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==3); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((3 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 12); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 8); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_in1Len, 0, _primIn, 4, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, ((_praIn[0].buf.nLen / 1)) >= (size_t)(_in1Len[0])); + _in1[0] = _praIn[0].buf.pv; + _ASSERT(_nErr, (_in1Len[0] > 0) && (_in1[0][(_in1Len[0] - 1)] == 0)); + _COPY(_in2Len, 0, _primIn, 8, 4); + _ASSERT(_nErr, ((_praIn[1].buf.nLen / 1)) >= (size_t)(_in2Len[0])); + _in2[0] = _praIn[1].buf.pv; + _ASSERT(_nErr, (_in2Len[0] > 0) && (_in2[0][(_in2Len[0] - 1)] == 0)); + _TRY(_nErr, _pfn((const char*)*_in1, (const char*)*_in2, (int*)_rout3, (int*)_rout4)); + _COPY(_primROut, 0, _rout3, 0, 4); + _COPY(_primROut, 4, _rout4, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_3(int (*_pfn)(const char*, const char*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + uint32_t _in0[1] = {0}; + char* _in1[1] = {0}; + uint32_t _in1Len[1] = {0}; + char* _in2[1] = {0}; + uint32_t _in2Len[1] = {0}; + uint32_t* _primIn= 0; + remote_arg* _praIn = 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==3); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((3 + 0) + (((0 + 0) + 0) + 0))) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 12); + _primIn = _pra[0].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_in1Len, 0, _primIn, 4, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, ((_praIn[0].buf.nLen / 1)) >= (size_t)(_in1Len[0])); + _in1[0] = _praIn[0].buf.pv; + _ASSERT(_nErr, (_in1Len[0] > 0) && (_in1[0][(_in1Len[0] - 1)] == 0)); + _COPY(_in2Len, 0, _primIn, 8, 4); + _ASSERT(_nErr, ((_praIn[1].buf.nLen / 1)) >= (size_t)(_in2Len[0])); + _in2[0] = _praIn[1].buf.pv; + _ASSERT(_nErr, (_in2Len[0] > 0) && (_in2[0][(_in2Len[0] - 1)] == 0)); + _TRY(_nErr, _pfn((const char*)*_in1, (const char*)*_in2)); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_4(int (*_pfn)(apps_std_FILE, int), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + uint32_t _in0[1] = {0}; + uint32_t _in1[1] = {0}; + uint32_t _in2[1] = {0}; + uint32_t* _primIn= 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((1 + 0) + (((0 + 0) + 0) + 0))) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 12); + _primIn = _pra[0].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_in1, 0, _primIn, 4, 4); + _COPY(_in2, 0, _primIn, 8, 4); + _TRY(_nErr, _pfn((apps_std_FILE)*_in1, (int)*_in2)); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_5(int (*_pfn)(const char*, apps_std_STAT*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + uint32_t _in0[1] = {0}; + char* _in1[1] = {0}; + uint32_t _in1Len[1] = {0}; + uint64_t _rout2[12] = {0}; + uint32_t* _primIn= 0; + int _numIn[1] = {0}; + uint64_t* _primROut= 0; + remote_arg* _praIn = 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==2); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((2 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 96); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_in1Len, 0, _primIn, 4, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, ((_praIn[0].buf.nLen / 1)) >= (size_t)(_in1Len[0])); + _in1[0] = _praIn[0].buf.pv; + _ASSERT(_nErr, (_in1Len[0] > 0) && (_in1[0][(_in1Len[0] - 1)] == 0)); + _TRY(_nErr, _pfn((const char*)*_in1, (apps_std_STAT*)_rout2)); + _COPY(_primROut, 0, _rout2, 0, 96); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_invoke(uint32_t _mid, uint32_t _sc, remote_arg* _pra) { + switch(_mid) + { + case 31: + return _skel_method_5(__QAIC_IMPL(apps_std_stat), _sc, _pra); + case 32: + return _skel_method_4(__QAIC_IMPL(apps_std_ftrunc), _sc, _pra); + case 33: + return _skel_method_3(__QAIC_IMPL(apps_std_frename), _sc, _pra); + case 34: + return _skel_method_2(__QAIC_IMPL(apps_std_fopen_fd), _sc, _pra); + case 35: + return _skel_method_1(__QAIC_IMPL(apps_std_fclose_fd), _sc, _pra); + case 36: + return _skel_method(__QAIC_IMPL(apps_std_fopen_with_env_fd), _sc, _pra); + } + return AEE_EUNSUPPORTED; +} +static __inline int _skel_method_6(int (*_pfn)(const char*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + char* _in0[1] = {0}; + uint32_t _in0Len[1] = {0}; + uint32_t* _primIn= 0; + remote_arg* _praIn = 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==2); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((2 + 0) + (((0 + 0) + 0) + 0))) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 4); + _primIn = _pra[0].buf.pv; + _COPY(_in0Len, 0, _primIn, 0, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, ((_praIn[0].buf.nLen / 1)) >= (size_t)(_in0Len[0])); + _in0[0] = _praIn[0].buf.pv; + _ASSERT(_nErr, (_in0Len[0] > 0) && (_in0[0][(_in0Len[0] - 1)] == 0)); + _TRY(_nErr, _pfn((const char*)*_in0)); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_7(int (*_pfn)(const char*, int), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + char* _in0[1] = {0}; + uint32_t _in0Len[1] = {0}; + uint32_t _in1[1] = {0}; + uint32_t* _primIn= 0; + remote_arg* _praIn = 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==2); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((2 + 0) + (((0 + 0) + 0) + 0))) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _COPY(_in0Len, 0, _primIn, 0, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, ((_praIn[0].buf.nLen / 1)) >= (size_t)(_in0Len[0])); + _in0[0] = _praIn[0].buf.pv; + _ASSERT(_nErr, (_in0Len[0] > 0) && (_in0[0][(_in0Len[0] - 1)] == 0)); + _COPY(_in1, 0, _primIn, 4, 4); + _TRY(_nErr, _pfn((const char*)*_in0, (int)*_in1)); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_8(int (*_pfn)(const apps_std_DIR*, apps_std_DIRENT*, int*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + uint64_t _in0[1] = {0}; + uint32_t _rout1[65] = {0}; + uint32_t _rout2[1] = {0}; + uint64_t* _primIn= 0; + int _numIn[1] = {0}; + uint32_t* _primROut= 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((1 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 264); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0, 0, _primIn, 0, 8); + _TRY(_nErr, _pfn((const apps_std_DIR*)_in0, (apps_std_DIRENT*)_rout1, (int*)_rout2)); + _COPY(_primROut, 0, _rout1, 0, 260); + _COPY(_primROut, 260, _rout2, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_9(int (*_pfn)(const apps_std_DIR*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + uint64_t _in0[1] = {0}; + uint64_t* _primIn= 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((1 + 0) + (((0 + 0) + 0) + 0))) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _COPY(_in0, 0, _primIn, 0, 8); + _TRY(_nErr, _pfn((const apps_std_DIR*)_in0)); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_10(int (*_pfn)(const char*, apps_std_DIR*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + char* _in0[1] = {0}; + uint32_t _in0Len[1] = {0}; + uint64_t _rout1[1] = {0}; + uint32_t* _primIn= 0; + int _numIn[1] = {0}; + uint64_t* _primROut= 0; + remote_arg* _praIn = 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==2); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((2 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 4); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 8); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0Len, 0, _primIn, 0, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, ((_praIn[0].buf.nLen / 1)) >= (size_t)(_in0Len[0])); + _in0[0] = _praIn[0].buf.pv; + _ASSERT(_nErr, (_in0Len[0] > 0) && (_in0[0][(_in0Len[0] - 1)] == 0)); + _TRY(_nErr, _pfn((const char*)*_in0, (apps_std_DIR*)_rout1)); + _COPY(_primROut, 0, _rout1, 0, 8); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_11(int (*_pfn)(apps_std_FILE, apps_std_FILE*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + uint32_t _in0[1] = {0}; + uint32_t _rout1[1] = {0}; + uint32_t* _primIn= 0; + int _numIn[1] = {0}; + uint32_t* _primROut= 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((1 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 4); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 4); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _TRY(_nErr, _pfn((apps_std_FILE)*_in0, (apps_std_FILE*)_rout1)); + _COPY(_primROut, 0, _rout1, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_12(int (*_pfn)(apps_std_FILE), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + uint32_t _in0[1] = {0}; + uint32_t* _primIn= 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((1 + 0) + (((0 + 0) + 0) + 0))) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 4); + _primIn = _pra[0].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _TRY(_nErr, _pfn((apps_std_FILE)*_in0)); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_13(int (*_pfn)(const char*, boolean*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + char* _in0[1] = {0}; + uint32_t _in0Len[1] = {0}; + uint8_t _rout1[1] = {0}; + uint32_t* _primIn= 0; + int _numIn[1] = {0}; + uint8_t* _primROut= 0; + remote_arg* _praIn = 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==2); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((2 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 4); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 1); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0Len, 0, _primIn, 0, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, ((_praIn[0].buf.nLen / 1)) >= (size_t)(_in0Len[0])); + _in0[0] = _praIn[0].buf.pv; + _ASSERT(_nErr, (_in0Len[0] > 0) && (_in0[0][(_in0Len[0] - 1)] == 0)); + _TRY(_nErr, _pfn((const char*)*_in0, (boolean*)_rout1)); + _COPY(_primROut, 0, _rout1, 0, 1); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_pack(_ATTRIBUTE_UNUSED remote_arg* _praROutPost, _ATTRIBUTE_UNUSED remote_arg* _ppraROutPost[1], _ATTRIBUTE_UNUSED void* _primROut, _ATTRIBUTE_UNUSED char* _rout0[1], _ATTRIBUTE_UNUSED uint32_t _rout0Len[1]) { + int _nErr = 0; + remote_arg* _praROutPostStart = _praROutPost; + remote_arg** _ppraROutPostStart = _ppraROutPost; + _ppraROutPost = &_praROutPost; + _ppraROutPostStart[0] += (_praROutPost - _praROutPostStart) +1; + return _nErr; +} +static __inline int _skel_unpack(_ATTRIBUTE_UNUSED _allocator* _al, _ATTRIBUTE_UNUSED remote_arg* _praIn, _ATTRIBUTE_UNUSED remote_arg* _ppraIn[1], _ATTRIBUTE_UNUSED remote_arg* _praROut, _ATTRIBUTE_UNUSED remote_arg* _ppraROut[1], _ATTRIBUTE_UNUSED remote_arg* _praHIn, _ATTRIBUTE_UNUSED remote_arg* _ppraHIn[1], _ATTRIBUTE_UNUSED remote_arg* _praHROut, _ATTRIBUTE_UNUSED remote_arg* _ppraHROut[1], _ATTRIBUTE_UNUSED void* _primIn, _ATTRIBUTE_UNUSED void* _primROut, _ATTRIBUTE_UNUSED char* _rout0[1], _ATTRIBUTE_UNUSED uint32_t _rout0Len[1]) { + int _nErr = 0; + remote_arg* _praInStart = _praIn; + remote_arg** _ppraInStart = _ppraIn; + remote_arg* _praROutStart = _praROut; + remote_arg** _ppraROutStart = _ppraROut; + _ppraIn = &_praIn; + _ppraROut = &_praROut; + _COPY(_rout0Len, 0, _primIn, 0, 4); + _ASSERT(_nErr, ((_praROut[0].buf.nLen / 1)) >= (size_t)(_rout0Len[0])); + _rout0[0] = _praROut[0].buf.pv; + _ppraInStart[0] += (_praIn - _praInStart) + 0; + _ppraROutStart[0] += (_praROut - _praROutStart) +1; + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_14(int (*_pfn)(const char*, const char*, _cstring1_t*, int, uint32*, uint16*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + char* _in0[1] = {0}; + uint32_t _in0Len[1] = {0}; + char* _in1[1] = {0}; + uint32_t _in1Len[1] = {0}; + void* _rout2[1] = {0}; + uint32_t _rout2Len[1] = {0}; + uint32_t _rout3[1] = {0}; + uint16_t _rout4[1] = {0}; + uint32_t* _primIn= 0; + int _numIn[1] = {0}; + uint32_t* _primROut= 0; + int _numInH[1] = {0}; + int _numROut[1] = {0}; + remote_arg* _praIn = 0; + remote_arg* _praROut = 0; + remote_arg* _praROutPost = 0; + remote_arg** _ppraROutPost = &_praROutPost; + _allocator _al[1] = {{0}}; + remote_arg** _ppraIn = &_praIn; + remote_arg** _ppraROut = &_praROut; + remote_arg* _praHIn = 0; + remote_arg** _ppraHIn = &_praHIn; + remote_arg* _praHROut = 0; + remote_arg** _ppraHROut = &_praHROut; + char* _seq_primIn2 = 0; + char* _seq_nat2 = 0; + int _ii = 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)>=1); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)>=1); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((4 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 12); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 6); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _numInH[0] = REMOTE_SCALARS_INHANDLES(_sc); + _numROut[0] = REMOTE_SCALARS_OUTBUFS(_sc); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 1); + _praROutPost = _praROut; + _COPY(_in0Len, 0, _primIn, 0, 4); + _ASSERT(_nErr, ((_praIn[0].buf.nLen / 1)) >= (size_t)(_in0Len[0])); + _in0[0] = _praIn[0].buf.pv; + _ASSERT(_nErr, (_in0Len[0] > 0) && (_in0[0][(_in0Len[0] - 1)] == 0)); + _COPY(_in1Len, 0, _primIn, 4, 4); + _ASSERT(_nErr, ((_praIn[1].buf.nLen / 1)) >= (size_t)(_in1Len[0])); + _in1[0] = _praIn[1].buf.pv; + _ASSERT(_nErr, (_in1Len[0] > 0) && (_in1[0][(_in1Len[0] - 1)] == 0)); + _COPY(_rout2Len, 0, _primIn, 8, 4); + _allocator_init(_al, 0, 0); + if(_praHIn == 0) + { + _praHIn = ((_praROut + _numROut[0]) + 1); + } + if(_praHROut == 0) + (_praHROut = _praHIn + _numInH[0] + 0); + _ASSERT(_nErr, ((_praIn[2].buf.nLen / 4)) >= (size_t)(_rout2Len[0])); + _ALLOCATE(_nErr, _al, (_rout2Len[0] * SLIM_IFPTR32(8, 16)), SLIM_IFPTR32(4, 8), _rout2[0]); + for(_ii = 0, _seq_primIn2 = (char*)_praIn[2].buf.pv, _seq_nat2 = (char*)_rout2[0];_ii < (int)_rout2Len[0];++_ii, _seq_primIn2 = (_seq_primIn2 + 4), _seq_nat2 = (_seq_nat2 + SLIM_IFPTR32(8, 16))) + { + _TRY(_nErr, _skel_unpack(_al, (_praIn + 3), _ppraIn, (_praROut + 0), _ppraROut, _praHIn, _ppraHIn, _praHROut, _ppraHROut, _seq_primIn2, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat2)[0]), (char**)&(((uint64_t*)_seq_nat2)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat2)[1]), (uint32_t*)&(((uint32_t*)_seq_nat2)[2])))); + } + _TRY(_nErr, _pfn((const char*)*_in0, (const char*)*_in1, (_cstring1_t*)*_rout2, (int)*_rout2Len, (uint32*)_rout3, (uint16*)_rout4)); + for(_ii = 0, _seq_nat2 = (char*)_rout2[0];_ii < (int)_rout2Len[0];++_ii, _seq_nat2 = (_seq_nat2 + SLIM_IFPTR32(8, 16))) + { + _TRY(_nErr, _skel_pack((_praROutPost + 0), _ppraROutPost, 0, SLIM_IFPTR32((char**)&(((uint32_t*)_seq_nat2)[0]), (char**)&(((uint64_t*)_seq_nat2)[0])), SLIM_IFPTR32((uint32_t*)&(((uint32_t*)_seq_nat2)[1]), (uint32_t*)&(((uint32_t*)_seq_nat2)[2])))); + } + _COPY(_primROut, 0, _rout3, 0, 4); + _COPY(_primROut, 4, _rout4, 0, 2); + _CATCH(_nErr) {} + _allocator_deinit(_al); + return _nErr; +} +static __inline int _skel_method_15(int (*_pfn)(apps_std_FILE, byte*, int, int*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + uint32_t _in0[1] = {0}; + char* _rout1[1] = {0}; + uint32_t _rout1Len[1] = {0}; + uint32_t _rout2[1] = {0}; + uint32_t* _primIn= 0; + int _numIn[1] = {0}; + uint32_t* _primROut= 0; + remote_arg* _praIn = 0; + remote_arg* _praROut = 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==2); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((1 + 2) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 4); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_rout1Len, 0, _primIn, 4, 4); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 1); + _ASSERT(_nErr, ((_praROut[0].buf.nLen / 1)) >= (size_t)(_rout1Len[0])); + _rout1[0] = _praROut[0].buf.pv; + _TRY(_nErr, _pfn((apps_std_FILE)*_in0, (byte*)*_rout1, (int)*_rout1Len, (int*)_rout2)); + _COPY(_primROut, 0, _rout2, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_16(int (*_pfn)(const char*, const char*, const char*, const char*, apps_std_FILE*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + char* _in0[1] = {0}; + uint32_t _in0Len[1] = {0}; + char* _in1[1] = {0}; + uint32_t _in1Len[1] = {0}; + char* _in2[1] = {0}; + uint32_t _in2Len[1] = {0}; + char* _in3[1] = {0}; + uint32_t _in3Len[1] = {0}; + uint32_t _rout4[1] = {0}; + uint32_t* _primIn= 0; + int _numIn[1] = {0}; + uint32_t* _primROut= 0; + remote_arg* _praIn = 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==5); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((5 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 16); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 4); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0Len, 0, _primIn, 0, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, ((_praIn[0].buf.nLen / 1)) >= (size_t)(_in0Len[0])); + _in0[0] = _praIn[0].buf.pv; + _ASSERT(_nErr, (_in0Len[0] > 0) && (_in0[0][(_in0Len[0] - 1)] == 0)); + _COPY(_in1Len, 0, _primIn, 4, 4); + _ASSERT(_nErr, ((_praIn[1].buf.nLen / 1)) >= (size_t)(_in1Len[0])); + _in1[0] = _praIn[1].buf.pv; + _ASSERT(_nErr, (_in1Len[0] > 0) && (_in1[0][(_in1Len[0] - 1)] == 0)); + _COPY(_in2Len, 0, _primIn, 8, 4); + _ASSERT(_nErr, ((_praIn[2].buf.nLen / 1)) >= (size_t)(_in2Len[0])); + _in2[0] = _praIn[2].buf.pv; + _ASSERT(_nErr, (_in2Len[0] > 0) && (_in2[0][(_in2Len[0] - 1)] == 0)); + _COPY(_in3Len, 0, _primIn, 12, 4); + _ASSERT(_nErr, ((_praIn[3].buf.nLen / 1)) >= (size_t)(_in3Len[0])); + _in3[0] = _praIn[3].buf.pv; + _ASSERT(_nErr, (_in3Len[0] > 0) && (_in3[0][(_in3Len[0] - 1)] == 0)); + _TRY(_nErr, _pfn((const char*)*_in0, (const char*)*_in1, (const char*)*_in2, (const char*)*_in3, (apps_std_FILE*)_rout4)); + _COPY(_primROut, 0, _rout4, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_17(int (*_pfn)(const char*, const char*, int), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + char* _in0[1] = {0}; + uint32_t _in0Len[1] = {0}; + char* _in1[1] = {0}; + uint32_t _in1Len[1] = {0}; + uint32_t _in2[1] = {0}; + uint32_t* _primIn= 0; + remote_arg* _praIn = 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==3); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((3 + 0) + (((0 + 0) + 0) + 0))) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 12); + _primIn = _pra[0].buf.pv; + _COPY(_in0Len, 0, _primIn, 0, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, ((_praIn[0].buf.nLen / 1)) >= (size_t)(_in0Len[0])); + _in0[0] = _praIn[0].buf.pv; + _ASSERT(_nErr, (_in0Len[0] > 0) && (_in0[0][(_in0Len[0] - 1)] == 0)); + _COPY(_in1Len, 0, _primIn, 4, 4); + _ASSERT(_nErr, ((_praIn[1].buf.nLen / 1)) >= (size_t)(_in1Len[0])); + _in1[0] = _praIn[1].buf.pv; + _ASSERT(_nErr, (_in1Len[0] > 0) && (_in1[0][(_in1Len[0] - 1)] == 0)); + _COPY(_in2, 0, _primIn, 8, 4); + _TRY(_nErr, _pfn((const char*)*_in0, (const char*)*_in1, (int)*_in2)); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_18(int (*_pfn)(const char*, char*, int, int*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + char* _in0[1] = {0}; + uint32_t _in0Len[1] = {0}; + char* _rout1[1] = {0}; + uint32_t _rout1Len[1] = {0}; + uint32_t _rout2[1] = {0}; + uint32_t* _primIn= 0; + int _numIn[1] = {0}; + uint32_t* _primROut= 0; + remote_arg* _praIn = 0; + remote_arg* _praROut = 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==2); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==2); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((2 + 2) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 4); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0Len, 0, _primIn, 0, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, ((_praIn[0].buf.nLen / 1)) >= (size_t)(_in0Len[0])); + _in0[0] = _praIn[0].buf.pv; + _ASSERT(_nErr, (_in0Len[0] > 0) && (_in0[0][(_in0Len[0] - 1)] == 0)); + _COPY(_rout1Len, 0, _primIn, 4, 4); + _praROut = (_praIn + _numIn[0] + 1); + _ASSERT(_nErr, ((_praROut[0].buf.nLen / 1)) >= (size_t)(_rout1Len[0])); + _rout1[0] = _praROut[0].buf.pv; + _TRY(_nErr, _pfn((const char*)*_in0, (char*)*_rout1, (int)*_rout1Len, (int*)_rout2)); + _COPY(_primROut, 0, _rout2, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_19(int (*_pfn)(apps_std_FILE, int*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + uint32_t _in0[1] = {0}; + uint32_t _rout1[1] = {0}; + uint32_t* _primIn= 0; + int _numIn[1] = {0}; + uint32_t* _primROut= 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((1 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 4); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 4); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _TRY(_nErr, _pfn((apps_std_FILE)*_in0, (int*)_rout1)); + _COPY(_primROut, 0, _rout1, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_20(int (*_pfn)(apps_std_FILE, uint64*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + uint32_t _in0[1] = {0}; + uint64_t _rout1[1] = {0}; + uint32_t* _primIn= 0; + int _numIn[1] = {0}; + uint64_t* _primROut= 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((1 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 4); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 8); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _TRY(_nErr, _pfn((apps_std_FILE)*_in0, (uint64*)_rout1)); + _COPY(_primROut, 0, _rout1, 0, 8); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_21(int (*_pfn)(apps_std_FILE, int, apps_std_SEEK), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + uint32_t _in0[1] = {0}; + uint32_t _in1[1] = {0}; + uint32_t _in2[1] = {0}; + uint32_t* _primIn= 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((1 + 0) + (((0 + 0) + 0) + 0))) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 12); + _primIn = _pra[0].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_in1, 0, _primIn, 4, 4); + _COPY(_in2, 0, _primIn, 8, 4); + _TRY(_nErr, _pfn((apps_std_FILE)*_in0, (int)*_in1, (apps_std_SEEK)*_in2)); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_22(int (*_pfn)(apps_std_FILE, const byte*, int), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + uint32_t _in0[1] = {0}; + char* _in1[1] = {0}; + uint32_t _in1Len[1] = {0}; + uint32_t* _primIn= 0; + remote_arg* _praIn = 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==2); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((2 + 0) + (((0 + 0) + 0) + 0))) <= _praEnd); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_in1Len, 0, _primIn, 4, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, ((_praIn[0].buf.nLen / 1)) >= (size_t)(_in1Len[0])); + _in1[0] = _praIn[0].buf.pv; + _TRY(_nErr, _pfn((apps_std_FILE)*_in0, (const byte*)*_in1, (int)*_in1Len)); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_23(int (*_pfn)(apps_std_FILE, const byte*, int, int*, int*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + uint32_t _in0[1] = {0}; + char* _in1[1] = {0}; + uint32_t _in1Len[1] = {0}; + uint32_t _rout2[1] = {0}; + uint32_t _rout3[1] = {0}; + uint32_t* _primIn= 0; + int _numIn[1] = {0}; + uint32_t* _primROut= 0; + remote_arg* _praIn = 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==2); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((2 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 8); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_in1Len, 0, _primIn, 4, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, ((_praIn[0].buf.nLen / 1)) >= (size_t)(_in1Len[0])); + _in1[0] = _praIn[0].buf.pv; + _TRY(_nErr, _pfn((apps_std_FILE)*_in0, (const byte*)*_in1, (int)*_in1Len, (int*)_rout2, (int*)_rout3)); + _COPY(_primROut, 0, _rout2, 0, 4); + _COPY(_primROut, 4, _rout3, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_24(int (*_pfn)(apps_std_FILE, byte*, int, int*, int*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + uint32_t _in0[1] = {0}; + char* _rout1[1] = {0}; + uint32_t _rout1Len[1] = {0}; + uint32_t _rout2[1] = {0}; + uint32_t _rout3[1] = {0}; + uint32_t* _primIn= 0; + int _numIn[1] = {0}; + uint32_t* _primROut= 0; + remote_arg* _praIn = 0; + remote_arg* _praROut = 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==2); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((1 + 2) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 8); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_rout1Len, 0, _primIn, 4, 4); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 1); + _ASSERT(_nErr, ((_praROut[0].buf.nLen / 1)) >= (size_t)(_rout1Len[0])); + _rout1[0] = _praROut[0].buf.pv; + _TRY(_nErr, _pfn((apps_std_FILE)*_in0, (byte*)*_rout1, (int)*_rout1Len, (int*)_rout2, (int*)_rout3)); + _COPY(_primROut, 0, _rout2, 0, 4); + _COPY(_primROut, 4, _rout3, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_25(int (*_pfn)(apps_std_FILE, const char*, const char*, apps_std_FILE*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + uint32_t _in0[1] = {0}; + char* _in1[1] = {0}; + uint32_t _in1Len[1] = {0}; + char* _in2[1] = {0}; + uint32_t _in2Len[1] = {0}; + uint32_t _rout3[1] = {0}; + uint32_t* _primIn= 0; + int _numIn[1] = {0}; + uint32_t* _primROut= 0; + remote_arg* _praIn = 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==3); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((3 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 12); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 4); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0, 0, _primIn, 0, 4); + _COPY(_in1Len, 0, _primIn, 4, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, ((_praIn[0].buf.nLen / 1)) >= (size_t)(_in1Len[0])); + _in1[0] = _praIn[0].buf.pv; + _ASSERT(_nErr, (_in1Len[0] > 0) && (_in1[0][(_in1Len[0] - 1)] == 0)); + _COPY(_in2Len, 0, _primIn, 8, 4); + _ASSERT(_nErr, ((_praIn[1].buf.nLen / 1)) >= (size_t)(_in2Len[0])); + _in2[0] = _praIn[1].buf.pv; + _ASSERT(_nErr, (_in2Len[0] > 0) && (_in2[0][(_in2Len[0] - 1)] == 0)); + _TRY(_nErr, _pfn((apps_std_FILE)*_in0, (const char*)*_in1, (const char*)*_in2, (apps_std_FILE*)_rout3)); + _COPY(_primROut, 0, _rout3, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +static __inline int _skel_method_26(int (*_pfn)(const char*, const char*, apps_std_FILE*), uint32_t _sc, remote_arg* _pra) { + remote_arg* _praEnd = 0; + char* _in0[1] = {0}; + uint32_t _in0Len[1] = {0}; + char* _in1[1] = {0}; + uint32_t _in1Len[1] = {0}; + uint32_t _rout2[1] = {0}; + uint32_t* _primIn= 0; + int _numIn[1] = {0}; + uint32_t* _primROut= 0; + remote_arg* _praIn = 0; + int _nErr = 0; + _praEnd = ((_pra + REMOTE_SCALARS_INBUFS(_sc)) + REMOTE_SCALARS_OUTBUFS(_sc) + REMOTE_SCALARS_INHANDLES(_sc) + REMOTE_SCALARS_OUTHANDLES(_sc)); + _ASSERT(_nErr, REMOTE_SCALARS_INBUFS(_sc)==3); + _ASSERT(_nErr, REMOTE_SCALARS_OUTBUFS(_sc)==1); + _ASSERT(_nErr, REMOTE_SCALARS_INHANDLES(_sc)==0); + _ASSERT(_nErr, REMOTE_SCALARS_OUTHANDLES(_sc)==0); + _ASSERT(_nErr, (_pra + ((3 + 1) + (((0 + 0) + 0) + 0))) <= _praEnd); + _numIn[0] = (REMOTE_SCALARS_INBUFS(_sc) - 1); + _ASSERT(_nErr, _pra[0].buf.nLen >= 8); + _primIn = _pra[0].buf.pv; + _ASSERT(_nErr, _pra[(_numIn[0] + 1)].buf.nLen >= 4); + _primROut = _pra[(_numIn[0] + 1)].buf.pv; + _COPY(_in0Len, 0, _primIn, 0, 4); + _praIn = (_pra + 1); + _ASSERT(_nErr, ((_praIn[0].buf.nLen / 1)) >= (size_t)(_in0Len[0])); + _in0[0] = _praIn[0].buf.pv; + _ASSERT(_nErr, (_in0Len[0] > 0) && (_in0[0][(_in0Len[0] - 1)] == 0)); + _COPY(_in1Len, 0, _primIn, 4, 4); + _ASSERT(_nErr, ((_praIn[1].buf.nLen / 1)) >= (size_t)(_in1Len[0])); + _in1[0] = _praIn[1].buf.pv; + _ASSERT(_nErr, (_in1Len[0] > 0) && (_in1[0][(_in1Len[0] - 1)] == 0)); + _TRY(_nErr, _pfn((const char*)*_in0, (const char*)*_in1, (apps_std_FILE*)_rout2)); + _COPY(_primROut, 0, _rout2, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_SKEL_EXPORT int __QAIC_SKEL(apps_std_skel_invoke)(uint32_t _sc, remote_arg* _pra) __QAIC_SKEL_ATTRIBUTE { + switch(REMOTE_SCALARS_METHOD(_sc)) + { + case 0: + return _skel_method_26(__QAIC_IMPL(apps_std_fopen), _sc, _pra); + case 1: + return _skel_method_25(__QAIC_IMPL(apps_std_freopen), _sc, _pra); + case 2: + return _skel_method_12(__QAIC_IMPL(apps_std_fflush), _sc, _pra); + case 3: + return _skel_method_12(__QAIC_IMPL(apps_std_fclose), _sc, _pra); + case 4: + return _skel_method_24(__QAIC_IMPL(apps_std_fread), _sc, _pra); + case 5: + return _skel_method_23(__QAIC_IMPL(apps_std_fwrite), _sc, _pra); + case 6: + return _skel_method_15(__QAIC_IMPL(apps_std_fgetpos), _sc, _pra); + case 7: + return _skel_method_22(__QAIC_IMPL(apps_std_fsetpos), _sc, _pra); + case 8: + return _skel_method_19(__QAIC_IMPL(apps_std_ftell), _sc, _pra); + case 9: + return _skel_method_21(__QAIC_IMPL(apps_std_fseek), _sc, _pra); + case 10: + return _skel_method_20(__QAIC_IMPL(apps_std_flen), _sc, _pra); + case 11: + return _skel_method_12(__QAIC_IMPL(apps_std_rewind), _sc, _pra); + case 12: + return _skel_method_19(__QAIC_IMPL(apps_std_feof), _sc, _pra); + case 13: + return _skel_method_19(__QAIC_IMPL(apps_std_ferror), _sc, _pra); + case 14: + return _skel_method_12(__QAIC_IMPL(apps_std_clearerr), _sc, _pra); + case 15: + return _skel_method_6(__QAIC_IMPL(apps_std_print_string), _sc, _pra); + case 16: + return _skel_method_18(__QAIC_IMPL(apps_std_getenv), _sc, _pra); + case 17: + return _skel_method_17(__QAIC_IMPL(apps_std_setenv), _sc, _pra); + case 18: + return _skel_method_6(__QAIC_IMPL(apps_std_unsetenv), _sc, _pra); + case 19: + return _skel_method_16(__QAIC_IMPL(apps_std_fopen_with_env), _sc, _pra); + case 20: + return _skel_method_15(__QAIC_IMPL(apps_std_fgets), _sc, _pra); + case 21: + return _skel_method_14(__QAIC_IMPL(apps_std_get_search_paths_with_env), _sc, _pra); + case 22: + return _skel_method_13(__QAIC_IMPL(apps_std_fileExists), _sc, _pra); + case 23: + return _skel_method_12(__QAIC_IMPL(apps_std_fsync), _sc, _pra); + case 24: + return _skel_method_6(__QAIC_IMPL(apps_std_fremove), _sc, _pra); + case 25: + return _skel_method_11(__QAIC_IMPL(apps_std_fdopen_decrypt), _sc, _pra); + case 26: + return _skel_method_10(__QAIC_IMPL(apps_std_opendir), _sc, _pra); + case 27: + return _skel_method_9(__QAIC_IMPL(apps_std_closedir), _sc, _pra); + case 28: + return _skel_method_8(__QAIC_IMPL(apps_std_readdir), _sc, _pra); + case 29: + return _skel_method_7(__QAIC_IMPL(apps_std_mkdir), _sc, _pra); + case 30: + return _skel_method_6(__QAIC_IMPL(apps_std_rmdir), _sc, _pra); + case 31: + { + uint32_t* _mid; + if(REMOTE_SCALARS_INBUFS(_sc) < 1 || _pra[0].buf.nLen < 4) { return AEE_EBADPARM; } + _mid = (uint32_t*)_pra[0].buf.pv; + return _skel_invoke(*_mid, _sc, _pra); + } + } + return AEE_EUNSUPPORTED; +} +#ifdef __cplusplus +} +#endif +#endif //_APPS_STD_SKEL_H diff --git a/src/atomic.c b/src/atomic.c new file mode 100644 index 0000000..2dad193 --- /dev/null +++ b/src/atomic.c @@ -0,0 +1,46 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#include "AEEatomic.h" + +uint32 atomic_Add(uint32 * volatile puDest, int nAdd) { + uint32 previous; + uint32 current; + uint32 sum; + do { + current = *puDest; + __builtin_add_overflow(current, nAdd, &sum); + previous = atomic_CompareAndExchange(puDest, sum, current); + } while(previous != current); + __builtin_add_overflow(current, nAdd, &sum); + return sum; +} + +uint32 atomic_Exchange(uint32* volatile puDest, uint32 uVal) { + uint32 previous; + uint32 current; + do { + current = *puDest; + previous = atomic_CompareAndExchange(puDest, uVal, current); + } while(previous != current); + return previous; +} + +uint32 atomic_CompareOrAdd(uint32* volatile puDest, uint32 uCompare, int nAdd) { + uint32 previous; + uint32 current; + uint32 result; + do { + current = *puDest; + previous = current; + result = current; + if(current != uCompare) { + previous = atomic_CompareAndExchange(puDest, current + nAdd, current); + if(previous == current) { + result = current + nAdd; + } + } + } while(previous != current); + return result; +} + diff --git a/src/cae.c b/src/cae.c new file mode 100644 index 0000000..4167998 --- /dev/null +++ b/src/cae.c @@ -0,0 +1,63 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#include "AEEatomic.h" + +#ifdef _WIN32 +#include "Windows.h" +uint32 atomic_CompareAndExchange(uint32 * volatile puDest, uint32 uExchange, uint32 uCompare) { + C_ASSERT(sizeof(LONG) == sizeof(uint32)); + return (uint32)InterlockedCompareExchange((LONG*)puDest, (LONG)uExchange, (LONG)uCompare); +} +uintptr_t atomic_CompareAndExchangeUP(uintptr_t * volatile puDest, uintptr_t uExchange, uintptr_t uCompare) { + C_ASSERT(sizeof(uintptr_t) == sizeof(void*)); + return (uintptr_t)InterlockedCompareExchangePointer((void**)puDest, (void*)uExchange, (void*)uCompare); +} +#elif __hexagon__ + +#ifndef C_ASSERT +#define C_ASSERT(test) \ + switch(0) {\ + case 0:\ + case test:;\ + } +#endif + +static inline unsigned int +qurt_atomic_compare_val_and_set(unsigned int* target, + unsigned int old_val, + unsigned int new_val) +{ + unsigned int current_val; + + __asm__ __volatile__( + "1: %0 = memw_locked(%2)\n" + " p0 = cmp.eq(%0, %3)\n" + " if !p0 jump 2f\n" + " memw_locked(%2, p0) = %4\n" + " if !p0 jump 1b\n" + "2:\n" + : "=&r" (current_val),"+m" (*target) + : "r" (target), "r" (old_val), "r" (new_val) + : "p0"); + + return current_val; +} +uint32 atomic_CompareAndExchange(uint32 * volatile puDest, uint32 uExchange, uint32 uCompare) { + return (uint32)qurt_atomic_compare_val_and_set((unsigned int*)puDest, uCompare, uExchange); +} +uintptr_t atomic_CompareAndExchangeUP(uintptr_t * volatile puDest, uintptr_t uExchange, uintptr_t uCompare) { + C_ASSERT(sizeof(uintptr_t) == sizeof(uint32)); + return (uint32)atomic_CompareAndExchange((uint32*)puDest, (uint32)uExchange, (uint32)uCompare); +} +#elif __GNUC__ +uint32 atomic_CompareAndExchange(uint32 * volatile puDest, uint32 uExchange, uint32 uCompare) { + return __sync_val_compare_and_swap(puDest, uCompare, uExchange); +} +uint64 atomic_CompareAndExchange64(uint64 * volatile puDest, uint64 uExchange, uint64 uCompare) { + return __sync_val_compare_and_swap(puDest, uCompare, uExchange); +} +uintptr_t atomic_CompareAndExchangeUP(uintptr_t * volatile puDest, uintptr_t uExchange, uintptr_t uCompare) { + return __sync_val_compare_and_swap(puDest, uCompare, uExchange); +} +#endif //compare and exchange diff --git a/src/cdsprpcd.c b/src/cdsprpcd.c new file mode 100644 index 0000000..bb01ad8 --- /dev/null +++ b/src/cdsprpcd.c @@ -0,0 +1,68 @@ +// 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 +#define VERIFY_PRINT_INFO 0 + +#include "AEEStdErr.h" +#include "HAP_farf.h" +#include "verify.h" +#include +#include +#include + +#ifndef CDSP_DEFAULT_LISTENER_NAME +#define CDSP_DEFAULT_LISTENER_NAME "libcdsp_default_listener.so" +#endif +#ifndef CDSP_LIBHIDL_NAME +#define CDSP_LIBHIDL_NAME "libhidlbase.so" +#endif + +typedef int (*adsp_default_listener_start_t)(int argc, char *argv[]); + +int main(int argc, char *argv[]) { + + int nErr = 0; + void *cdsphandler = NULL; +#ifndef NO_HAL + void *libhidlbaseHandler = NULL; +#endif + adsp_default_listener_start_t listener_start; + + VERIFY_EPRINTF("cdsp daemon starting"); +#ifndef NO_HAL + if (NULL != (libhidlbaseHandler = dlopen(CDSP_LIBHIDL_NAME, RTLD_NOW))) { +#endif + while (1) { + if (NULL != + (cdsphandler = dlopen(CDSP_DEFAULT_LISTENER_NAME, RTLD_NOW))) { + if (NULL != (listener_start = (adsp_default_listener_start_t)dlsym( + cdsphandler, "adsp_default_listener_start"))) { + VERIFY_IPRINTF("cdsp_default_listener_start called"); + nErr = listener_start(argc, argv); + } + if (0 != dlclose(cdsphandler)) { + VERIFY_EPRINTF("dlclose failed"); + } + } else { + VERIFY_EPRINTF("cdsp daemon error %s", dlerror()); + } + if (nErr == AEE_ECONNREFUSED) { + VERIFY_EPRINTF("fastRPC device driver is disabled, daemon exiting..."); + break; + } + VERIFY_EPRINTF("cdsp daemon will restart after 100ms..."); + usleep(100000); + } +#ifndef NO_HAL + if (0 != dlclose(libhidlbaseHandler)) { + VERIFY_EPRINTF("libhidlbase dlclose failed"); + } + } +#endif + VERIFY_EPRINTF("cdsp daemon exiting %x", nErr); + + return nErr; +} diff --git a/src/dspqueue/dspqueue_cpu.c b/src/dspqueue/dspqueue_cpu.c new file mode 100644 index 0000000..e4ea572 --- /dev/null +++ b/src/dspqueue/dspqueue_cpu.c @@ -0,0 +1,2296 @@ +// 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 +#ifndef VERIFY_PRINT_WARN +#define VERIFY_PRINT_WARN +#endif // VERIFY_PRINT_WARN +#define FARF_ERROR 1 +#define FARF_HIGH 0 +#define FARF_MEDIUM 0 +//#ifndef _DEBUG +//# define _DEBUG +//#endif +//#ifdef NDEBUG +//# undef NDEBUG +//#endif + +#include "AEEQList.h" // Needed by fastrpc_mem.h +#include "dspqueue.h" +#include "dspqueue_rpc.h" +#include "dspqueue_shared.h" +#include "dspsignal.h" +#include "fastrpc_apps_user.h" +#include "fastrpc_internal.h" +#include "fastrpc_mem.h" +#include "remote.h" +#include "verify.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct dspqueue { + unsigned id; + int domain; + struct dspqueue_header *header; + void *user_queue; + int user_queue_fd; + uint32_t user_queue_size; + remote_handle64 dsp_handle; + uint64 dsp_id; + uint16_t seq_no; + pthread_mutex_t mutex; + uint32_t read_packet_count; + uint32_t write_packet_count; + uint32_t req_packet_count; + uint32_t req_space_count; + uint32_t resp_packet_count; + uint32_t resp_space_count; + uint32_t packet_mask; + pthread_mutex_t packet_mutex; + pthread_cond_t packet_cond; + uint32_t space_mask; + pthread_mutex_t space_mutex; + pthread_cond_t space_cond; + int signal_threads; + dspqueue_callback_t packet_callback; + dspqueue_callback_t error_callback; + void *callback_context; + pthread_t packet_callback_thread; + uint64_t early_wakeup_wait; + uint32_t early_wakeup_misses; + uint32_t queue_count; + int have_wait_counts; + int have_driver_signaling; + pthread_t error_callback_thread; +}; + +struct dspqueue_domain_queues { + int domain; + unsigned num_queues; + pthread_mutex_t + queue_list_mutex; // Hold this to manipulate queues[] or max_queue + unsigned max_queue; + struct dspqueue *queues[DSPQUEUE_MAX_PROCESS_QUEUES]; + struct dspqueue_process_queue_state *state; + int state_fd; + remote_handle64 dsp_handle; + pthread_t send_signal_thread; + pthread_mutex_t send_signal_mutex; + pthread_cond_t send_signal_cond; + uint32_t send_signal_mask; + pthread_t receive_signal_thread; + int dsp_error; + int have_dspsignal; +}; + +static inline void free_skel_uri(remote_rpc_get_uri_t *dspqueue_skel) { + if (dspqueue_skel->domain_name) { + free(dspqueue_skel->domain_name); + } + if (dspqueue_skel->module_uri) { + free(dspqueue_skel->module_uri); + } + if (dspqueue_skel->uri) { + free(dspqueue_skel->uri); + } +} + +#define UNUSED_QUEUE ((struct dspqueue *)NULL) +#define INVALID_QUEUE ((struct dspqueue *)-1) + +struct dspqueue_process_queues { + pthread_mutex_t mutex; // Hold this to manipulate domain_queues or + // domain_queues[i]->num_queues; In other words, must + // hold this mutex to decide when to create/destroy a + // new struct dspqueue_domain_queues. + struct dspqueue_domain_queues *domain_queues[NUM_DOMAINS_EXTEND]; + uint32_t count; + int notif_registered[NUM_DOMAINS_EXTEND]; +}; + +static struct dspqueue_process_queues proc_queues; +static struct dspqueue_process_queues *queues = &proc_queues; +static pthread_once_t queues_once = PTHREAD_ONCE_INIT; + +static void *dspqueue_send_signal_thread(void *arg); +static void *dspqueue_receive_signal_thread(void *arg); +static void *dspqueue_packet_callback_thread(void *arg); + +#define QUEUE_CACHE_ALIGN 256 +#define CACHE_ALIGN_SIZE(x) \ + ((x + (QUEUE_CACHE_ALIGN - 1)) & (~(QUEUE_CACHE_ALIGN - 1))) + +// Cache maintenance ops. No-op for now - assuming cache coherency. +// Leave macros in place in case we want to make the buffer non-coherent +#define cache_invalidate_word(x) +#define cache_flush_word(x) +#define cache_invalidate_line(x) +#define cache_flush_line(x) +#define barrier_full() __asm__ __volatile__("dmb sy" : : : "memory") +#define barrier_store() __asm__ __volatile__("dmb st" : : : "memory"); +#define cache_flush(a, l) +#define cache_invalidate(a, l) +#define cache_flush_invalidate(a, l) + +#define DEFAULT_EARLY_WAKEUP_WAIT 1000 +#define MAX_EARLY_WAKEUP_WAIT 2500 +#define EARLY_WAKEUP_SLEEP 100 + +// Signal ID to match a specific queue signal +#define QUEUE_SIGNAL(queue_id, signal_no) \ + ((DSPQUEUE_NUM_SIGNALS * queue_id) + signal_no + DSPSIGNAL_DSPQUEUE_MIN) + +// Packet/space/send signal bit mask values +#define SIGNAL_BIT_SIGNAL 1 +#define SIGNAL_BIT_CANCEL 2 + +static int dspqueue_notif_callback(void *context, int domain, int session, + remote_rpc_status_flags_t status); + +// Initialize process static queue structure. This should realistically never +// fail. +static void init_process_queues_once(void) { + if (pthread_mutex_init(&queues->mutex, NULL) != 0) { + FARF(ERROR, "Mutex init failed"); + return; + } + queues->count = 1; // Start non-zero to help spot certain errors +} + +// Dynamically initialize process queue structure. This allocates memory and +// creates threads for queue signaling. The resources will be freed after +// the last queue in the process is closed. +// Must hold queues->mutex. +static AEEResult init_domain_queues_locked(int domain) { + + AEEResult nErr = AEE_SUCCESS; + pthread_attr_t tattr; + int sendmutex = 0, sendcond = 0, sendthread = 0, recvthread = 0, + dom = domain & DOMAIN_ID_MASK; + struct dspqueue_domain_queues *dq = NULL; + remote_rpc_get_uri_t dspqueue_skel = {0}; + int state_mapped = 0; + uint32_t cap = 0; + + errno = 0; + assert(domain < NUM_DOMAINS_EXTEND); + if (queues->domain_queues[domain] != NULL) { + return AEE_SUCCESS; + } + + VERIFYC((dq = calloc(1, sizeof(*dq))) != NULL, AEE_ENOMEMORY); + dq->domain = domain; + + /* Get URI of session */ + dspqueue_skel.domain_name_len = strlen(CDSP_DOMAIN_NAME) + 1; + VERIFYC((dspqueue_skel.domain_name = (char *)calloc( + dspqueue_skel.domain_name_len, sizeof(char))) != NULL, + AEE_ENOMEMORY); + + // Open session on the right DSP + if (dom == CDSP_DOMAIN_ID) { + std_strlcpy(dspqueue_skel.domain_name, CDSP_DOMAIN_NAME, + dspqueue_skel.domain_name_len); + } else if (dom == ADSP_DOMAIN_ID) { + std_strlcpy(dspqueue_skel.domain_name, ADSP_DOMAIN_NAME, + dspqueue_skel.domain_name_len); + } else { + nErr = AEE_EUNSUPPORTED; + goto bail; + } + dspqueue_skel.session_id = GET_SESSION_ID_FROM_DOMAIN_ID(domain); + + /* One extra character for NULL termination */ + dspqueue_skel.module_uri_len = strlen(dspqueue_rpc_URI) + 1; + VERIFYC((dspqueue_skel.module_uri = (char *)calloc( + dspqueue_skel.module_uri_len, sizeof(char))) != NULL, + AEE_ENOMEMORY); + std_strlcpy(dspqueue_skel.module_uri, dspqueue_rpc_URI, + dspqueue_skel.module_uri_len); + + /* One extra character for NULL termination is already part of module_uri_len + */ + dspqueue_skel.uri_len = dspqueue_skel.module_uri_len + FASTRPC_URI_BUF_LEN; + VERIFYC((dspqueue_skel.uri = + (char *)calloc(dspqueue_skel.uri_len, sizeof(char))) != NULL, + AEE_ENOMEMORY); + if ((nErr = remote_session_control(FASTRPC_GET_URI, (void *)&dspqueue_skel, + sizeof(dspqueue_skel))) != AEE_SUCCESS) { + FARF(ERROR, + "Error 0x%x: %s: obtaining session URI for %s on domain %d, session " + "%u failed\n", + nErr, __func__, dspqueue_rpc_URI, domain, dspqueue_skel.session_id); + nErr = AEE_EUNSUPPORTED; + goto bail; + } + + if ((nErr = dspqueue_rpc_open(dspqueue_skel.uri, &dq->dsp_handle)) != 0) { + FARF(ERROR, + "dspqueue_rpc_open failed with %x on domain %d - packet queue support " + "likely not present on DSP", + nErr, domain); + nErr = AEE_EUNSUPPORTED; + goto bail; + } + + if (!queues->notif_registered[domain]) { + // Register for process exit notifications. Only do this once for the + // lifetime of the process to avoid multiple registrations and leaks. + remote_rpc_notif_register_t reg = {.context = queues, + .domain = domain, + .notifier_fn = dspqueue_notif_callback}; + nErr = remote_session_control(FASTRPC_REGISTER_STATUS_NOTIFICATIONS, + (void *)®, sizeof(reg)); + if (nErr == AEE_EUNSUPPORTED) { + FARF(ERROR, "Warning 0x%x: %s: DSP doesn't support status notification", + nErr, __func__); + nErr = 0; + } else if (!nErr) { + queues->notif_registered[domain] = 1; + } else { + goto bail; + } + } + + // Allocate shared state structure and pass to DSP + VERIFYC((dq->state = rpcmem_alloc( + RPCMEM_HEAP_ID_SYSTEM, RPCMEM_DEFAULT_FLAGS | RPCMEM_HEAP_NOREG, + sizeof(struct dspqueue_process_queue_state))) != NULL, + AEE_ENORPCMEMORY); + VERIFYC((((uintptr_t)dq->state) & 4095) == 0, AEE_ERPC); + VERIFYC((dq->state_fd = rpcmem_to_fd(dq->state)) > 0, AEE_ERPC); + VERIFY((nErr = fastrpc_mmap(domain, dq->state_fd, dq->state, 0, + sizeof(struct dspqueue_process_queue_state), + FASTRPC_MAP_FD)) == 0); + state_mapped = 1; + VERIFY((nErr = dspqueue_rpc_init_process_state(dq->dsp_handle, + dq->state_fd)) == 0); + + // Check if we have driver signaling (a.k.a. dspsignal) support + nErr = fastrpc_get_cap(domain, DSPSIGNAL_DSP_SUPPORT, &cap); + if ((nErr != 0) || (cap == 0)) { + FARF(HIGH, "dspqueue: No driver signaling support on DSP"); + } else { + nErr = fastrpc_get_cap(domain, DSPSIGNAL_DRIVER_SUPPORT, &cap); + if ((nErr != 0) || (cap == 0)) { + FARF(HIGH, "dspqueue: No driver signaling support in CPU driver"); + } else { + FARF(HIGH, "dspqueue: Optimized driver signaling supported"); + dq->have_dspsignal = 1; + } + } + + if (!dq->have_dspsignal) { + // Create thread and resources to send signals to the DSP + VERIFY((nErr = pthread_mutex_init(&dq->send_signal_mutex, NULL)) == 0); + sendmutex = 1; + VERIFY((nErr = pthread_cond_init(&dq->send_signal_cond, NULL)) == 0); + sendcond = 1; + dq->send_signal_mask = 0; + pthread_attr_init(&tattr); + pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE); + VERIFY((nErr = pthread_create(&dq->send_signal_thread, &tattr, + dspqueue_send_signal_thread, dq)) == 0); + sendthread = 1; + + // Create thread to receive signals from the DSP + pthread_attr_init(&tattr); + pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE); + VERIFY((nErr = pthread_create(&dq->receive_signal_thread, &tattr, + dspqueue_receive_signal_thread, dq)) == 0); + recvthread = 1; + } + + free_skel_uri(&dspqueue_skel); + queues->domain_queues[domain] = dq; + return AEE_SUCCESS; + +bail: + if (dq) { + if (recvthread) { + void *res; + dspqueue_rpc_cancel_wait_signal(dq->dsp_handle); + pthread_join(dq->receive_signal_thread, &res); + } + if (sendthread) { + void *res; + pthread_mutex_lock(&dq->send_signal_mutex); + dq->send_signal_mask |= SIGNAL_BIT_CANCEL; + pthread_cond_signal(&dq->send_signal_cond); + pthread_mutex_unlock(&dq->send_signal_mutex); + pthread_join(dq->send_signal_thread, &res); + } + if (sendcond) { + pthread_cond_destroy(&dq->send_signal_cond); + } + if (sendmutex) { + pthread_mutex_destroy(&dq->send_signal_mutex); + } + if (state_mapped) { + fastrpc_munmap(domain, dq->state_fd, dq->state, + sizeof(struct dspqueue_process_queue_state)); + } + if (dq->dsp_handle) { + dspqueue_rpc_close(dq->dsp_handle); + } + if (dq->state) { + rpcmem_free(dq->state); + } + free(dq); + } + free_skel_uri(&dspqueue_skel); + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed (domain %d) errno %s", nErr, __func__, + domain, strerror(errno)); + } + return nErr; +} + +// Must hold queues->mutex. +static AEEResult destroy_domain_queues_locked(int domain) { + + AEEResult nErr = AEE_SUCCESS; + struct dspqueue_domain_queues *dq = NULL; + void *ret; + + errno = 0; + FARF(HIGH, "destroy_domain_queues_locked"); + assert(domain < NUM_DOMAINS_EXTEND); + assert(queues->domain_queues[domain] != NULL); + dq = queues->domain_queues[domain]; + assert(dq->num_queues == 0); + + if (!dq->have_dspsignal) { + if (dq->dsp_error) { + // Ignore errors if the DSP process died + dspqueue_rpc_cancel_wait_signal(dq->dsp_handle); + } else { + VERIFY((nErr = dspqueue_rpc_cancel_wait_signal(dq->dsp_handle)) == 0); + } + FARF(MEDIUM, "Join receive signal thread"); + VERIFY((nErr = pthread_join(dq->receive_signal_thread, &ret)) == 0); + FARF(MEDIUM, " - Join receive signal thread done"); + if (!dq->dsp_error) { + VERIFY(((uintptr_t)ret) == 0); + } + + pthread_mutex_lock(&dq->send_signal_mutex); + dq->send_signal_mask |= SIGNAL_BIT_CANCEL; + pthread_cond_signal(&dq->send_signal_cond); + pthread_mutex_unlock(&dq->send_signal_mutex); + FARF(MEDIUM, "Join send signal thread"); + VERIFY((nErr = pthread_join(dq->send_signal_thread, &ret)) == 0); + if (!dq->dsp_error) { + VERIFY(((uintptr_t)ret) == 0); + } + FARF(MEDIUM, " - Join send signal thread done"); + + pthread_cond_destroy(&dq->send_signal_cond); + pthread_mutex_destroy(&dq->send_signal_mutex); + } + + if (dq->dsp_error) { + dspqueue_rpc_close(dq->dsp_handle); + fastrpc_munmap(dq->domain, dq->state_fd, dq->state, + sizeof(struct dspqueue_process_queue_state)); + } else { + VERIFY((nErr = dspqueue_rpc_close(dq->dsp_handle)) == 0); + VERIFY((nErr = fastrpc_munmap( + dq->domain, dq->state_fd, dq->state, + sizeof(struct dspqueue_process_queue_state))) == 0); + } + + rpcmem_free(dq->state); + free(dq); + + queues->domain_queues[domain] = NULL; + +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed (domain %d) errno %s", nErr, __func__, + domain, strerror(errno)); + } + return nErr; +} + +AEEResult dspqueue_create(int domain, uint32_t flags, uint32_t req_queue_size, + uint32_t resp_queue_size, + dspqueue_callback_t packet_callback, + dspqueue_callback_t error_callback, + void *callback_context, dspqueue_t *queue) { + + struct dspqueue *q = NULL; + AEEResult nErr = AEE_SUCCESS; + uint32_t o; + int mutex_init = 0; + pthread_attr_t tattr; + unsigned id = DSPQUEUE_MAX_PROCESS_QUEUES; + struct dspqueue_domain_queues *dq = NULL; + int packetmutex = 0, packetcond = 0, spacemutex = 0, spacecond = 0; + int callbackthread = 0; + uint32_t queue_count; + int queue_mapped = 0; + unsigned signals = 0; + + VERIFYC(queue, AEE_EBADPARM); + *queue = NULL; + errno = 0; + + if (domain == -1) { + PRINT_WARN_USE_DOMAINS(); + domain = get_current_domain(); + if ((domain < 0) || (domain >= NUM_DOMAINS_EXTEND)) { + return AEE_ERPC; + } + } else if ((domain < 0) || (domain >= NUM_DOMAINS_EXTEND)) { + return AEE_EBADPARM; + } + + // Initialize process-level and per-domain queue structures and signaling + if (pthread_once(&queues_once, init_process_queues_once) != 0) { + FARF(ERROR, "dspqueue init failed"); + return AEE_ERPC; + } + pthread_mutex_lock(&queues->mutex); + if ((nErr = init_domain_queues_locked(domain)) != 0) { + pthread_mutex_unlock(&queues->mutex); + return nErr; + } + dq = queues->domain_queues[domain]; + if (!dq) { + FARF(ERROR, "No queues in process for domain %d", domain); + pthread_mutex_unlock(&queues->mutex); + return AEE_EBADPARM; + } + if ((dq && (dq->num_queues >= DSPQUEUE_MAX_PROCESS_QUEUES))) { + FARF(ERROR, "Too many queues in process for domain %d", domain); + pthread_mutex_unlock(&queues->mutex); + return AEE_EBADPARM; + } + dq->num_queues++; + queue_count = queues->count++; + pthread_mutex_unlock(&queues->mutex); + + // Find a free queue slot + pthread_mutex_lock(&dq->queue_list_mutex); + for (id = 0; id < DSPQUEUE_MAX_PROCESS_QUEUES; id++) { + if (dq->queues[id] == UNUSED_QUEUE) { + if (dq->max_queue < id) { + dq->max_queue = id; + } + break; + } + } + if (id >= DSPQUEUE_MAX_PROCESS_QUEUES) { + FARF(ERROR, "Queue list corrupt"); + pthread_mutex_unlock(&dq->queue_list_mutex); + nErr = AEE_ERPC; + goto bail; + } + dq->queues[id] = INVALID_QUEUE; + pthread_mutex_unlock(&dq->queue_list_mutex); + + VERIFYC(flags == 0, AEE_EBADPARM); + + // Check queue size limits + VERIFYC(req_queue_size <= DSPQUEUE_MAX_QUEUE_SIZE, AEE_EBADPARM); + VERIFYC(resp_queue_size <= DSPQUEUE_MAX_QUEUE_SIZE, AEE_EBADPARM); + + // Allocate internal queue structure + VERIFYC((q = calloc(1, sizeof(*q))) != NULL, AEE_ENOMEMORY); + VERIFY((nErr = pthread_mutex_init(&q->mutex, NULL)) == 0); + mutex_init = 1; + q->packet_callback = packet_callback; + q->error_callback = error_callback; + q->callback_context = callback_context; + q->id = id; + q->domain = domain; + + // Use defaults for unspecified parameters + if (req_queue_size == 0) { + req_queue_size = DSPQUEUE_DEFAULT_REQ_SIZE; + } + if (resp_queue_size == 0) { + resp_queue_size = DSPQUEUE_DEFAULT_RESP_SIZE; + } + + // Determine queue shared memory size and allocate memory. The memory + // contains: + // - Queue headers + // - Read and write states for both request and response queues (four total) + // - Request and response queues + // All are aligned to QUEUE_CACHE_ALIGN. + q->user_queue_size = + CACHE_ALIGN_SIZE(sizeof(struct dspqueue_header)) + + 4 * CACHE_ALIGN_SIZE(sizeof(struct dspqueue_packet_queue_state)) + + CACHE_ALIGN_SIZE(req_queue_size) + CACHE_ALIGN_SIZE(resp_queue_size); + + // Allocate queue shared memory and map to DSP + VERIFYC((q->user_queue = rpcmem_alloc( + RPCMEM_HEAP_ID_SYSTEM, RPCMEM_DEFAULT_FLAGS | RPCMEM_HEAP_NOREG, + q->user_queue_size)) != NULL, + AEE_ENOMEMORY); + VERIFYC((((uintptr_t)q->user_queue) & 4095) == 0, AEE_ERPC); + VERIFYC((q->user_queue_fd = rpcmem_to_fd(q->user_queue)) > 0, AEE_ERPC); + VERIFY((nErr = fastrpc_mmap(domain, q->user_queue_fd, q->user_queue, 0, + q->user_queue_size, FASTRPC_MAP_FD)) == 0); + queue_mapped = 1; + q->header = q->user_queue; + + // Initialize queue header, including all offsets, and clear the queue + memset(q->header, 0, q->user_queue_size); + q->header->version = 1; + q->header->queue_count = queue_count; + q->queue_count = queue_count; + + // Request packet queue (CPU->DSP) + o = CACHE_ALIGN_SIZE(sizeof(struct dspqueue_header)); + q->header->req_queue.queue_offset = o; + q->header->req_queue.queue_length = req_queue_size; + o += CACHE_ALIGN_SIZE(req_queue_size); + q->header->req_queue.read_state_offset = o; + o += CACHE_ALIGN_SIZE(sizeof(struct dspqueue_packet_queue_state)); + q->header->req_queue.write_state_offset = o; + o += CACHE_ALIGN_SIZE(sizeof(struct dspqueue_packet_queue_state)); + + // Response packet queue (DSP->CPU) + q->header->resp_queue.queue_offset = o; + q->header->resp_queue.queue_length = resp_queue_size; + o += CACHE_ALIGN_SIZE(resp_queue_size); + q->header->resp_queue.read_state_offset = o; + o += CACHE_ALIGN_SIZE(sizeof(struct dspqueue_packet_queue_state)); + q->header->resp_queue.write_state_offset = o; + o += CACHE_ALIGN_SIZE(sizeof(struct dspqueue_packet_queue_state)); + + assert(o == q->user_queue_size); + + dq->state->req_packet_count[id] = 0; + cache_flush_word(&dq->state->req_packet_count[id]); + dq->state->resp_space_count[id] = 0; + cache_flush_word(&dq->state->resp_space_count[id]); + + // Try to create driver signals + if (dq->have_dspsignal) { + q->have_driver_signaling = 1; + for (signals = 0; signals < DSPQUEUE_NUM_SIGNALS; signals++) { + VERIFY((nErr = dspsignal_create(domain, QUEUE_SIGNAL(id, signals), 0)) == + AEE_SUCCESS); + } + } + + // First attempt to create the queue with an invalid version. If the call + // succeeds we know the DSP side is ignoring the version and flags and does + // not support wait counts in the header, driver signaling, or any other + // post-v1 features. Unfortunately the initial DSP codebase ignores the + // version and flags... + q->header->version = MAX_UINT32; + nErr = dspqueue_rpc_create_queue(dq->dsp_handle, q->id, q->user_queue_fd, + queue_count, &q->dsp_id); + if ((nErr == AEE_EUNSUPPORTED) || + (nErr == (int)(DSP_AEE_EOFFSET + AEE_EUNSUPPORTED))) { + // OK, the DSP does pay attention to the version. It should also support + // wait counts and optionally driver signaling. Create the queue. + FARF(HIGH, "Initial queue create failed with %0x%x as expected", nErr); + q->header->version = DSPQUEUE_HEADER_CURRENT_VERSION; + q->header->flags = DSPQUEUE_HEADER_FLAG_WAIT_COUNTS; + if (q->have_driver_signaling) { + q->header->flags |= DSPQUEUE_HEADER_FLAG_DRIVER_SIGNALING; + } + VERIFY((nErr = dspqueue_rpc_create_queue(dq->dsp_handle, q->id, + q->user_queue_fd, queue_count, + &q->dsp_id)) == 0); + q->have_wait_counts = 1; + // Note that we expect the DSP will support both wait counts and driver + // signaling or neither. However we can operate with wait counts only in + // case we have an updated DSP image but an older CPU kernel driver without + // driver signaling support. + } else if (nErr != AEE_SUCCESS) { + FARF(ERROR, "dspqueue_rpc_create_queue failed: 0x%x", nErr); + goto bail; + } else { + FARF(HIGH, "First-cut queue create succeeded unexpectedly? 0x%x", nErr); + // No new features available, including driver signaling + if (q->have_driver_signaling) { + unsigned i; + FARF(HIGH, "Driver signaling not supported on DSP, fall back to FastRPC " + "signaling"); + for (i = 0; i < signals; i++) { + VERIFY((nErr = dspsignal_destroy(domain, QUEUE_SIGNAL(id, i))) == 0); + } + signals = 0; + } + q->have_driver_signaling = 0; + } + + // Create synchronization resources + VERIFY((nErr = pthread_mutex_init(&q->packet_mutex, NULL)) == 0); + packetmutex = 1; + VERIFY((nErr = pthread_mutex_init(&q->space_mutex, NULL)) == 0); + spacemutex = 1; + if (!q->have_driver_signaling) { + VERIFY((nErr = pthread_cond_init(&q->packet_cond, NULL)) == 0); + packetcond = 1; + VERIFY((nErr = pthread_cond_init(&q->space_cond, NULL)) == 0); + packetcond = 1; + } + + // Callback thread (if we have a message callback) + if (q->packet_callback) { + pthread_attr_init(&tattr); + pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE); + VERIFY((nErr = pthread_create(&q->packet_callback_thread, &tattr, + dspqueue_packet_callback_thread, q)) == 0); + callbackthread = 1; + } + + *queue = q; + pthread_mutex_lock(&dq->queue_list_mutex); + dq->queues[id] = q; + pthread_mutex_unlock(&dq->queue_list_mutex); + FARF(ALWAYS, "%s: created Queue %u, %p, DSP 0x%08x for domain %d", __func__, + q->id, q, (unsigned)q->dsp_id, q->domain); + + return AEE_SUCCESS; + +bail: + if (q) { + if (callbackthread) { + if (q->have_driver_signaling) { + dspsignal_cancel_wait(domain, + QUEUE_SIGNAL(id, DSPQUEUE_SIGNAL_RESP_PACKET)); + } else { + pthread_mutex_lock(&q->packet_mutex); + q->packet_mask |= SIGNAL_BIT_CANCEL; + pthread_cond_signal(&q->packet_cond); + pthread_mutex_unlock(&q->packet_mutex); + } + } + if (q->have_driver_signaling && (signals > 0)) { + unsigned i; + for (i = 0; i < signals; i++) { + dspsignal_destroy(domain, QUEUE_SIGNAL(id, i)); + } + } + if (packetmutex) { + pthread_mutex_destroy(&q->packet_mutex); + } + if (packetcond) { + pthread_cond_destroy(&q->packet_cond); + } + if (spacemutex) { + pthread_mutex_destroy(&q->space_mutex); + } + if (spacecond) { + pthread_cond_destroy(&q->space_cond); + } + if (q->dsp_id) { + dspqueue_rpc_destroy_queue(dq->dsp_handle, q->dsp_id); + } + if (queue_mapped) { + fastrpc_munmap(domain, q->user_queue_fd, q->user_queue, + q->user_queue_size); + } + if (q->user_queue) { + rpcmem_free(q->user_queue); + } + if (mutex_init) { + pthread_mutex_destroy(&q->mutex); + } + free(q); + } + if (dq != NULL) { + if (id < DSPQUEUE_MAX_PROCESS_QUEUES) { + pthread_mutex_lock(&dq->queue_list_mutex); + dq->queues[id] = UNUSED_QUEUE; + pthread_mutex_unlock(&dq->queue_list_mutex); + } + pthread_mutex_lock(&queues->mutex); + assert(dq->num_queues > 0); + dq->num_queues--; + if (dq->num_queues == 0) { + // This would have been the first queue for this domain + destroy_domain_queues_locked(domain); + } + pthread_mutex_unlock(&queues->mutex); + } + if (nErr != AEE_SUCCESS) { + FARF(ERROR, + "Error 0x%x: %s failed (domain %d, flags 0x%x, sizes %u, %u errno %s)", + nErr, __func__, domain, (unsigned)flags, (unsigned)req_queue_size, + (unsigned)resp_queue_size, strerror(errno)); + } + return nErr; +} + +AEEResult dspqueue_close(dspqueue_t queue) { + + struct dspqueue *q = queue; + struct dspqueue_domain_queues *dq = NULL; + AEEResult nErr = AEE_SUCCESS; + int32_t imported; + unsigned i; + + errno = 0; + VERIFYC(q, AEE_EBADPARM); + VERIFYC(q->domain >= 0 && q->domain < NUM_DOMAINS_EXTEND, AEE_EINVALIDDOMAIN); + pthread_mutex_lock(&queues->mutex); + dq = queues->domain_queues[q->domain]; + if (dq == NULL) { + FARF(ERROR, "No domain queues"); + pthread_mutex_unlock(&queues->mutex); + return AEE_ERPC; + } + pthread_mutex_unlock(&queues->mutex); + + // Check if the queue is still imported on the DSP + if (!dq->dsp_error) { + VERIFY((nErr = dspqueue_rpc_is_imported(dq->dsp_handle, q->dsp_id, + &imported)) == 0); + if (imported) { + FARF(ERROR, "Attempting to close queue 0x%p still open on the DSP", + queue); + nErr = AEE_EBADPARM; + goto bail; + } + } + + VERIFYC(q->header->queue_count == q->queue_count, AEE_ERPC); + + pthread_mutex_lock(&dq->queue_list_mutex); + dq->queues[q->id] = INVALID_QUEUE; + pthread_mutex_unlock(&dq->queue_list_mutex); + + if (q->error_callback_thread) { + nErr = pthread_join(q->error_callback_thread, NULL); + if (nErr == EDEADLK || nErr == EINVAL) { + FARF(ERROR, + "Error %d: %s: Error callback thread join failed for thread : %d", + nErr, __func__, q->error_callback_thread); + nErr = AEE_ERPC; + q->error_callback_thread = 0; + goto bail; + } + nErr = AEE_SUCCESS; + q->error_callback_thread = 0; + } + + // Cancel any outstanding blocking read/write calls (from callback threads) + if (q->have_driver_signaling) { + // Cancel driver signal waits + for (i = 0; i < DSPQUEUE_NUM_SIGNALS; i++) { + nErr = dspsignal_cancel_wait(q->domain, QUEUE_SIGNAL(q->id, i)); + if (nErr && nErr != AEE_EBADSTATE) { + goto bail; + } + } + } else { + pthread_mutex_lock(&q->packet_mutex); + q->packet_mask |= SIGNAL_BIT_CANCEL; + pthread_cond_broadcast(&q->packet_cond); + pthread_mutex_unlock(&q->packet_mutex); + pthread_mutex_lock(&q->space_mutex); + q->space_mask |= SIGNAL_BIT_CANCEL; + pthread_cond_broadcast(&q->space_cond); + pthread_mutex_unlock(&q->space_mutex); + } + + if (q->packet_callback) { + void *ret; + FARF(MEDIUM, "Join packet callback thread"); + nErr = pthread_join(q->packet_callback_thread, &ret); + /* Ignore error if thread has already exited */ + if (nErr && nErr != ESRCH) { + FARF( + ERROR, + "Error: %s: packet callback thread for queue %p joined with error %d", + __func__, q, nErr); + goto bail; + } + FARF(MEDIUM, " - Join packet callback thread done"); + VERIFY((uintptr_t)ret == 0); + } + + if (dq->dsp_error) { + // Ignore errors if the process died + dspqueue_rpc_destroy_queue(dq->dsp_handle, q->dsp_id); + fastrpc_munmap(dq->domain, q->user_queue_fd, q->user_queue, + q->user_queue_size); + } else { + VERIFY((nErr = dspqueue_rpc_destroy_queue(dq->dsp_handle, q->dsp_id)) == 0); + VERIFY((nErr = fastrpc_munmap(dq->domain, q->user_queue_fd, q->user_queue, + q->user_queue_size)) == 0); + } + rpcmem_free(q->user_queue); + + if (q->have_driver_signaling) { + FARF(MEDIUM, "%s: Destroy signals", __func__); + for (i = 0; i < DSPQUEUE_NUM_SIGNALS; i++) { + nErr = dspsignal_destroy(q->domain, QUEUE_SIGNAL(q->id, i)); + if (nErr && nErr != AEE_EBADSTATE) { + goto bail; + } + } + } + + if (!q->have_driver_signaling) { + pthread_cond_destroy(&q->packet_cond); + pthread_cond_destroy(&q->space_cond); + } + pthread_mutex_destroy(&q->packet_mutex); + pthread_mutex_destroy(&q->space_mutex); + pthread_mutex_destroy(&q->mutex); + + pthread_mutex_lock(&dq->queue_list_mutex); + dq->queues[q->id] = UNUSED_QUEUE; + dq->max_queue = 0; + for (i = 0; i < DSPQUEUE_MAX_PROCESS_QUEUES; i++) { + if (dq->queues[i] != UNUSED_QUEUE) { + dq->max_queue = i; + } + } + pthread_mutex_unlock(&dq->queue_list_mutex); + + pthread_mutex_lock(&queues->mutex); + dq->num_queues--; + if (dq->num_queues == 0) { + FARF(ALWAYS, "%s: destroying queues and signals for domain %d", __func__, + q->domain); + destroy_domain_queues_locked(q->domain); + if (q->have_driver_signaling) + dspsignal_domain_deinit(q->domain); + } + pthread_mutex_unlock(&queues->mutex); + FARF(ALWAYS, "%s: closed Queue %u, %p, DSP 0x%08x for domain %d", __func__, + q->id, q, (unsigned)q->dsp_id, q->domain); + free(q); + +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed errno %s", nErr, __func__, + strerror(errno)); + } + return nErr; +} + +AEEResult dspqueue_export(dspqueue_t queue, uint64_t *queue_id) { + + struct dspqueue *q = queue; + *queue_id = q->dsp_id; + return AEE_SUCCESS; +} + +static void get_queue_state_write(void *memory, + struct dspqueue_packet_queue_header *pq, + uint32_t *space_left, uint32_t *read_pos, + uint32_t *write_pos) { + + struct dspqueue_packet_queue_state *read_state = + (struct dspqueue_packet_queue_state *)(((uintptr_t)memory) + + pq->read_state_offset); + struct dspqueue_packet_queue_state *write_state = + (struct dspqueue_packet_queue_state *)(((uintptr_t)memory) + + pq->write_state_offset); + uint32_t qsize = pq->queue_length; + uint32_t r, w, qleft; + + cache_invalidate_word(&read_state->position); + r = read_state->position; + barrier_full(); + w = write_state->position; + assert(((r & 7) == 0) && ((w & 7) == 0)); + if (space_left != NULL) { + if (r == w) { + qleft = qsize - 8; + } else if (w > r) { + qleft = qsize - w + r - 8; + } else { + qleft = r - w - 8; + } + assert((qleft & 7) == 0); + *space_left = qleft; + } + if (read_pos != NULL) { + *read_pos = r; + } + if (write_pos != NULL) { + *write_pos = w; + } +} + +static void get_queue_state_read(void *memory, + struct dspqueue_packet_queue_header *pq, + uint32_t *data_left, uint32_t *read_pos, + uint32_t *write_pos) { + + struct dspqueue_packet_queue_state *read_state = + (struct dspqueue_packet_queue_state *)(((uintptr_t)memory) + + pq->read_state_offset); + struct dspqueue_packet_queue_state *write_state = + (struct dspqueue_packet_queue_state *)(((uintptr_t)memory) + + pq->write_state_offset); + uint32_t qsize = pq->queue_length; + uint32_t r, w, qleft; + + cache_invalidate_word(&write_state->position); + w = write_state->position; + barrier_full(); + r = read_state->position; + assert(((r & 7) == 0) && ((w & 7) == 0)); + if (data_left != NULL) { + if (r == w) { + qleft = 0; + } else if (w > r) { + qleft = w - r; + } else { + qleft = qsize - r + w; + } + assert((qleft & 7) == 0); + *data_left = qleft; + } + if (read_pos != NULL) { + *read_pos = r; + } + if (write_pos != NULL) { + *write_pos = w; + } +} + +static inline uint32_t write_64(volatile uint8_t *packet_queue, + uint32_t write_pos, uint32_t queue_len, + uint64_t data) { + *(volatile uint64_t *)((uintptr_t)packet_queue + write_pos) = data; + cache_flush_line((void *)((uintptr_t)packet_queue + write_pos)); + write_pos += 8; + if (write_pos >= queue_len) { + write_pos = 0; + } + return write_pos; +} + +static inline uint32_t write_data(volatile uint8_t *packet_queue, + uint32_t write_pos, uint32_t queue_len, + const void *data, uint32_t data_len) { + + uintptr_t qp = (uintptr_t)packet_queue; + + assert(data != NULL); + assert(data_len > 0); + assert((write_pos & 7) == 0); + assert((queue_len - write_pos) >= data_len); + + memcpy((void *)(qp + write_pos), data, data_len); + cache_flush((void *)(qp + write_pos), data_len); + write_pos += (data_len + 7) & (~7); + assert(write_pos <= queue_len); + if (write_pos >= queue_len) { + write_pos = 0; + } + + return write_pos; +} + +// Timespec difference in microseconds (a-b). If aUINT32_MAX returns UINT32_MAX +static uint32_t timespec_diff_us(struct timespec *a, struct timespec *b) { + int64_t diffsec = ((int64_t)a->tv_sec) - ((int64_t)b->tv_sec); + int64_t diffnsec = a->tv_nsec - b->tv_nsec; + int64_t diffusec; + + if ((diffsec < 0) || ((diffsec == 0) && (diffnsec < 0))) { + return 0; + } + if (diffsec > UINT32_MAX) { + // Would overflow for sure + return UINT32_MAX; + } + diffusec = (diffsec * 1000000LL) + (diffnsec / 1000LL); + if (diffusec > UINT32_MAX) { + return UINT32_MAX; + } + return (uint32_t)diffusec; +} + +// Send a signal +static AEEResult send_signal(struct dspqueue *q, uint32_t signal_no) { + + struct dspqueue_domain_queues *dq = queues->domain_queues[q->domain]; + int nErr = AEE_SUCCESS; + + if (q->have_driver_signaling) { + VERIFYC(signal_no < DSPQUEUE_NUM_SIGNALS, AEE_EBADPARM); + VERIFY((nErr = dspsignal_signal(q->domain, + QUEUE_SIGNAL(q->id, signal_no))) == 0); + } else { + pthread_mutex_lock(&dq->send_signal_mutex); + dq->send_signal_mask |= SIGNAL_BIT_SIGNAL; + pthread_cond_signal(&dq->send_signal_cond); + pthread_mutex_unlock(&dq->send_signal_mutex); + } + +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed for queue %p signal %u", nErr, __func__, + q, (unsigned)signal_no); + } + return nErr; +} + +// Wait for a signal with an optional timeout. +// Set timeout to the expiry time (not length of timeout) or NULL for an +// infinite wait. Only DSPQUEUE_SIGNAL_REQ_SPACE and DSPQUEUE_SIGNAL_RESP_PACKET +// supported. The appropriate mutex must be locked. +static AEEResult wait_signal_locked(struct dspqueue *q, uint32_t signal_no, + struct timespec *timeout) { + + AEEResult nErr = AEE_SUCCESS; + + if (q->have_driver_signaling) { + uint32_t to_now; + + if (timeout) { + struct timespec now; + VERIFYC(clock_gettime(CLOCK_REALTIME, &now) == 0, AEE_EFAILED); + to_now = timespec_diff_us(timeout, &now); // microseconds until expiry + if (to_now == 0) { + return AEE_EEXPIRED; + } + } else { + to_now = DSPSIGNAL_TIMEOUT_NONE; + } + + VERIFY((nErr = dspsignal_wait(q->domain, QUEUE_SIGNAL(q->id, signal_no), + to_now)) == 0); + + } else { + // Not using driver signaling, wait for the appropriate condition variable + // and its associated state + uint32_t *count; + uint32_t *mask; + pthread_mutex_t *mutex; + pthread_cond_t *cond; + uint32_t c; + + if (signal_no == DSPQUEUE_SIGNAL_REQ_SPACE) { + count = &q->req_space_count; + mask = &q->space_mask; + mutex = &q->space_mutex; + cond = &q->space_cond; + } else if (signal_no == DSPQUEUE_SIGNAL_RESP_PACKET) { + count = &q->resp_packet_count; + mask = &q->packet_mask; + mutex = &q->packet_mutex; + cond = &q->packet_cond; + } else { + nErr = AEE_EBADPARM; + goto bail; + } + + c = *count; + if (timeout) { + int rc = 0; + while ((c == *count) && (rc == 0)) { + if (*mask & 2) { + return AEE_EINTERRUPTED; + } + rc = pthread_cond_timedwait(cond, mutex, timeout); + if (rc == ETIMEDOUT) { + return AEE_EEXPIRED; + } + VERIFY(rc == 0); + } + } else { + while (c == *count) { + pthread_cond_wait(cond, mutex); + if (*mask & 2) { + return AEE_EINTERRUPTED; + } + } + } + } + +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed for queue %p signal %u", nErr, __func__, + q, (unsigned)signal_no); + } + return nErr; +} + +AEEResult dspqueue_write_noblock(dspqueue_t queue, uint32_t flags, + uint32_t num_buffers, + struct dspqueue_buffer *buffers, + uint32_t message_length, + const uint8_t *message) { + + AEEResult nErr = AEE_SUCCESS; + struct dspqueue *q = queue; + struct dspqueue_packet_queue_header *pq = &q->header->req_queue; + volatile uint8_t *qp = + (volatile uint8_t *)(((uintptr_t)q->header) + pq->queue_offset); + struct dspqueue_packet_queue_state *read_state = + (struct dspqueue_packet_queue_state *)(((uintptr_t)q->header) + + pq->read_state_offset); + struct dspqueue_packet_queue_state *write_state = + (struct dspqueue_packet_queue_state *)(((uintptr_t)q->header) + + pq->write_state_offset); + struct dspqueue_domain_queues *dq = queues->domain_queues[q->domain]; + unsigned len, alen; + uint32_t r, w; + uint32_t qleft; + uint32_t qsize = pq->queue_length; + int locked = 0; + uint64_t phdr; + int wrap = 0; + uint32_t i; + uint32_t buf_refs = 0; + + // Check properties + VERIFYC(num_buffers <= DSPQUEUE_MAX_BUFFERS, AEE_EBADPARM); + VERIFYC(message_length <= DSPQUEUE_MAX_MESSAGE_SIZE, AEE_EBADPARM); + + // Prepare flags + if (num_buffers > 0) { + flags |= DSPQUEUE_PACKET_FLAG_BUFFERS; + VERIFYC(buffers != NULL, AEE_EBADPARM); + } else { + flags &= ~DSPQUEUE_PACKET_FLAG_BUFFERS; + } + if (message_length > 0) { + flags |= DSPQUEUE_PACKET_FLAG_MESSAGE; + VERIFYC(message != NULL, AEE_EBADPARM); + } else { + flags &= ~DSPQUEUE_PACKET_FLAG_MESSAGE; + } + + // Calculate packet length in the queue + assert(sizeof(struct dspqueue_buffer) == 24); + len = 8 + num_buffers * sizeof(struct dspqueue_buffer) + message_length; + alen = (len + 7) & (~7); + + if (alen > (qsize - 8)) { + FARF(ERROR, "Packet size %u too large for queue size %u", (unsigned)len, + (unsigned)qsize); + nErr = AEE_EBADPARM; + goto bail; + } + + pthread_mutex_lock(&q->mutex); + locked = 1; + + VERIFYC(q->header->queue_count == q->queue_count, AEE_ERPC); + + // Check that we have space for the packet in the queue + get_queue_state_write(q->header, pq, &qleft, &r, &w); + if (qleft < alen) { + pthread_mutex_unlock(&q->mutex); + return AEE_EWOULDBLOCK; + } + if ((qsize - w) < alen) { + // Don't wrap the packet around queue end, but rather move it to the + // beginning, replicating the header + wrap = 1; + if ((qleft - (qsize - w)) < alen) { + pthread_mutex_unlock(&q->mutex); + return AEE_EWOULDBLOCK; + } + } + + // Go through buffers + for (i = 0; i < num_buffers; i++) { + struct dspqueue_buffer *b = &buffers[i]; + void *va; + size_t size; + + // Find buffer in internal FastRPC structures and handle refcounts + if (b->flags & DSPQUEUE_BUFFER_FLAG_REF) { + VERIFYC((b->flags & DSPQUEUE_BUFFER_FLAG_DEREF) == 0, AEE_EBADPARM); + nErr = fastrpc_buffer_ref(q->domain, b->fd, 1, &va, &size); + } else if (b->flags & DSPQUEUE_BUFFER_FLAG_DEREF) { + nErr = fastrpc_buffer_ref(q->domain, b->fd, -1, &va, &size); + } else { + nErr = fastrpc_buffer_ref(q->domain, b->fd, 0, &va, &size); + } + if (nErr == AEE_ENOSUCHMAP) { + FARF(ERROR, "Buffer FD %d in queue message not mapped to domain %d", + b->fd, q->domain); + goto bail; + } + VERIFY(nErr == 0); + buf_refs = i + 1; + + // Ensure buffer offset and size are within the buffer as mapped. + // Use mapped size if not specified by the client + if (b->size != 0) { + uint64_t bend = ((uint64_t)b->offset) + ((uint64_t)b->size); + VERIFYC(bend <= size, AEE_EBADPARM); + // Calculate new bounds for cache ops + va = (void *)(((uintptr_t)va) + b->offset); + size = b->size; + } else { + VERIFYC(b->offset == 0, AEE_EBADPARM); + } + } + + // Write packet header + flags |= DSPQUEUE_PACKET_FLAG_USER_READY; + phdr = + (((uint64_t)(len & 0xffffffff)) | (((uint64_t)(flags & 0xffff)) << 32) | + (((uint64_t)(num_buffers & 0xff)) << 48) | + (((uint64_t)(q->seq_no & 0xff)) << 56)); + w = write_64(qp, w, qsize, phdr); + if (wrap) { + // Write the packet at the beginning of the queue, + // replicating the header + w = write_64(qp, 0, qsize, phdr); + } + + // Write buffer information + if (num_buffers > 0) { + w = write_data(qp, w, qsize, buffers, + num_buffers * sizeof(struct dspqueue_buffer)); + } + + // Write message + if (message_length > 0) { + w = write_data(qp, w, qsize, message, message_length); + } + + // Update write pointer. This marks the message available in the user queue + q->write_packet_count++; + barrier_store(); + write_state->position = w; + write_state->packet_count = q->write_packet_count; + cache_flush_line(write_state); + + // Signal that we've written a packet + q->req_packet_count++; + dq->state->req_packet_count[q->id] = q->req_packet_count; + FARF(LOW, "Queue %u req_packet_count %u", (unsigned)q->id, + (unsigned)q->req_packet_count); + cache_flush_word(&dq->state->req_packet_count[q->id]); + if (q->have_wait_counts) { + // Only send a signal if the other end is potentially waiting + cache_invalidate_word(&read_state->wait_count); + if (read_state->wait_count) { + FARF(MEDIUM, "%s: Send signal", __func__); + VERIFY((nErr = send_signal(q, DSPQUEUE_SIGNAL_REQ_PACKET)) == 0); + } else { + FARF(MEDIUM, "%s: Don't send signal", __func__); + } + } else { + FARF(MEDIUM, "%s: No wait counts - send signal", __func__); + VERIFY((nErr = send_signal(q, DSPQUEUE_SIGNAL_REQ_PACKET)) == 0); + } + + q->seq_no++; + + pthread_mutex_unlock(&q->mutex); + locked = 0; + return 0; + +bail: + for (i = 0; i < buf_refs; i++) { + // Undo buffer reference changes + struct dspqueue_buffer *b = &buffers[i]; + if (b->flags & DSPQUEUE_BUFFER_FLAG_REF) { + fastrpc_buffer_ref(q->domain, b->fd, -1, NULL, NULL); + } else if (b->flags & DSPQUEUE_BUFFER_FLAG_DEREF) { + fastrpc_buffer_ref(q->domain, b->fd, 1, NULL, NULL); + } + } + if (locked) { + pthread_mutex_unlock(&q->mutex); + } + if (nErr != AEE_SUCCESS) { + FARF(ERROR, + "Error 0x%x: %s failed for queue %p (flags 0x%x, num_buffers %u, " + "message_length %u)", + nErr, __func__, queue, (unsigned)flags, (unsigned)num_buffers, + (unsigned)message_length); + } + return nErr; +} + +static void timespec_add_us(struct timespec *ts, uint32_t us) { + uint64_t ns = (uint64_t)ts->tv_nsec + (uint64_t)(1000 * (us % 1000000)); + if (ns > 1000000000ULL) { + ts->tv_nsec = (long)(ns - 1000000000ULL); + ts->tv_sec += (us / 1000000) + 1; + } else { + ts->tv_nsec = ns; + ts->tv_sec += us / 1000000; + } +} + +AEEResult dspqueue_write(dspqueue_t queue, uint32_t flags, uint32_t num_buffers, + struct dspqueue_buffer *buffers, + uint32_t message_length, const uint8_t *message, + uint32_t timeout_us) { + + AEEResult nErr = AEE_SUCCESS; + struct dspqueue *q = queue; + struct dspqueue_packet_queue_header *pq = &q->header->req_queue; + struct dspqueue_packet_queue_state *write_state = + (struct dspqueue_packet_queue_state *)(((uintptr_t)q->header) + + pq->write_state_offset); + _Atomic uint32_t *wait_count = (_Atomic uint32_t *)&write_state->wait_count; + int waiting = 0; + struct timespec *timeout_ts = NULL; // no timeout by default + struct timespec ts; + + errno = 0; + pthread_mutex_lock(&q->space_mutex); + + // Try a write first before dealing with timeouts + nErr = dspqueue_write_noblock(queue, flags, num_buffers, buffers, + message_length, message); + if (nErr != AEE_EWOULDBLOCK) { + // Write got through or failed permanently + goto bail; + } + + if (q->have_wait_counts) { + // Flag that we're potentially waiting and try again + atomic_fetch_add(wait_count, 1); + cache_flush_word(wait_count); + waiting = 1; + nErr = dspqueue_write_noblock(queue, flags, num_buffers, buffers, + message_length, message); + if (nErr != AEE_EWOULDBLOCK) { + goto bail; + } + } + + if (timeout_us != DSPQUEUE_TIMEOUT_NONE) { + // Calculate timeout expiry and use timeout + VERIFYC(clock_gettime(CLOCK_REALTIME, &ts) == 0, AEE_EFAILED); + timespec_add_us(&ts, timeout_us); + timeout_ts = &ts; + } + + while (1) { + FARF(LOW, "Queue %u wait space", (unsigned)q->id); + VERIFY((nErr = wait_signal_locked(q, DSPQUEUE_SIGNAL_REQ_SPACE, + timeout_ts)) == 0); + FARF(LOW, "Queue %u got space", (unsigned)q->id); + nErr = dspqueue_write_noblock(queue, flags, num_buffers, buffers, + message_length, message); + if (nErr != AEE_EWOULDBLOCK) { + goto bail; + } + } + +bail: + if (waiting) { + atomic_fetch_sub(wait_count, 1); + cache_flush_word(wait_count); + } + pthread_mutex_unlock(&q->space_mutex); + if (nErr != AEE_SUCCESS) { + FARF(ERROR, + "Error 0x%x: %s failed for queue %p (flags 0x%x, num_buffers %u, " + "message_length %u errno %s)", + nErr, __func__, queue, (unsigned)flags, (unsigned)num_buffers, + (unsigned)message_length, strerror(errno)); + } + return nErr; +} + +AEEResult dspqueue_write_early_wakeup_noblock(dspqueue_t queue, + uint32_t wakeup_delay, + uint32_t packet_flags) { + + uint32_t flags = packet_flags | DSPQUEUE_PACKET_FLAG_WAKEUP; + + if (wakeup_delay != 0) { + return dspqueue_write_noblock(queue, flags, 0, NULL, 4, + (const uint8_t *)&wakeup_delay); + } else { + return dspqueue_write_noblock(queue, flags, 0, NULL, 0, NULL); + } +} + +static AEEResult peek_locked(volatile const uint8_t *qp, uint32_t r, + uint32_t *flags, uint32_t *num_buffers, + uint32_t *message_length, uint64_t *raw_header) { + + AEEResult nErr = 0; + uint32_t f, nb, len; + uint64_t d; + + // Read packet header + cache_invalidate_line((void *)((uintptr_t)qp + r)); + d = *((uint64_t *)((uintptr_t)qp + r)); + len = d & 0xffffffff; + f = (d >> 32) & 0xffff; + if (f & DSPQUEUE_PACKET_FLAG_BUFFERS) { + nb = (d >> 48) & 0xff; + } else { + nb = 0; + } + VERIFYC(len >= (8 + nb * sizeof(struct dspqueue_buffer)), AEE_EBADITEM); + + // Populate response + if (flags != NULL) { + *flags = f; + } + if (num_buffers != NULL) { + *num_buffers = nb; + } + if (message_length != NULL) { + if (f & DSPQUEUE_PACKET_FLAG_MESSAGE) { + *message_length = len - 8 - nb * sizeof(struct dspqueue_buffer); + } else { + *message_length = 0; + } + } + if (raw_header != NULL) { + *raw_header = d; + } + + // Fall through +bail: + return nErr; +} + +AEEResult dspqueue_peek_noblock(dspqueue_t queue, uint32_t *flags, + uint32_t *num_buffers, + uint32_t *message_length) { + + AEEResult nErr = AEE_SUCCESS; + struct dspqueue *q = queue; + struct dspqueue_packet_queue_header *pq = &q->header->resp_queue; + volatile const uint8_t *qp = + (volatile const uint8_t *)(((uintptr_t)q->header) + pq->queue_offset); + uint32_t r, qleft; + int locked = 0; + + pthread_mutex_lock(&q->mutex); + locked = 1; + + // Check if we have a packet available + get_queue_state_read(q->header, pq, &qleft, &r, NULL); + if (qleft < 8) { + pthread_mutex_unlock(&q->mutex); + return AEE_EWOULDBLOCK; + } + + VERIFY((nErr = peek_locked(qp, r, flags, num_buffers, message_length, + NULL)) == 0); + + // Fall through +bail: + if (locked) { + pthread_mutex_unlock(&q->mutex); + } + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed for queue %p", nErr, __func__, queue); + } + return nErr; +} + +AEEResult dspqueue_peek(dspqueue_t queue, uint32_t *flags, + uint32_t *num_buffers, uint32_t *message_length, + uint32_t timeout_us) { + + AEEResult nErr = AEE_SUCCESS; + struct dspqueue *q = queue; + struct dspqueue_packet_queue_header *pq = &q->header->resp_queue; + struct dspqueue_packet_queue_state *read_state = + (struct dspqueue_packet_queue_state *)(((uintptr_t)q->header) + + pq->read_state_offset); + _Atomic uint32_t *wait_count = (_Atomic uint32_t *)&read_state->wait_count; + int waiting = 0; + struct timespec *timeout_ts = NULL; // no timeout by default + struct timespec ts; + + pthread_mutex_lock(&q->packet_mutex); + + // Try a read first before dealing with timeouts + nErr = dspqueue_peek_noblock(queue, flags, num_buffers, message_length); + if (nErr != AEE_EWOULDBLOCK) { + // Have a packet or got an error + goto bail; + } + + if (q->have_wait_counts) { + // Mark that we're potentially waiting and try again + atomic_fetch_add(wait_count, 1); + cache_flush_word(wait_count); + waiting = 1; + nErr = dspqueue_peek_noblock(queue, flags, num_buffers, message_length); + if (nErr != AEE_EWOULDBLOCK) { + goto bail; + } + } + + if (timeout_us != DSPQUEUE_TIMEOUT_NONE) { + // Calculate timeout expiry and use timeout + VERIFYC(clock_gettime(CLOCK_REALTIME, &ts) == 0, AEE_EFAILED); + timespec_add_us(&ts, timeout_us); + timeout_ts = &ts; + } + + while (1) { + FARF(LOW, "Queue %u wait packet", (unsigned)q->id); + VERIFY((nErr = wait_signal_locked(q, DSPQUEUE_SIGNAL_RESP_PACKET, + timeout_ts)) == 0); + FARF(LOW, "Queue %u got packet", (unsigned)q->id); + nErr = dspqueue_peek_noblock(queue, flags, num_buffers, message_length); + if (nErr != AEE_EWOULDBLOCK) { + // Have a packet or got an error + goto bail; + } + } + +bail: + if (waiting) { + atomic_fetch_sub(wait_count, 1); + cache_flush_word(wait_count); + } + pthread_mutex_unlock(&q->packet_mutex); + return nErr; +} + +static uint64_t get_time_usec(uint64_t *t) { + + struct timespec ts; + int err = clock_gettime(CLOCK_MONOTONIC, &ts); + *t = ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000; + return err; +} + +static inline uint32_t read_data(volatile const uint8_t *packet_queue, + uint32_t read_pos, uint32_t queue_len, + void *data, uint32_t data_len) { + + uintptr_t qp = (uintptr_t)packet_queue; + + assert(data != NULL); + assert(data_len > 0); + assert((read_pos & 7) == 0); + assert((queue_len - read_pos) >= data_len); + + cache_invalidate((void *)(qp + read_pos), data_len); + memcpy(data, (void *)(qp + read_pos), data_len); + read_pos += (data_len + 7) & (~7); + assert(read_pos <= queue_len); + if (read_pos >= queue_len) { + read_pos = 0; + } + + return read_pos; +} + +AEEResult dspqueue_read_noblock(dspqueue_t queue, uint32_t *flags, + uint32_t max_buffers, uint32_t *num_buffers, + struct dspqueue_buffer *buffers, + uint32_t max_message_length, + uint32_t *message_length, uint8_t *message) { + + AEEResult nErr = AEE_SUCCESS; + struct dspqueue *q = queue; + struct dspqueue_domain_queues *dq = queues->domain_queues[q->domain]; + struct dspqueue_packet_queue_header *pq = &q->header->resp_queue; + volatile const uint8_t *qp = + (volatile const uint8_t *)(((uintptr_t)q->header) + pq->queue_offset); + struct dspqueue_packet_queue_state *read_state = + (struct dspqueue_packet_queue_state *)(((uintptr_t)q->header) + + pq->read_state_offset); + struct dspqueue_packet_queue_state *write_state = + (struct dspqueue_packet_queue_state *)(((uintptr_t)q->header) + + pq->write_state_offset); + uint32_t r, qleft; + uint32_t f, num_b, msg_l; + uint32_t qsize = pq->queue_length; + uint32_t len; + int locked = 0; + unsigned i; + uint32_t buf_refs = 0; + uint64_t header; + + errno = 0; + pthread_mutex_lock(&q->mutex); + locked = 1; + + VERIFYC(q->header->queue_count == q->queue_count, AEE_ERPC); + + // Check if we have a packet available + FARF(LOW, "Queue %u wp %u", (unsigned)q->id, (unsigned)write_state->position); + get_queue_state_read(q->header, pq, &qleft, &r, NULL); + if (qleft < 8) { + pthread_mutex_unlock(&q->mutex); + return AEE_EWOULDBLOCK; + } + + // Get and parse packet header + VERIFY((nErr = peek_locked(qp, r, &f, &num_b, &msg_l, &header)) == 0); + + // Check if this is an early wakeup packet; handle accordingly + if (f & DSPQUEUE_PACKET_FLAG_WAKEUP) { + uint32_t wakeup = 0; + uint32_t waittime = DEFAULT_EARLY_WAKEUP_WAIT; + uint64_t t1 = 0; + + // Read packet, handling possible wraparound + VERIFYC(num_b == 0, AEE_ERPC); + len = 8 + msg_l; + if ((qsize - r) < len) { + assert((qleft - (qsize - r)) >= len); + r = 8; + } else { + r += 8; + } + if (msg_l > 0) { + VERIFYC(msg_l == 4, AEE_EBADITEM); + r = read_data(qp, r, qsize, (uint8_t *)&wakeup, 4); + if (wakeup > MAX_EARLY_WAKEUP_WAIT) { + waittime = MAX_EARLY_WAKEUP_WAIT; + } else { + if (wakeup != 0) { + waittime = wakeup; + } + } + } + + // Update read pointer + q->read_packet_count++; + barrier_full(); + read_state->position = r; + read_state->packet_count = q->read_packet_count; + cache_flush_line(read_state); + + // Signal that we've consumed a packet + q->resp_space_count++; + dq->state->resp_space_count[q->id] = q->resp_space_count; + FARF(LOW, "Queue %u resp_space_count %u", (unsigned)q->id, + (unsigned)q->resp_space_count); + cache_flush_word(&dq->state->resp_space_count[q->id]); + if (q->have_wait_counts) { + // Only signal if the other end is potentially waiting + cache_invalidate_word(&write_state->wait_count); + if (write_state->wait_count) { + VERIFY((nErr = send_signal(q, DSPQUEUE_SIGNAL_RESP_SPACE)) == + AEE_SUCCESS); + } + } else { + VERIFY((nErr = send_signal(q, DSPQUEUE_SIGNAL_RESP_SPACE)) == + AEE_SUCCESS); + } + + // Wait for a packet to become available + FARF(LOW, "Early wakeup, %u usec", (unsigned)waittime); + get_queue_state_read(q->header, pq, &qleft, &r, NULL); + if (qleft < 8) { + VERIFY((nErr = get_time_usec(&t1)) == 0); + uint64_t t2 = 0; + do { + VERIFY((nErr = get_time_usec(&t2)) == 0); + if (((t1 + waittime) > t2) && + (((t1 + waittime) - t2) > EARLY_WAKEUP_SLEEP)) { + FARF(LOW, "No sleep %u", (unsigned)EARLY_WAKEUP_SLEEP); + } + get_queue_state_read(q->header, pq, &qleft, &r, NULL); + if (qleft >= 8) { + if (t2 != 0) { + q->early_wakeup_wait += t2 - t1; + FARF(LOW, "Got packet after %uus", (unsigned)(t2 - t1)); + } else { + FARF(LOW, "Got packet"); + } + break; + } + } while ((t1 + waittime) > t2); + + if (qleft < 8) { + // The next packet didn't get here in time + q->early_wakeup_wait += t2 - t1; + q->early_wakeup_misses++; + FARF(LOW, "Didn't get packet after %uus", (unsigned)(t2 - t1)); + pthread_mutex_unlock(&q->mutex); + return AEE_EWOULDBLOCK; + } + } + + // Have the next packet. Parse header and continue + VERIFY((nErr = peek_locked(qp, r, &f, &num_b, &msg_l, &header)) == 0); + } + + // Check the client has provided enough space for the packet + if ((f & DSPQUEUE_PACKET_FLAG_BUFFERS) && (buffers != NULL)) { + if (max_buffers < num_b) { + FARF(ERROR, + "Too many buffer references in packet to fit in output buffer"); + nErr = AEE_EBADPARM; + goto bail; + } + } + VERIFYC(num_b <= DSPQUEUE_MAX_BUFFERS, AEE_EBADITEM); + if ((f & DSPQUEUE_PACKET_FLAG_MESSAGE) && (message != NULL)) { + if (max_message_length < msg_l) { + FARF(ERROR, "Message in packet too large to fit in output buffer"); + nErr = AEE_EBADPARM; + goto bail; + } + } + + // Check if the packet can fit to the queue without being split by the + // queue end. If not, the writer has wrapped it around to the + // beginning of the queue + len = 8 + num_b * sizeof(struct dspqueue_buffer) + msg_l; + if ((qsize - r) < len) { + assert((qleft - (qsize - r)) >= len); + r = 8; + } else { + r += 8; + } + + VERIFYC(f & DSPQUEUE_PACKET_FLAG_USER_READY, AEE_EBADITEM); + + // Read packet data + if (flags != NULL) { + *flags = f; + } + if (num_b > 0) { + if (buffers != NULL) { + r = read_data(qp, r, qsize, buffers, + num_b * sizeof(struct dspqueue_buffer)); + } else { + r += num_b * sizeof(struct dspqueue_buffer); + } + } + if (msg_l > 0) { + if (message != NULL) { + r = read_data(qp, r, qsize, message, msg_l); + } else { + r += (msg_l + 7) & (~7); + } + } + if (message_length != NULL) { + *message_length = msg_l; + } + + // Update read pointer + assert(r <= qsize); + if (r >= qsize) { + r = 0; + } + q->read_packet_count++; + barrier_full(); + read_state->position = r; + read_state->packet_count = q->read_packet_count; + cache_flush_line(read_state); + + // Signal that we've consumed a packet + q->resp_space_count++; + dq->state->resp_space_count[q->id] = q->resp_space_count; + FARF(LOW, "Queue %u resp_space_count %u", (unsigned)q->id, + (unsigned)q->resp_space_count); + cache_flush_word(&dq->state->resp_space_count[q->id]); + if (q->have_wait_counts) { + // Only signal if the other end is potentially waiting + cache_invalidate_word(&write_state->wait_count); + if (write_state->wait_count) { + VERIFY((nErr = send_signal(q, DSPQUEUE_SIGNAL_RESP_SPACE)) == + AEE_SUCCESS); + } + } else { + VERIFY((nErr = send_signal(q, DSPQUEUE_SIGNAL_RESP_SPACE)) == AEE_SUCCESS); + } + + // Go through buffers + if ((buffers != NULL) && (num_b > 0)) { + for (i = 0; i < num_b; i++) { + struct dspqueue_buffer *b = &buffers[i]; + void *va; + size_t size; + + // Find buffer in internal FastRPC structures and handle refcounts + if (b->flags & DSPQUEUE_BUFFER_FLAG_REF) { + VERIFYC((b->flags & DSPQUEUE_BUFFER_FLAG_DEREF) == 0, AEE_EBADPARM); + nErr = fastrpc_buffer_ref(q->domain, b->fd, 1, &va, &size); + } else if (b->flags & DSPQUEUE_BUFFER_FLAG_DEREF) { + nErr = fastrpc_buffer_ref(q->domain, b->fd, -1, &va, &size); + } else { + nErr = fastrpc_buffer_ref(q->domain, b->fd, 0, &va, &size); + } + if (nErr == AEE_ENOSUCHMAP) { + FARF(ERROR, "Buffer FD %d in queue message not mapped to domain %d", + b->fd, q->domain); + goto bail; + } + VERIFY(nErr == 0); + buf_refs = i + 1; + + // Check and use offset and size from the packet if specified + if (b->size != 0) { + uint64_t bend = ((uint64_t)b->offset) + ((uint64_t)b->size); + VERIFYC(bend <= size, AEE_EBADITEM); + va = (void *)(((uintptr_t)va) + b->offset); + b->ptr = va; + size = b->size; + } else { + VERIFYC(b->offset == 0, AEE_EBADITEM); + b->ptr = va; + b->size = size; + } + } + } + + if (num_buffers != NULL) { + *num_buffers = num_b; + } + + pthread_mutex_unlock(&q->mutex); + locked = 0; + return AEE_SUCCESS; + +bail: + for (i = 0; i < buf_refs; i++) { + // Undo buffer reference changes + struct dspqueue_buffer *b = &buffers[i]; + if (b->flags & DSPQUEUE_BUFFER_FLAG_REF) { + nErr = fastrpc_buffer_ref(q->domain, b->fd, -1, NULL, NULL); + } else if (b->flags & DSPQUEUE_BUFFER_FLAG_DEREF) { + nErr = fastrpc_buffer_ref(q->domain, b->fd, 1, NULL, NULL); + } + } + if (locked) { + pthread_mutex_unlock(&q->mutex); + } + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed for queue %p errno %s", nErr, __func__, + queue, strerror(errno)); + } + return nErr; +} + +AEEResult dspqueue_read(dspqueue_t queue, uint32_t *flags, uint32_t max_buffers, + uint32_t *num_buffers, struct dspqueue_buffer *buffers, + uint32_t max_message_length, uint32_t *message_length, + uint8_t *message, uint32_t timeout_us) { + + AEEResult nErr = AEE_SUCCESS; + struct dspqueue *q = queue; + struct dspqueue_packet_queue_header *pq = &q->header->resp_queue; + struct dspqueue_packet_queue_state *read_state = + (struct dspqueue_packet_queue_state *)(((uintptr_t)q->header) + + pq->read_state_offset); + _Atomic uint32_t *wait_count = (_Atomic uint32_t *)&read_state->wait_count; + int waiting = 0; + struct timespec *timeout_ts = NULL; // no timeout by default + struct timespec ts; + + pthread_mutex_lock(&q->packet_mutex); + + // Try a read first before dealing with timeouts + nErr = dspqueue_read_noblock(queue, flags, max_buffers, num_buffers, buffers, + max_message_length, message_length, message); + if (nErr != AEE_EWOULDBLOCK) { + // Have a packet or got an error + goto bail; + } + + if (q->have_wait_counts) { + // Mark that we're potentially waiting and try again + atomic_fetch_add(wait_count, 1); + cache_flush_word(wait_count); + waiting = 1; + nErr = + dspqueue_read_noblock(queue, flags, max_buffers, num_buffers, buffers, + max_message_length, message_length, message); + if (nErr != AEE_EWOULDBLOCK) { + goto bail; + } + } + + if (timeout_us != DSPQUEUE_TIMEOUT_NONE) { + // Calculate timeout expiry and use timeout + VERIFYC(clock_gettime(CLOCK_REALTIME, &ts) == 0, AEE_EFAILED); + timespec_add_us(&ts, timeout_us); + timeout_ts = &ts; + } + + while (1) { + FARF(LOW, "Queue %u wait packet", (unsigned)q->id); + VERIFY((nErr = wait_signal_locked(q, DSPQUEUE_SIGNAL_RESP_PACKET, + timeout_ts)) == 0); + FARF(LOW, "Queue %u got packet", (unsigned)q->id); + nErr = + dspqueue_read_noblock(queue, flags, max_buffers, num_buffers, buffers, + max_message_length, message_length, message); + if (nErr != AEE_EWOULDBLOCK) { + // Have a packet or got an error + goto bail; + } + } + +bail: + if (waiting) { + atomic_fetch_sub(wait_count, 1); + cache_flush_word(wait_count); + } + pthread_mutex_unlock(&q->packet_mutex); + return nErr; +} + +AEEResult dspqueue_get_stat(dspqueue_t queue, enum dspqueue_stat stat, + uint64_t *value) { + + AEEResult nErr = 0; + struct dspqueue *q = queue; + + pthread_mutex_lock(&q->mutex); + + switch (stat) { + case DSPQUEUE_STAT_EARLY_WAKEUP_WAIT_TIME: + *value = q->early_wakeup_wait; + q->early_wakeup_wait = 0; + break; + + case DSPQUEUE_STAT_EARLY_WAKEUP_MISSES: + *value = q->early_wakeup_misses; + q->early_wakeup_misses = 0; + break; + + case DSPQUEUE_STAT_READ_QUEUE_PACKETS: { + struct dspqueue_packet_queue_header *pq = &q->header->resp_queue; + struct dspqueue_packet_queue_state *write_state = + (struct dspqueue_packet_queue_state *)(((uintptr_t)q->header) + + pq->write_state_offset); + uint32_t c; + cache_invalidate_word(&write_state->packet_count); + c = write_state->packet_count - q->read_packet_count; + *value = c; + break; + } + + case DSPQUEUE_STAT_WRITE_QUEUE_PACKETS: { + struct dspqueue_packet_queue_header *pq = &q->header->req_queue; + struct dspqueue_packet_queue_state *read_state = + (struct dspqueue_packet_queue_state *)(((uintptr_t)q->header) + + pq->read_state_offset); + uint32_t c; + cache_invalidate_word(&read_state->packet_count); + c = q->write_packet_count - read_state->packet_count; + *value = c; + break; + } + + case DSPQUEUE_STAT_READ_QUEUE_BYTES: { + struct dspqueue_packet_queue_header *pq = &q->header->resp_queue; + uint32_t b; + get_queue_state_read(q->header, pq, &b, NULL, NULL); + *value = b; + break; + } + + case DSPQUEUE_STAT_WRITE_QUEUE_BYTES: { + struct dspqueue_packet_queue_header *pq = &q->header->req_queue; + uint32_t b; + get_queue_state_write(q->header, pq, &b, NULL, NULL); + *value = pq->queue_length - b - 8; + break; + } + + case DSPQUEUE_STAT_SIGNALING_PERF: { + if (q->have_driver_signaling) { + *value = DSPQUEUE_SIGNALING_PERF_OPTIMIZED_SIGNALING; + } else if (q->have_wait_counts) { + *value = DSPQUEUE_SIGNALING_PERF_REDUCED_SIGNALING; + } else { + *value = 0; + } + break; + } + + default: + FARF(ERROR, "Unsupported statistic %d", (int)stat); + nErr = AEE_EBADPARM; + goto bail; + } + +bail: + pthread_mutex_unlock(&q->mutex); + return nErr; +} + +struct error_callback_args { + struct dspqueue *queue; + AEEResult error; +}; + +static void *error_callback_thread(void *arg) { + struct error_callback_args *a = (struct error_callback_args *)arg; + assert(a->queue->error_callback); + FARF(ALWAYS, "%s starting for queue %p with id %u", __func__, a->queue, + a->queue->id); + a->queue->error_callback(a->queue, a->error, a->queue->callback_context); + free(a); + return NULL; +} + +// Make an error callback in a separate thread. We do this to ensure the queue +// can be destroyed safely from the callback - all regular threads can exit +// while the callback is in progres. This function won't return error codes; if +// error reporting fails there isn't much we can do to report errors... +static void error_callback(struct dspqueue_domain_queues *dq, AEEResult error) { + + unsigned i; + + FARF(HIGH, "error_callback %d", (int)error); + + // Only report errors once per domain + if (dq->dsp_error != 0) { + return; + } + + if ((error == (AEEResult)0x8000040d) || (error == -1)) { + // Process died (probably) + error = AEE_ECONNRESET; + } + dq->dsp_error = error; + + // Send error callbacks to all queues attached to this domain + pthread_mutex_lock(&dq->queue_list_mutex); + for (i = 0; i <= dq->max_queue; i++) { + if ((dq->queues[i] != UNUSED_QUEUE) && (dq->queues[i] != INVALID_QUEUE)) { + struct dspqueue *q = dq->queues[i]; + // Cancel pending waits + if (q->have_driver_signaling) { + int s; + FARF(HIGH, "%s: Cancel all signal waits", __func__); + for (s = 0; s < DSPQUEUE_NUM_SIGNALS; s++) { + dspsignal_cancel_wait(q->domain, QUEUE_SIGNAL(q->id, s)); + } + } else { + pthread_mutex_lock(&q->packet_mutex); + q->packet_mask |= SIGNAL_BIT_CANCEL; + pthread_cond_broadcast(&q->packet_cond); + pthread_mutex_unlock(&q->packet_mutex); + pthread_mutex_lock(&q->space_mutex); + q->space_mask |= SIGNAL_BIT_CANCEL; + pthread_cond_broadcast(&q->space_cond); + pthread_mutex_unlock(&q->space_mutex); + } + if (q->error_callback != NULL) { + struct error_callback_args *a; + pthread_attr_t tattr; + a = calloc(1, sizeof(*a)); + if (a != NULL) { + int err; + pthread_attr_init(&tattr); + pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE); + a->queue = q; + a->error = error; + err = pthread_create(&q->error_callback_thread, &tattr, + error_callback_thread, a); + if (err != 0) { + FARF(ERROR, "Error callback thread creation failed: %d", err); + free(a); + } + } else { + FARF(ERROR, "Out of memory"); + } + } + } + } + pthread_mutex_unlock(&dq->queue_list_mutex); +} + +static void *dspqueue_send_signal_thread(void *arg) { + + struct dspqueue_domain_queues *dq = (struct dspqueue_domain_queues *)arg; + AEEResult nErr = 0; + + errno = 0; + while (1) { + pthread_mutex_lock(&dq->send_signal_mutex); + while (dq->send_signal_mask == 0) { + pthread_cond_wait(&dq->send_signal_cond, &dq->send_signal_mutex); + } + if (dq->send_signal_mask & SIGNAL_BIT_CANCEL) { + // Exit + pthread_mutex_unlock(&dq->send_signal_mutex); + return NULL; + } else if (dq->send_signal_mask & SIGNAL_BIT_SIGNAL) { + dq->send_signal_mask = dq->send_signal_mask & (~SIGNAL_BIT_SIGNAL); + pthread_mutex_unlock(&dq->send_signal_mutex); + FARF(LOW, "Send signal"); + VERIFY((nErr = dspqueue_rpc_signal(dq->dsp_handle)) == 0); + } + } + +bail: + FARF(ERROR, "dspqueue_send_signal_thread failed with %d errno %s", nErr, + strerror(errno)); + error_callback(dq, nErr); + return (void *)(uintptr_t)nErr; +} + +static void *dspqueue_receive_signal_thread(void *arg) { + + struct dspqueue_domain_queues *dq = (struct dspqueue_domain_queues *)arg; + AEEResult nErr = 0; + unsigned i; + + errno = 0; + while (1) { + int32_t signal; + VERIFY((nErr = dspqueue_rpc_wait_signal(dq->dsp_handle, &signal)) == 0); + + if (signal == -1) { + // Exit + assert(dq->num_queues == 0); + return NULL; + } + + // Got a signal - at least one queue has more packets or space. Find out + // which one and signal it. + FARF(LOW, "Got signal"); + + // Ensure we have visibility into updates from the DSP + cache_invalidate(dq->state->req_space_count, + sizeof(dq->state->req_space_count)); + cache_invalidate(dq->state->resp_packet_count, + sizeof(dq->state->resp_packet_count)); + + pthread_mutex_lock(&dq->queue_list_mutex); + FARF(LOW, "Go through queues"); + for (i = 0; i <= dq->max_queue; i++) { + if ((dq->queues[i] != UNUSED_QUEUE) && (dq->queues[i] != INVALID_QUEUE)) { + struct dspqueue *q = dq->queues[i]; + assert(!q->have_driver_signaling); + pthread_mutex_lock(&q->packet_mutex); + if (q->resp_packet_count != dq->state->resp_packet_count[i]) { + q->resp_packet_count = dq->state->resp_packet_count[i]; + FARF(LOW, "Queue %u new resp_packet_count %u", i, + (unsigned)q->resp_packet_count); + pthread_cond_broadcast(&q->packet_cond); + } + pthread_mutex_unlock(&q->packet_mutex); + pthread_mutex_lock(&q->space_mutex); + if (q->req_space_count != dq->state->req_space_count[i]) { + q->req_space_count = dq->state->req_space_count[i]; + FARF(LOW, "Queue %u new req_space_count %u", i, + (unsigned)q->req_space_count); + pthread_cond_broadcast(&q->space_cond); + } + pthread_mutex_unlock(&q->space_mutex); + } + } + FARF(LOW, "Done"); + pthread_mutex_unlock(&dq->queue_list_mutex); + } + +bail: + FARF(ERROR, "dspqueue_receive_signal_thread failed with %d errno %s", nErr, + strerror(errno)); + if (nErr == -1) { + // Process died (probably) + nErr = AEE_ECONNRESET; + } + error_callback(dq, nErr); + return (void *)(uintptr_t)nErr; +} + +static void *dspqueue_packet_callback_thread(void *arg) { + + struct dspqueue *q = (struct dspqueue *)arg; + struct dspqueue_packet_queue_header *pq = &q->header->resp_queue; + struct dspqueue_packet_queue_state *read_state = + (struct dspqueue_packet_queue_state *)(((uintptr_t)q->header) + + pq->read_state_offset); + struct dspqueue_packet_queue_state *write_state = + (struct dspqueue_packet_queue_state *)(((uintptr_t)q->header) + + pq->write_state_offset); + _Atomic uint32_t *wait_count = (_Atomic uint32_t *)&read_state->wait_count; + uint32_t packet_count = 0; + AEEResult nErr = AEE_SUCCESS; + + FARF(ALWAYS, "%s starting for queue %p", __func__, q); + while (1) { + pthread_mutex_lock(&q->packet_mutex); + + // Call the callback if we have any packets we haven't seen yet. + cache_invalidate_word(&write_state->packet_count); + if (packet_count != write_state->packet_count) { + packet_count = write_state->packet_count; + q->packet_callback(q, 0, q->callback_context); + } + + // Mark we're waiting and call again if we just got more packets + if (q->have_wait_counts) { + atomic_fetch_add(wait_count, 1); + cache_flush_word(wait_count); + } + cache_invalidate_word(&write_state->packet_count); + if (packet_count != write_state->packet_count) { + packet_count = write_state->packet_count; + q->packet_callback(q, 0, q->callback_context); + } + + // Wait for a signal + nErr = wait_signal_locked(q, DSPQUEUE_SIGNAL_RESP_PACKET, NULL); + if (nErr == AEE_EINTERRUPTED || nErr == AEE_EBADSTATE) { + FARF(HIGH, "Queue %u exit callback thread", (unsigned)q->id); + if (q->have_wait_counts) { + atomic_fetch_sub(wait_count, 1); + cache_flush_word(wait_count); + } + pthread_mutex_unlock(&q->packet_mutex); + goto bail; + } else if (nErr != AEE_SUCCESS) { + pthread_mutex_unlock(&q->packet_mutex); + FARF(ERROR, "Error: %s: wait_signal failed with 0x%x (queue %p)", + __func__, nErr, q); + return (void *)((intptr_t)nErr); + } + + // Mark we aren't waiting right now + if (q->have_wait_counts) { + atomic_fetch_sub(wait_count, 1); + cache_flush_word(wait_count); + } + + pthread_mutex_unlock(&q->packet_mutex); + } +bail: + FARF(ALWAYS, "%s exiting", __func__); + return NULL; +} + +static int dspqueue_notif_callback(void *context, int domain, int session, + remote_rpc_status_flags_t status) { + int nErr = AEE_SUCCESS, effec_domain_id = domain; + + if (status == FASTRPC_USER_PD_UP) { + return 0; + } + // All other statuses are some kind of process exit or DSP crash. + assert(context == queues); + if (session && domain < NUM_DOMAINS) { + // Did not receive effective domain ID for extended session. Compute it. + effec_domain_id = GET_EFFECTIVE_DOMAIN_ID(domain, session); + } + FARF(ALWAYS, "%s for domain %d, session %d, status %u", __func__, domain, + session, status); + assert(effec_domain_id < NUM_DOMAINS_EXTEND); + + // Send different error codes for SSR and remote-process exit + nErr = (status == FASTRPC_DSP_SSR) ? AEE_ECONNRESET : AEE_ENOSUCH; + if (queues->domain_queues[effec_domain_id] != NULL) { + error_callback(queues->domain_queues[effec_domain_id], nErr); + } + return 0; +} diff --git a/src/dspqueue/dspqueue_rpc_stub.c b/src/dspqueue/dspqueue_rpc_stub.c new file mode 100644 index 0000000..dd072ee --- /dev/null +++ b/src/dspqueue/dspqueue_rpc_stub.c @@ -0,0 +1,566 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _DSPQUEUE_RPC_STUB_H +#define _DSPQUEUE_RPC_STUB_H +#include "dspqueue_rpc.h" +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#include + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef _ATTRIBUTE_VISIBILITY + +#ifdef _WIN32 +#define _ATTRIBUTE_VISIBILITY +#else +#define _ATTRIBUTE_VISIBILITY __attribute__ ((visibility("default"))) +#endif + +#endif // _ATTRIBUTE_VISIBILITY + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i = 0; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#endif + + +#endif // _QAIC_ENV_H + +#include +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include +#include + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc((size_t)size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + (size_t)size) < (uintptr_t)me->stack + (size_t)me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _DSPQUEUE_RPC_SLIM_H +#define _DSPQUEUE_RPC_SLIM_H +#include + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Parameter parameters[8] = {{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)0x0,0}}, 4,SLIM_IFPTR32(0x4,0x8),0,0},{SLIM_IFPTR32(0x4,0x8),{{(const uintptr_t)0xdeadc0de,(const uintptr_t)0}}, 0,SLIM_IFPTR32(0x4,0x8),3,0},{SLIM_IFPTR32(0x4,0x8),{{(const uintptr_t)0xdeadc0de,(const uintptr_t)0}}, 0,SLIM_IFPTR32(0x4,0x8),0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{0x8,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x8,3,0},{0x8,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x8,0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0}}; +static const Parameter* const parameterArrays[9] = {(&(parameters[4])),(&(parameters[3])),(&(parameters[4])),(&(parameters[5])),(&(parameters[6])),(&(parameters[7])),(&(parameters[0])),(&(parameters[1])),(&(parameters[2]))}; +static const Method methods[8] = {{REMOTE_SCALARS_MAKEX(0,0,0x2,0x0,0x0,0x1),0x4,0x0,2,2,(&(parameterArrays[6])),0x4,0x1},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x0,0x1,0x0),0x0,0x0,1,1,(&(parameterArrays[8])),0x1,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0x4,0x0,1,1,(&(parameterArrays[1])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x1,0x0,0x0),0xc,0x8,4,4,(&(parameterArrays[0])),0x4,0x8},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0x8,0x0,3,1,(&(parameterArrays[4])),0x8,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x1,0x0,0x0),0x8,0x4,4,2,(&(parameterArrays[4])),0x8,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x1,0x0,0x0),0x0,0x4,1,1,(&(parameterArrays[5])),0x1,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x0,0x0,0x0),0x0,0x0,0,0,0,0x0,0x0}}; +static const Method* const methodArrays[9] = {&(methods[0]),&(methods[1]),&(methods[2]),&(methods[3]),&(methods[4]),&(methods[5]),&(methods[6]),&(methods[7]),&(methods[7])}; +static const char strings[136] = "cancel_wait_signal\0init_process_state\0process_state_fd\0destroy_queue\0create_queue\0is_imported\0queue_id\0queue_fd\0count\0close\0open\0uri\0h\0"; +static const uint16_t methodStrings[20] = {69,100,103,112,94,82,94,85,124,129,133,7,12,55,94,19,38,118,133,0}; +static const uint16_t methodStringsArrays[9] = {8,17,15,0,13,5,11,19,12}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(dspqueue_rpc_slim) = {9,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_DSPQUEUE_RPC_SLIM_H + + +#ifdef __cplusplus +extern "C" { +#endif +__QAIC_STUB_EXPORT int __QAIC_STUB(dspqueue_rpc_open)(const char* uri, remote_handle64* h) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle64_open)(uri, h); +} +__QAIC_STUB_EXPORT int __QAIC_STUB(dspqueue_rpc_close)(remote_handle64 h) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle64_close)(h); +} +static __inline int _stub_method(remote_handle64 _handle, uint32_t _mid, uint32_t _in0[1]) { + remote_arg _pra[1] = {0}; + uint32_t _primIn[1]= {0}; + int _nErr = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _COPY(_primIn, 0, _in0, 0, 4); + _TRY(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 0, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT AEEResult __QAIC_STUB(dspqueue_rpc_init_process_state)(remote_handle64 _handle, int32 process_state_fd) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 2; + return _stub_method(_handle, _mid, (uint32_t*)&process_state_fd); +} +static __inline int _stub_method_1(remote_handle64 _handle, uint32_t _mid, uint32_t _in0[1], uint32_t _in1[1], uint32_t _in2[1], uint64_t _rout3[1]) { + int _numIn[1] = {0}; + remote_arg _pra[2] = {0}; + uint32_t _primIn[3]= {0}; + uint64_t _primROut[1]= {0}; + int _nErr = 0; + _numIn[0] = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _pra[(_numIn[0] + 1)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 1)].buf.nLen = sizeof(_primROut); + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _in1, 0, 4); + _COPY(_primIn, 8, _in2, 0, 4); + _TRY(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 1, 0, 0), _pra)); + _COPY(_rout3, 0, _primROut, 0, 8); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT AEEResult __QAIC_STUB(dspqueue_rpc_create_queue)(remote_handle64 _handle, uint32 id, int32 queue_fd, uint32 count, uint64* queue_id) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 3; + return _stub_method_1(_handle, _mid, (uint32_t*)&id, (uint32_t*)&queue_fd, (uint32_t*)&count, (uint64_t*)queue_id); +} +static __inline int _stub_method_2(remote_handle64 _handle, uint32_t _mid, uint64_t _in0[1]) { + remote_arg _pra[1] = {0}; + uint64_t _primIn[1]= {0}; + int _nErr = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _COPY(_primIn, 0, _in0, 0, 8); + _TRY(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 0, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT AEEResult __QAIC_STUB(dspqueue_rpc_destroy_queue)(remote_handle64 _handle, uint64 queue_id) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 4; + return _stub_method_2(_handle, _mid, (uint64_t*)&queue_id); +} +static __inline int _stub_method_3(remote_handle64 _handle, uint32_t _mid, uint64_t _in0[1], uint32_t _rout1[1]) { + int _numIn[1] = {0}; + remote_arg _pra[2] = {0}; + uint64_t _primIn[1]= {0}; + uint32_t _primROut[1]= {0}; + int _nErr = 0; + _numIn[0] = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _pra[(_numIn[0] + 1)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 1)].buf.nLen = sizeof(_primROut); + _COPY(_primIn, 0, _in0, 0, 8); + _TRY(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 1, 0, 0), _pra)); + _COPY(_rout1, 0, _primROut, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT AEEResult __QAIC_STUB(dspqueue_rpc_is_imported)(remote_handle64 _handle, uint64 queue_id, int32* imported) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 5; + return _stub_method_3(_handle, _mid, (uint64_t*)&queue_id, (uint32_t*)imported); +} +static __inline int _stub_method_4(remote_handle64 _handle, uint32_t _mid, uint32_t _rout0[1]) { + int _numIn[1] = {0}; + remote_arg _pra[1] = {0}; + uint32_t _primROut[1]= {0}; + int _nErr = 0; + _numIn[0] = 0; + _pra[(_numIn[0] + 0)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 0)].buf.nLen = sizeof(_primROut); + _TRY(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 0, 1, 0, 0), _pra)); + _COPY(_rout0, 0, _primROut, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT AEEResult __QAIC_STUB(dspqueue_rpc_wait_signal)(remote_handle64 _handle, int32* signal) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 6; + return _stub_method_4(_handle, _mid, (uint32_t*)signal); +} +static __inline int _stub_method_5(remote_handle64 _handle, uint32_t _mid) { + remote_arg* _pra = 0; + int _nErr = 0; + _TRY(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 0, 0, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT AEEResult __QAIC_STUB(dspqueue_rpc_cancel_wait_signal)(remote_handle64 _handle) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 7; + return _stub_method_5(_handle, _mid); +} +__QAIC_STUB_EXPORT AEEResult __QAIC_STUB(dspqueue_rpc_signal)(remote_handle64 _handle) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 8; + return _stub_method_5(_handle, _mid); +} +#ifdef __cplusplus +} +#endif +#endif //_DSPQUEUE_RPC_STUB_H diff --git a/src/dspsignal.c b/src/dspsignal.c new file mode 100644 index 0000000..ab482cd --- /dev/null +++ b/src/dspsignal.c @@ -0,0 +1,301 @@ +// 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 +#define FARF_ERROR 1 +#define FARF_HIGH 0 +#define FARF_MEDIUM 0 + +#include +#include +#include +#include +#include + + +#include "dspsignal.h" +#include "fastrpc_common.h" +#include "fastrpc_internal.h" +#include "remote.h" +#include "verify.h" +#include "AEEStdErr.h" +#include "HAP_farf.h" + +struct dspsignal_domain_signals { + int domain; + int dev; +}; + +struct dspsignal_process_signals { + struct dspsignal_domain_signal *domain_signals[NUM_DOMAINS_EXTEND]; + pthread_mutex_t mutex; +}; + +static struct dspsignal_process_signals *signals; +static pthread_once_t signals_once = PTHREAD_ONCE_INIT; + +// Initialize process static signal structure. This should realistically never +// fail. +static void init_process_signals_once(void) { + + signals = calloc(1, sizeof(*signals)); + if (signals == NULL) { + FARF(ERROR, "Out of memory"); + return; + } + if (pthread_mutex_init(&signals->mutex, NULL) != 0) { + FARF(ERROR, "Mutex init failed"); + free(signals); + signals = NULL; + return; + } +} + +void deinit_process_signals() { + if (signals) { + pthread_mutex_destroy(&signals->mutex); + free(signals); + signals = NULL; + } +} + +// Dynamically initialize process signals structure. +static AEEResult init_domain_signals(int domain) { + + AEEResult nErr = AEE_SUCCESS; + struct dspsignal_domain_signals *ds = NULL; + + VERIFY((domain < NUM_DOMAINS_EXTEND) && (domain >= 0)); + + // Initialize process-level structure + if ((pthread_once(&signals_once, init_process_signals_once) != 0) || + (signals == NULL)) { + FARF(ERROR, "dspsignal init failed"); + return AEE_ERPC; + } + + pthread_mutex_lock(&signals->mutex); + if (signals->domain_signals[domain] != NULL) { + // Already initialized + goto bail; + } + + VERIFYC((ds = calloc(1, sizeof(*ds))) != NULL, AEE_ENOMEMORY); + ds->domain = domain; + + VERIFY(AEE_SUCCESS == (nErr = fastrpc_session_dev(domain, &ds->dev))); + VERIFYC(-1 != ds->dev, AEE_ERPC); + + signals->domain_signals[domain] = (struct dspsignal_domain_signal *)ds; + +bail: + pthread_mutex_unlock(&signals->mutex); + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed (domain %d) errno %s", nErr, __func__, + domain, strerror(errno)); + } + return nErr; +} + +static int get_domain(int domain) { + if (domain == -1) { + domain = get_current_domain(); + } + return domain; +} + +void dspsignal_domain_deinit(int domain) { + AEEResult nErr = AEE_SUCCESS; + + if (!signals) + return; + VERIFYC((domain >= 0) && (domain < NUM_DOMAINS_EXTEND), AEE_EBADPARM); + pthread_mutex_lock(&signals->mutex); + if (signals->domain_signals[domain]) { + free(signals->domain_signals[domain]); + signals->domain_signals[domain] = NULL; + } + pthread_mutex_unlock(&signals->mutex); + FARF(ALWAYS, "%s done for domain %d", __func__, domain); + +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed (domain %d)", nErr, __func__, domain); + } + return; +} + +AEEResult dspsignal_create(int domain, uint32_t id, uint32_t flags) { + + AEEResult nErr = AEE_SUCCESS; + struct dspsignal_domain_signals *ds = NULL; + int e; + + VERIFYC(id < DSPSIGNAL_NUM_SIGNALS, AEE_EBADPARM); + domain = get_domain(domain); + VERIFYC(flags == 0, AEE_EBADPARM); + VERIFYC((domain >= 0) && (domain < NUM_DOMAINS_EXTEND), AEE_EBADPARM); + VERIFY((nErr = init_domain_signals(domain)) == 0); + VERIFYC((ds = (struct dspsignal_domain_signals *)signals->domain_signals[domain]) != NULL, AEE_EBADSTATE); + e = ioctl_signal_create(ds->dev, id, flags); + if (e != 0) { + e = errno; + if (e == ENOTTY) { + FARF(HIGH, "dspsignal support not present in the FastRPC driver"); + nErr = AEE_EUNSUPPORTED; + goto bail; + } else if (e == EBUSY) { + nErr = AEE_EITEMBUSY; + goto bail; + } else { + nErr = AEE_EFAILED; + goto bail; + } + } + FARF(HIGH, "%s: Signal %u created", __func__, id); + +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed (domain %d, ID %u, flags 0x%x) errno %s", + nErr, __func__, domain, id, flags, strerror(errno)); + } + return nErr; +} + +AEEResult dspsignal_destroy(int domain, uint32_t id) { + + AEEResult nErr = AEE_SUCCESS; + struct dspsignal_domain_signals *ds = NULL; + int e; + + VERIFYC(id < DSPSIGNAL_NUM_SIGNALS, AEE_EBADPARM); + domain = get_domain(domain); + VERIFYC((domain >= 0) && (domain < NUM_DOMAINS_EXTEND), AEE_EBADPARM); + VERIFYC((ds = (struct dspsignal_domain_signals *)signals->domain_signals[domain]) != NULL, AEE_EBADSTATE); + e = ioctl_signal_destroy(ds->dev, id); + if (e != 0) { + e = errno; + if (e == ENOENT) { + nErr = AEE_ENOSUCH; + goto bail; + } else { + nErr = AEE_EFAILED; + goto bail; + } + } + FARF(HIGH, "%s: Signal %u destroyed", __func__, id); + +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed (domain %d, ID %u) errno %s", nErr, + __func__, domain, id, strerror(errno)); + } + return nErr; +} + +AEEResult dspsignal_signal(int domain, uint32_t id) { + + AEEResult nErr = AEE_SUCCESS; + struct dspsignal_domain_signals *ds = NULL; + int e; + + VERIFYC(id < DSPSIGNAL_NUM_SIGNALS, AEE_EBADPARM); + domain = get_domain(domain); + VERIFYC((domain >= 0) && (domain < NUM_DOMAINS_EXTEND), AEE_EBADPARM); + VERIFYC((ds = (struct dspsignal_domain_signals *)signals->domain_signals[domain]) != NULL, AEE_EBADSTATE); + + FARF(MEDIUM, "%s: Send signal %u", __func__, id); + e = ioctl_signal_signal(ds->dev, id); + if (e != 0) { + e = errno; + if (e == ENOENT) { + nErr = AEE_ENOSUCH; + goto bail; + } else { + nErr = AEE_EFAILED; + goto bail; + } + } + +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed (domain %d, ID %u) errno %s", nErr, + __func__, domain, id, strerror(errno)); + } + return nErr; +} + +AEEResult dspsignal_wait(int domain, uint32_t id, uint32_t timeout_usec) { + + AEEResult nErr = AEE_SUCCESS; + struct dspsignal_domain_signals *ds = NULL; + int e; + + VERIFYC(id < DSPSIGNAL_NUM_SIGNALS, AEE_EBADPARM); + domain = get_domain(domain); + VERIFYC((domain >= 0) && (domain < NUM_DOMAINS_EXTEND), 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); + e = ioctl_signal_wait(ds->dev, id, timeout_usec); + + if (e != 0) { + e = errno; + if (e == ENOENT) { + nErr = AEE_ENOSUCH; + goto bail; + } else if (e == ETIMEDOUT) { + FARF(MEDIUM, "%s: Signal %u timed out", __func__, id); + return AEE_EEXPIRED; + } else if (e == EINTR) { + FARF(MEDIUM, "%s: Signal %u canceled", __func__, id); + return AEE_EINTERRUPTED; + } else { + nErr = AEE_EFAILED; + goto bail; + } + } + +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed (domain %d, ID %u, timeout %u) errno %s", + nErr, __func__, domain, id, timeout_usec, strerror(errno)); + } + return nErr; +} + +AEEResult dspsignal_cancel_wait(int domain, uint32_t id) { + + AEEResult nErr = AEE_SUCCESS; + struct dspsignal_domain_signals *ds = NULL; + int e; + + VERIFYC(id < DSPSIGNAL_NUM_SIGNALS, AEE_EBADPARM); + domain = get_domain(domain); + VERIFYC((domain >= 0) && (domain < NUM_DOMAINS_EXTEND), AEE_EBADPARM); + VERIFYC((ds = (struct dspsignal_domain_signals *)signals->domain_signals[domain]) != NULL, AEE_EBADSTATE); + + FARF(MEDIUM, "%s: Cancel wait signal %u", __func__, id); + e = ioctl_signal_cancel_wait(ds->dev, id); + + if (e != 0) { + e = errno; + if (e == ENOENT) { + nErr = AEE_ENOSUCH; + goto bail; + } else { + nErr = AEE_EFAILED; + goto bail; + } + } + +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed (domain %d, ID %u) errno %s", nErr, + __func__, domain, id, strerror(errno)); + } + return nErr; +} diff --git a/src/fastrpc_apps_user.c b/src/fastrpc_apps_user.c new file mode 100644 index 0000000..2e76533 --- /dev/null +++ b/src/fastrpc_apps_user.c @@ -0,0 +1,4271 @@ +// 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 +//#ifndef VERIFY_PRINT_INFO +//#define VERIFY_PRINT_INFO +//#endif // VERIFY_PRINT_INFO + +#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 + +#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. + +#include "AEEQList.h" +#include "AEEStdErr.h" +#include "AEEatomic.h" +#include "AEEstd.h" +#include "HAP_farf.h" +#include "adsp_current_process.h" +#include "adsp_current_process1.h" +#include "adsp_listener1.h" +#include "adsp_perf1.h" +#include "adspmsgd_adsp1.h" +#include "adspmsgd_internal.h" +#include "apps_mem_internal.h" +#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" +#include "fastrpc_internal.h" +#include "fastrpc_latency.h" +#include "fastrpc_log.h" +#include "fastrpc_mem.h" +#include "fastrpc_notif.h" +#include "fastrpc_perf.h" +#include "fastrpc_pm.h" +#include "fastrpc_procbuf.h" +#include "listener_android.h" +#include "log_config.h" +#include "platform_libs.h" +#include "remotectl.h" +#include "remotectl1.h" +#include "rpcmem_internal.h" +#include "shared.h" +#include "verify.h" +#ifndef NO_HAL +#include "DspClient.h" +#endif +#include "fastrpc_process_attributes.h" +#include "fastrpc_trace.h" + +#ifndef ENABLE_UPSTREAM_DRIVER_INTERFACE +#define DSP_MOUNT_LOCATION "/dsp/" +#define DSP_DOM_LOCATION "/dsp/xdsp" +#else +#define DSP_MOUNT_LOCATION "/usr/lib/dsp/" +#define DSP_DOM_LOCATION "/usr/lib/dsp/xdsp" +#endif +#define VENDOR_DSP_LOCATION "/vendor/dsp/" +#define VENDOR_DOM_LOCATION "/vendor/dsp/xdsp/" + +#ifdef LE_ENABLE +#define PROPERTY_VALUE_MAX \ + 92 // as this macro is defined in cutils for Android platforms, defined + // explicitly for LE platform +#elif (defined _ANDROID) || (defined ANDROID) +/// TODO: Bharath #include "cutils/properties.h" +#define PROPERTY_VALUE_MAX 92 +#else +#define PROPERTY_VALUE_MAX 92 +#endif + +#ifndef _WIN32 +#include +#include +#include +#include +#endif // __WIN32 + +#ifndef INT_MAX +#define INT_MAX (int)(-1) +#endif + +#ifndef ULLONG_MAX +#define ULLONG_MAX (unsigned long long int)(-1) +#endif + +#define MAX_DMA_HANDLES 256 +#define MAX_DLERRSTR_LEN 255 +#define ENV_PATH_LEN 256 + +#define FASTRPC_TRACE_INVOKE_START "fastrpc_trace_invoke_start" +#define FASTRPC_TRACE_INVOKE_END "fastrpc_trace_invoke_end" +#define FASTRPC_TRACE_LOG(k, handle, sc) \ + if (fastrpc_trace == 1 && !IS_STATIC_HANDLE(handle)) { \ + FARF(ALWAYS, "%s: sc 0x%x", (k), (sc)); \ + } + +/* Number of dsp library instances allowed per process. */ +#define MAX_LIB_INSTANCE_ALLOWED 1 +#define ERRNO (errno ? errno : nErr ? nErr : -1) + +static void check_multilib_util(void); + +/* Array to store fastrpc library names. */ +static const char *fastrpc_library[NUM_DOMAINS] = { + "libadsprpc.so", "libmdsprpc.so", "libsdsprpc.so", "libcdsprpc.so"}; + +/* Array to store env variable names. */ +static char *fastrpc_dsp_lib_refcnt[NUM_DOMAINS]; +static int total_dsp_lib_refcnt = 0; + +/* Function to free the memory allocated for env variable names */ +inline static void deinit_fastrpc_dsp_lib_refcnt(void) { + for (int ii = 0; ii < NUM_DOMAINS; ii++) { + if (fastrpc_dsp_lib_refcnt[ii]) { + unsetenv(fastrpc_dsp_lib_refcnt[ii]); + free(fastrpc_dsp_lib_refcnt[ii]); + fastrpc_dsp_lib_refcnt[ii] = NULL; + } + } +} + +enum fastrpc_proc_attr { + FASTRPC_MODE_DEBUG = 0x1, + FASTRPC_MODE_PTRACE = 0x2, + FASTRPC_MODE_CRC = 0x4, + FASTRPC_MODE_UNSIGNED_MODULE = 0x8, + FASTRPC_MODE_ADAPTIVE_QOS = 0x10, + FASTRPC_MODE_SYSTEM_PROCESS = 0x20, + FASTRPC_MODE_PRIVILEGED = 0x40, // this attribute will be populated in kernel + // Attribute to enable pd dump feature for both signed/unsigned pd + FASTRPC_MODE_ENABLE_PDDUMP = 0x80, + // System attribute to enable pd dump debug data collection on rooted devices + FASTRPC_MODE_DEBUG_PDDUMP = 0x100, + // Attribute to enable kernel perf keys data collection + FASTRPC_MODE_PERF_KERNEL = 0x200, + // Attribute to enable dsp perf keys data collection + FASTRPC_MODE_PERF_DSP = 0x400, + // Attribute to log iregion buffer + FASTRPC_MODE_ENABLE_IREGION_LOG = 0x800, + // Attribute to enable QTF tracing on DSP + FASTRPC_MODE_ENABLE_QTF_TRACING = 0x1000, + // Attribute to enable debug logging + FASTRPC_MODE_ENABLE_DEBUG_LOGGING = 0x2000, + // Attribute to set caller level for heap + FASTRPC_MODE_CALLER_LEVEL_MASK = 0xE000, + // Attribute to enable uaf for heap + FASTRPC_MODE_ENABLE_UAF = 0x10000, + // Attribute to launch system unsignedPD on CDSP + FASTRPC_MODE_SYSTEM_UNSIGNED_PD = 0x20000, + // Reserved attribute bit for sys mon application + FASTRPC_MODE_SYSMON_RESERVED_BIT = 0x40000000, + // Attribute to enable log packet + FASTRPC_MODE_LOG_PACKET = 0x40000, + // Attribute to set Leak detect for heap. Bits 19-20 are reserved for leak + // detect. + FASTRPC_MODE_ENABLE_LEAK_DETECT = 0x180000, + // Attribute to change caller stack for heap. Bits 21-23 are reserved the call + // stack num + FASTRPC_MODE_CALLER_STACK_NUM = 0xE00000, +}; + +#define M_CRCLIST (64) +#define IS_DEBUG_MODE_ENABLED(var) (var & FASTRPC_MODE_DEBUG) +#define IS_CRC_CHECK_ENABLED(var) (var & FASTRPC_MODE_CRC) +extern int perf_v2_kernel; +extern int perf_v2_dsp; +#define IS_KERNEL_PERF_ENABLED(var) \ + ((var & FASTRPC_MODE_PERF_KERNEL) && perf_v2_kernel) +#define IS_DSP_PERF_ENABLED(var) ((var & FASTRPC_MODE_PERF_DSP) && perf_v2_dsp) +#define IS_QTF_TRACING_ENABLED(var) (var & FASTRPC_MODE_ENABLE_QTF_TRACING) + +#define POLY32 \ + 0x04C11DB7 // G(x) = x^32+x^26+x^23+x^22+x^16+x^12 + // +x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1 + +#define DEFAULT_UTHREAD_PRIORITY 0xC0 +#define DEFAULT_UTHREAD_STACK_SIZE 16 * 1024 +#define DEFAULT_PD_INITMEM_SIZE 3 * 1024 * 1024 + +/* Valid QuRT thread priorities are 1 to 255 */ +#define MIN_THREAD_PRIORITY 1 +#define MAX_THREAD_PRIORITY 255 + +/* Remote thread stack size should be between 16 KB and 8 MB */ +#define MIN_UTHREAD_STACK_SIZE (16 * 1024) +#define MAX_UTHREAD_STACK_SIZE (8 * 1024 * 1024) + +/* Remote userpd init memlen should be between 3MB and 200MB */ +#define MIN_PD_INITMEM_SIZE (3 * 1024 * 1024) +#define MAX_PD_INITMEM_SIZE (200 * 1024 * 1024) + +#define PM_TIMEOUT_MS 5 + +enum handle_list_id { + MULTI_DOMAIN_HANDLE_LIST_ID = 1, + NON_DOMAIN_HANDLE_LIST_ID = 2, + REVERSE_HANDLE_LIST_ID = 3, +}; + +const char *ENV_DEBUG_VAR_NAME[] = {"FASTRPC_PROCESS_ATTRS", + "FASTRPC_DEBUG_TRACE", + "FASTRPC_DEBUG_TESTSIG", + "FASTRPC_PERF_KERNEL", + "FASTRPC_PERF_ADSP", + "FASTRPC_PERF_FREQ", + "FASTRPC_DEBUG_SYSTRACE", + "FASTRPC_DEBUG_PDDUMP", + "FASTRPC_PROCESS_ATTRS_PERSISTENT", + "ro.debuggable"}; +const char *ANDROIDP_DEBUG_VAR_NAME[] = {"vendor.fastrpc.process.attrs", + "vendor.fastrpc.debug.trace", + "vendor.fastrpc.debug.testsig", + "vendor.fastrpc.perf.kernel", + "vendor.fastrpc.perf.adsp", + "vendor.fastrpc.perf.freq", + "vendor.fastrpc.debug.systrace", + "vendor.fastrpc.debug.pddump", + "persist.vendor.fastrpc.process.attrs", + "ro.build.type"}; +const char *ANDROID_DEBUG_VAR_NAME[] = {"fastrpc.process.attrs", + "fastrpc.debug.trace", + "fastrpc.debug.testsig", + "fastrpc.perf.kernel", + "fastrpc.perf.adsp", + "fastrpc.perf.freq", + "fastrpc.debug.systrace", + "fastrpc.debug.pddump", + "persist.fastrpc.process.attrs", + "ro.build.type"}; + +const char *SUBSYSTEM_NAME[] = {"adsp", "mdsp", "sdsp", "cdsp"}; + +/* Strings for trace event logging */ +#define INVOKE_BEGIN_TRACE_STR "fastrpc_msg: userspace_call: begin" +#define INVOKE_END_TRACE_STR "fastrpc_msg: userspace_call: end" + +static const size_t invoke_begin_trace_strlen = + sizeof(INVOKE_BEGIN_TRACE_STR) - 1; +static const size_t invoke_end_trace_strlen = sizeof(INVOKE_END_TRACE_STR) - 1; + +int NO_ENV_DEBUG_VAR_NAME_ARRAY_ELEMENTS = + sizeof(ENV_DEBUG_VAR_NAME) / sizeof(char *); +int NO_ANDROIDP_DEBUG_VAR_NAME_ARRAY_ELEMENTS = + sizeof(ANDROIDP_DEBUG_VAR_NAME) / sizeof(char *); +int NO_ANDROID_DEBUG_VAR_NAME_ARRAY_ELEMENTS = + sizeof(ANDROID_DEBUG_VAR_NAME) / sizeof(char *); + +/* Shell prefix for signed and unsigned */ +const char *const SIGNED_SHELL = "fastrpc_shell_"; +const char *const UNSIGNED_SHELL = "fastrpc_shell_unsigned_"; + +struct handle_info { + QNode qn; + struct handle_list *hlist; + remote_handle64 local; + remote_handle64 remote; +}; + +// Fastrpc client notification request node to be queued to +struct fastrpc_notif { + QNode qn; + remote_rpc_notif_register_t notif; +}; + +struct other_handle_list { // For non-domain and reverse handle list + QList ql; +}; + +// Fastrpc timer function for RPC timeout +typedef struct fastrpc_timer_info { + timer_t timer; + uint64_t timeout_millis; + int domain; + int sc; + int handle; +} fastrpc_timer; + +// Macro to check if a remote session is already open on given domain +#define IS_SESSION_OPEN_ALREADY(domain) (hlist && (hlist[domain].dev != -1)) + +struct handle_list *hlist = 0; + +/* Mutex to protect notif_list */ +static pthread_mutex_t update_notif_list_mut; + +static pthread_key_t tlsKey = INVALID_KEY; + +// Flag to check if there is any client notification request +static bool fastrpc_notif_flag = false; +static int fastrpc_trace = 0; +static uint32_t fastrpc_wake_lock_enable[NUM_DOMAINS_EXTEND] = {0}; + +#ifndef NO_HAL +static pthread_mutex_t dsp_client_mut; +static void *dsp_client_instance[NUM_SESSIONS]; +#endif + +static int domain_init(int domain, int *dev); +static void domain_deinit(int domain); +static int open_device_node(int domain_id); +static int close_device_node(int domain_id, int dev); + +static uint32_t crc_table[256]; +uint32 timer_expired = 0; + +void set_thread_context(int domain) { + if (tlsKey != INVALID_KEY) { + pthread_setspecific(tlsKey, (void *)&hlist[domain]); + } +} + +int fastrpc_session_open(int domain, int *dev) { + int device = -1; + device = open_device_node(domain); + if (device >= 0) { + *dev = device; + return 0; + } + return AEE_EUNKNOWN; +} + +int fastrpc_session_close(int dev) { + close(dev); + return 0; +} + +int fastrpc_session_get(int domain) { + int ref = -1; + do { + if (hlist) { + pthread_mutex_lock(&hlist[domain].mut); + if (hlist[domain].state == FASTRPC_DOMAIN_STATE_DEINIT) { + pthread_mutex_unlock(&hlist[domain].mut); + return AEE_ENOTINITIALIZED; + } + hlist[domain].ref++; + ref = hlist[domain].ref; + pthread_mutex_unlock(&hlist[domain].mut); + set_thread_context(domain); + FARF(RUNTIME_RPC_HIGH, "%s, domain %d, state %d, ref %d\n", __func__, domain, + hlist[domain].state, ref); + } else { + return AEE_ENOTINITIALIZED; + } + } while (0); + return 0; +} + +int fastrpc_session_put(int domain) { + int ref = -1; + do { + if (hlist) { + pthread_mutex_lock(&hlist[domain].mut); + 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, + hlist[domain].state, ref); + } else { + return AEE_ENOTINITIALIZED; + } + } while (0); + return ref; +} + +int fastrpc_session_dev(int domain, int *dev) { + *dev = INVALID_DEVICE; + if (domain < 0 || domain >= NUM_DOMAINS_EXTEND) + return AEE_ENOTINITIALIZED; + do { + if (hlist) { + pthread_mutex_lock(&hlist[domain].mut); + if (hlist[domain].state == FASTRPC_DOMAIN_STATE_DEINIT) { + pthread_mutex_unlock(&hlist[domain].mut); + return AEE_ENOTINITIALIZED; + } + if (hlist[domain].dev < 0) { + pthread_mutex_unlock(&hlist[domain].mut); + return AEE_ENOTINITIALIZED; + } else { + *dev = hlist[domain].dev; + pthread_mutex_unlock(&hlist[domain].mut); + return AEE_SUCCESS; + } + pthread_mutex_unlock(&hlist[domain].mut); + } else { + return AEE_ENOTINITIALIZED; + } + } while (0); + return AEE_ENOTINITIALIZED; +} + +inline int is_domain_valid(int domain) { + if ((domain >= 0) && (domain < NUM_DOMAINS_EXTEND)) { + return 1; + } else { + return 0; + } +} + +int check_rpc_error(int err) { + if (check_error_code_change_present() == 1) { + if (err > KERNEL_ERRNO_START && err <= HLOS_ERR_END) // driver or HLOS err + return 0; + else if (err > (int)DSP_AEE_EOFFSET && + err <= (int)DSP_AEE_EOFFSET + 1024) // DSP err + return 0; + else if (err == AEE_ENOSUCH || + err == AEE_EINTERRUPTED) // common DSP HLOS err + return 0; + else + return -1; + } else + return 0; +} + +static void GenCrc32Tab(uint32_t GenPoly, uint32_t *crctab) { + uint32_t crc; + int i, j; + + for (i = 0; i < 256; i++) { + crc = i << 24; + for (j = 0; j < 8; j++) { + crc = (crc << 1) ^ (crc & 0x80000000 ? GenPoly : 0); + } + crctab[i] = crc; + } +} + +static uint32_t crc32_lut(unsigned char *data, int nbyte, uint32_t *crctab) { + uint32_t crc = 0; + if (!data || !crctab) + return 0; + + while (nbyte--) { + crc = (crc << 8) ^ crctab[(crc >> 24) ^ *data++]; + } + return crc; +} + +int property_get_int32(const char *name, int value) { return 0; } + +int property_get(const char *name, int *def, int *value) { return 0; } + +int fastrpc_get_property_int(fastrpc_properties UserPropKey, int defValue) { + if (((int)UserPropKey > NO_ENV_DEBUG_VAR_NAME_ARRAY_ELEMENTS)) { + FARF(ERROR, + "%s: Index %d out-of-bound for ENV_DEBUG_VAR_NAME array of len %d", + __func__, UserPropKey, NO_ENV_DEBUG_VAR_NAME_ARRAY_ELEMENTS); + return defValue; + } + const char *env = getenv(ENV_DEBUG_VAR_NAME[UserPropKey]); + if (env != 0) + return (int)atoi(env); +#if !defined(LE_ENABLE) // Android platform +#if !defined(SYSTEM_RPC_LIBRARY) // vendor library + if (((int)UserPropKey > NO_ANDROIDP_DEBUG_VAR_NAME_ARRAY_ELEMENTS)) { + FARF( + ERROR, + "%s: Index %d out-of-bound for ANDROIDP_DEBUG_VAR_NAME array of len %d", + __func__, UserPropKey, NO_ANDROIDP_DEBUG_VAR_NAME_ARRAY_ELEMENTS); + return defValue; + } + return (int)property_get_int32(ANDROIDP_DEBUG_VAR_NAME[UserPropKey], + defValue); +#else // system library + if (((int)UserPropKey > NO_ANDROID_DEBUG_VAR_NAME_ARRAY_ELEMENTS)) { + FARF(ERROR, + "%s: Index %d out-of-bound for ANDROID_DEBUG_VAR_NAME array of len %d", + __func__, UserPropKey, NO_ANDROID_DEBUG_VAR_NAME_ARRAY_ELEMENTS); + return defValue; + } + return (int)property_get_int32(ANDROID_DEBUG_VAR_NAME[UserPropKey], defValue); +#endif +#else // non-Android platforms + return defValue; +#endif +} +int fastrpc_get_property_string(fastrpc_properties UserPropKey, char *value, + char *defValue) { + int len = 0; + if (((int)UserPropKey > NO_ENV_DEBUG_VAR_NAME_ARRAY_ELEMENTS)) { + FARF(ERROR, + "%s: Index %d out-of-bound for ENV_DEBUG_VAR_NAME array of len %d", + __func__, UserPropKey, NO_ENV_DEBUG_VAR_NAME_ARRAY_ELEMENTS); + return len; + } + char *env = getenv(ENV_DEBUG_VAR_NAME[UserPropKey]); + if (env != 0) { + len = strlen(env); + std_memscpy(value, PROPERTY_VALUE_MAX, env, len + 1); + return len; + } +#if !defined(LE_ENABLE) // Android platform +#if !defined(SYSTEM_RPC_LIBRARY) // vendor library + if (((int)UserPropKey > NO_ANDROIDP_DEBUG_VAR_NAME_ARRAY_ELEMENTS)) { + FARF( + ERROR, + "%s: Index %d out-of-bound for ANDROIDP_DEBUG_VAR_NAME array of len %d", + __func__, UserPropKey, NO_ANDROIDP_DEBUG_VAR_NAME_ARRAY_ELEMENTS); + return len; + } + return property_get(ANDROIDP_DEBUG_VAR_NAME[UserPropKey], (int *)value, + (int *)defValue); +#else // system library + if (((int)UserPropKey > NO_ANDROID_DEBUG_VAR_NAME_ARRAY_ELEMENTS)) { + FARF(ERROR, + "%s: Index %d out-of-bound for ANDROID_DEBUG_VAR_NAME array of len %d", + __func__, UserPropKey, NO_ANDROID_DEBUG_VAR_NAME_ARRAY_ELEMENTS); + return len; + } + return property_get(ANDROID_DEBUG_VAR_NAME[UserPropKey], value, defValue); +#endif +#else // non-Android platforms + if (defValue != NULL) { + len = strlen(defValue); + std_memscpy(value, PROPERTY_VALUE_MAX, defValue, len + 1); + } + return len; +#endif +} + +/* + is_first_reverse_rpc_call: + + Checks if first reverse RPC call is already done + Args: + @domain - Remote subsystem domain ID + @handle - Session handle + @sc - Scalar + Returns: 1 - if first reverse RPC call already done + 0 - otherwise +*/ + +static inline int is_first_reverse_rpc_call(int domain, remote_handle handle, + uint32_t sc) { + int ret = 0; + + if (IS_REVERSE_RPC_CALL(handle, sc) && IS_SESSION_OPEN_ALREADY(domain)) { + if (hlist[domain].first_revrpc_done) + ret = 0; + else { + hlist[domain].first_revrpc_done = 1; + ret = 1; + } + } + return ret; +} + +static inline void trace_marker_init(int domain) { + const char TRACE_MARKER_FILE[] = "/sys/kernel/tracing/trace_marker"; + + if (IS_QTF_TRACING_ENABLED(hlist[domain].procattrs)) { + hlist[domain].trace_marker_fd = open(TRACE_MARKER_FILE, O_WRONLY); + ; + if (hlist[domain].trace_marker_fd < 0) { + FARF(ERROR, "Error: %s: failed to open '%s' for domain %d, errno %d (%s)", + __func__, TRACE_MARKER_FILE, domain, errno, strerror(errno)); + } + } +} + +static inline void trace_marker_deinit(int domain) { + if (hlist[domain].trace_marker_fd > 0) { + close(hlist[domain].trace_marker_fd); + hlist[domain].trace_marker_fd = -1; + } +} + +int get_logger_state(int domain) { + int ret = AEE_EFAILED; + + if (hlist && hlist[domain].disable_exit_logs) { + ret = AEE_SUCCESS; + } + return ret; +} + +/* Thread function that will be invoked to update remote user PD parameters */ +int fastrpc_set_remote_uthread_params(int domain) { + int nErr = AEE_SUCCESS, paramsLen = 2; + remote_handle64 handle = INVALID_HANDLE; + struct fastrpc_thread_params *th_params = &hlist[domain].th_params; + + VERIFYC(th_params != NULL, AEE_ERPC); + if ((handle = get_remotectl1_handle(domain)) != INVALID_HANDLE) { + nErr = remotectl1_set_param(handle, th_params->reqID, (uint32_t *)th_params, + paramsLen); + if (nErr) { + FARF(ALWAYS, + "Warning 0x%x: %s: remotectl1 domains not supported for domain %d\n", + nErr, __func__, domain); + fastrpc_update_module_list(DOMAIN_LIST_DEQUEUE, domain, + hlist[domain].remotectlhandle, NULL); + + // Set remotectlhandle to INVALID_HANDLE, so that all subsequent calls are + // non-domain calls + hlist[domain].remotectlhandle = INVALID_HANDLE; + VERIFY(AEE_SUCCESS == + (nErr = remotectl_set_param(th_params->reqID, + (uint32_t *)th_params, paramsLen))); + } + } else { + VERIFY(AEE_SUCCESS == + (nErr = remotectl_set_param(th_params->reqID, (uint32_t *)th_params, + paramsLen))); + } +bail: + if (nErr != AEE_SUCCESS) { + if (th_params) { + FARF(ERROR, + "Error 0x%x: %s failed domain %d thread priority %d stack size %d " + "(errno %s)", + nErr, __func__, domain, th_params->thread_priority, + th_params->stack_size, strerror(errno)); + } else { + FARF(ERROR, "Error 0x%x: %s failed", nErr, __func__); + } + } else { + FARF(ALWAYS, + "Successfully set remote user thread priority to %d and stack size to " + "%d for domain %d", + th_params->thread_priority, th_params->stack_size, domain); + } + return nErr; +} + +static inline bool is_valid_local_handle(int domain, struct handle_info *hinfo) { + QNode *pn; + int ii = 0; + if(domain == -1) { + for (ii = 0; ii < NUM_DOMAINS_EXTEND; ii++) { + pthread_mutex_lock(&hlist[ii].lmut); + QLIST_FOR_ALL(&hlist[ii].ql, pn) { + struct handle_info *hi = STD_RECOVER_REC(struct handle_info, qn, pn); + if (hi == hinfo) { + pthread_mutex_unlock(&hlist[ii].lmut); + return true; + } + } + pthread_mutex_unlock(&hlist[ii].lmut); + } + } else { + pthread_mutex_lock(&hlist[domain].lmut); + QLIST_FOR_ALL(&hlist[domain].ql, pn) { + struct handle_info *hi = STD_RECOVER_REC(struct handle_info, qn, pn); + if (hi == hinfo) { + pthread_mutex_unlock(&hlist[domain].lmut); + return true; + } + } + pthread_mutex_unlock(&hlist[domain].lmut); + } + return false; +} + +static int verify_local_handle(int domain, remote_handle64 local) { + struct handle_info *hinfo = (struct handle_info *)(uintptr_t)local; + int nErr = AEE_SUCCESS; + + VERIFYC((local != (remote_handle64)-1) && hinfo, AEE_EINVHANDLE); + VERIFYC(is_valid_local_handle(domain, hinfo), AEE_EINVHANDLE); + VERIFYC((hinfo->hlist >= &hlist[0]) && + (hinfo->hlist < &hlist[NUM_DOMAINS_EXTEND]), + AEE_ERPC); + VERIFYC(QNode_IsQueuedZ(&hinfo->qn), AEE_EINVHANDLE); +bail: + if (nErr != AEE_SUCCESS) { + FARF(RUNTIME_RPC_HIGH, "Error 0x%x: %s failed. handle 0x%" PRIx64 "\n", + nErr, __func__, local); + } + return nErr; +} + +int get_domain_from_handle(remote_handle64 local, int *domain) { + struct handle_info *hinfo = (struct handle_info *)(uintptr_t)local; + int dom, nErr = AEE_SUCCESS; + + VERIFY(AEE_SUCCESS == (nErr = verify_local_handle(-1, local))); + dom = (int)(hinfo->hlist - &hlist[0]); + VERIFYM((dom >= 0) && (dom < NUM_DOMAINS_EXTEND), AEE_EINVHANDLE, + "Error 0x%x: domain mapped to handle is out of range domain %d " + "handle 0x%" PRIx64 "\n", + nErr, dom, local); + *domain = dom; +bail: + if (nErr != AEE_SUCCESS) { + FARF(RUNTIME_RPC_HIGH, "Error 0x%x: %s failed. handle 0x%" PRIx64 "\n", + nErr, __func__, local); + } + return nErr; +} + +/** + * Function to get domain id from domain name + * @param[in] : Domain name of DSP + * @param[int]: Domain name length + * @return : Domain ID + */ +static int get_domain_from_domain_name(const char *domain_name, + int domain_name_len) { + int domain = INVALID_DOMAIN_ID; + + if (domain_name_len < std_strlen(SUBSYSTEM_NAME[ADSP_DOMAIN_ID])) { + FARF(ERROR, "ERROR: %s Invalid domain name length: %u\n", __func__, + domain_name_len); + goto bail; + } + if (domain_name) { + if (!std_strncmp(domain_name, SUBSYSTEM_NAME[ADSP_DOMAIN_ID], + std_strlen(SUBSYSTEM_NAME[ADSP_DOMAIN_ID]))) { + domain = ADSP_DOMAIN_ID; + } else if (!std_strncmp(domain_name, SUBSYSTEM_NAME[MDSP_DOMAIN_ID], + std_strlen(SUBSYSTEM_NAME[MDSP_DOMAIN_ID]))) { + domain = MDSP_DOMAIN_ID; + } else if (!std_strncmp(domain_name, SUBSYSTEM_NAME[SDSP_DOMAIN_ID], + std_strlen(SUBSYSTEM_NAME[SDSP_DOMAIN_ID]))) { + domain = SDSP_DOMAIN_ID; + } else if (!std_strncmp(domain_name, SUBSYSTEM_NAME[CDSP_DOMAIN_ID], + std_strlen(SUBSYSTEM_NAME[CDSP_DOMAIN_ID]))) { + domain = CDSP_DOMAIN_ID; + } else { + FARF(ERROR, "ERROR: %s Invalid domain name: %s\n", __func__, domain_name); + } + } + VERIFY_IPRINTF("%s: %d\n", __func__, domain); +bail: + return domain; +} + +static const char *get_domain_from_id(int domain_id) { + const char *uri_domain_suffix; + switch (domain_id) { + case ADSP_DOMAIN_ID: + uri_domain_suffix = ADSP_DOMAIN; + break; + case CDSP_DOMAIN_ID: + uri_domain_suffix = CDSP_DOMAIN; + break; + case MDSP_DOMAIN_ID: + uri_domain_suffix = MDSP_DOMAIN; + break; + case SDSP_DOMAIN_ID: + uri_domain_suffix = SDSP_DOMAIN; + break; + default: + uri_domain_suffix = "invalid domain"; + break; + } + return uri_domain_suffix; +} + +#define IS_CONST_HANDLE(h) (((h) < 0xff) ? 1 : 0) + +static int is_last_handle(int domain) { + int nErr = AEE_SUCCESS, last = 0; + + VERIFYC((domain >= 0) && (domain < NUM_DOMAINS_EXTEND), AEE_EBADPARM); + pthread_mutex_lock(&hlist[domain].lmut); + last = hlist[domain].domainsCount + hlist[domain].nondomainsCount; + pthread_mutex_unlock(&hlist[domain].lmut); +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_IPRINTF("Error 0x%x: %s failed for domain %d\n", nErr, __func__, + domain); + } + return last; +} + +static int get_handle_remote(remote_handle64 local, remote_handle64 *remote) { + struct handle_info *hinfo = (struct handle_info *)(uintptr_t)local; + int nErr = AEE_SUCCESS; + + VERIFY(AEE_SUCCESS == (nErr = verify_local_handle(-1, local))); + *remote = hinfo->remote; +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error %x: get handle remote failed %p\n", nErr, &local); + } + return nErr; +} + +inline int is_smmu_enabled(void) { + return hlist[get_current_domain()].info & FASTRPC_INFO_SMMU; +} + +static int fastrpc_alloc_handle(int domain, QList *me, remote_handle64 remote, + remote_handle64 *local) { + struct handle_info *hinfo = {0}; + int nErr = 0; + + VERIFYC(NULL != (hinfo = calloc(1, sizeof(*hinfo))), AEE_ENOMEMORY); + hinfo->local = (remote_handle64)(uintptr_t)hinfo; + hinfo->remote = remote; + hinfo->hlist = &hlist[domain]; + *local = hinfo->local; + + QNode_CtorZ(&hinfo->qn); + pthread_mutex_lock(&hlist[domain].lmut); + QList_PrependNode(me, &hinfo->qn); + pthread_mutex_unlock(&hlist[domain].lmut); +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, + "Error 0x%x: %s failed for local handle 0x%x, remote handle 0x%x, " + "domain %d\n", + nErr, __func__, local, remote, domain); + } + return nErr; +} + +static int fastrpc_free_handle(int domain, QList *me, remote_handle64 remote) { + pthread_mutex_lock(&hlist[domain].lmut); + if (!QList_IsEmpty(me)) { + QNode *pn = NULL, *pnn = NULL; + QLIST_NEXTSAFE_FOR_ALL(me, pn, pnn) { + struct handle_info *hi = STD_RECOVER_REC(struct handle_info, qn, pn); + if (hi->remote == remote) { + QNode_DequeueZ(&hi->qn); + free(hi); + hi = NULL; + break; + } + } + } + pthread_mutex_unlock(&hlist[domain].lmut); + return 0; +} + +int fastrpc_update_module_list(uint32_t req, int domain, remote_handle64 h, + remote_handle64 *local) { + int nErr = AEE_SUCCESS; + + switch (req) { + case DOMAIN_LIST_PREPEND: { + VERIFY(AEE_SUCCESS == + (nErr = fastrpc_alloc_handle(domain, &hlist[domain].ql, h, local))); + if(IS_CONST_HANDLE(h)) { + pthread_mutex_lock(&hlist[domain].lmut); + hlist[domain].constCount++; + pthread_mutex_unlock(&hlist[domain].lmut); + } else { + pthread_mutex_lock(&hlist[domain].lmut); + hlist[domain].domainsCount++; + pthread_mutex_unlock(&hlist[domain].lmut); + } + break; + } + case DOMAIN_LIST_DEQUEUE: { + VERIFY(AEE_SUCCESS == + (nErr = fastrpc_free_handle(domain, &hlist[domain].ql, h))); + if(IS_CONST_HANDLE(h)) { + pthread_mutex_lock(&hlist[domain].lmut); + hlist[domain].constCount--; + pthread_mutex_unlock(&hlist[domain].lmut); + } else { + pthread_mutex_lock(&hlist[domain].lmut); + hlist[domain].domainsCount--; + pthread_mutex_unlock(&hlist[domain].lmut); + } + break; + } + case NON_DOMAIN_LIST_PREPEND: { + VERIFY(AEE_SUCCESS == + (nErr = fastrpc_alloc_handle(domain, &hlist[domain].nql, h, local))); + pthread_mutex_lock(&hlist[domain].lmut); + hlist[domain].nondomainsCount++; + pthread_mutex_unlock(&hlist[domain].lmut); + break; + } + case NON_DOMAIN_LIST_DEQUEUE: { + VERIFY(AEE_SUCCESS == + (nErr = fastrpc_free_handle(domain, &hlist[domain].nql, h))); + pthread_mutex_lock(&hlist[domain].lmut); + hlist[domain].nondomainsCount--; + pthread_mutex_unlock(&hlist[domain].lmut); + break; + } + case REVERSE_HANDLE_LIST_PREPEND: { + VERIFY(AEE_SUCCESS == + (nErr = fastrpc_alloc_handle(domain, &hlist[domain].rql, h, local))); + pthread_mutex_lock(&hlist[domain].lmut); + hlist[domain].reverseCount++; + pthread_mutex_unlock(&hlist[domain].lmut); + break; + } + case REVERSE_HANDLE_LIST_DEQUEUE: { + VERIFY(AEE_SUCCESS == + (nErr = fastrpc_free_handle(domain, &hlist[domain].rql, h))); + pthread_mutex_lock(&hlist[domain].lmut); + hlist[domain].reverseCount--; + pthread_mutex_unlock(&hlist[domain].lmut); + break; + } + default: { + nErr = AEE_EUNSUPPORTEDAPI; + goto bail; + } + } +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, + "Error 0x%x: %s failed for request ID %u, handle 0x%x, domain %d\n", + nErr, __func__, req, h, domain); + } else { + FARF(RUNTIME_RPC_HIGH, "Library D count %d, C count %d, N count %d, R count %d\n", hlist[domain].domainsCount, hlist[domain].constCount, hlist[domain].nondomainsCount, hlist[domain].reverseCount); + } + return nErr; +} + +static void fastrpc_clear_handle_list(uint32_t req, int domain) { + int nErr = AEE_SUCCESS; + QNode *pn = NULL; + char dlerrstr[MAX_DLERRSTR_LEN]; + int dlerr = 0; + + switch (req) { + case MULTI_DOMAIN_HANDLE_LIST_ID: { + pthread_mutex_lock(&hlist[domain].lmut); + if (!QList_IsNull(&hlist[domain].ql)) { + while ((pn = QList_Pop(&hlist[domain].ql))) { + struct handle_info *hi = STD_RECOVER_REC(struct handle_info, qn, pn); + free(hi); + hi = NULL; + } + } + pthread_mutex_unlock(&hlist[domain].lmut); + break; + } + case NON_DOMAIN_HANDLE_LIST_ID: { + pthread_mutex_lock(&hlist[domain].lmut); + if (!QList_IsNull(&hlist[domain].nql)) { + while ((pn = QList_Pop(&hlist[domain].nql))) { + struct handle_info *h = STD_RECOVER_REC(struct handle_info, qn, pn); + free(h); + h = NULL; + } + } + pthread_mutex_unlock(&hlist[domain].lmut); + break; + } + case REVERSE_HANDLE_LIST_ID: { + if (!QList_IsNull(&hlist[domain].rql)) { + while ((pn = QList_Pop(&hlist[domain].rql))) { + struct handle_info *hi = STD_RECOVER_REC(struct handle_info, qn, pn); + close_reverse_handle(hi->local, dlerrstr, sizeof(dlerrstr), &dlerr); + free(hi); + hi = NULL; + } + } + break; + } + default: { + nErr = AEE_EUNSUPPORTEDAPI; + goto bail; + } + } +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed for request ID %u, domain %d\n", nErr, + __func__, req, domain); + } + return; +} + +// Notify kernel to awake PM +static int wakelock_control_kernel_pm(int domain, int dev, uint32_t timeout) { + int nErr = AEE_SUCCESS; + struct fastrpc_ctrl_pm pm = {0}; + + pm.timeout = timeout; + nErr = ioctl_control(dev, DSPRPC_PM, &pm); + if (nErr) { + if (errno == EBADRQC || errno == ENOTTY) { + VERIFY_WPRINTF("Warning: %s: kernel does not support PM management (%s)", + __func__, strerror(errno)); + } else if (errno == EACCES || errno == EPERM) { + VERIFY_WPRINTF("Warning: %s: application does not have permission for PM " + "management (%s)", + __func__, strerror(errno)); + } + FARF(ERROR, + "Error 0x%x: %s PM control failed for domain %d, dev %d with timeout " + "%d (errno %s)", + nErr, __func__, domain, dev, timeout, strerror(errno)); + } + return nErr; +} + +// Callback function for posix timer +static void fastrpc_timer_callback(void *ptr) { + fastrpc_timer *frpc_timer = (fastrpc_timer *)ptr; + int nErr = AEE_SUCCESS; + remote_rpc_process_exception data; + + if (1 == atomic_CompareAndExchange(&timer_expired, 1, 0)) { + return; + } + + FARF(ALWAYS, + "%s fastrpc time out of %d ms on domain %d sc 0x%x handle 0x%x\n", + __func__, frpc_timer->timeout_millis, frpc_timer->domain, frpc_timer->sc, + frpc_timer->handle); + data.domain = frpc_timer->domain; + nErr = remote_session_control(FASTRPC_REMOTE_PROCESS_EXCEPTION, &data, + sizeof(remote_rpc_process_exception)); + if (nErr) { + FARF(ERROR, + "%s: Failed to create exception in the remote process on domain %d " + "(errno %s)", + __func__, data.domain, strerror(errno)); + } +} + +// Function to add timer before remote RPC call +static void fastrpc_add_timer(fastrpc_timer *frpc_timer) { + struct sigevent sigevent; + struct itimerspec time_spec; + int err = 0; + + memset(&sigevent, 0, sizeof(sigevent)); + sigevent.sigev_notify = SIGEV_THREAD; + sigevent.sigev_notify_function = + (void (*)(union sigval))fastrpc_timer_callback; + sigevent.sigev_value.sival_ptr = frpc_timer; + err = timer_create(CLOCK_MONOTONIC, &sigevent, &(frpc_timer->timer)); + if (err) { + FARF(ERROR, "%s: failed to create timer with error 0x%x\n", __func__, err); + goto bail; + } + + time_spec.it_value.tv_sec = frpc_timer->timeout_millis / 1000; + time_spec.it_value.tv_nsec = + (frpc_timer->timeout_millis % 1000) * 1000 * 1000; + err = timer_settime(frpc_timer->timer, 0, &time_spec, NULL); + if (err) { + FARF(ERROR, "%s: failed to set timer with error 0x%x\n", __func__, err); + goto bail; + } +bail: + return; +} + +// Function to delete timer after remote RPC call +static void fastrpc_delete_timer(timer_t *timer) { + int nErr = AEE_SUCCESS; + nErr = timer_delete(*timer); + if (nErr) { + FARF(ERROR, "%s: Failed to delete timer", __func__); + } +} + +int remote_handle_invoke_domain(int domain, remote_handle handle, + fastrpc_async_descriptor_t *desc, 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; + struct handle_list *list; + uint32_t *crc_remote = NULL; + 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; + + 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; + } + + VERIFY(AEE_SUCCESS == (nErr = fastrpc_session_dev(domain, &dev))); + + errno = 0; + if (fastrpc_wake_lock_enable[domain]) { + if (!IS_REVERSE_RPC_CALL(handle, sc) || + is_first_reverse_rpc_call(domain, handle, sc)) { + if (!fastrpc_wake_lock()) + wake_lock = 1; + } else if (IS_REVERSE_RPC_CALL(handle, sc)) + /* Since wake-lock is not released at the end of previous + * "remote_handle_invoke" for subsequent reverse RPC calls, it doesn't + * have to be taken again here. + * It will be released before "ioctl invoke" call to kernel */ + wake_lock = 1; + } + + list = &hlist[domain]; + if (list->setmode) { + list->setmode = 0; + nErr = ioctl_setmode(dev, list->mode); + if (nErr) { + nErr = convert_kernel_to_user_error(nErr, errno); + goto bail; + } + } + + bufs = REMOTE_SCALARS_INBUFS(sc) + REMOTE_SCALARS_OUTBUFS(sc); + handles = REMOTE_SCALARS_INHANDLES(sc) + REMOTE_SCALARS_OUTHANDLES(sc); + total = bufs + handles; + + 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 == args && NULL == pra && total > 0), AEE_EBADPARM); + for (i = 0; i < bufs; i++) { + set_args(i, pra[i].buf.pv, pra[i].buf.nLen, -1, 0); + if (pra[i].buf.nLen) { + void *base; + int nova = 0, attr = 0, fd = -1; + VERIFY(AEE_SUCCESS == + (nErr = fdlist_fd_from_buf(pra[i].buf.pv, (int)pra[i].buf.nLen, + &nova, &base, &attr, &fd))); + if (fd != -1) { + 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); + // pra[i].buf.pv = (void*)((uintptr_t)pra[i].buf.pv - (uintptr_t)base); + VERIFY_IPRINTF("nova buffer idx: %d addr: %p size: %d", i, + pra[i].buf.pv, pra[i].buf.nLen); + } + if (attr & FASTRPC_ATTR_NON_COHERENT) { + req = INVOKE_ATTRS; + append_args_attr(i, FASTRPC_ATTR_NON_COHERENT); + VERIFY_IPRINTF("non-coherent buffer idx: %d addr: %p size: %d", i, + pra[i].buf.pv, pra[i].buf.nLen); + } + if (attr & FASTRPC_ATTR_COHERENT) { + req = INVOKE_ATTRS; + append_args_attr(i, FASTRPC_ATTR_COHERENT); + VERIFY_IPRINTF("coherent buffer idx: %d addr: %p size: %d", i, + pra[i].buf.pv, pra[i].buf.nLen); + } + if (attr & FASTRPC_ATTR_FORCE_NOFLUSH) { + req = INVOKE_ATTRS; + append_args_attr(i, FASTRPC_ATTR_FORCE_NOFLUSH); + VERIFY_IPRINTF("force no flush for buffer idx: %d addr: %p size: %d", i, + pra[i].buf.pv, pra[i].buf.nLen); + } + if (attr & FASTRPC_ATTR_FORCE_NOINVALIDATE) { + req = INVOKE_ATTRS; + append_args_attr(i, FASTRPC_ATTR_FORCE_NOINVALIDATE); + VERIFY_IPRINTF("force no invalidate buffer idx: %d addr: %p size: %d", + i, pra[i].buf.pv, pra[i].buf.nLen); + } + if (attr & FASTRPC_ATTR_KEEP_MAP) { + req = INVOKE_ATTRS; + append_args_attr(i, FASTRPC_ATTR_KEEP_MAP); + VERIFY_IPRINTF("invoke: mapping with attribute KEEP_MAP"); + } + } + } + + for (i = bufs; i < total; i++) { + unsigned int attr = 0; + int dma_fd = -1; + + req = INVOKE_ATTRS; + unregister_dma_handle(pra[i].dma.fd, &len, &attr); + if (hlist[domain].dma_handle_reverse_rpc_map_capability && + (attr & FASTRPC_ATTR_NOMAP)) { + // Register fd again, for reverse RPC call to retrive FASTRPC_ATTR_NOMAP + // flag for fd + remote_register_dma_handle_attr(pra[i].dma.fd, len, FASTRPC_ATTR_NOMAP); + } + dma_fd = pra[i].dma.fd; + set_args(i, (void *)(uintptr_t)pra[i].dma.offset, len, dma_fd, attr); + append_args_attr(i, FASTRPC_ATTR_NOVA); + } + + if (IS_CRC_CHECK_ENABLED(hlist[domain].procattrs) && + (!IS_STATIC_HANDLE(handle)) && !asyncjob.isasyncjob) { + 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)); + VERIFYC(crc_local != NULL && crc_remote != NULL, AEE_ENOMEMORY); + VERIFYC(!(NULL == pra && nInBufs > 0), AEE_EBADPARM); + for (i = 0; (i < nInBufs) && (i < M_CRCLIST); i++) + crc_local[i] = crc32_lut((unsigned char *)pra[i].buf.pv, + (int)pra[i].buf.nLen, crc_table); + req = INVOKE_CRC; + } + + if (IS_KERNEL_PERF_ENABLED(hlist[domain].procattrs) && + (!IS_STATIC_HANDLE(handle))) { + perf_kernel = (uint64_t *)calloc(PERF_KERNEL_KEY_MAX, sizeof(uint64_t)); + VERIFYC(perf_kernel != NULL, AEE_ENOMEMORY); + req = INVOKE_PERF; + } + if (IS_DSP_PERF_ENABLED(hlist[domain].procattrs) && + (!IS_STATIC_HANDLE(handle))) { + perf_dsp = (uint64_t *)calloc(PERF_DSP_KEY_MAX, sizeof(uint64_t)); + VERIFYC(perf_dsp != NULL, AEE_ENOMEMORY); + req = INVOKE_PERF; + } + + 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; + frpc_timer.handle = handle; + frpc_timer.timeout_millis = rpc_timeout; + fastrpc_add_timer(&frpc_timer); + } + } + + FASTRPC_TRACE_LOG(FASTRPC_TRACE_INVOKE_START, handle, sc); + if (wake_lock) { + wakelock_control_kernel_pm(domain, dev, PM_TIMEOUT_MS); + fastrpc_wake_unlock(); + wake_lock = 0; + } + // Macros are initializing and destroying pfds and pattrs. + nErr = ioctl_invoke(dev, req, handle, sc, get_args(), pfds, pattrs, job, + crc_remote, perf_kernel, perf_dsp); + if (nErr) { + nErr = convert_kernel_to_user_error(nErr, errno); + } + + if (fastrpc_wake_lock_enable[domain]) { + if (!fastrpc_wake_lock()) + wake_lock = 1; + } + FASTRPC_TRACE_LOG(FASTRPC_TRACE_INVOKE_END, handle, sc); + if (!IS_STATIC_HANDLE(handle) && rpc_timeout > 0) { + fastrpc_delete_timer(&(frpc_timer.timer)); + } + + if (IS_CRC_CHECK_ENABLED(hlist[domain].procattrs) && + (!IS_STATIC_HANDLE(handle)) && !asyncjob.isasyncjob) { + int nInBufs = REMOTE_SCALARS_INBUFS(sc); + VERIFYC(crc_local != NULL && crc_remote != NULL, AEE_ENOMEMORY); + for (i = nInBufs; i < bufs; i++) + crc_local[i] = crc32_lut((unsigned char *)pra[i].buf.pv, + (int)pra[i].buf.nLen, crc_table); + for (i = 0; (i < bufs) && (i < M_CRCLIST); i++) { + if (crc_local[i] != crc_remote[i]) { + FARF(ERROR, "CRC mismatch for buffer %d[%d], crc local %x remote %x", i, + bufs, crc_local[i], crc_remote[i]); + break; + } + } + } + + if (IS_KERNEL_PERF_ENABLED(hlist[domain].procattrs) && + (!IS_STATIC_HANDLE(handle)) && !asyncjob.isasyncjob) { + 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)) && !asyncjob.isasyncjob) { + 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]); + } + + if (!(perf_v2_kernel && perf_v2_dsp)) { + 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); + crc_local = NULL; + } + if (crc_remote) { + free(crc_remote); + crc_remote = NULL; + } + if (perf_kernel && !asyncjob.isasyncjob) { + free(perf_kernel); + perf_kernel = NULL; + } + if (perf_dsp && !asyncjob.isasyncjob) { + free(perf_dsp); + perf_dsp = NULL; + } + if (wake_lock) { + // Keep holding wake-lock for reverse RPC calls to keep CPU awake for any + // further processing + if (!IS_REVERSE_RPC_CALL(handle, sc)) { + fastrpc_wake_unlock(); + wake_lock = 0; + } + } + if (trace_enabled) { + write(trace_marker_fd, INVOKE_END_TRACE_STR, invoke_end_trace_strlen); + } + if (nErr != AEE_SUCCESS) { + if ((nErr == -1) && (errno == ECONNRESET)) { + nErr = AEE_ECONNRESET; + } + // FARF(ERROR, "Error 0x%x: %s failed for handle 0x%x on domain %d (sc + // 0x%x)\n", nErr, __func__, (int)handle, domain, sc); + } + return nErr; +} + +int remote_handle_invoke(remote_handle handle, 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 sc %X remote_arg %p\n", + __func__, handle, sc, pra); + PRINT_WARN_USE_DOMAINS(); + 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, NULL, sc, pra))); +bail: + FASTRPC_PUT_REF(domain); + if (nErr != AEE_SUCCESS) { + if (is_process_exiting(domain)) { + return 0; + } + if (0 == check_rpc_error(nErr)) { + if (get_logger_state(domain)) { + FARF(ERROR, + "Error 0x%x: %s failed for handle 0x%x, method %d on domain %d " + "(sc 0x%x) (errno %s)\n", + nErr, __func__, (int)handle, REMOTE_SCALARS_METHOD(sc), domain, sc, + strerror(errno)); + } + } + } + FASTRPC_ATRACE_END(); + return nErr; +} + +int remote_handle64_invoke(remote_handle64 local, 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())); + + 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, NULL, sc, pra))); +bail: + FASTRPC_PUT_REF(domain); + if (nErr != AEE_SUCCESS) { + if (is_process_exiting(domain)) { + return 0; + } + if (0 == check_rpc_error(nErr)) { + if (get_logger_state(domain)) { + 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 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); + PRINT_WARN_USE_DOMAINS(); + 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) { + char dlerrstr[255]; + int dlerr = 0, nErr = AEE_SUCCESS; + int dev = -1; + char *pdname_uri = NULL; + int name_len = 0; + remote_handle64 handle = INVALID_HANDLE; + + FASTRPC_ATRACE_BEGIN_L("%s called with domain %d, name %s, handle 0x%x", + __func__, domain, name, ph); + /* If the total reference count exceeds one then exit the application. */ + if (total_dsp_lib_refcnt > MAX_LIB_INSTANCE_ALLOWED) { + FARF(ERROR, + "Error: aborting due to %d instances of libxdsprpc. Only %d allowed\n", + total_dsp_lib_refcnt, MAX_LIB_INSTANCE_ALLOWED); + deinit_fastrpc_dsp_lib_refcnt(); + exit(EXIT_FAILURE); + } + if (!std_strncmp(name, ITRANSPORT_PREFIX "geteventfd", + std_strlen(ITRANSPORT_PREFIX "geteventfd"))) { + FARF(RUNTIME_RPC_HIGH, "getting event fd"); + return listener_android_geteventfd(domain, (int *)ph); + } + if (!std_strncmp(name, ITRANSPORT_PREFIX "attachguestos", + std_strlen(ITRANSPORT_PREFIX "attachguestos"))) { + FARF(RUNTIME_RPC_HIGH, "setting attach mode to guestos : %d", domain); + hlist[domain].dsppd = ROOT_PD; + return AEE_SUCCESS; + } + if (!std_strncmp(name, ITRANSPORT_PREFIX "createstaticpd", + std_strlen(ITRANSPORT_PREFIX "createstaticpd"))) { + FARF(RUNTIME_RPC_HIGH, "creating static pd on domain: %d", domain); + name_len = strlen(name); + VERIFYC(NULL != + (pdname_uri = (char *)malloc((name_len + 1) * sizeof(char))), + AEE_ENOMEMORY); + std_strlcpy(pdname_uri, name, name_len + 1); + char *pdName = pdname_uri + std_strlen(ITRANSPORT_PREFIX "createstaticpd:"); + + /* + * Support sessions feature for static PDs. + * For eg, the same app can call 'remote_handle64_open' with + * "createstaticpd:sensorspd&_dom=adsp&_session=0" and + * "createstaticpd:oispd&_dom=adsp&_session=1" to create a session + * on both static PDs. + */ + if (std_strstr(pdName, get_domain_from_id(domain & DOMAIN_ID_MASK)) && + std_strstr(pdName, FASTRPC_SESSION_URI)) { + std_strlcpy(pdName, pdName, + (std_strlen(pdName) - + std_strlen(get_domain_from_id(domain & DOMAIN_ID_MASK)) - + std_strlen(FASTRPC_SESSION1_URI) + 1)); + } else if (std_strstr(pdName, get_domain_from_id(domain))) { + std_strlcpy( + pdName, pdName, + (std_strlen(pdName) - std_strlen(get_domain_from_id(domain)) + 1)); + } + VERIFYC(MAX_DSPPD_NAMELEN > std_strlen(pdName), AEE_EBADPARM); + std_strlcpy(hlist[domain].dsppdname, pdName, std_strlen(pdName) + 1); + if (!std_strncmp(pdName, "audiopd", std_strlen("audiopd"))) { + hlist[domain].dsppd = AUDIO_STATICPD; + } else if (!std_strncmp(pdName, "securepd", std_strlen("securepd"))) { + FARF(ALWAYS, "%s: attaching to securePD\n", __func__); + hlist[domain].dsppd = SECURE_STATICPD; + } else if (!std_strncmp(pdName, "sensorspd", std_strlen("sensorspd"))) { + hlist[domain].dsppd = SENSORS_STATICPD; + } else if (!std_strncmp(pdName, "rootpd", std_strlen("rootpd"))) { + hlist[domain].dsppd = GUEST_OS_SHARED; + } else if (!std_strncmp(pdName, "oispd", std_strlen("oispd"))) { + hlist[domain].dsppd = OIS_STATICPD; + } + return AEE_SUCCESS; + } + if (std_strbegins(name, ITRANSPORT_PREFIX "attachuserpd")) { + FARF(RUNTIME_RPC_HIGH, "setting attach mode to userpd : %d", domain); + hlist[domain].dsppd = USERPD; + return AEE_SUCCESS; + } + PROFILE_ALWAYS(t_spawn, + VERIFY(AEE_SUCCESS == (nErr = domain_init(domain, &dev))); + VERIFYM(-1 != dev, AEE_ERPC, "open dev failed\n");); + PROFILE_ALWAYS( + t_load, + if ((handle = get_remotectl1_handle(domain)) != INVALID_HANDLE) { + nErr = remotectl1_open1(handle, name, (int *)ph, dlerrstr, + sizeof(dlerrstr), &dlerr); + if (nErr) { + FARF(ALWAYS, + "Warning 0x%x: %s: remotectl1 domains not supported for domain " + "%d\n", + nErr, __func__, domain); + fastrpc_update_module_list(DOMAIN_LIST_DEQUEUE, domain, + hlist[domain].remotectlhandle, NULL); + + // Set remotectlhandle to INVALID_HANDLE, so that all subsequent calls + // are non-domain calls + hlist[domain].remotectlhandle = INVALID_HANDLE; + VERIFY(AEE_SUCCESS == + (nErr = remotectl_open(name, (int *)ph, dlerrstr, + sizeof(dlerrstr), &dlerr))); + } + } else { + VERIFY(AEE_SUCCESS == + (nErr = remotectl_open(name, (int *)ph, dlerrstr, + sizeof(dlerrstr), &dlerr))); + } VERIFY(AEE_SUCCESS == (nErr = dlerr));); +bail: + if (dlerr != 0) { + FARF(ERROR, + "Error 0x%x: %s: dynamic loading failed for %s on domain %d (dlerror " + "%s) (errno %s)\n", + nErr, __func__, name, domain, dlerrstr, strerror(errno)); + } + if (pdname_uri) { + free(pdname_uri); + pdname_uri = NULL; + } + if (nErr == AEE_ECONNRESET) { + if (is_last_handle(domain)) { + hlist[domain].disable_exit_logs = 1; + domain_deinit(domain); + } + } + FASTRPC_ATRACE_END(); + return nErr; +} + +int remote_handle_open(const char *name, remote_handle *ph) { + int nErr = 0, domain = -1, ref = 0; + uint64_t t_spawn = 0, t_load = 0; + remote_handle64 local; + + VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); + + FARF(RUNTIME_RPC_HIGH, "Entering %s, name %s\n", __func__, name); + PRINT_WARN_USE_DOMAINS(); + FASTRPC_ATRACE_BEGIN_L("%s for %s", __func__, name); + + if (!name || !ph) { + FARF(ERROR, "%s: Invalid input", __func__); + return AEE_EBADPARM; + } + + domain = get_current_domain(); + FASTRPC_GET_REF(domain); + VERIFY(AEE_SUCCESS == (nErr = remote_handle_open_domain(domain, name, ph, + &t_spawn, &t_load))); + fastrpc_update_module_list(NON_DOMAIN_LIST_PREPEND, domain, *ph, &local); +bail: + if (nErr) { + if (*ph) { + remote_handle64_close(*ph); + } else { + FASTRPC_PUT_REF(domain); + } + if (0 == check_rpc_error(nErr)) { + FARF(ERROR, "Error 0x%x: %s failed for %s (errno %s)", nErr, __func__, name, + strerror(errno)); + } + } else { + FARF(ALWAYS, + "%s: Successfully opened handle 0x%x for %s on domain %d (spawn time " + "%" PRIu64 " us, load time %" PRIu64 " us)", + __func__, (int)(*ph), name, domain, t_spawn, t_load); + } + FASTRPC_ATRACE_END(); + return nErr; +} + +int remote_handle64_open(const char *name, remote_handle64 *ph) { + remote_handle h = 0; + remote_handle64 remote = 0, local; + int domain = -1, nErr = 0, ref = 0; + uint64_t t_spawn = 0, t_load = 0; + + VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); + FARF(RUNTIME_RPC_HIGH, "Entering %s, name %s\n", __func__, name); + FASTRPC_ATRACE_BEGIN_L("%s for %s", __func__, name); + + if (!name || !ph) { + FARF(ERROR, "%s: Invalid input", __func__); + return AEE_EBADPARM; + } + + domain = get_domain_from_name(name, DOMAIN_NAME_IN_URI); + VERIFYC(domain >= 0, AEE_EBADPARM); + FASTRPC_GET_REF(domain); + hlist[domain].domainsupport = 1; + VERIFY(AEE_SUCCESS == (nErr = remote_handle_open_domain(domain, name, &h, + &t_spawn, &t_load))); + /* Returning local handle to "geteventd" call causes bad fd error when daemon + polls on it, hence return remote handle (which is the actual fd) for + "geteventd" call*/ + if (!std_strncmp(name, ITRANSPORT_PREFIX "geteventfd", + std_strlen(ITRANSPORT_PREFIX "geteventfd"))) { + *ph = h; + } else { + fastrpc_update_module_list(DOMAIN_LIST_PREPEND, domain, h, &local); + *ph = local; + } +bail: + if (nErr) { + if (h) + remote_handle_close(h); + else + FASTRPC_PUT_REF(domain); + if (0 == check_rpc_error(nErr)) { + FARF(ERROR, "Error 0x%x: %s failed for %s (errno %s)\n", nErr, __func__, + name, strerror(errno)); + } + } else { + FARF(ALWAYS, + "%s: Successfully opened handle 0x%" PRIx64 " (remote 0x%" PRIx64 + ") for %s on domain %d (spawn time %" PRIu64 " us, load time %" PRIu64 + " us), num handles %u", + __func__, (*ph), remote, name, domain, t_spawn, t_load, + hlist[domain].open_handle_count); + } + FASTRPC_ATRACE_END(); + return nErr; +} + +int remote_handle_close_domain(int domain, remote_handle h) { + char *dlerrstr = NULL; + int dlerr = 0, nErr = AEE_SUCCESS; + size_t err_str_len = MAX_DLERRSTR_LEN * sizeof(char); + uint64_t t_close = 0; + remote_handle64 handle = INVALID_HANDLE; + + FASTRPC_ATRACE_BEGIN_L("%s called with handle 0x%x", __func__, (int)h); + VERIFYC(h != (remote_handle)-1, AEE_EINVHANDLE); + VERIFYC(NULL != (dlerrstr = (char *)calloc(1, err_str_len)), AEE_ENOMEMORY); + PROFILE_ALWAYS( + &t_close, + if ((handle = get_remotectl1_handle(domain)) != INVALID_HANDLE) { + VERIFY(AEE_SUCCESS == (nErr = remotectl1_close1(handle, h, dlerrstr, + err_str_len, &dlerr))); + } else { + VERIFY(AEE_SUCCESS == + (nErr = remotectl_close(h, dlerrstr, err_str_len, &dlerr))); + } VERIFY(AEE_SUCCESS == (nErr = dlerr));); +bail: + if (nErr != AEE_SUCCESS) { + if (0 == check_rpc_error(nErr)) { + FARF(ERROR, + "Error 0x%x: %s failed for handle 0x%x, domain %d (dlerr %s) (errno " + "%s)\n", + nErr, __func__, h, domain, dlerrstr, strerror(errno)); + } + } else { + FARF(ALWAYS, "%s: closed handle 0x%x (skel unload time %" PRIu64 " us)", + __func__, h, t_close); + } + if (dlerrstr) { + free(dlerrstr); + dlerrstr = NULL; + } + FASTRPC_ATRACE_END(); + return nErr; +} + +int remote_handle_close(remote_handle h) { + int nErr = AEE_SUCCESS, domain = get_current_domain(), ref = 1; + + FARF(RUNTIME_RPC_HIGH, "Entering %s, handle %lu\n", __func__, h); + + PRINT_WARN_USE_DOMAINS(); + VERIFY(AEE_SUCCESS == (nErr = remote_handle_close_domain(domain, h))); + FASTRPC_PUT_REF(domain); + fastrpc_update_module_list(NON_DOMAIN_LIST_DEQUEUE, domain, h, NULL); +bail: + if (nErr != AEE_SUCCESS) { + if (is_process_exiting(domain)) { + return 0; + } + if (0 == check_rpc_error(nErr)) { + FARF(ERROR, "Error 0x%x: %s failed for handle 0x%x\n", nErr, __func__, h); + } + } + return nErr; +} + +int remote_handle64_close(remote_handle64 handle) { + remote_handle64 remote = 0; + int domain = -1, nErr = AEE_SUCCESS, ref = 1; + + FARF(RUNTIME_RPC_HIGH, "Entering %s, handle %llu\n", __func__, handle); + FASTRPC_ATRACE_BEGIN_L("%s called with handle 0x%" PRIx64 "\n", __func__, + handle); + VERIFYC(handle != (remote_handle64)-1, AEE_EINVHANDLE); + VERIFY(AEE_SUCCESS == (nErr = get_domain_from_handle(handle, &domain))); + VERIFY(AEE_SUCCESS == (nErr = get_handle_remote(handle, &remote))); + set_thread_context(domain); + if (remote) { + VERIFY(AEE_SUCCESS == + (nErr = remote_handle_close_domain(domain, (remote_handle)remote))); + } + fastrpc_update_module_list(DOMAIN_LIST_DEQUEUE, domain, handle, NULL); + FASTRPC_PUT_REF(domain); +bail: + if (nErr != AEE_EINVHANDLE) { + if (is_valid_local_handle(domain, (struct handle_info *)handle) && is_last_handle(domain)) { + domain_deinit(domain); + } else { + nErr = AEE_ERPC; + } + } else if (nErr != AEE_SUCCESS) { + if (is_process_exiting(domain)) { + return 0; + } + if (0 == check_rpc_error(nErr)) { + FARF(ERROR, + "Error 0x%x: %s failed for handle 0x%" PRIx64 + " remote handle 0x%" PRIx64 " (errno %s), num of open handles: %u\n", + nErr, __func__, handle, remote, strerror(errno), + hlist[domain].open_handle_count); + } + } else { + FARF(ALWAYS, + "%s: closed handle 0x%" PRIx64 " remote handle 0x%" PRIx64 + ", num of open handles: %u", + __func__, handle, remote, hlist[domain].open_handle_count); + } + FASTRPC_ATRACE_END(); + 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)) + return nErr; + + if (hlist[domain].dev != -1) { + /* If session is already open on DSP, then make rpc call directly to user PD + */ + if ((handle = get_remotectl1_handle(domain)) != INVALID_HANDLE) { + nErr = remotectl1_set_param(handle, RPC_ADAPTIVE_QOS, &enable, 1); + if (nErr) { + FARF(ALWAYS, + "Warning 0x%x: %s: remotectl1 domains not supported for domain " + "%d\n", + nErr, __func__, domain); + fastrpc_update_module_list(DOMAIN_LIST_DEQUEUE, domain, + hlist[domain].remotectlhandle, NULL); + + // Set remotectlhandle to INVALID_HANDLE, so that all subsequent calls + // are non-domain calls + hlist[domain].remotectlhandle = INVALID_HANDLE; + nErr = remotectl_set_param(RPC_ADAPTIVE_QOS, &enable, 1); + } + } else { + nErr = remotectl_set_param(RPC_ADAPTIVE_QOS, &enable, 1); + } + if (nErr) { + FARF(ERROR, + "Error: %s: remotectl_set_param failed to reset adaptive QoS on DSP " + "to %d on domain %d", + __func__, enable, domain); + goto bail; + } else { + hlist[domain].qos.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); + } + + if (enable) + FARF(ALWAYS, "%s: Successfully enabled adaptive QoS on domain %d", __func__, + domain); + else + FARF(ALWAYS, "%s: Disabled adaptive QoS on domain %d", __func__, domain); +bail: + return nErr; +} + +static int manage_poll_qos(int domain, remote_handle64 h, uint32_t enable, + uint32_t latency) { + int nErr = AEE_SUCCESS, dev = -1; + const unsigned int MAX_POLL_TIMEOUT = 10000; + struct fastrpc_ctrl_latency lp = {0}; + + /* Handle will be -1 in non-domains invocation. Create DSP session if + * necessary */ + if (h == INVALID_HANDLE) { + if (!hlist || (hlist && hlist[domain].dev == -1)) { + VERIFY(AEE_SUCCESS == (nErr = domain_init(domain, &dev))); + VERIFYM(-1 != dev, AEE_ERPC, "open dev failed\n"); + } + } + /* If the multi-domain handle is valid, then verify that session is created + * already */ + VERIFYC((hlist) && (-1 != (dev = hlist[domain].dev)), AEE_ERPC); + + // Max poll timeout allowed is 10 ms + VERIFYC(latency < MAX_POLL_TIMEOUT, AEE_EBADPARM); + + /* Update polling mode in kernel */ + lp.enable = enable; + lp.latency = latency; + nErr = ioctl_control(dev, DSPRPC_RPC_POLL, &lp); + if (nErr) { + nErr = convert_kernel_to_user_error(nErr, errno); + goto bail; + } + + /* Update polling mode in DSP */ + if (h == INVALID_HANDLE) { + VERIFY(AEE_SUCCESS == + (nErr = adsp_current_process_poll_mode(enable, latency))); + } else { + remote_handle64 handle = get_adsp_current_process1_handle(domain); + VERIFY(AEE_SUCCESS == + (nErr = adsp_current_process1_poll_mode(handle, enable, latency))); + } + FARF(ALWAYS, + "%s: poll mode updated to %u for domain %d, handle 0x%" PRIx64 + " for timeout %u\n", + __func__, enable, domain, h, latency); +bail: + if (nErr) { + FARF(ERROR, + "Error 0x%x (errno %d): %s failed for domain %d, handle 0x%" PRIx64 + ", enable %u, timeout %u (%s)\n", + nErr, errno, __func__, domain, h, enable, latency, strerror(errno)); + } + 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 ((domain >= 0) && (domain < NUM_DOMAINS_EXTEND) && 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; + + fastrpc_notif_domain_init(domain); + if ((notif_handle = get_adsp_current_process1_handle(domain)) != + INVALID_HANDLE) { + VERIFY(AEE_SUCCESS == + (nErr = adsp_current_process1_enable_notifications(notif_handle))); + } else { + VERIFY(AEE_SUCCESS == (nErr = adsp_current_process_enable_notifications())); + } +bail: + 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(domain < NUM_DOMAINS_EXTEND, 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. + FastRPC driver tries to meet latency requirement but may not be + guaranteed. +*/ +static int fastrpc_set_qos_latency(int domain, remote_handle64 h, + uint32_t latency) { + int nErr = 0; + + if (h == (remote_handle64)-1) { + nErr = adsp_current_process_setQoS(latency); + } else { + remote_handle64 handle = get_adsp_current_process1_handle(domain); + nErr = adsp_current_process1_setQoS(handle, latency); + } + return nErr; +} + +// Notify kernel to enable/disable wakelock control between calls to DSP +static int update_kernel_wakelock_status(int domain, int dev, + uint32_t wl_enable) { + int nErr = AEE_SUCCESS; + struct fastrpc_ctrl_wakelock wl = {0}; + + wl.enable = wl_enable; + nErr = ioctl_control(dev, DSPRPC_CONTROL_WAKELOCK, &wl); + if (nErr) { + if (errno == EBADRQC || errno == ENOTTY || errno == ENXIO || + errno == EINVAL) { + VERIFY_WPRINTF( + "Warning: %s: kernel does not support wakelock management (%s)", + __func__, strerror(errno)); + return AEE_SUCCESS; + } + FARF(ERROR, + "Error 0x%x: %s failed for domain %d, dev %d, wakelock control %d " + "errno %s", + nErr, __func__, domain, dev, wl_enable, strerror(errno)); + } else + FARF(ALWAYS, + "%s: updated kernel wakelock control status to %d for domain %d", + __func__, wl_enable, domain); + return nErr; +} + +// Update wakelock status in userspace and notify kernel if necessary +static int wakelock_control(int domain, remote_handle64 h, uint32_t wl_enable) { + int nErr = AEE_SUCCESS; + + if (fastrpc_wake_lock_enable[domain] == wl_enable) + goto bail; + + if (wl_enable) { + VERIFY(AEE_SUCCESS == (nErr = fastrpc_wake_lock_init())); + } else { + VERIFY(AEE_SUCCESS == (nErr = fastrpc_wake_lock_deinit())); + } + if (IS_SESSION_OPEN_ALREADY(domain)) + VERIFY(AEE_SUCCESS == (nErr = update_kernel_wakelock_status( + domain, hlist[domain].dev, wl_enable))); + fastrpc_wake_lock_enable[domain] = wl_enable; +bail: + if (nErr) + FARF(ERROR, "Error 0x%x: %s failed for domain %d, handle 0x%x, enable %d", + nErr, __func__, domain, h, wl_enable); + else { + if (wl_enable) + FARF(ALWAYS, "%s: enabled wakelock control for domain %d", __func__, + domain); + else + FARF(ALWAYS, "%s: disable wakelock control for domain %d", __func__, + domain); + } + return nErr; +} + +// Make IOCTL call to kill remote process +static int fastrpc_dsp_process_clean(int domain) { + int nErr = AEE_SUCCESS, dev; + + VERIFYM(IS_SESSION_OPEN_ALREADY(domain), AEE_ERPC, + "Session not open for domain %d", domain); + dev = hlist[domain].dev; + nErr = ioctl_control(dev, DSPRPC_REMOTE_PROCESS_KILL, NULL); +bail: + if (nErr) + FARF(ERROR, "Error 0x%x: %s failed for domain %d (errno: %s) ", nErr, + __func__, domain, strerror(errno)); + return nErr; +} + +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); + + switch (req) { + case DSPRPC_CONTROL_LATENCY: { + struct remote_rpc_control_latency *lp = + (struct remote_rpc_control_latency *)data; + VERIFYC(lp, AEE_EBADPARM); + VERIFYC(len == sizeof(struct remote_rpc_control_latency), AEE_EBADPARM); + + switch (lp->enable) { + /* Only one of PM QoS or adaptive QoS can be enabled */ + 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 + * to error out in later targets */ + 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))); + VERIFY(AEE_SUCCESS == + (nErr = manage_adaptive_qos(domain, RPC_ADAPTIVE_QOS))); + /* 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_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: + nErr = AEE_EBADPARM; + FARF(ERROR, "Error: %s: Bad enable parameter %d passed for QoS control", + __func__, lp->enable); + goto bail; + } + FARF(ALWAYS, + "%s: requested QOS %d, latency %u for domain %d handle 0x%" PRIx64 + "\n", + __func__, lp->enable, lp->latency, domain, h); + break; + } + case DSPRPC_GET_DSP_INFO: { + int dev = -1; + struct remote_dsp_capability *cap = (struct remote_dsp_capability *)data; + + (void)dev; + VERIFYC(cap, AEE_EBADPARM); + VERIFYC(cap->domain >= 0 && cap->domain < NUM_DOMAINS_EXTEND, AEE_EBADPARM); + + nErr = fastrpc_get_cap(cap->domain, cap->attribute_ID, &cap->capability); + VERIFY(AEE_SUCCESS == nErr); + break; + } + case DSPRPC_CONTROL_WAKELOCK: { + struct remote_rpc_control_wakelock *wp = + (struct remote_rpc_control_wakelock *)data; + + VERIFYC(wp, AEE_EBADPARM); + VERIFYC(len == sizeof(struct remote_rpc_control_wakelock), AEE_EBADPARM); + VERIFY(AEE_SUCCESS == (nErr = wakelock_control(domain, h, wp->enable))); + break; + } + case DSPRPC_GET_DOMAIN: { + remote_rpc_get_domain_t *pGet = (remote_rpc_get_domain_t *)data; + + VERIFYC(pGet, AEE_EBADPARM); + VERIFYC(len == sizeof(remote_rpc_get_domain_t), AEE_EBADPARM); + pGet->domain = domain; + break; + } + default: + nErr = AEE_EUNSUPPORTED; + FARF(RUNTIME_RPC_LOW, + "Error: %s: remote handle control called with unsupported request ID " + "%d", + __func__, req); + break; + } +bail: + if (nErr != AEE_SUCCESS) + FARF(ERROR, + "Error 0x%x: %s failed for request ID %d on domain %d (errno %s)", + nErr, __func__, req, domain, strerror(errno)); + return nErr; +} + +int remote_handle_control(uint32_t req, void *data, uint32_t len) { + int domain = -1, nErr = AEE_SUCCESS, ref = 0; + + VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); + + FARF(RUNTIME_HIGH, "Entering %s, req %d, data %p, size %d\n", __func__, req, + data, len); + PRINT_WARN_USE_DOMAINS(); + + domain = get_current_domain(); + FASTRPC_GET_REF(domain); + VERIFY(AEE_SUCCESS == (nErr = remote_handle_control_domain( + domain, INVALID_HANDLE, req, data, len))); +bail: + FASTRPC_PUT_REF(domain); + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed for request ID %d (errno %s)", nErr, + __func__, req, strerror(errno)); + if (0 == check_rpc_error(nErr)) { + FARF(ERROR, "Error 0x%x: %s failed for request ID %d (errno %s)", nErr, + __func__, req, strerror(errno)); + } + } + return nErr; +} + +int remote_handle64_control(remote_handle64 handle, uint32_t req, void *data, + uint32_t len) { + int nErr = AEE_SUCCESS, domain = -1, ref = 0; + + VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); + + FARF(RUNTIME_HIGH, "Entering %s, handle %llu, req %d, data %p, size %d\n", + __func__, handle, req, data, len); + + VERIFY(AEE_SUCCESS == (nErr = get_domain_from_handle(handle, &domain))); + FASTRPC_GET_REF(domain); + VERIFY(AEE_SUCCESS == + (nErr = remote_handle_control_domain(domain, handle, req, data, len))); +bail: + FASTRPC_PUT_REF(domain); + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed for request ID %d (errno %s)", nErr, + __func__, req, strerror(errno)); + if (0 == check_rpc_error(nErr)) { + FARF(ERROR, "Error 0x%x: %s failed for request ID %d (errno %s)", nErr, + __func__, req, strerror(errno)); + } + } + return nErr; +} + +static int close_domain_session(int domain) { + QNode *pn = NULL, *pnn = NULL; + char dlerrstr[255]; + int dlerr = 0, nErr = AEE_SUCCESS; + remote_handle64 proc_handle = 0; + + FARF(ALWAYS, + "%s: user requested to close fastrpc session on domain %d, dev %d\n", + __func__, domain, hlist[domain].dev); + VERIFY(hlist[domain].dev != -1); + proc_handle = get_adsp_current_process1_handle(domain); + if (proc_handle != INVALID_HANDLE) { + adsp_current_process1_exit(proc_handle); + } else { + adsp_current_process_exit(); + } + pthread_mutex_lock(&hlist[domain].lmut); + 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); + remote_handle_close(hi->remote); + pthread_mutex_lock(&hlist[domain].lmut); + } + } + if (!QList_IsEmpty(&hlist[domain].rql)) { + QLIST_NEXTSAFE_FOR_ALL(&hlist[domain].rql, 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); + close_reverse_handle(hi->local, dlerrstr, sizeof(dlerrstr), &dlerr); + pthread_mutex_lock(&hlist[domain].lmut); + } + } + if (!QList_IsEmpty(&hlist[domain].ql)) { + QLIST_NEXTSAFE_FOR_ALL(&hlist[domain].ql, 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); + remote_handle64_close(hi->local); + pthread_mutex_lock(&hlist[domain].lmut); + } + } + pthread_mutex_unlock(&hlist[domain].lmut); +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed for domain %d (errno %s)", nErr, + __func__, domain, strerror(errno)); + } + return nErr; +} + +int get_unsigned_pd_attribute(uint32 domain, int *unsigned_module) { + int nErr = AEE_SUCCESS; + + VERIFYC(hlist, AEE_EBADPARM); + VERIFYC(unsigned_module, AEE_EBADPARM); + VERIFYC(domain < NUM_DOMAINS_EXTEND, AEE_EBADPARM); + *unsigned_module = hlist[domain].unsigned_module; +bail: + return nErr; +} + +static int set_unsigned_pd_attribute(int domain, int enable) { + int nErr = AEE_SUCCESS; + + VERIFYC(hlist, AEE_EBADPARM); + VERIFYC((domain >= 0) && (domain < NUM_DOMAINS_EXTEND), AEE_EBADPARM); + if (hlist[domain].dev != -1) { + if (hlist[domain].unsigned_module == enable) { + FARF(HIGH, "%s: %s session already open on domain %d , enable %d ", + __func__, hlist[domain].unsigned_module ? "Unsigned" : "Signed", + domain, enable); + } else { + nErr = AEE_EALREADYLOADED; + FARF(ERROR, + "Error 0x%x: %s: %s session already open on domain %d , enable %d ", + nErr, __func__, + hlist[domain].unsigned_module ? "Unsigned" : "Signed", domain, + enable); + } + goto bail; + } + hlist[domain].unsigned_module = enable ? 1 : 0; +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed for domain %d", nErr, __func__, domain); + } + return nErr; +} + +static int store_domain_thread_params(int domain, int thread_priority, + int stack_size) { + int nErr = AEE_SUCCESS; + + VERIFYC(hlist, AEE_EBADPARM); + VERIFYC((domain >= 0) && (domain < NUM_DOMAINS_EXTEND), AEE_EBADPARM); + if (thread_priority != -1) { + if ((thread_priority < MIN_THREAD_PRIORITY) || + (thread_priority > MAX_THREAD_PRIORITY)) { + nErr = AEE_EBADPARM; + FARF(ERROR, + "%s: Thread priority %d is invalid! Should be between %d and %d", + __func__, thread_priority, MIN_THREAD_PRIORITY, MAX_THREAD_PRIORITY); + goto bail; + } else { + hlist[domain].th_params.thread_priority = (uint32_t)thread_priority; + } + } + if (stack_size != -1) { + if ((stack_size < MIN_UTHREAD_STACK_SIZE) || + (stack_size > MAX_UTHREAD_STACK_SIZE)) { + nErr = AEE_EBADPARM; + FARF(ERROR, "%s: Stack size %d is invalid! Should be between %d and %d", + __func__, stack_size, MIN_UTHREAD_STACK_SIZE, + MAX_UTHREAD_STACK_SIZE); + goto bail; + } else + hlist[domain].th_params.stack_size = (uint32_t)stack_size; + } + hlist[domain].th_params.reqID = FASTRPC_THREAD_PARAMS; + hlist[domain].th_params.update_requested = 1; + if (hlist[domain].dev != -1) { + VERIFY(AEE_SUCCESS == (nErr = fastrpc_set_remote_uthread_params(domain))); + FARF(ALWAYS, + "Dynamically set remote user thread priority to %d and stack size to " + "%d for domain %d", + thread_priority, stack_size, domain); + } +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, + "Error 0x%x: %s failed for domain %d for thread priority %d, stack " + "size %d", + nErr, __func__, domain, thread_priority, stack_size); + } + return nErr; +} + +/* Set attribute to enable/disable pd dump */ +static int set_pd_dump_attribute(int domain, int enable) { + int nErr = AEE_SUCCESS; + + VERIFYC(hlist, AEE_ERPC); + VERIFYC((domain >= 0) && (domain < NUM_DOMAINS_EXTEND), AEE_EBADPARM); + if (hlist[domain].dev != -1) { + nErr = AEE_ERPC; + FARF(ERROR, + "%s: Session already open on domain %d ! Request unsigned offload " + "before making any RPC calls", + __func__, domain); + goto bail; + } + hlist[domain].pd_dump = enable ? true : false; +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed to enable %d for domain %d", nErr, + __func__, enable, domain); + } + return nErr; +} + +/* Set userpd memlen for a requested domain */ +static int store_domain_pd_initmem_size(int domain, uint32_t pd_initmem_size) { + int nErr = AEE_SUCCESS; + + if ((pd_initmem_size < MIN_PD_INITMEM_SIZE) || + (pd_initmem_size > MAX_PD_INITMEM_SIZE)) { + nErr = AEE_EBADPARM; + goto bail; + } else { + hlist[domain].pd_initmem_size = pd_initmem_size; + } +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, + "Error 0x%x: %s failed for domain %d for pd init mem size :0x%x", nErr, + __func__, domain, pd_initmem_size); + } + return nErr; +} + +/* Set remote session parameters like thread stack size, running on unsigned PD, + * killing remote process PD etc */ +int remote_session_control(uint32_t req, void *data, uint32_t datalen) { + int nErr = AEE_SUCCESS, domain = DEFAULT_DOMAIN_ID, ref = 0; + + VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); + + FARF(RUNTIME_RPC_HIGH, "Entering %s, req %d, data %p, size %d\n", __func__, req, data, + datalen); + FASTRPC_GET_REF(domain); + switch (req) { + case FASTRPC_THREAD_PARAMS: { + struct remote_rpc_thread_params *params = + (struct remote_rpc_thread_params *)data; + if (!params) { + nErr = AEE_EBADPARM; + FARF(RUNTIME_RPC_LOW, "%s: Thread params struct passed is %p", __func__, + params); + goto bail; + } + VERIFYC(datalen == sizeof(struct remote_rpc_thread_params), AEE_EBADPARM); + if (params->domain != -1) { + if ((params->domain < 0) || (params->domain >= NUM_DOMAINS_EXTEND)) { + nErr = AEE_EBADPARM; + FARF(RUNTIME_RPC_LOW, "%s: Invalid domain ID %d passed", __func__, + params->domain); + goto bail; + } + VERIFY(AEE_SUCCESS == + (nErr = store_domain_thread_params(params->domain, params->prio, + params->stack_size))); + } else { + /* If domain is -1, then set parameters for all domains */ + for (int i = 0; i < NUM_DOMAINS_EXTEND; i++) { + VERIFY(AEE_SUCCESS == (nErr = store_domain_thread_params( + i, params->prio, params->stack_size))); + } + } + FARF(ALWAYS, + "%s DSP info request for domain %d, thread priority %d, stack size %d", + __func__, params->domain, params->prio, params->stack_size); + break; + } + case DSPRPC_CONTROL_UNSIGNED_MODULE: { + // Handle the unsigned module offload request + struct remote_rpc_control_unsigned_module *um = + (struct remote_rpc_control_unsigned_module *)data; + VERIFYC(datalen == sizeof(struct remote_rpc_control_unsigned_module), + AEE_EBADPARM); + VERIFYC(um != NULL, AEE_EBADPARM); + if (um->domain != -1) { + VERIFYC((um->domain >= 0) && (um->domain < NUM_DOMAINS_EXTEND), + AEE_EBADPARM); + VERIFY(AEE_SUCCESS == + (nErr = set_unsigned_pd_attribute(um->domain, um->enable))); + } else { + for (int ii = 0; ii < NUM_DOMAINS_EXTEND; ii++) { + VERIFY(AEE_SUCCESS == + (nErr = set_unsigned_pd_attribute(ii, um->enable))); + } + } + FARF(ALWAYS, "%s Unsigned PD enable %d request for domain %d", __func__, + um->enable, um->domain); + break; + } + case FASTRPC_RELATIVE_THREAD_PRIORITY: { + int thread_priority = DEFAULT_UTHREAD_PRIORITY, rel_thread_prio = 0; + struct remote_rpc_relative_thread_priority *params = + (struct remote_rpc_relative_thread_priority *)data; + + VERIFYC(datalen == sizeof(struct remote_rpc_relative_thread_priority), + AEE_EBADPARM); + VERIFYC(params, AEE_EBADPARM); + rel_thread_prio = params->relative_thread_priority; + + // handle thread priority overflow and out-of-range conditions + if (rel_thread_prio < 0) { + thread_priority = ((~rel_thread_prio) >= DEFAULT_UTHREAD_PRIORITY - 1) + ? MIN_THREAD_PRIORITY + : (thread_priority + rel_thread_prio); + } else { + thread_priority = + (rel_thread_prio > (MAX_THREAD_PRIORITY - DEFAULT_UTHREAD_PRIORITY)) + ? MAX_THREAD_PRIORITY + : (thread_priority + rel_thread_prio); + } + if (params->domain != -1) { + VERIFYC((params->domain >= 0) && (params->domain < NUM_DOMAINS_EXTEND), + AEE_EBADPARM); + VERIFY(AEE_SUCCESS == (nErr = store_domain_thread_params( + params->domain, thread_priority, -1))); + } else { + for (int i = 0; i < NUM_DOMAINS_EXTEND; i++) { + VERIFY(AEE_SUCCESS == + (nErr = store_domain_thread_params(i, thread_priority, -1))); + } + } + FARF(ALWAYS, "%s DSP thread priority request for domain %d, priority %d", + __func__, req, params->domain, thread_priority); + break; + } + case FASTRPC_REMOTE_PROCESS_KILL: { + struct remote_rpc_process_clean_params *dp = + (struct remote_rpc_process_clean_params *)data; + + VERIFYC(datalen == sizeof(struct remote_rpc_process_clean_params), + AEE_EBADPARM); + VERIFYC(dp, AEE_EBADPARM); + domain = dp->domain; + VERIFY(AEE_SUCCESS == (nErr = fastrpc_dsp_process_clean(domain))); + FARF(ALWAYS, "%s Remote process kill request for domain %d", __func__, + domain); + break; + } + case FASTRPC_SESSION_CLOSE: { + struct remote_rpc_session_close *sclose = + (struct remote_rpc_session_close *)data; + if (!sclose) { + nErr = AEE_EBADPARM; + FARF(RUNTIME_RPC_LOW, + "Error: %s: session close data pointer passed is NULL\n", __func__); + goto bail; + } + VERIFYC(datalen == sizeof(struct remote_rpc_session_close), AEE_EBADPARM); + if (sclose->domain != -1) { + VERIFYC((sclose->domain >= 0) && (sclose->domain < NUM_DOMAINS_EXTEND), + AEE_EBADPARM); + VERIFY(AEE_SUCCESS == (nErr = close_domain_session(sclose->domain))); + } else { + for (int ii = 0; ii < NUM_DOMAINS_EXTEND; ii++) { + VERIFY(AEE_SUCCESS == (nErr = close_domain_session(ii))); + } + } + FARF(ALWAYS, "%s Fastrpc session close request for domain %d\n", __func__, + sclose->domain); + break; + } + case FASTRPC_CONTROL_PD_DUMP: { + // Handle pd dump enable/disable request + struct remote_rpc_control_pd_dump *pddump = + (struct remote_rpc_control_pd_dump *)data; + VERIFYC(datalen == sizeof(struct remote_rpc_control_pd_dump), AEE_EBADPARM); + VERIFYC(pddump != NULL, AEE_EBADPARM); + if (pddump->domain != -1) { + VERIFY(AEE_SUCCESS == + (nErr = set_pd_dump_attribute(pddump->domain, pddump->enable))); + } else { + for (int ii = 0; ii < NUM_DOMAINS_EXTEND; ii++) { + VERIFY(AEE_SUCCESS == + (nErr = set_pd_dump_attribute(ii, pddump->enable))); + } + } + FARF(ALWAYS, "%s PD dump request to enable(%d) for domain %d", __func__, + pddump->enable, pddump->domain); + break; + } + case FASTRPC_REMOTE_PROCESS_EXCEPTION: { + // Trigger non fatal exception in the User PD of DSP. + remote_rpc_process_exception *dp = (remote_rpc_process_exception *)data; + remote_handle64 handle = 0; + int ret = 0; + + VERIFYC(datalen == sizeof(remote_rpc_process_exception), AEE_EBADPARM); + VERIFYC(dp, AEE_EBADPARM); + domain = dp->domain; + VERIFYC(domain >= 0 && domain < NUM_DOMAINS_EXTEND, AEE_EBADPARM); + /* + * If any request causes exception on DSP, DSP returns AEE_EBADSTATE for the + * request thread. + */ + if ((handle = get_adsp_current_process1_handle(domain)) != INVALID_HANDLE) { + ret = adsp_current_process1_exception(handle); + } else { + ret = adsp_current_process_exception(); + } + ret = (ret == AEE_SUCCESS) ? AEE_ERPC : ret; + VERIFYC(ret == (int)(DSP_AEE_EOFFSET + AEE_EBADSTATE), ret); + FARF(ALWAYS, + "%s Remote process exception request for domain %d, handle 0x%" PRIx64 + "\n", + __func__, domain, handle); + break; + } + case FASTRPC_REMOTE_PROCESS_TYPE: { + struct remote_process_type *typ = (struct remote_process_type *)data; + int ret_val = -1; + VERIFYC(datalen == sizeof(struct remote_process_type), AEE_EBADPARM); + VERIFYC(typ, AEE_EBADPARM); + domain = typ->domain; + VERIFYC(domain >= 0 && domain < NUM_DOMAINS_EXTEND, AEE_EBADPARM); + ret_val = hlist[domain].unsigned_module; + if (ret_val != PROCESS_TYPE_UNSIGNED && ret_val != PROCESS_TYPE_SIGNED) { + typ->process_type = -1; + nErr = AEE_EBADPARM; + } else { + typ->process_type = ret_val; + } + break; + } + case FASTRPC_REGISTER_STATUS_NOTIFICATIONS: { + // Handle DSP PD notification request + struct remote_rpc_notif_register *notif = + (struct remote_rpc_notif_register *)data; + VERIFYC(datalen == sizeof(struct remote_rpc_notif_register), AEE_EBADPARM); + VERIFYC(notif != NULL, AEE_EBADPARM); + domain = notif->domain; + VERIFYC(domain >= 0 && domain < NUM_DOMAINS_EXTEND, AEE_EBADPARM); + if (domain != -1) { + VERIFYC(is_status_notif_version2_supported(domain), AEE_EUNSUPPORTED); + VERIFY(AEE_SUCCESS == (nErr = fastrpc_notif_register(domain, notif))); + } else { + for (int ii = 0; ii < NUM_DOMAINS_EXTEND; ii++) { + VERIFYC(is_status_notif_version2_supported(ii), AEE_EUNSUPPORTED); + VERIFY(AEE_SUCCESS == (nErr = fastrpc_notif_register(ii, notif))); + } + } + FARF(ALWAYS, "%s Register PD status notification request for domain %d\n", + __func__, domain); + break; + } + case FASTRPC_PD_INITMEM_SIZE: { + // Handle DSP User PD init memory size request + struct remote_rpc_pd_initmem_size *params = + (struct remote_rpc_pd_initmem_size *)data; + VERIFYC(datalen == sizeof(struct remote_rpc_pd_initmem_size), AEE_EBADPARM); + VERIFYC(params != NULL, AEE_EBADPARM); + if (params->domain != -1) { + if ((params->domain < 0) || (params->domain >= NUM_DOMAINS_EXTEND)) { + nErr = AEE_EBADPARM; + FARF(ERROR, "%s: Invalid domain ID %d passed", __func__, + params->domain); + goto bail; + } + if (hlist[params->domain].unsigned_module) { + nErr = AEE_EUNSUPPORTED; + FARF(ERROR, "Configuring User PD init mem length is not supported for " + "unsigned PDs"); + goto bail; + } + VERIFY(AEE_SUCCESS == (nErr = store_domain_pd_initmem_size( + params->domain, params->pd_initmem_size))); + } else { + /* If domain is -1, then set parameters for all domains */ + for (int ii = 0; ii < NUM_DOMAINS_EXTEND; ii++) { + if (hlist[ii].unsigned_module) { + FARF(ALWAYS, + "Warning: %s: Configuring User PD init mem length for domain %d " + "is not supported for unsigned PDs", + __func__, ii); + } else { + VERIFY(AEE_SUCCESS == (nErr = store_domain_pd_initmem_size( + ii, params->pd_initmem_size))); + } + } + } + FARF(ALWAYS, + "%s DSP userpd memlen request for domain %d, userpd memlen 0x%x", + __func__, params->domain, params->pd_initmem_size); + break; + } + case FASTRPC_RESERVE_NEW_SESSION: { + remote_rpc_reserve_new_session_t *sess = + (remote_rpc_reserve_new_session_t *)data; + int ii = 0, jj = 0; + + VERIFYC(datalen == sizeof(remote_rpc_reserve_new_session_t), AEE_EBADPARM); + VERIFYC(sess && sess->domain_name != NULL && sess->domain_name_len > 0 && + sess->session_name && sess->session_name_len > 0, + AEE_EBADPARM); + domain = get_domain_from_name(sess->domain_name, DOMAIN_NAME_STAND_ALONE); + VERIFYC(domain >= 0 && domain < NUM_DOMAINS, AEE_EBADPARM); + // Initialize effective domain ID to 2nd session of domain, first session is + // default usage and cannot be reserved + ii = domain + NUM_DOMAINS; + // Initialize session to 1, session 0 is default session + jj = 1; + // Set effective_domain_id and session_id to invalid IDs + sess->effective_domain_id = NUM_DOMAINS_EXTEND; + sess->session_id = NUM_SESSIONS; + do { + pthread_mutex_lock(&hlist[ii].init); + if (!hlist[ii].is_session_reserved) { + hlist[ii].is_session_reserved = true; + sess->effective_domain_id = ii; + sess->session_id = jj; + std_strlcpy(hlist[ii].sessionname, sess->session_name, + STD_MIN(sess->session_name_len, (MAX_DSPPD_NAMELEN - 1))); + pthread_mutex_unlock(&hlist[ii].init); + break; + } + pthread_mutex_unlock(&hlist[ii].init); + // Increment to next session of domain + ii = ii + NUM_DOMAINS; + // Increment the session + jj++; + } while (ii < NUM_DOMAINS_EXTEND); + VERIFYC(sess->effective_domain_id < NUM_DOMAINS_EXTEND, AEE_ENOSESSION); + break; + } + case FASTRPC_GET_EFFECTIVE_DOMAIN_ID: { + remote_rpc_effective_domain_id_t *effec_domain_id = + (remote_rpc_effective_domain_id_t *)data; + VERIFYC(datalen == sizeof(remote_rpc_effective_domain_id_t), AEE_EBADPARM); + VERIFYC(effec_domain_id && effec_domain_id->domain_name && + effec_domain_id->domain_name_len > 0 && + effec_domain_id->session_id < NUM_SESSIONS, + AEE_EBADPARM); + domain = get_domain_from_name(effec_domain_id->domain_name, + DOMAIN_NAME_STAND_ALONE); + VERIFYC(domain >= 0 && domain < NUM_DOMAINS, AEE_EBADPARM); + effec_domain_id->effective_domain_id = + GET_EFFECTIVE_DOMAIN_ID(domain, effec_domain_id->session_id); + VERIFYC(effec_domain_id->effective_domain_id < NUM_DOMAINS_EXTEND, + AEE_ENOSESSION); + break; + } + case FASTRPC_GET_URI: { + remote_rpc_get_uri_t *rpc_uri = (remote_rpc_get_uri_t *)data; + int ret_val = -1; + + VERIFYC(datalen == sizeof(remote_rpc_get_uri_t), AEE_EBADPARM); + VERIFYC(rpc_uri && rpc_uri->domain_name && rpc_uri->domain_name_len > 0 && + rpc_uri->session_id < NUM_SESSIONS, + AEE_EBADPARM); + domain = + get_domain_from_name(rpc_uri->domain_name, DOMAIN_NAME_STAND_ALONE); + VERIFYC(domain >= 0 && domain < NUM_DOMAINS, AEE_EBADPARM); + VERIFYC(rpc_uri->module_uri != NULL && rpc_uri->module_uri_len > 0, + AEE_EBADPARM); + VERIFYC(rpc_uri->uri != NULL && rpc_uri->uri_len > rpc_uri->module_uri_len, + AEE_EBADPARM); + ret_val = snprintf(0, 0, "%s%s%s%s%d", rpc_uri->module_uri, + FASTRPC_DOMAIN_URI, SUBSYSTEM_NAME[domain], + FASTRPC_SESSION_URI, rpc_uri->session_id); + if (rpc_uri->uri_len <= ret_val) { + nErr = AEE_EBADSIZE; + FARF(ERROR, + "ERROR 0x%x: %s Session URI length %u is not enough, need %u " + "characters", + nErr, __func__, rpc_uri->uri_len, ret_val); + } + ret_val = snprintf(rpc_uri->uri, rpc_uri->uri_len, "%s%s%s%s%d", + rpc_uri->module_uri, FASTRPC_DOMAIN_URI, + SUBSYSTEM_NAME[domain], FASTRPC_SESSION_URI, + rpc_uri->session_id); + if (ret_val < 0) { + nErr = AEE_EBADSIZE; + FARF(ERROR, "ERROR 0x%x: %s Invalid Session URI length %u", nErr, + __func__, rpc_uri->uri_len); + } + break; + } + default: + nErr = AEE_EUNSUPPORTED; + FARF(ERROR, "ERROR 0x%x: %s Unsupported request ID %d", nErr, __func__, + req); + break; + } +bail: + FASTRPC_PUT_REF(domain); + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed for request ID %d (errno %s)", nErr, + __func__, req, strerror(errno)); + if (0 == check_rpc_error(nErr)) { + FARF(ERROR, "Error 0x%x: %s failed for request ID %d (errno %s)", nErr, + __func__, req, strerror(errno)); + } + } + return nErr; +} + +/* Function to get domain id from URI + * @uri: URI string + * @type: Type of URI + * @returns: 0 on success, valid non-zero error code on failure + */ +int get_domain_from_name(const char *uri, uint32_t type) { + int domain = DEFAULT_DOMAIN_ID; + char *session_uri = NULL; + int session_id = 0; + + if (uri && type == DOMAIN_NAME_STAND_ALONE) { + if (!std_strncmp(uri, ADSP_DOMAIN_NAME, std_strlen(ADSP_DOMAIN_NAME))) { + domain = ADSP_DOMAIN_ID; + } else if (!std_strncmp(uri, MDSP_DOMAIN_NAME, + std_strlen(MDSP_DOMAIN_NAME))) { + domain = MDSP_DOMAIN_ID; + } else if (!std_strncmp(uri, SDSP_DOMAIN_NAME, + std_strlen(SDSP_DOMAIN_NAME))) { + domain = SDSP_DOMAIN_ID; + } else if (!std_strncmp(uri, CDSP_DOMAIN_NAME, + std_strlen(CDSP_DOMAIN_NAME))) { + domain = CDSP_DOMAIN_ID; + } else { + domain = INVALID_DOMAIN_ID; + FARF(ERROR, "Invalid domain name: %s\n", uri); + return domain; + } + } + if (uri && type == DOMAIN_NAME_IN_URI) { + if (std_strstr(uri, ADSP_DOMAIN)) { + domain = ADSP_DOMAIN_ID; + } else if (std_strstr(uri, MDSP_DOMAIN)) { + domain = MDSP_DOMAIN_ID; + } else if (std_strstr(uri, SDSP_DOMAIN)) { + domain = SDSP_DOMAIN_ID; + } else if (std_strstr(uri, CDSP_DOMAIN)) { + domain = CDSP_DOMAIN_ID; + } else { + domain = INVALID_DOMAIN_ID; + FARF(ERROR, "Invalid domain name: %s\n", uri); + goto bail; + } + if (NULL != (session_uri = std_strstr(uri, FASTRPC_SESSION_URI))) { + session_uri = session_uri + std_strlen(FASTRPC_SESSION_URI); + // Get Session ID from URI + session_id = strtol(session_uri, NULL, 10); + if (session_id < NUM_SESSIONS) { + domain = GET_EFFECTIVE_DOMAIN_ID(domain, session_id); + } else { + domain = INVALID_DOMAIN_ID; + FARF(ERROR, "Invalid domain name: %s\n", uri); + } + } + } +bail: + VERIFY_IPRINTF("%s: %d\n", __func__, domain); + return domain; +} + +int get_current_domain(void) { + struct handle_list *list; + int domain = -1; + + /* user hint to pick default domain id + * first try tlskey before using default domain + */ + list = (struct handle_list *)pthread_getspecific(tlsKey); + if (list) { + domain = (int)(list - &hlist[0]); + } + if (domain < 0 || domain >= NUM_DOMAINS_EXTEND) { + // use default domain if thread tlskey not found + domain = DEFAULT_DOMAIN_ID; + } + return domain; +} + +bool is_process_exiting(int domain) { + int nErr = 0, state = 1; + + (void)nErr; + VERIFYC((domain >= 0) && (domain < NUM_DOMAINS_EXTEND), AEE_EBADDOMAIN); + pthread_mutex_lock(&hlist[domain].mut); + state = hlist[domain].state; + pthread_mutex_unlock(&hlist[domain].mut); + if (state != FASTRPC_DOMAIN_STATE_INIT) + return true; + else + return false; +bail: + return true; +} + +int remote_set_mode(uint32_t mode) { + int i; + for (i = 0; i < NUM_DOMAINS_EXTEND; i++) { + hlist[i].mode = mode; + hlist[i].setmode = 1; + } + return AEE_SUCCESS; +} + +PL_DEP(fastrpc_apps_user); +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; + + switch (domain & DOMAIN_ID_MASK) { + case MDSP_DOMAIN_ID: + case ADSP_DOMAIN_ID: + case CDSP_DOMAIN_ID: + case SDSP_DOMAIN_ID: + attach = USERPD; + break; + default: + attach = ROOT_PD; + break; + } + return attach; +} + +static void domain_deinit(int domain) { + int olddev; + remote_handle64 handle = 0; + uint64_t t_kill; + + if (!hlist) { + return; + } + olddev = hlist[domain].dev; + FARF(ALWAYS, "%s for domain %d: dev %d", __func__, domain, olddev); + if (olddev != -1) { + + FASTRPC_ATRACE_BEGIN_L("%s called for handle 0x%x, domain %d, dev %d", + __func__, handle, domain, olddev); + + handle = get_adsp_current_process1_handle(domain); + if (handle != INVALID_HANDLE) { + adsp_current_process1_exit(handle); + } else { + adsp_current_process_exit(); + } + + pthread_mutex_lock(&hlist[domain].mut); + hlist[domain].state = FASTRPC_DOMAIN_STATE_DEINIT; + pthread_mutex_unlock(&hlist[domain].mut); + + 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); + if (domain == DEFAULT_DOMAIN_ID) { + 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); + fastrpc_mem_close(domain); + apps_mem_deinit(domain); + hlist[domain].state = 0; + hlist[domain].ref = 0; + + hlist[domain].cphandle = 0; + hlist[domain].msghandle = 0; + hlist[domain].remotectlhandle = 0; + hlist[domain].domainsupport = 0; + hlist[domain].listenerhandle = 0; + hlist[domain].dev = -1; + hlist[domain].info = -1; + hlist[domain].dsppd = attach_guestos(domain); + memset(hlist[domain].dsppdname, 0, MAX_DSPPD_NAMELEN); + memset(hlist[domain].sessionname, 0, MAX_DSPPD_NAMELEN); + PROFILE_ALWAYS(&t_kill, close_device_node(domain, olddev);); + FARF(ALWAYS, "%s: closed device %d on domain %d (kill time %" PRIu64 " us)", + __func__, olddev, domain, t_kill); + FASTRPC_ATRACE_END(); + } + if (hlist[domain].pdmem) { + rpcmem_free_internal(hlist[domain].pdmem); + hlist[domain].pdmem = NULL; + } + hlist[domain].proc_sharedbuf_cur_addr = NULL; + if (hlist[domain].proc_sharedbuf) { + rpcmem_free_internal(hlist[domain].proc_sharedbuf); + hlist[domain].proc_sharedbuf = NULL; + } + // Free the session, on session deinit + pthread_mutex_lock(&hlist[domain].init); + hlist[domain].is_session_reserved = false; + pthread_mutex_unlock(&hlist[domain].init); + pthread_mutex_lock(&hlist[domain].mut); + hlist[domain].state = FASTRPC_DOMAIN_STATE_CLEAN; + pthread_mutex_unlock(&hlist[domain].mut); +} + +static const char *get_domain_name(int domain_id) { + const char *name; + int domain = domain_id & DOMAIN_ID_MASK; + + switch (domain) { + case ADSP_DOMAIN_ID: + name = ADSPRPC_DEVICE; + break; + case SDSP_DOMAIN_ID: + name = SDSPRPC_DEVICE; + break; + case MDSP_DOMAIN_ID: + name = MDSPRPC_DEVICE; + break; + case CDSP_DOMAIN_ID: + name = CDSPRPC_DEVICE; + break; + default: + name = DEFAULT_DEVICE; + break; + } + return name; +} + +/* Opens device node based on the domain + This function takes care of the backward compatibility to open + approriate device for following configurations of the device nodes + 1. 4 different device nodes + 2. 1 device node (adsprpc-smd) + 3. 2 device nodes (adsprpc-smd, adsprpc-smd-secure) + Algorithm + For ADSP, SDSP, MDSP domains: + Open secure device node fist + if no secure device, open actual device node + if still no device, open default node + if failed to open the secure node due to permission, + open default node + For CDSP domain: + Open secure device node fist + If the node does not exist or if no permission, open actual device node + If still no device, open default node + If no permission to access the default node, access thorugh HAL. +*/ +static int open_device_node(int domain_id) { + int dev = -1, nErr = 0; + int domain = domain_id & DOMAIN_ID_MASK; + 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: + dev = open(get_secure_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)," + "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))) { + // 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); +#ifndef NO_HAL + if ((dev < 0) && (errno == EACCES)) { + FARF(ALWAYS, + "%s: no access to default device of domain %d, open thru HAL, " + "(sess_id %d)\n", + __func__, domain, sess_id); + VERIFYC(sess_id < NUM_SESSIONS, AEE_EBADITEM); + pthread_mutex_lock(&dsp_client_mut); + if (!dsp_client_instance[sess_id]) { + dsp_client_instance[sess_id] = create_dsp_client_instance(); + } + pthread_mutex_unlock(&dsp_client_mut); + dev = open_hal_session(dsp_client_instance[sess_id], domain_id); + } +#endif + } + } + break; + default: + break; + } + if (dev < 0) + FARF(ERROR, + "Error 0x%x: %s failed for domain ID %d, sess ID %d secure dev : %s, " + "dev : %s. (errno %d, %s)", + nErr, __func__, domain_id, sess_id, get_secure_domain_name(domain), + get_domain_name(domain), errno, strerror(errno)); + return dev; +} + +static int close_device_node(int domain_id, int dev) { + int nErr = 0; + +#ifndef NO_HAL + int sess_id = GET_SESSION_ID_FROM_DOMAIN_ID(domain_id); + if (((domain_id & DOMAIN_ID_MASK) == CDSP_DOMAIN_ID) && + dsp_client_instance[sess_id]) { + nErr = close_hal_session(dsp_client_instance[sess_id], domain_id, dev); + FARF(ALWAYS, "%s: close device %d thru HAL on session %d\n", __func__, dev, + sess_id); + } else { +#endif + nErr = close(dev); + FARF(ALWAYS, "%s: closed dev %d on domain %d", __func__, dev, domain_id); +#ifndef NO_HAL + } +#endif + return nErr; +} + +static int get_process_attrs(int domain) { + int attrs = 0; + + 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].unsigned_module ? FASTRPC_MODE_UNSIGNED_MODULE : 0; + attrs |= (hlist[domain].pd_dump | fastrpc_config_is_pddump_enabled()) + ? FASTRPC_MODE_ENABLE_PDDUMP + : 0; + attrs |= fastrpc_get_property_int(FASTRPC_DEBUG_PDDUMP, 0) + ? FASTRPC_MODE_DEBUG_PDDUMP + : 0; + attrs |= (fastrpc_config_is_perfkernel_enabled() | + fastrpc_get_property_int(FASTRPC_PERF_KERNEL, 0)) + ? FASTRPC_MODE_PERF_KERNEL + : 0; + attrs |= (fastrpc_config_is_perfdsp_enabled() | + fastrpc_get_property_int(FASTRPC_PERF_ADSP, 0)) + ? FASTRPC_MODE_PERF_DSP + : 0; + attrs |= fastrpc_config_is_log_iregion_enabled() + ? FASTRPC_MODE_ENABLE_IREGION_LOG + : 0; + attrs |= fastrpc_config_is_qtf_tracing_enabled() + ? FASTRPC_MODE_ENABLE_QTF_TRACING + : 0; + attrs |= (fastrpc_config_get_caller_level() << 13) & + FASTRPC_MODE_CALLER_LEVEL_MASK; + attrs |= fastrpc_config_is_uaf_enabled() ? FASTRPC_MODE_ENABLE_UAF : 0; + attrs |= fastrpc_config_is_debug_logging_enabled() + ? FASTRPC_MODE_ENABLE_DEBUG_LOGGING + : 0; +#ifdef SYSTEM_RPC_LIBRARY + attrs |= FASTRPC_MODE_SYSTEM_PROCESS; +#endif + attrs |= fastrpc_config_is_sysmon_reserved_bit_enabled() + ? FASTRPC_MODE_SYSMON_RESERVED_BIT + : 0; + attrs |= fastrpc_config_is_logpacket_enabled() ? FASTRPC_MODE_LOG_PACKET : 0; + attrs |= (fastrpc_config_get_leak_detect() << 19) & + FASTRPC_MODE_ENABLE_LEAK_DETECT; + attrs |= (fastrpc_config_get_caller_stack_num() << 21) & + FASTRPC_MODE_CALLER_STACK_NUM; + return attrs; +} + +static void get_process_testsig(apps_std_FILE *fp, uint64 *ptrlen) { + int nErr = 0; + uint64 len = 0; + char testsig[PROPERTY_VALUE_MAX]; + + if (fp == NULL || ptrlen == NULL) + return; + + if (fastrpc_get_property_string(FASTRPC_DEBUG_TESTSIG, testsig, NULL)) { + FARF(RUNTIME_RPC_HIGH, "testsig file loading is %s", testsig); + nErr = apps_std_fopen_with_env(ADSP_LIBRARY_PATH, ";", testsig, "r", fp); + if (nErr == AEE_SUCCESS && *fp != -1) + nErr = apps_std_flen(*fp, &len); + } + if (nErr) + len = 0; + *ptrlen = len; + return; +} + +int is_kernel_alloc_supported(int dev, int domain) { + int nErr = 0; + + if (!is_domain_valid(domain)) + return 0; + + if (hlist && !hlist[domain].kmem_support) { + struct fastrpc_ctrl_kalloc kalloc = {0}; + + kalloc.kalloc_support = -ENOTTY; + nErr = ioctl_control(dev, DSPRPC_KALLOC_SUPPORT, &kalloc); + if (!nErr) { + if (kalloc.kalloc_support != 1 && + (((int32_t)kalloc.kalloc_support != -ENOTTY) || + ((int32_t)kalloc.kalloc_support != -ENXIO) || + ((int32_t)kalloc.kalloc_support != -EINVAL))) { + nErr = AEE_ERPC; + FARF(ERROR, + "Error 0x%x: IOCTL control for kernel alloc support failed with " + "%d for domain %d errno %s", + nErr, kalloc.kalloc_support, domain, strerror(errno)); + return 0; + } + hlist[domain].kmem_support = kalloc.kalloc_support; + } + } + nErr = ((hlist[domain].kmem_support == 1) ? hlist[domain].kmem_support : 0); + + return nErr; +} + +static int open_shell(int domain_id, apps_std_FILE *fh, int unsigned_shell) { + char *absName = NULL; + char *shell_absName = NULL; + char *domain_str = NULL; + uint16 shell_absNameLen = 0, absNameLen = 0; + ; + int nErr = AEE_SUCCESS; + int domain = domain_id & DOMAIN_ID_MASK; + const char *shell_name = SIGNED_SHELL; + + if (1 == unsigned_shell) { + shell_name = UNSIGNED_SHELL; + } + + if (domain == MDSP_DOMAIN_ID) { + return nErr; + } + VERIFYC(NULL != (domain_str = (char *)malloc(sizeof(domain))), AEE_ENOMEMORY); + snprintf(domain_str, sizeof(domain), "%d", domain); + + shell_absNameLen = std_strlen(shell_name) + std_strlen(domain_str) + 1; + + VERIFYC(NULL != + (shell_absName = (char *)malloc(sizeof(char) * shell_absNameLen)), + AEE_ENOMEMORY); + std_strlcpy(shell_absName, shell_name, shell_absNameLen); + + std_strlcat(shell_absName, domain_str, shell_absNameLen); + + absNameLen = std_strlen(DSP_MOUNT_LOCATION) + shell_absNameLen + 1; + VERIFYC(NULL != (absName = (char *)malloc(sizeof(char) * absNameLen)), + AEE_ENOMEMORY); + std_strlcpy(absName, DSP_MOUNT_LOCATION, absNameLen); + std_strlcat(absName, shell_absName, absNameLen); + + nErr = apps_std_fopen(absName, "r", fh); + if (nErr) { + absNameLen = std_strlen(DSP_DOM_LOCATION) + shell_absNameLen + 1; + VERIFYC(NULL != + (absName = (char *)realloc(absName, sizeof(char) * absNameLen)), + AEE_ENOMEMORY); + std_strlcpy(absName, DSP_MOUNT_LOCATION, absNameLen); + std_strlcat(absName, SUBSYSTEM_NAME[domain], absNameLen); + std_strlcat(absName, "/", absNameLen); + std_strlcat(absName, shell_absName, absNameLen); + nErr = apps_std_fopen(absName, "r", fh); + } + if (nErr) { + absNameLen = std_strlen(VENDOR_DSP_LOCATION) + shell_absNameLen + 1; + VERIFYC(NULL != + (absName = (char *)realloc(absName, sizeof(char) * absNameLen)), + AEE_ENOMEMORY); + std_strlcpy(absName, VENDOR_DSP_LOCATION, absNameLen); + std_strlcat(absName, shell_absName, absNameLen); + + nErr = apps_std_fopen(absName, "r", fh); + if (nErr) { + absNameLen = std_strlen(VENDOR_DOM_LOCATION) + shell_absNameLen + 1; + VERIFYC(NULL != (absName = + (char *)realloc(absName, sizeof(char) * absNameLen)), + AEE_ENOMEMORY); + std_strlcpy(absName, VENDOR_DSP_LOCATION, absNameLen); + std_strlcat(absName, SUBSYSTEM_NAME[domain], absNameLen); + std_strlcat(absName, "/", absNameLen); + std_strlcat(absName, shell_absName, absNameLen); + + nErr = apps_std_fopen(absName, "r", fh); + } + } + if (!nErr) + FARF(ALWAYS, "Successfully opened %s, domain %d", absName, domain); +bail: + if (domain_str) { + free(domain_str); + domain_str = NULL; + } + if (shell_absName) { + free(shell_absName); + shell_absName = NULL; + } + if (absName) { + free(absName); + absName = NULL; + } + if (nErr != AEE_SUCCESS) { + if (domain == SDSP_DOMAIN_ID && fh != NULL) { + nErr = AEE_SUCCESS; + *fh = -1; + } else { + FARF(ERROR, + "Error 0x%x: %s failed for domain %d search paths used are %s, %s, " + "%s (errno %s)\n", + nErr, __func__, domain, DSP_MOUNT_LOCATION, VENDOR_DSP_LOCATION, + VENDOR_DOM_LOCATION, strerror(errno)); + } + } + return nErr; +} + +/* + * Request kernel to do optimizations to reduce RPC overhead. + * + * Provide the max user concurrency level to kernel which will + * enable appropriate optimizations based on that info. + * Args + * @domain : Remote subsystem ID + * + * Return : 0 on success + */ +static int fastrpc_enable_kernel_optimizations(int domain) { + int nErr = AEE_SUCCESS, dev = hlist[domain].dev, + dom = domain & DOMAIN_ID_MASK; + const uint32_t max_concurrency = 25; + + if ((dom != CDSP_DOMAIN_ID) || (hlist[domain].dsppd != USERPD)) + goto bail; + errno = 0; + + nErr = ioctl_optimization(dev, max_concurrency); + // TODO:Bharath + if ((nErr == -1 || nErr == (DSP_AEE_EOFFSET + AEE_ERPC)) && + (errno == ENOTTY || errno == EINVAL || errno == EBADRQC)) { + /* + * Kernel optimizations not supported. Ignore IOCTL failure + * TODO: kernel cleanup to return ENOTTY for all unsupported IOCTLs + */ + nErr = 0; + } +bail: + if (nErr) { + FARF(ERROR, "Error 0x%x: %s failed for domain %d (%s)\n", nErr, __func__, + domain, strerror(errno)); + } + /* + * Since this is a performance optimization, print error but ignore + * failure until the feature is stable enough. + */ + return 0; +} + +void print_process_attrs(int domain) { + bool dbgMode = false, crc = false, signedMd = false, unsignedMd = false, + qos = false, configPDdump = false; + bool debugPDdump = false, KernelPerf = false, DSPperf = false, + iregion = false, qtf = false, uaf = false; + int one_mb = 1024 * 1024; + int pd_initmem_size = 0; + bool logpkt = false; + + if (IS_DEBUG_MODE_ENABLED(hlist[domain].procattrs)) + dbgMode = true; + if (IS_CRC_CHECK_ENABLED(hlist[domain].procattrs)) + crc = true; + if (hlist[domain].unsigned_module) { + unsignedMd = true; + pd_initmem_size = 5 * one_mb; + } else { + signedMd = true; + pd_initmem_size = hlist[domain].pd_initmem_size; + } + if (hlist[domain].qos.adaptive_qos) + qos = true; + if (hlist[domain].pd_dump | fastrpc_config_is_pddump_enabled()) + configPDdump = true; + if (fastrpc_get_property_int(FASTRPC_DEBUG_PDDUMP, 0)) + debugPDdump = true; + if (hlist[domain].procattrs & FASTRPC_MODE_PERF_KERNEL) + KernelPerf = true; + if (hlist[domain].procattrs & FASTRPC_MODE_PERF_DSP) + DSPperf = true; + if (fastrpc_config_is_log_iregion_enabled()) + iregion = true; + if (fastrpc_config_is_qtf_tracing_enabled()) + qtf = true; + if (fastrpc_config_is_uaf_enabled()) + uaf = true; + if (fastrpc_config_is_logpacket_enabled()) + logpkt = true; + FARF(ALWAYS, + "Created user PD on domain %d, dbg_trace 0x%x, enabled attr=> RPC " + "timeout:%d, Dbg Mode:%s, CRC:%s, Unsigned:%s, Signed:%s, Adapt QOS:%s, " + "PD dump: (Config:%s, Dbg:%s), Perf: (Kernel:%s, DSP:%s), Iregion:%s, " + "QTF:%s, UAF:%s userPD initmem len:0x%x, Log pkt: %s", + domain, fastrpc_trace, fastrpc_config_get_rpctimeout(), + (dbgMode ? "Y" : "N"), (crc ? "Y" : "N"), (unsignedMd ? "Y" : "N"), + (signedMd ? "Y" : "N"), (qos ? "Y" : "N"), (configPDdump ? "Y" : "N"), + (debugPDdump ? "Y" : "N"), (KernelPerf ? "Y" : "N"), + (DSPperf ? "Y" : "N"), (iregion ? "Y" : "N"), (qtf ? "Y" : "N"), + (uaf ? "Y" : "N"), pd_initmem_size, (logpkt ? "Y" : "N")); + return; +} + +static int remote_init(int domain) { + int nErr = AEE_SUCCESS, ioErr = 0; + int dev = -1; + struct fastrpc_proc_sess_info sess_info = {0}; + apps_std_FILE fh = -1; + int pd_type = 0, errno_save = 0; + uint32_t info = domain & DOMAIN_ID_MASK; + int one_mb = 1024 * 1024, shared_buf_support = 0; + char *file = NULL, *mem = NULL; + int flags = 0, filelen = 0, memlen = 0, filefd = -1, memfd = -1; + + FARF(RUNTIME_RPC_HIGH, "starting %s for domain %d", __func__, domain); + /* + * is_proc_sharedbuf_supported_dsp call should be made before + * mutex lock (hlist[domain].mut), Since remote_get_info is also locked + * by the same mutex + */ + shared_buf_support = is_proc_sharedbuf_supported_dsp(domain); + pthread_setspecific(tlsKey, (void *)&hlist[domain]); + pd_type = hlist[domain].dsppd; + VERIFYC(pd_type > DEFAULT_UNUSED && pd_type < MAX_PD_TYPE, AEE_EBADITEM); + if (hlist[domain].dev == -1) { + dev = open_device_node(domain); + VERIFYM(dev >= 0, AEE_ERPC, "open dev failed\n"); + // Set session relation info using FASTRPC_INVOKE2_SESS_INFO + sess_info.domain_id = info; + sess_info.pd_type = pd_type; + sess_info.session_id = GET_SESSION_ID_FROM_DOMAIN_ID(domain); + + nErr = ioctl_session_info(dev, &sess_info); + if (nErr == AEE_SUCCESS) { + info = sess_info.domain_id; + // Skip setting session related info in multiple ioctl calls, if + // FASTRPC_CONTROL_SESS_INFO is supported + goto set_sess_info_supported; + } else { + // Fallback to previous approach, if FASTRPC_CONTROL_SESS_INFO is not + // supported + FARF(RUNTIME_RPC_HIGH, + "%s: FASTRPC_CONTROL_SESS_INFO not supported with error %d", + __func__, nErr); + } + + if (pd_type == SENSORS_STATICPD || pd_type == GUEST_OS_SHARED) { + struct fastrpc_ctrl_smmu smmu = {0}; + smmu.sharedcb = 1; + if (ioctl_control(dev, DSPRPC_SMMU_SUPPORT, &smmu)) { + FARF(RUNTIME_RPC_HIGH, "%s: DSPRPC_SMMU_SUPPORT not supported", + __func__); + } + } + nErr = ioctl_getinfo(dev, &info); + set_sess_info_supported: + hlist[domain].info = -1; + if (nErr == AEE_SUCCESS) { + hlist[domain].info = info; + } else if (errno == EACCES) { + FARF(ERROR, + "Error %d: %s: app does not have access to fastrpc device of domain " + "%d (%s)", + nErr, __func__, domain, strerror(errno)); + goto bail; + } else if (errno == ECONNREFUSED || (errno == ENODEV)) { + nErr = AEE_ECONNREFUSED; + FARF(ERROR, "Error %d: %s: fastRPC device driver is disabled (%s)", nErr, + __func__, strerror(errno)); + goto bail; + } else if (nErr) { + FARF(ERROR, "Error 0x%x: %s: failed to setup fastrpc session in kernel", + nErr, __func__); + goto bail; + } + + // Set session id + if (domain >= NUM_DOMAINS && domain < NUM_DOMAINS_EXTEND) + VERIFY(AEE_SUCCESS == (nErr = ioctl_setmode(dev, FASTRPC_SESSION_ID1))); + + FARF(RUNTIME_RPC_HIGH, "%s: device %d opened with info 0x%x (attach %d)", + __func__, dev, hlist[domain].info, pd_type); + // keep the memory we used to allocate + if (pd_type == ROOT_PD || pd_type == GUEST_OS_SHARED || + pd_type == SECURE_STATICPD) { + FARF(RUNTIME_RPC_HIGH, + "%s: attaching to guest OS/Secure PD (attach %d) for domain %d", + __func__, pd_type, domain); + if (pd_type == SECURE_STATICPD) { + file = calloc(1, (int)(std_strlen(hlist[domain].dsppdname) + 1)); + VERIFYC(file, AEE_ENOMEMORY); + std_strlcpy((char *)file, hlist[domain].dsppdname, + std_strlen(hlist[domain].dsppdname) + 1); + filelen = std_strlen(hlist[domain].dsppdname) + 1; + } + flags = FASTRPC_INIT_ATTACH; + ioErr = ioctl_init(dev, flags, 0, (byte *)file, filelen, -1, 0, 0, 0, 0); + if (file) { + free(file); + file = NULL; + } + VERIFYC((!ioErr || errno == ENOTTY || errno == ENXIO || errno == EINVAL), + AEE_ERPC); + } else if (pd_type == AUDIO_STATICPD || pd_type == OIS_STATICPD) { + FARF(RUNTIME_RPC_HIGH, "%s: creating static user PD for domain %d", + __func__, domain); + file = + rpcmem_alloc_internal(0, RPCMEM_HEAP_DEFAULT, + (int)(std_strlen(hlist[domain].dsppdname) + 1)); + VERIFYC(file, AEE_ENORPCMEMORY); + std_strlcpy((char *)file, hlist[domain].dsppdname, + std_strlen(hlist[domain].dsppdname) + 1); + filelen = std_strlen(hlist[domain].dsppdname) + 1; + flags = FASTRPC_INIT_CREATE_STATIC; + // 2MB of remote heap for dynamic loading is available only for Audio PD. + if (pd_type == AUDIO_STATICPD) { + memlen = 2 * 1024 * 1024; + } + ioErr = + ioctl_init(dev, flags, 0, (byte *)file, filelen, -1, 0, memlen, 0, 0); + if (ioErr) { + nErr = convert_kernel_to_user_error(ioErr, errno); + goto bail; + } + } else if (pd_type == SENSORS_STATICPD) { + FARF(RUNTIME_RPC_HIGH, "%s: attaching to sensors PD for domain %d", + __func__, domain); + flags = FASTRPC_INIT_ATTACH_SENSORS; + ioErr = ioctl_init(dev, flags, 0, (byte *)0, 0, -1, 0, 0, 0, 0); + VERIFYC((!ioErr || errno == ENOTTY || errno == ENXIO || errno == EINVAL), + AEE_ERPC); + } else if (pd_type == USERPD) { + uint64 len = 0; + int readlen = 0, eof; + apps_std_FILE fsig = -1; + uint64 siglen = 0; + +#ifndef VIRTUAL_FASTRPC +#if !defined(SYSTEM_RPC_LIBRARY) + open_shell(domain, &fh, hlist[domain].unsigned_module); +#endif +#endif + + hlist[domain].procattrs = get_process_attrs(domain); + if (IS_DEBUG_MODE_ENABLED(hlist[domain].procattrs)) + get_process_testsig(&fsig, &siglen); + + flags = FASTRPC_INIT_CREATE; + if (fh != -1) { + VERIFY(AEE_SUCCESS == (nErr = apps_std_flen(fh, &len))); + filelen = len + siglen; + VERIFYC(filelen && filelen < INT_MAX, AEE_EFILE); + file = rpcmem_alloc_internal(0, RPCMEM_HEAP_DEFAULT, (size_t)filelen); + VERIFYC(file, AEE_ENORPCMEMORY); + VERIFY(AEE_SUCCESS == + (nErr = apps_std_fread(fh, (byte *)file, len, &readlen, &eof))); + VERIFYC((int)len == readlen, AEE_EFILE); + filefd = rpcmem_to_fd_internal((void *)file); + filelen = (int)len; + VERIFYC(filefd != -1, AEE_ERPC); + } else { + siglen = 0; + fsig = -1; + } + if (!is_kernel_alloc_supported(dev, domain)) { + FARF(RUNTIME_RPC_HIGH, + "Allocating DSP donated memory in userspace for domain %d", + domain); + memlen = + ALIGN_B(STD_MAX(DEFAULT_PD_INITMEM_SIZE, (int)len * 4), one_mb); + if (hlist[domain].pd_initmem_size > (uint32_t)memlen) + memlen = ALIGN_B(hlist[domain].pd_initmem_size, one_mb); + mem = rpcmem_alloc_internal( + 0, RPCMEM_HEAP_DEFAULT | RPCMEM_HEAP_UNCACHED, (size_t)memlen); + VERIFYC(mem, AEE_ENORPCMEMORY); + memfd = rpcmem_to_fd_internal(mem); + VERIFYC(memfd != -1, AEE_ERPC); + } + + if (!(FASTRPC_MODE_UNSIGNED_MODULE & hlist[domain].procattrs)) { + memlen = hlist[domain].pd_initmem_size; + } else { + if (hlist[domain].pd_initmem_size != DEFAULT_PD_INITMEM_SIZE) + FARF(ERROR, "Setting user PD initial memory length is not supported " + "for unsigned PD, using default size\n"); + } + errno = 0; + + if (shared_buf_support) { + fastrpc_process_pack_params(dev, domain); + } + if (hlist[domain].procattrs) { + if (siglen && fsig != -1) { + VERIFY(AEE_SUCCESS == + (nErr = apps_std_fread(fsig, (byte *)(file + len), siglen, + &readlen, &eof))); + VERIFYC(siglen == (uint64)readlen, AEE_EFILE); + filelen = len + siglen; + } + } + ioErr = ioctl_init(dev, flags, hlist[domain].procattrs, (byte *)file, + filelen, filefd, mem, memlen, memfd, siglen); + if (ioErr) { + nErr = ioErr; + if (errno == ECONNREFUSED) { + nErr = AEE_ECONNREFUSED; + FARF(ERROR, + "Error 0x%x: %s: untrusted app trying to offload to signed " + "remote process (errno %d, %s). Try offloading to unsignedPD " + "using remote_session_control", + nErr, __func__, errno, strerror(errno)); + } + goto bail; + } + print_process_attrs(domain); + } else { + FARF(ERROR, "Error: %s called for unknown mode %d", __func__, pd_type); + } + hlist[domain].dev = dev; + dev = -1; + hlist[domain].pdmem = mem; + hlist[domain].disable_exit_logs = 0; + } +bail: + // errno is being set to 0 in apps_std_fclose and we need original errno to + // return proper error to user call + errno_save = errno; + if (nErr && mem) { + rpcmem_free_internal(mem); + mem = NULL; + } + if (file) { + rpcmem_free_internal(file); + file = NULL; + } + if (dev >= 0) { + close_device_node(domain, dev); + } + if (fh != -1) { + apps_std_fclose(fh); + } + if (nErr != AEE_SUCCESS) { + errno = errno_save; + if ((nErr == -1) && (errno == ECONNRESET)) { + nErr = AEE_ECONNRESET; + } + FARF(ERROR, "Error 0x%x: %s failed for domain %d, errno %s, ioErr %d\n", + nErr, __func__, domain, strerror(errno), ioErr); + } + FARF(RUNTIME_RPC_HIGH, "Done with %s, err: 0x%x, dev: %d", __func__, nErr, + hlist[domain].dev); + return nErr; +} + +__attribute__((destructor)) static void close_dev(void) { + int i; + + FARF(ALWAYS, "%s: unloading library %s", __func__, + fastrpc_library[DEFAULT_DOMAIN_ID]); + for (i = 0; i < NUM_DOMAINS_EXTEND; i++) { + domain_deinit(i); + } + deinit_fastrpc_dsp_lib_refcnt(); + pl_deinit(); + PL_DEINIT(fastrpc_apps_user); +} + +remote_handle64 get_adsp_current_process1_handle(int domain) { + remote_handle64 local; + int nErr = AEE_SUCCESS; + + if (hlist[domain].cphandle) { + return hlist[domain].cphandle; + } + VERIFY(AEE_SUCCESS == (nErr = fastrpc_update_module_list( + DOMAIN_LIST_PREPEND, domain, + _const_adsp_current_process1_handle, &local))); + hlist[domain].cphandle = local; + return hlist[domain].cphandle; +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, + "Error 0x%x: adsp current process handle failed. domain %d (errno " + "%s)\n", + nErr, domain, strerror(errno)); + } + return INVALID_HANDLE; +} + +remote_handle64 get_adspmsgd_adsp1_handle(int domain) { + remote_handle64 local; + int nErr = AEE_SUCCESS; + + if (hlist[domain].msghandle) { + return hlist[domain].msghandle; + } + VERIFY(AEE_SUCCESS == (nErr = fastrpc_update_module_list( + DOMAIN_LIST_PREPEND, domain, + _const_adspmsgd_adsp1_handle, &local))); + hlist[domain].msghandle = local; + return hlist[domain].msghandle; +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, + "Error 0x%x: get adsp msgd handle failed. domain %d (errno %s)\n", + nErr, domain, strerror(errno)); + } + return INVALID_HANDLE; +} + +remote_handle64 get_adsp_listener1_handle(int domain) { + remote_handle64 local; + int nErr = AEE_SUCCESS; + + if (hlist[domain].listenerhandle) { + return hlist[domain].listenerhandle; + } + VERIFY(AEE_SUCCESS == (nErr = fastrpc_update_module_list( + DOMAIN_LIST_PREPEND, domain, + _const_adsp_listener1_handle, &local))); + hlist[domain].listenerhandle = local; + return hlist[domain].listenerhandle; +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed for domain %d (errno %s)\n", nErr, + __func__, domain, strerror(errno)); + } + return INVALID_HANDLE; +} + +remote_handle64 get_remotectl1_handle(int domain) { + remote_handle64 local; + int nErr = AEE_SUCCESS; + + // If remotectlhandle is 0 allocate handle, else return handle even though + // INVALID_HANDLE handle + if (hlist[domain].remotectlhandle) { + return hlist[domain].remotectlhandle; + } + VERIFY(AEE_SUCCESS == + (nErr = fastrpc_update_module_list(DOMAIN_LIST_PREPEND, domain, + _const_remotectl1_handle, &local))); + hlist[domain].remotectlhandle = local; + return hlist[domain].remotectlhandle; +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: remotectl1 handle failed. domain %d (errno %s)\n", + nErr, domain, strerror(errno)); + } + return INVALID_HANDLE; +} + +remote_handle64 get_adsp_perf1_handle(int domain) { + remote_handle64 local; + int nErr = AEE_SUCCESS; + + if (hlist[domain].adspperfhandle) { + return hlist[domain].adspperfhandle; + } + VERIFY(AEE_SUCCESS == + (nErr = fastrpc_update_module_list(DOMAIN_LIST_PREPEND, domain, + _const_adsp_perf1_handle, &local))); + hlist[domain].adspperfhandle = local; + return hlist[domain].adspperfhandle; +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: adsp_perf1 handle failed. domain %d (errno %s)\n", + nErr, domain, strerror(errno)); + } + return INVALID_HANDLE; +} + +static int domain_init(int domain, int *dev) { + int nErr = AEE_SUCCESS, dom = domain & DOMAIN_ID_MASK; + remote_handle64 panic_handle = 0; + struct err_codes *err_codes_to_send = NULL; + + pthread_mutex_lock(&hlist[domain].mut); + if (hlist[domain].state != FASTRPC_DOMAIN_STATE_CLEAN) { + *dev = hlist[domain].dev; + pthread_mutex_unlock(&hlist[domain].mut); + return AEE_SUCCESS; + } + + QList_Ctor(&hlist[domain].ql); + QList_Ctor(&hlist[domain].nql); + QList_Ctor(&hlist[domain].rql); + hlist[domain].is_session_reserved = true; + VERIFY(AEE_SUCCESS == (nErr = remote_init(domain))); + if (fastrpc_wake_lock_enable[domain]) { + VERIFY(AEE_SUCCESS == + (nErr = update_kernel_wakelock_status( + domain, hlist[domain].dev, fastrpc_wake_lock_enable[domain]))); + } + VERIFY(AEE_SUCCESS == (nErr = fastrpc_mem_open(domain))); + VERIFY(AEE_SUCCESS == (nErr = apps_mem_init(domain))); + + if (dom == CDSP_DOMAIN_ID) { + panic_handle = get_adsp_current_process1_handle(domain); + if (panic_handle != INVALID_HANDLE) { + int ret = -1; + /* If error codes are available in debug config, send panic error codes to + * dsp to crash. */ + err_codes_to_send = fastrpc_config_get_errcodes(); + if (err_codes_to_send) { + ret = adsp_current_process1_panic_err_codes( + panic_handle, err_codes_to_send->err_code, + err_codes_to_send->num_err_codes); + if (AEE_SUCCESS == ret) { + FARF(ALWAYS, "%s : panic error codes sent successfully\n", __func__); + } else { + FARF(ERROR, "Error 0x%x: %s : panic error codes send failed\n", ret, + __func__); + } + } + } else { + FARF(ALWAYS, "%s : current process handle is not valid\n", __func__); + } + } + VERIFY(AEE_SUCCESS == (nErr = fastrpc_enable_kernel_optimizations(domain))); + initFileWatcher(domain); // Ignore errors + trace_marker_init(domain); + + // If client notifications are registered, initialize notification thread and + // enable notifications on domains + if (fastrpc_notif_flag) { + int ret = 0; + ret = enable_process_state_notif_on_dsp(domain); + if (ret == (int)(DSP_AEE_EOFFSET + AEE_EUNSUPPORTED)) { + VERIFY_WPRINTF("Warning: %s: DSP does not support notifications", + __func__); + } + VERIFYC(ret == AEE_SUCCESS || + ret == (int)(DSP_AEE_EOFFSET + AEE_EUNSUPPORTED), + ret); + } +#ifdef PD_EXCEPTION_LOGGING + if ((dom != SDSP_DOMAIN_ID) && hlist[domain].dsppd == ROOT_PD) { + remote_handle64 handle = 0; + handle = get_adspmsgd_adsp1_handle(domain); + if (handle != INVALID_HANDLE) { + adspmsgd_init(handle, 0x10); // enable PD exception logging + } + } +#endif + 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; + pthread_mutex_unlock(&hlist[domain].mut); + VERIFY(AEE_SUCCESS == (nErr = listener_android_domain_init( + domain, hlist[domain].th_params.update_requested, + &hlist[domain].th_params.r_sem))); +bail: + if (nErr != AEE_SUCCESS) { + domain_deinit(domain); + if (hlist) { + FARF(ERROR, "Error 0x%x: %s (%d) failed for domain %d (errno %s)\n", nErr, + __func__, hlist[domain].dev, domain, strerror(errno)); + } + *dev = -1; + return nErr; + } + if (hlist) { + FARF(RUNTIME_RPC_LOW, "Done %s with dev %d, err %d", __func__, + hlist[domain].dev, nErr); + *dev = hlist[domain].dev; + return nErr; + } else { + *dev = -1; + FARF(ERROR, + "Error 0x%x: Unable to get dev as hlist is NULL for domain %d\n", nErr, + __func__, domain); + return nErr; + } +} + +static void fastrpc_apps_user_deinit(void) { + int i; + + FARF(RUNTIME_RPC_HIGH, "%s called\n", __func__); + if (tlsKey != INVALID_KEY) { + pthread_key_delete(tlsKey); + tlsKey = INVALID_KEY; + } + fastrpc_notif_deinit(); + if (hlist) { + for (i = 0; i < NUM_DOMAINS_EXTEND; i++) { + fastrpc_clear_handle_list(MULTI_DOMAIN_HANDLE_LIST_ID, i); + fastrpc_clear_handle_list(REVERSE_HANDLE_LIST_ID, i); + sem_destroy(&hlist[i].th_params.r_sem); + 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); + hlist = NULL; + } + fastrpc_clear_handle_list(NON_DOMAIN_HANDLE_LIST_ID, DEFAULT_DOMAIN_ID); +#ifndef NO_HAL + for (i = 0; i < NUM_SESSIONS; i++) { + destroy_dsp_client_instance(dsp_client_instance[i]); + dsp_client_instance[i] = NULL; + } + pthread_mutex_destroy(&dsp_client_mut); +#endif + deinit_process_signals(); + fastrpc_cleanup_notif_list(); + fastrpc_wake_lock_deinit(); + fastrpc_log_deinit(); + fastrpc_mem_deinit(); + PL_DEINIT(apps_std); + PL_DEINIT(rpcmem); + PL_DEINIT(gpls); + + FARF(ALWAYS, "%s done\n", __func__); + return; +} + +static void exit_thread(void *value) { + remote_handle64 handle = 0; + int domain; + int nErr = AEE_SUCCESS; + struct handle_list *list = NULL; + + if (!hlist) { + FARF(CRITICAL, "%s: Invalid hlist", __func__); + return; + } + list = (struct handle_list *)value; + if (list) { + domain = (int)(list - &hlist[0]); + FARF(RUNTIME_RPC_CRITICAL, "%s: dom:%d, dev:%d", __func__, domain, + list->dev); + } + + for (domain = 0; domain < NUM_DOMAINS_EXTEND; domain++) { + if (hlist[domain].dev != -1) { + FARF(RUNTIME_RPC_CRITICAL, "%s: dom:%d", __func__, domain); + if ((handle = get_adsp_current_process1_handle(domain)) != + INVALID_HANDLE) { + nErr = adsp_current_process1_thread_exit(handle); + if (nErr) { + FARF(CRITICAL, "%s: nErr:0x%x, dom:%d, h:0x%llx", __func__, nErr, + domain, handle); + } + } else if (domain == DEFAULT_DOMAIN_ID) { + nErr = adsp_current_process_thread_exit(); + if (nErr) { + FARF(CRITICAL, "%s: nErr:0x%x, dom:%d", __func__, nErr, domain); + } + } + } + } + // Set tlsKey to NULL, so that exit_thread won't be called recursively + pthread_setspecific(tlsKey, (void *)NULL); +} + +/* + * Called only once by fastrpc_init_once + * Initializes the data structures + */ + +static int fastrpc_apps_user_init(void) { + int nErr = AEE_SUCCESS, i; + pthread_mutexattr_t attr; + + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + + VERIFY(AEE_SUCCESS == (nErr = PL_INIT(gpls))); + VERIFY(AEE_SUCCESS == (nErr = PL_INIT(rpcmem))); + fastrpc_mem_init(); + fastrpc_log_init(); + fastrpc_config_init(); + pthread_mutex_init(&update_notif_list_mut, 0); +#ifndef NO_HAL + pthread_mutex_init(&dsp_client_mut, 0); +#endif + VERIFYC(NULL != (hlist = calloc(NUM_DOMAINS_EXTEND, sizeof(*hlist))), + AEE_ENOMEMORY); + for (i = 0; i < NUM_DOMAINS_EXTEND; 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, + 0); // Initialize semaphore count to 0 + hlist[i].dsppd = attach_guestos(i); + hlist[i].trace_marker_fd = -1; + hlist[i].state = FASTRPC_DOMAIN_STATE_CLEAN; + hlist[i].pd_initmem_size = DEFAULT_PD_INITMEM_SIZE; + QList_Ctor(&hlist[i].ql); + QList_Ctor(&hlist[i].nql); + QList_Ctor(&hlist[i].rql); + memset(hlist[i].dsppdname, 0, MAX_DSPPD_NAMELEN); + memset(hlist[i].sessionname, 0, MAX_DSPPD_NAMELEN); + 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 = pthread_key_create(&tlsKey, exit_thread))); + VERIFY(AEE_SUCCESS == (nErr = PL_INIT(apps_std))); + GenCrc32Tab(POLY32, crc_table); + fastrpc_notif_init(); +bail: + /* + print address of static variable + to know duplicate instance of libcdsprpc.so + */ + if (nErr) { + FARF(ERROR, + "Error 0x%x: %s failed. default domain:%x and &fastrpc_trace:%p \n", + nErr, __func__, DEFAULT_DOMAIN_ID, &fastrpc_trace); + fastrpc_apps_user_deinit(); + } else { + FARF(ALWAYS, "%s done. default domain:%x and &fastrpc_trace:%p\n", __func__, + DEFAULT_DOMAIN_ID, &fastrpc_trace); + } + return nErr; +} + +PL_DEFINE(fastrpc_apps_user, fastrpc_apps_user_init, fastrpc_apps_user_deinit); + +static void frpc_init(void) { PL_INIT(fastrpc_apps_user); } + +int fastrpc_init_once(void) { + static pthread_once_t frpc = PTHREAD_ONCE_INIT; + int nErr = AEE_SUCCESS; + VERIFY(AEE_SUCCESS == (nErr = pthread_once(&frpc, (void *)frpc_init))); +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error %x: fastrpc init once failed\n", nErr); + } + return nErr == AEE_SUCCESS ? _pl_fastrpc_apps_user()->nErr : nErr; +} + +static int rpcmem_init_me(void) { + rpcmem_init_internal(); + return AEE_SUCCESS; +} + +static void rpcmem_deinit_me(void) { + rpcmem_deinit_internal(); + return; +} + +/* + * check_multilib_util() - Debug utility to terminate the process when multiple + * instances of dsp library linked to the process by reading process env + * variable values. + * Return : void. + */ + +static void check_multilib_util(void) { + int nErr = 0, ret = -1; + const char *env_name = fastrpc_dsp_lib_refcnt[DEFAULT_DOMAIN_ID]; + + /* Set env variable of default domain id to 1. */ + ret = setenv(env_name, "1", 1); + if (ret != 0 && errno == ENOMEM) { + nErr = ERRNO; + FARF(ERROR, "Error 0x%x: setenv failed for %s (domain %u), errno is %s\n", + nErr, env_name, DEFAULT_DOMAIN_ID, strerror(ERRNO)); + /* + * If failed to set env variable then free the memory allocated to + * env variables and exit the application. + */ + deinit_fastrpc_dsp_lib_refcnt(); + exit(EXIT_FAILURE); + } else { + total_dsp_lib_refcnt = 1; + } + + /* Get the values of all env variables and increment the refcount accordingly. + */ + for (int ii = 0; ii < NUM_DOMAINS; ii++) { + char *env_val = NULL; + env_name = fastrpc_dsp_lib_refcnt[ii]; + + /* Skip the check to get default domain env variable value as we already set + * its value. */ + if (ii == DEFAULT_DOMAIN_ID) + continue; + + env_val = getenv(env_name); + if (NULL != env_val) { + /* + * Add env value to total reference count to check + * the total number of dsp library instances loaded. + */ + total_dsp_lib_refcnt += atoi(env_val); + + /* If the total reference count exceeds one then show warning, application + * will abort on first handle open. */ + if (total_dsp_lib_refcnt > MAX_LIB_INSTANCE_ALLOWED) { + FARF(ERROR, + "Warning: %s %d instances of libxdsprpc (already loaded %s). Only " + "%d allowed\n", + fastrpc_library[DEFAULT_DOMAIN_ID], total_dsp_lib_refcnt, + fastrpc_library[ii], MAX_LIB_INSTANCE_ALLOWED); + } + } + } +} + +__CONSTRUCTOR_ATTRIBUTE__ +static void multidsplib_env_init(void) { + const char *local_fastrpc_lib_refcnt[NUM_DOMAINS] = { + "FASTRPC_ADSP_REFCNT", "FASTRPC_MDSP_REFCNT", "FASTRPC_SDSP_REFCNT", + "FASTRPC_CDSP_REFCNT"}; + char buf[64] = {0}; + size_t env_name_len = 0; + char *env_name = NULL; + + pid_t pid = getpid(); + + /* Initialize all global array with env variable names along with process id. + */ + for (int ii = 0; ii < NUM_DOMAINS; ii++) { + snprintf(buf, sizeof(buf), "%s_%d", local_fastrpc_lib_refcnt[ii], pid); + env_name_len = (sizeof(char) * strlen(buf)) + 1; + env_name = malloc(env_name_len); + if (env_name) { + std_strlcpy(env_name, buf, env_name_len); + fastrpc_dsp_lib_refcnt[ii] = env_name; + } else { + FARF(ERROR, + "Error %d: %s: env variable allocation for %zu bytes failed, domain " + "%d\n", + ENOMEM, __func__, env_name_len, ii); + deinit_fastrpc_dsp_lib_refcnt(); + exit(EXIT_FAILURE); + } + } + check_multilib_util(); + FARF(ALWAYS, "%s: %s loaded", __func__, fastrpc_library[DEFAULT_DOMAIN_ID]); +} + +PL_DEFINE(rpcmem, rpcmem_init_me, rpcmem_deinit_me); diff --git a/src/fastrpc_async.c b/src/fastrpc_async.c new file mode 100644 index 0000000..693a7bf --- /dev/null +++ b/src/fastrpc_async.c @@ -0,0 +1,489 @@ +// 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; + boolean 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; + boolean jobfound = FALSE; + struct fastrpc_async_job_node *lasync_node; + + domain = GET_DOMAIN_FROM_JOBID(jobid); + hash = GET_HASH_FROM_JOBID(jobid); + VERIFYC((domain >= 0) && (domain < NUM_DOMAINS_EXTEND), 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, + boolean 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; + boolean 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(domain < NUM_DOMAINS_EXTEND, 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 new file mode 100644 index 0000000..4139da5 --- /dev/null +++ b/src/fastrpc_cap.c @@ -0,0 +1,231 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#include +#include +#include + +#define FARF_ERROR 1 + +#include "remote.h" +#include "AEEStdErr.h" +#include "verify.h" +#include "HAP_farf.h" +#include "fastrpc_cap.h" +#include "fastrpc_common.h" +#include "fastrpc_internal.h" + + +#define BUF_SIZE 50 + +const char * RPROC_SUBSYSTEM_NAME[] = {"adsp", "mss", "spss", "cdsp"}; + +static inline uint32_t fastrpc_check_if_dsp_present_pil(uint32_t domain) { + uint32_t domain_supported = 0; + struct stat sb; + // mark rest of the list as reserved to avoid out of bound access + const char *SUBSYSTEM_DEV_NAME[] = {"/dev/subsys_adsp", "", "/dev/subsys_slpi", "/dev/subsys_cdsp", "/dev/subsys_cdsp1", "reserved", "reserved", "reserved", "reserved", "reserved", "reserved", "reserved", "reserved", "reserved", "reserved", "reserved"}; + + // If device file is present, then target supports that DSP + if (!stat(SUBSYSTEM_DEV_NAME[domain], &sb)) { + domain_supported = 1; + } + return domain_supported; +} + +/* + * Function to check whether particular remote subsystem is present or not. + * Return 0 if subsystem is not available otherwise 1. +*/ +static inline uint32_t fastrpc_check_if_dsp_present_rproc(uint32_t domain) { + char *dir_base_path = "/sys/class/remoteproc/remoteproc"; + const char *search_string = NULL; + uint32_t domain_supported = 0; + int dir_index = 0, nErr = AEE_SUCCESS; + struct stat dir_stat; + char *buffer = NULL; + + if (domain < ADSP_DOMAIN_ID || domain > CDSP_DOMAIN_ID) { + FARF(ERROR, "%s Invalid domain 0x%x ", __func__, domain); + return 0; + } + + VERIFYC(NULL != (buffer = malloc(BUF_SIZE)), AEE_ENOMEMORY); + search_string = RPROC_SUBSYSTEM_NAME[domain]; + + while (1) { + memset(buffer, 0, BUF_SIZE); + snprintf(buffer, BUF_SIZE, "%s%d", dir_base_path, dir_index); + if (stat(buffer, &dir_stat) == -1) { + break; + } + std_strlcat(buffer, "/name", BUF_SIZE); + FILE *file = fopen(buffer, "r"); + if (file != NULL) { + memset(buffer, 0, BUF_SIZE); + if (fgets(buffer, BUF_SIZE, file) != NULL) { + buffer[BUF_SIZE - 1] = '\0'; + if (std_strstr(buffer, search_string) != NULL) { + domain_supported = 1; + fclose(file); + break; + } + } + fclose(file); + } + dir_index++; + } +bail : + if (buffer){ + free(buffer); + } + if (nErr) { + FARF(ERROR, "Error 0x%x: %s failed for domain %d\n", nErr, __func__, domain); + } + return domain_supported; +} + +int fastrpc_get_cap(uint32_t domain, uint32_t attributeID, uint32_t *capability) { + int nErr = AEE_SUCCESS, dev = -1, dom = domain & DOMAIN_ID_MASK; + + VERIFYC(domain >= 0 && domain < NUM_DOMAINS_EXTEND, AEE_EBADPARM); + VERIFYC(capability != NULL, AEE_EBADPARM); + VERIFYC(attributeID < FASTRPC_MAX_ATTRIBUTES, AEE_EBADPARM); //Check if the attribute ID is less than max attributes accepted by userspace + + *capability = 0; + + if (attributeID == DOMAIN_SUPPORT) { + *capability = fastrpc_check_if_dsp_present_pil(dom); + if (*capability == 0) { + *capability = fastrpc_check_if_dsp_present_rproc(dom); + } + if (*capability == 0) { + FARF(ALWAYS, "Warning! %s domain %d is not present\n", __func__, dom); + } + 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; + nErr = ioctl_getdspinfo(dev, dom, attributeID, capability); + if(nErr) { + goto bail; + } + if (attributeID == STATUS_NOTIFICATION_SUPPORT) { + *capability = (*capability == STATUS_NOTIF_V2) ? 1 : 0; + } + +bail: + if(dev != -1) + fastrpc_session_close(dev); + if (nErr) { + FARF(ERROR, "Warning 0x%x: %s failed to get attribute %u for domain %u (errno %s)", nErr, __func__, attributeID, domain, strerror(errno)); + } + return nErr; +} + +uint32_t get_dsp_dma_reverse_rpc_map_capability(int domain) { + int nErr = 0; + uint32_t capability = 0; + + nErr= fastrpc_get_cap(domain, MAP_DMA_HANDLE_REVERSERPC, &capability); + if (nErr == 0) { + return capability; + } + return 0; +} + +static int check_status_notif_version2_capability(int domain) +{ + int nErr = 0; + struct remote_dsp_capability cap = {0}; + cap.domain = (domain & DOMAIN_ID_MASK); + cap.attribute_ID = STATUS_NOTIFICATION_SUPPORT; + + nErr= fastrpc_get_cap(cap.domain, cap.attribute_ID, &cap.capability); + if (nErr == 0) { + return cap.capability; + } else { + FARF(RUNTIME_RPC_HIGH, "%s: Capability not found. nErr: 0x%x", __func__, nErr); + } + return 0; +} + +int is_status_notif_version2_supported(int domain) +{ + static int status_notif_version2_capability = -1; + + if(status_notif_version2_capability == -1) { + status_notif_version2_capability = check_status_notif_version2_capability(domain); + } + return status_notif_version2_capability; +} + +static int check_userspace_allocation_capability(void) +{ + int nErr = 0; + struct remote_dsp_capability cap = {0}; + + cap.domain = DEFAULT_DOMAIN_ID; + cap.attribute_ID = USERSPACE_ALLOCATION_SUPPORT; + + nErr= fastrpc_get_cap(cap.domain, cap.attribute_ID, &cap.capability); + if (nErr == 0) { + return cap.capability; + } else { + FARF(RUNTIME_RPC_HIGH, "%s: Capability not found. nErr: 0x%x", __func__, nErr); + } + return 0; +} + +int is_userspace_allocation_supported(void) +{ + static int userspace_allocation_capability = -1; + + if(userspace_allocation_capability == -1) { + userspace_allocation_capability = check_userspace_allocation_capability(); + } + return userspace_allocation_capability; +} + +int is_proc_sharedbuf_supported_dsp(int domain) +{ + int nErr = AEE_SUCCESS; + static int proc_sharedbuf_capability = -1; + struct remote_dsp_capability cap = {domain, PROC_SHARED_BUFFER_SUPPORT, 0}; + + if (proc_sharedbuf_capability == -1) { + nErr = fastrpc_get_cap(cap.domain, cap.attribute_ID, &cap.capability); + if (nErr == AEE_SUCCESS) { + proc_sharedbuf_capability = cap.capability; + } else { + FARF(RUNTIME_RPC_HIGH, "Error 0x%x: %s: capability not found", nErr, __func__); + proc_sharedbuf_capability = 0; + } + } + return proc_sharedbuf_capability; +} + +int check_error_code_change_present() { + int nErr = 0; + struct remote_dsp_capability cap = {0}; + static int driver_error_code_capability = -1; + cap.domain = DEFAULT_DOMAIN_ID; + cap.attribute_ID = DRIVER_ERROR_CODE_CHANGE; + + if(driver_error_code_capability == -1) { + nErr= fastrpc_get_cap(cap.domain, cap.attribute_ID, &cap.capability); + if (nErr == 0) { + driver_error_code_capability = cap.capability; + } + } + return driver_error_code_capability; +} diff --git a/src/fastrpc_config.c b/src/fastrpc_config.c new file mode 100644 index 0000000..7cf45ef --- /dev/null +++ b/src/fastrpc_config.c @@ -0,0 +1,432 @@ +// 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AEEStdErr.h" +#include "AEEstd.h" +#include "HAP_farf.h" +#include "apps_std.h" +#include "fastrpc_common.h" +#include "fastrpc_config.h" +#include "apps_std_internal.h" +#include "verify.h" + +#define CONFIG_PDDUMP "pddump" +#define CONFIG_RPCTIMEOUT "rpctimeout" +#define CONFIG_PERF_KERNEL "perfkernel" +#define CONFIG_PERF_DSP "perfdsp" +#define CONFIG_COLLECT_RUNTIME_FARF "collectRuntimeFARF" +#define CONFIG_COLLECT_RUNTIME_FARF_USERSPACE "collectUserspaceRuntimeFARF" +#define CONFIG_LOG_IREGION "logiregion" +#define CONFIG_QTF_TRACING "qtftracing" +#define CONFIG_CALLER_LEVEL "callerlevel" +#define CONFIG_ENABLE_UAF "uafenabled" +#define CONFIG_DEBUG_LOGGING "debuglogging" +#define CONFIG_DEBUG_SYSMON_LOGGING "sysmonreservedbit" +#define CONFIG_ERR_CODES "errcodes" +#define MIN_DSP_ERR_RNG 0x80000401 +#define MAX_DSP_ERR_RNG 0x80000601 +#define CONFIG_LOGPACKET "logPackets" +#define CONFIG_LEAK_DETECT "leak_detect" +#define CONFIG_CALL_STACK_NUM "num_call_stack" + +struct fastrpc_config_param { + boolean pddump; + int rpc_timeout; + boolean perfkernel; + boolean perfdsp; + _cstring1_t *paths; + char *farf_log_filename; + char *farf_log_filename_userspace; + boolean log_iregion; + boolean qtf_tracing; + int caller_level; + boolean uaf_enabled; + boolean debug_logging; + struct err_codes err_codes_to_crash; + boolean sysmonreservedbit; + boolean logPackets; + int leak_detect; + int num_call_stack; +}; + +static struct fastrpc_config_param frpc_config; + +// Function to read and parse config file +int fastrpc_read_config_file_from_path(const char *base, const char *file) { + int nErr = 0; + apps_std_FILE fp = -1; + uint64 len; + byte *buf = NULL; + int eof; + char *path = NULL, *param = NULL, *saveptr = NULL; + boolean fileExists = FALSE; + char *delim = "=", *delim2 = ","; + uint64 logFileNameLen = 0; + frpc_config.err_codes_to_crash.num_err_codes = 0; + + len = std_snprintf(0, 0, "%s/%s", base, file) + 1; + VERIFYC(NULL != (path = calloc(1, sizeof(char) * len)), AEE_ENOMEMORY); + std_snprintf(path, (int)len, "%s/%s", base, file); + VERIFY(AEE_SUCCESS == (nErr = apps_std_fileExists(path, &fileExists))); + if (fileExists == FALSE) { + nErr = AEE_ENOSUCHFILE; + goto bail; + } + + VERIFY(AEE_SUCCESS == (nErr = apps_std_fopen(path, "r", &fp))); + VERIFY(AEE_SUCCESS == (nErr = apps_std_flen(fp, &len))); + // Allocate buffer for reading each line + VERIFYC(NULL != (buf = calloc(1, sizeof(byte) * (len + 1))), + AEE_ENOMEMORY); // extra 1 byte for null character + + do { + // Read each line at a time + VERIFY(AEE_SUCCESS == (nErr = apps_std_fgets(fp, buf, len, &eof))); + if (eof) { + break; + } + param = strtok_r((char *)buf, delim, &saveptr); + if (param == NULL) { + continue; + } + + if (std_strncmp(param, CONFIG_ERR_CODES, std_strlen(CONFIG_ERR_CODES)) == + 0) { + int ii = 0, num_err_codes = 0; + unsigned int err_code = 0; + + FARF(ALWAYS, "%s: panic error codes applicable only to cdsp domain\n", + __func__); + do { + param = strtok_r(NULL, delim2, &saveptr); + if (param != NULL) { + err_code = strtol(param, NULL, 16); + if (err_code >= MIN_DSP_ERR_RNG && err_code <= MAX_DSP_ERR_RNG) { + frpc_config.err_codes_to_crash.err_code[ii] = err_code; + FARF(ALWAYS, "%s : panic error codes : 0x%x\n", __func__, + frpc_config.err_codes_to_crash.err_code[ii]); + ii++; + if (ii >= MAX_PANIC_ERR_CODES) { + FARF(ERROR, "%s : Max panic error codes limit reached\n", + __func__, MAX_PANIC_ERR_CODES); + break; + } + } else { + FARF(ALWAYS, + "%s : panic error code read from debugcnfig : 0x%x is not in " + "dsp error codes range\n", + __func__, err_code); + } + } + } while (param != NULL); + num_err_codes = ii; + frpc_config.err_codes_to_crash.num_err_codes = num_err_codes; + } else if (std_strncmp(param, CONFIG_PDDUMP, std_strlen(CONFIG_PDDUMP)) == + 0) { + param = strtok_r(NULL, delim, &saveptr); + if (param != NULL && atoi(param)) { + frpc_config.pddump = TRUE; + FARF(ALWAYS, "fastrpc config enabling PD dump\n"); + } + } else if (std_strncmp(param, CONFIG_RPCTIMEOUT, + std_strlen(CONFIG_RPCTIMEOUT)) == 0) { + param = strtok_r(NULL, delim, &saveptr); + if (param != NULL) { + frpc_config.rpc_timeout = atoi(param); + FARF(ALWAYS, "fastrpc config set rpc timeout with %d\n", + frpc_config.rpc_timeout); + } + } else if (std_strncmp(param, CONFIG_PERF_KERNEL, + std_strlen(CONFIG_PERF_KERNEL)) == 0) { + param = strtok_r(NULL, delim, &saveptr); + if (param != NULL && atoi(param)) { + frpc_config.perfkernel = TRUE; + FARF(ALWAYS, "fastrpc config enabling profiling on kernel\n"); + } + } else if (std_strncmp(param, CONFIG_PERF_DSP, + std_strlen(CONFIG_PERF_DSP)) == 0) { + param = strtok_r(NULL, delim, &saveptr); + if (param != NULL && atoi(param)) { + frpc_config.perfdsp = TRUE; + FARF(ALWAYS, "fastrpc config enabling profiling on dsp\n"); + } + } else if (std_strncmp(param, CONFIG_COLLECT_RUNTIME_FARF, + std_strlen(CONFIG_COLLECT_RUNTIME_FARF)) == 0) { + param = strtok_r(NULL, delim, &saveptr); + if (param != NULL) { + logFileNameLen = std_strlen(param) + 1; + VERIFYC(NULL != (frpc_config.farf_log_filename = + (char *)malloc(sizeof(char) * logFileNameLen)), + AEE_ENOMEMORY); + std_strlcpy(frpc_config.farf_log_filename, param, logFileNameLen); + FARF(ALWAYS, + "fastrpc config enabling farf logs collection into file %s", + frpc_config.farf_log_filename); + } + } else if (std_strncmp(param, CONFIG_COLLECT_RUNTIME_FARF_USERSPACE, + std_strlen(CONFIG_COLLECT_RUNTIME_FARF_USERSPACE)) == + 0) { + param = strtok_r(NULL, delim, &saveptr); + if (param != NULL) { + logFileNameLen = std_strlen(param) + 1; + VERIFYC(NULL != (frpc_config.farf_log_filename_userspace = + (char *)malloc(sizeof(char) * logFileNameLen)), + AEE_ENOMEMORY); + std_strlcpy(frpc_config.farf_log_filename_userspace, param, + logFileNameLen); + FARF(ALWAYS, + "fastrpc config enabling userspace farf logs collection into file " + "%s", + frpc_config.farf_log_filename_userspace); + } + } else if (std_strncmp(param, CONFIG_LOG_IREGION, + std_strlen(CONFIG_LOG_IREGION)) == 0) { + param = strtok_r(NULL, delim, &saveptr); + if (param != NULL) { + frpc_config.log_iregion = TRUE; + FARF(ALWAYS, "fastrpc config enabling iregion logging\n"); + } + } else if (std_strncmp(param, CONFIG_QTF_TRACING, + std_strlen(CONFIG_QTF_TRACING)) == 0) { + param = strtok_r(NULL, delim, &saveptr); + if (param != NULL && atoi(param)) { + frpc_config.qtf_tracing = TRUE; + FARF(ALWAYS, "fastrpc config enabling QTF tracing\n"); + } + } else if (std_strncmp(param, CONFIG_CALLER_LEVEL, + std_strlen(CONFIG_CALLER_LEVEL)) == 0) { + param = strtok_r(NULL, delim, &saveptr); + if (param != NULL && atoi(param)) { + frpc_config.caller_level = atoi(param); + FARF(ALWAYS, "fastrpc config setting heap caller level with %d\n", + frpc_config.caller_level); + } + } else if (std_strncmp(param, CONFIG_ENABLE_UAF, + std_strlen(CONFIG_ENABLE_UAF)) == 0) { + param = strtok_r(NULL, delim, &saveptr); + if (param != NULL && atoi(param)) { + frpc_config.uaf_enabled = TRUE; + FARF(ALWAYS, "fastrpc config enabling uaf on heap\n"); + } + } else if (std_strncmp(param, CONFIG_DEBUG_LOGGING, + std_strlen(CONFIG_DEBUG_LOGGING)) == 0) { + param = strtok_r(NULL, delim, &saveptr); + if (param != NULL) { + frpc_config.debug_logging = TRUE; + FARF(ALWAYS, "fastrpc config enabling debug logging\n"); + } + } else if (std_strncmp(param, CONFIG_DEBUG_SYSMON_LOGGING, + std_strlen(CONFIG_DEBUG_SYSMON_LOGGING)) == 0) { + param = strtok_r(NULL, delim, &saveptr); + if (param != NULL) { + frpc_config.sysmonreservedbit = TRUE; + FARF(ALWAYS, "fastrpc config enabling sysmon logging \n"); + } + } else if (std_strncmp(param, CONFIG_LOGPACKET, + std_strlen(CONFIG_LOGPACKET)) == 0) { + param = strtok_r(NULL, delim, &saveptr); + if (param != NULL) { + frpc_config.logPackets = TRUE; + FARF(ALWAYS, "fastrpc config enabling Log packets\n"); + } + } else if (std_strncmp(param, CONFIG_LEAK_DETECT, + std_strlen(CONFIG_LEAK_DETECT)) == 0) { + param = strtok_r(NULL, delim, &saveptr); + if (param != NULL && atoi(param)) { + frpc_config.leak_detect = atoi(param); + FARF(ALWAYS, "fastrpc config enabling leak detect with %d\n", + frpc_config.leak_detect); + } + } else if (std_strncmp(param, CONFIG_CALL_STACK_NUM, + std_strlen(CONFIG_CALL_STACK_NUM)) == 0) { + param = strtok_r(NULL, delim, &saveptr); + if (param != NULL && atoi(param)) { + frpc_config.num_call_stack = atoi(param); + FARF(ALWAYS, "fastrpc config setting call stack num with %d\n", + frpc_config.num_call_stack); + } + } + param = NULL; + } while (!eof); +bail: + if (buf != NULL) { + free(buf); + buf = NULL; + } + if (fp != -1) { + apps_std_fclose(fp); + } + if (path != NULL) { + free(path); + path = NULL; + } + if (nErr != AEE_SUCCESS && nErr != AEE_ENOSUCHFILE) { + FARF(ALWAYS, "Error 0x%x: failed for %s/%s with errno(%s)\n", nErr, base, + file, strerror(errno)); + } + return nErr; +} + +// Function to get panic error codes. +struct err_codes *fastrpc_config_get_errcodes(void) { + if (frpc_config.err_codes_to_crash.num_err_codes != 0) + return (&(frpc_config.err_codes_to_crash)); + return NULL; +} + +// Function to get rpc timeout. +int fastrpc_config_get_rpctimeout(void) { return frpc_config.rpc_timeout; } + +// Function to get if PD dump feature is enabled. +boolean fastrpc_config_is_pddump_enabled(void) { return frpc_config.pddump; } + +// Functions to get if profiling mode is enabled. +boolean fastrpc_config_is_perfkernel_enabled(void) { + return frpc_config.perfkernel; +} +boolean fastrpc_config_is_perfdsp_enabled(void) { return frpc_config.perfdsp; } + +// Function to get the file name to collect runtime farf logs. +char *fastrpc_config_get_runtime_farf_file(void) { + return frpc_config.farf_log_filename; +} +// Function to get the file name to collect userspace runtime farf logs. +char *fastrpc_config_get_userspace_runtime_farf_file(void) { + return frpc_config.farf_log_filename_userspace; +} +// Function to get if iregion logging feature is enabled. +boolean fastrpc_config_is_log_iregion_enabled(void) { + return frpc_config.log_iregion; +} +// Function to get if debug logging feature is enabled. +boolean fastrpc_config_is_debug_logging_enabled(void) { + return frpc_config.debug_logging; +} + +// Function to get if debug logging feature is enabled for sysmon reserved bit. +boolean fastrpc_config_is_sysmon_reserved_bit_enabled(void) { + return frpc_config.sysmonreservedbit; +} + +// Function to get if QTF tracing is enabled. +boolean fastrpc_config_is_qtf_tracing_enabled(void) { + return frpc_config.qtf_tracing; +} + +// Function to get heap caller level. +int fastrpc_config_get_caller_level(void) { return frpc_config.caller_level; } + +// Function to get if uaf should be enabled in heap +boolean fastrpc_config_is_uaf_enabled(void) { return frpc_config.uaf_enabled; } + +// Function to get if Log packet is enabled. +boolean fastrpc_config_is_logpacket_enabled(void) { + return frpc_config.logPackets; +} + +// Function to get if leak detect is enabled +int fastrpc_config_get_leak_detect(void) { return frpc_config.leak_detect; } + +// Function to return the call stack num +int fastrpc_config_get_caller_stack_num(void) { + return frpc_config.num_call_stack; +} + +// Fastrpc config init function +int fastrpc_config_init() { + int nErr = AEE_SUCCESS, i = 0; + const char *file_extension = ".debugconfig"; + char *name = NULL; + char *data_paths = NULL; + char *config_file = NULL; + _cstring1_t *paths = NULL; + uint32 len = 0; + uint16 maxPathLen = 0; + uint32 numPaths = 0; + int file_found = 0; + + VERIFYC(NULL != (name = std_basename(__progname)), AEE_EINVALIDPROCNAME); + len = strlen(name) + strlen(file_extension) + 1; + VERIFYC(NULL != (config_file = calloc(1, sizeof(char) * len)), AEE_ENOMEMORY); + // Prepare config filename + snprintf(config_file, len, "%s%s", name, file_extension); + FARF(ALWAYS, "Reading configuration file: %s\n", config_file); + + // Get the required size for PATH + apps_std_get_search_paths_with_env(ADSP_LIBRARY_PATH, ";", NULL, 0, &numPaths, + &maxPathLen); + maxPathLen += +1; + + // Allocate memory for the PATH's + VERIFYC(NULL != (paths = calloc(1, sizeof(_cstring1_t) * numPaths)), + AEE_ENOMEMORY); + for (i = 0; i < (int)numPaths; ++i) { + VERIFYC(NULL != (paths[i].data = calloc(1, sizeof(char) * maxPathLen)), + AEE_ENOMEMORY); + paths[i].dataLen = maxPathLen; + } + + // Allocate single buffer for all the PATHs + VERIFYC(NULL != + (data_paths = calloc(1, sizeof(char) * maxPathLen * numPaths)), + AEE_ENOMEMORY); + + // Get the paths + VERIFY(AEE_SUCCESS == + (nErr = apps_std_get_search_paths_with_env( + ADSP_LIBRARY_PATH, ";", paths, numPaths, &len, &maxPathLen))); + maxPathLen += 1; + for (i = 0; i < (int)numPaths; ++i) { + std_strlcat(data_paths, paths[i].data, + sizeof(char) * maxPathLen * numPaths); + std_strlcat(data_paths, ", ", sizeof(char) * maxPathLen * numPaths); + if (0 == fastrpc_read_config_file_from_path(paths[i].data, config_file)) { + file_found = 1; + FARF(ALWAYS, "Read fastrpc config file %s found at %s\n", config_file, + paths[i].data); + break; + } + } + if (!file_found) { + FARF(ALWAYS, "%s: Couldn't find file %s, errno (%s) at %s\n", __func__, + config_file, strerror(errno), data_paths); + } +bail: + if (nErr) { + FARF(ERROR, "%s: failed for process %s", __func__, name); + } + if (paths) { + for (i = 0; i < (int)numPaths; ++i) { + if (paths[i].data) { + free(paths[i].data); + paths[i].data = NULL; + } + } + free(paths); + paths = NULL; + } + if (config_file) { + free(config_file); + config_file = NULL; + } + if (data_paths) { + free(data_paths); + } + return nErr; +} diff --git a/src/fastrpc_ioctl.c b/src/fastrpc_ioctl.c new file mode 100644 index 0000000..dbe579c --- /dev/null +++ b/src/fastrpc_ioctl.c @@ -0,0 +1,244 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +/* File only compiled when support to upstream kernel is required*/ + +#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 + */ +const char *get_secure_domain_name(int domain_id) { + const char *name; + int domain = domain_id & DOMAIN_ID_MASK; + + 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; + default: + name = DEFAULT_DEVICE; + break; + } + return name; +} + +int ioctl_init(int dev, uint32_t flags, int attr, byte *shell, int shelllen, + int shellfd, char *mem, int memlen, int memfd, int tessiglen) { + int ioErr = 0; + struct fastrpc_ioctl_init_create init = {0}; + struct fastrpc_ioctl_init_create_static init_static = {0}; + + switch (flags) { + case FASTRPC_INIT_ATTACH: + ioErr = ioctl(dev, FASTRPC_IOCTL_INIT_ATTACH, NULL); + break; + case FASTRPC_INIT_ATTACH_SENSORS: + ioErr = ioctl(dev, FASTRPC_IOCTL_INIT_ATTACH_SNS, NULL); + break; + case FASTRPC_INIT_CREATE_STATIC: + init_static.namelen = shelllen; + init_static.memlen = memlen; + init_static.name = (uint64_t)shell; + ioErr = ioctl(dev, FASTRPC_IOCTL_INIT_CREATE_STATIC, + (unsigned long)&init_static); + break; + case FASTRPC_INIT_CREATE: + init.file = (uint64_t)shell; + init.filelen = shelllen; + init.filefd = shellfd; + init.attrs = attr; + init.siglen = tessiglen; + ioErr = ioctl(dev, FASTRPC_IOCTL_INIT_CREATE, (unsigned long)&init); + break; + default: + FARF(ERROR, "ERROR: %s Invalid init flags passed %d", __func__, flags); + ioErr = AEE_EBADPARM; + break; + } + + return ioErr; +} + +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 ioErr = AEE_SUCCESS; + struct fastrpc_ioctl_invoke invoke = {0}; + + invoke.handle = handle; + invoke.sc = sc; + invoke.args = (uint64_t)pra; + if (req >= INVOKE && req <= INVOKE_FD) + ioErr = ioctl(dev, FASTRPC_IOCTL_INVOKE, (unsigned long)&invoke); + else + return AEE_EUNSUPPORTED; + + 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; +} + +int ioctl_mmap(int dev, int req, uint32_t flags, int attr, int fd, int offset, + size_t len, uintptr_t vaddrin, uint64_t *vaddrout) { + int ioErr = AEE_SUCCESS; + + switch (req) { + case MEM_MAP: { + struct fastrpc_ioctl_mem_map map = {0}; + map.version = 0; + map.fd = fd; + map.offset = offset; + map.flags = flags; + map.vaddrin = (uint64_t)vaddrin; + map.length = len; + map.attrs = attr; + ioErr = ioctl(dev, FASTRPC_IOCTL_MEM_MAP, (unsigned long)&map); + *vaddrout = (uint64_t)map.vaddrout; + } break; + case MMAP: + case MMAP_64: { + struct fastrpc_ioctl_req_mmap map = {0}; + map.fd = fd; + map.flags = flags; + map.vaddrin = (uint64_t)vaddrin; + map.size = len; + ioErr = ioctl(dev, FASTRPC_IOCTL_MMAP, (unsigned long)&map); + *vaddrout = (uint64_t)map.vaddrout; + } break; + default: + FARF(ERROR, "ERROR: %s Invalid request passed %d", __func__, req); + ioErr = AEE_EBADPARM; + break; + } + return ioErr; +} + +int ioctl_munmap(int dev, int req, int attr, void *buf, int fd, int len, + uint64_t vaddr) { + int ioErr = AEE_SUCCESS; + + switch (req) { + case MEM_UNMAP: + case MUNMAP_FD: { + struct fastrpc_ioctl_mem_unmap unmap = {0}; + unmap.version = 0; + unmap.fd = fd; + unmap.vaddr = vaddr; + unmap.length = len; + ioErr = ioctl(dev, FASTRPC_IOCTL_MEM_UNMAP, (unsigned long)&unmap); + } break; + case MUNMAP: + case MUNMAP_64: { + struct fastrpc_ioctl_req_munmap unmap = {0}; + unmap.vaddrout = vaddr; + unmap.size = (ssize_t)len; + ioErr = ioctl(dev, FASTRPC_IOCTL_MUNMAP, (unsigned long)&unmap); + } break; + default: + FARF(ERROR, "ERROR: %s Invalid request passed %d", __func__, req); + break; + } + + return ioErr; +} + +int ioctl_getinfo(int dev, uint32_t *info) { + *info = 1; + return AEE_SUCCESS; +} + +int ioctl_getdspinfo(int dev, int domain, uint32_t attr, uint32_t *capability) { + int ioErr = AEE_SUCCESS; + static struct fastrpc_ioctl_capability cap = {0}; + + if (attr == PERF_V2_DRIVER_SUPPORT) { + *capability = 2; + return 0; + } + if (attr > PERF_V2_DRIVER_SUPPORT && attr < FASTRPC_MAX_ATTRIBUTES) { + *capability = 1; + return 0; + } + + cap.domain = domain; + cap.attribute_id = attr; + cap.capability = 0; + ioErr = ioctl(dev, FASTRPC_IOCTL_GET_DSP_INFO, &cap); + *capability = cap.capability; + return ioErr; +} + +int ioctl_setmode(int dev, int mode) { + return AEE_EUNSUPPORTED; +} + +int ioctl_control(int dev, int req, void *c) { + return AEE_EUNSUPPORTED; +} + +int ioctl_getperf(int dev, int key, void *data, int *datalen) { + return AEE_EUNSUPPORTED; +} + +int ioctl_signal_create(int dev, uint32_t signal, uint32_t flags) { + return AEE_EUNSUPPORTED; +} + +int ioctl_signal_destroy(int dev, uint32_t signal) { + return AEE_EUNSUPPORTED; +} + +int ioctl_signal_signal(int dev, uint32_t signal) { + return AEE_EUNSUPPORTED; +} + +int ioctl_signal_wait(int dev, uint32_t signal, uint32_t timeout_usec) { + return AEE_EUNSUPPORTED; +} + +int ioctl_signal_cancel_wait(int dev, uint32_t signal) { + return AEE_EUNSUPPORTED; +} + +int ioctl_sharedbuf(int dev, + struct fastrpc_proc_sharedbuf_info *sharedbuf_info) { + return AEE_EUNSUPPORTED; +} + +int ioctl_session_info(int dev, struct fastrpc_proc_sess_info *sess_info) { + return AEE_EUNSUPPORTED; +} + +int ioctl_optimization(int dev, uint32_t max_concurrency) { + return AEE_EUNSUPPORTED; +} diff --git a/src/fastrpc_latency.c b/src/fastrpc_latency.c new file mode 100644 index 0000000..becc26d --- /dev/null +++ b/src/fastrpc_latency.c @@ -0,0 +1,197 @@ +// 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 { + 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 { + 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; +} diff --git a/src/fastrpc_log.c b/src/fastrpc_log.c new file mode 100644 index 0000000..685cd18 --- /dev/null +++ b/src/fastrpc_log.c @@ -0,0 +1,346 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#include +#include +#include +#include +#include + +#include "AEEStdErr.h" +#include "fastrpc_config.h" +#include "HAP_farf_internal.h" +#include "fastrpc_common.h" +#include "fastrpc_trace.h" +#include "rpcmem.h" +#include "verify.h" + +#define PROPERTY_VALUE_MAX 72 +/* Create persist buffer of size 1 MB */ +#define DEBUG_BUF_SIZE 1024 * 1024 + +/* Prepend index, pid, tid, domain */ +#define PREPEND_DBGBUF_FARF_SIZE 30 + +/* trace to update start of persist buffer. */ +#define DEBUF_BUF_TRACE "frpc_dbgbuf:" + +#define IS_PERSIST_BUF_DATA(len, level) \ + ((len > 0) && (len < MAX_FARF_LEN) && (level == HAP_LEVEL_RPC_CRITICAL)) + +typedef struct persist_buffer { + /* Debug logs to be printed on dsp side */ + char *buf; + + /* Buffer index */ + unsigned int size; + + /* Lock to protect global logger buffer */ + pthread_mutex_t mut; +} persist_buffer; + +static persist_buffer persist_buf; +static uint32_t fastrpc_logmask; +static FILE *log_userspace_file_fd; // file descriptor to save userspace runtime + // farf logs + +void set_runtime_logmask(uint32_t mask) { fastrpc_logmask = mask; } + +#if defined(__LE_TVM__) || defined(__ANDROID__) +#include +extern const char *__progname; + +static inline int hap_2_android_log_level(int hap_level) { + switch (hap_level) { + case HAP_LEVEL_LOW: + case HAP_LEVEL_RPC_LOW: + case HAP_LEVEL_CRITICAL: + case HAP_LEVEL_RPC_CRITICAL: + return ANDROID_LOG_DEBUG; + case HAP_LEVEL_MEDIUM: + case HAP_LEVEL_HIGH: + case HAP_LEVEL_RPC_MEDIUM: + case HAP_LEVEL_RPC_HIGH: + return ANDROID_LOG_INFO; + case HAP_LEVEL_ERROR: + case HAP_LEVEL_RPC_ERROR: + return ANDROID_LOG_ERROR; + case HAP_LEVEL_FATAL: + case HAP_LEVEL_RPC_FATAL: + return ANDROID_LOG_FATAL; + } + return ANDROID_LOG_UNKNOWN; +} +#elif defined(USE_SYSLOG) +#include + +int hap_2_syslog_level(int log_type) { + switch (log_type) { + case HAP_LEVEL_LOW: + case HAP_LEVEL_RPC_LOW: + case HAP_LEVEL_RPC_CRITICAL: + case HAP_LEVEL_CRITICAL: + return LOG_DEBUG; + case HAP_LEVEL_MEDIUM: + case HAP_LEVEL_HIGH: + case HAP_LEVEL_RPC_MEDIUM: + case HAP_LEVEL_RPC_HIGH: + return LOG_INFO; + case HAP_LEVEL_ERROR: + case HAP_LEVEL_RPC_ERROR: + return LOG_ERR; + case HAP_LEVEL_FATAL: + case HAP_LEVEL_RPC_FATAL: + return LOG_CRIT; + } + return 0; +} +#endif + +static unsigned long long GetTime(void) { + struct timeval tv; + struct timezone tz; + + gettimeofday(&tv, &tz); + + /* Integer overflow check. */ + if (tv.tv_sec > (ULLONG_MAX - tv.tv_usec) / 1000000ULL) { + return 0; + } + return tv.tv_sec * 1000000ULL + tv.tv_usec; +} + +/* Function to append CRITICAL debug logs to persist_buf */ +static void print_dbgbuf_data(char *data, int size) { + int len = 0; + + pthread_mutex_lock(&persist_buf.mut); + if (persist_buf.buf) { + if (((persist_buf.size + PREPEND_DBGBUF_FARF_SIZE + size) > + DEBUG_BUF_SIZE)) { + persist_buf.size = strlen(DEBUF_BUF_TRACE) + 1; + } + len = snprintf(persist_buf.buf + persist_buf.size, + DEBUG_BUF_SIZE - persist_buf.size, "%llu:%d:%d:dom:%d: %s\n", + GetTime(), getpid(), gettid(), get_current_domain(), data); + persist_buf.size += (len + 1); + } + pthread_mutex_unlock(&persist_buf.mut); +} + +void HAP_debug_v2(int level, const char *file, int line, const char *format, + ...) { + char *buf = NULL; + int len = 0; + va_list argp; + + buf = (char *)malloc(sizeof(char) * MAX_FARF_LEN); + if (buf == NULL) { + return; + } + va_start(argp, format); + len = vsnprintf(buf, MAX_FARF_LEN, format, argp); + va_end(argp); + /* If level is set to HAP_LEVEL_DEBUG append the farf message to persist + * buffer. */ + if (persist_buf.buf && IS_PERSIST_BUF_DATA(len, level)) { + print_dbgbuf_data(buf, len); + } + HAP_debug(buf, level, file, line); + if (buf) { + free(buf); + buf = NULL; + } +} + +void HAP_debug_runtime(int level, const char *file, int line, + const char *format, ...) { + int len = 0; + va_list argp; + char *buf = NULL, *log = NULL; + + /* + * Adding logs to persist buffer when level is set to + * RUNTIME_RPC_CRITICAL and fastrpc_log mask is disabled. + */ + if (((1 << level) & (fastrpc_logmask)) || + ((level == HAP_LEVEL_RPC_CRITICAL) && persist_buf.buf) || + log_userspace_file_fd != NULL) { + buf = (char *)malloc(sizeof(char) * MAX_FARF_LEN); + if (buf == NULL) { + return; + } + va_start(argp, format); + len = vsnprintf(buf, MAX_FARF_LEN, format, argp); + va_end(argp); + log = (char *)malloc(sizeof(char) * MAX_FARF_LEN); + if (log == NULL) { + return; + } + snprintf(log, MAX_FARF_LEN, "%d:%d:%s:%s:%d: %s", getpid(), gettid(), + __progname, file, line, buf); + } + + print_dbgbuf_data(log, len); + if (((1 << level) & (fastrpc_logmask))) { + if (log_userspace_file_fd != NULL) { + fputs(log, log_userspace_file_fd); + fputs("\n", log_userspace_file_fd); + } + HAP_debug(buf, level, file, line); + } + if (buf) { + free(buf); + } + if (log) { + free(log); + } +} + +#ifdef __LE_TVM__ +static char android_log_level_to_char(int level) { + char log_level; + + switch (level) { + case ANDROID_LOG_DEBUG: + case ANDROID_LOG_DEFAULT: + log_level = 'D'; + break; + case ANDROID_LOG_INFO: + log_level = 'I'; + break; + case ANDROID_LOG_WARN: + log_level = 'W'; + break; + case ANDROID_LOG_ERROR: + log_level = 'E'; + break; + case ANDROID_LOG_FATAL: + log_level = 'F'; + break; + default: + log_level = 'D'; + } + + return log_level; +} + +static char *get_filename(const char *str, const char delim) { + char *iter = NULL, *token = str; + + for (iter = str; *iter != '\0'; iter++) { + if (*iter == delim) + token = iter + 1; + } + return token; +} + +int get_newlines(const char *str) { + char *iter = NULL; + int newlines = 0; + + for (iter = str; *iter != '\0'; iter++) { + if (*iter == '\n') + newlines++; + } + return newlines; +} +#endif + +void HAP_debug(const char *msg, int level, const char *filename, int line) { +#ifdef __ANDROID__ + __android_log_print(hap_2_android_log_level(level), __progname, "%s:%d: %s", + filename, line, msg); +#elif defined(USE_SYSLOG) + syslog(hap_2_syslog_level(level), "%s:%d: %s", filename, line, msg); +#elif defined(__LE_TVM__) + const char delim = '/'; + char *short_filename = NULL; + int newlines = 0; + + short_filename = get_filename(filename, delim); + newlines = get_newlines(msg); + level = hap_2_android_log_level(level); + if (newlines) + printf("ADSPRPC: %d %d %c %s: %s:%d: %s", getpid(), gettid(), + android_log_level_to_char(level), __progname, short_filename, line, + msg); + else + printf("ADSPRPC: %d %d %c %s: %s:%d: %s\n", getpid(), gettid(), + android_log_level_to_char(level), __progname, short_filename, line, + msg); + fflush(stdout); +#endif +} + +void fastrpc_log_init() { + bool debug_build_type = false; + int nErr = AEE_SUCCESS, fd = -1; + char build_type[PROPERTY_VALUE_MAX]; + char *logfilename; + + pthread_mutex_init(&persist_buf.mut, 0); + pthread_mutex_lock(&persist_buf.mut); + /* + * Get build type by reading the target properties, + * if buuid type is eng or userdebug allocate 1 MB persist buf. + */ + if (fastrpc_get_property_string(FASTRPC_BUILD_TYPE, build_type, NULL)) { +#if !defined(LE_ENABLE) + if (!strncmp(build_type, "eng", PROPERTY_VALUE_MAX) || + !strncmp(build_type, "userdebug", PROPERTY_VALUE_MAX)) + debug_build_type = true; +#else + if (atoi(build_type)) + debug_build_type = true; +#endif + } + if (persist_buf.buf == NULL && debug_build_type) { + /* Create a debug buffer to append DEBUG FARF level message. */ + persist_buf.buf = (char *)rpcmem_alloc( + RPCMEM_HEAP_ID_SYSTEM, RPCMEM_DEFAULT_FLAGS | RPCMEM_TRY_MAP_STATIC, + DEBUG_BUF_SIZE * sizeof(char)); + if (persist_buf.buf) { + fd = rpcmem_to_fd(persist_buf.buf); + FARF(RUNTIME_RPC_HIGH, "%s: persist_buf.buf created %d size %d", __func__, + fd, DEBUG_BUF_SIZE); + /* Appending header to persist buffer, to identify the start address + * through script. */ + std_strlcpy(persist_buf.buf, DEBUF_BUF_TRACE, DEBUG_BUF_SIZE); + persist_buf.size = strlen(DEBUF_BUF_TRACE) + 1; + } else { + nErr = AEE_ENORPCMEMORY; + FARF(ERROR, "Error 0x%x: %s allocation failed for persist_buf of size %d", + nErr, __func__, DEBUG_BUF_SIZE); + } + } + pthread_mutex_unlock(&persist_buf.mut); + logfilename = fastrpc_config_get_userspace_runtime_farf_file(); + if (logfilename) { + log_userspace_file_fd = fopen(logfilename, "w"); + if (log_userspace_file_fd == NULL) { + VERIFY_EPRINTF("Error 0x%x: %s failed to collect userspace runtime farf " + "logs into file %s with errno %s\n", + nErr, __func__, logfilename, strerror(errno)); + } else { + FARF(RUNTIME_RPC_HIGH, "%s done\n", __func__); + } + } +} + +void fastrpc_log_deinit() { + + pthread_mutex_lock(&persist_buf.mut); + if (persist_buf.buf) { + rpcmem_free(persist_buf.buf); + persist_buf.buf = NULL; + } + pthread_mutex_unlock(&persist_buf.mut); + if (log_userspace_file_fd) { + fclose(log_userspace_file_fd); + log_userspace_file_fd = NULL; + } + pthread_mutex_destroy(&persist_buf.mut); +} diff --git a/src/fastrpc_mem.c b/src/fastrpc_mem.c new file mode 100644 index 0000000..e247b8b --- /dev/null +++ b/src/fastrpc_mem.c @@ -0,0 +1,1011 @@ +// 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 +//#ifndef VERIFY_PRINT_INFO +//#define VERIFY_PRINT_INFO +//#endif // VERIFY_PRINT_INFO + +#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 + +#define FARF_ERROR 1 + +#include "AEEQList.h" +#include "AEEStdErr.h" +#include "AEEstd.h" +#include "HAP_farf.h" +#include "fastrpc_common.h" +#include "fastrpc_internal.h" +#include "fastrpc_mem.h" +#include "rpcmem.h" +#include "shared.h" +#include "verify.h" + +#ifdef LE_ENABLE +#define PROPERTY_VALUE_MAX \ + 92 // as this macro is defined in cutils for Android platforms, defined + // explicitly for LE platform +#elif (defined _ANDROID) || (defined ANDROID) +// TODO: Bharath #include "cutils/properties.h" +#define PROPERTY_VALUE_MAX 92 +#else +#define PROPERTY_VALUE_MAX 92 +#endif + +#ifndef _WIN32 +#include +#include +#include +#include +#endif // __WIN32 + +#ifndef INT_MAX +#define INT_MAX (int)(-1) +#endif + +#define INVALID_DOMAIN_ID -1 +#define INVALID_HANDLE (remote_handle64)(-1) +#define INVALID_KEY (pthread_key_t)(-1) + +#define MAX_DMA_HANDLES 256 + +// Mask for Map control flags +#define FASTRPC_MAP_FLAGS_MASK (0xFFFF) + +struct mem_to_fd { + QNode qn; + void *buf; + size_t size; + int fd; + int nova; + int attr; + int refcount; + bool mapped[NUM_DOMAINS_EXTEND]; //! Buffer persistent mapping status +}; + +struct mem_to_fd_list { + QList ql; + pthread_mutex_t mut; +}; + +struct dma_handle_info { + int fd; + int len; + int used; + uint32_t attr; +}; + +/** + * List to maintain static mappings of a fastrpc session. + * Access to the list is protected with mutex. + */ +struct static_map { + QNode qn; + struct fastrpc_mem_map map; + int refs; +}; + +struct static_map_list { + QList ql; + pthread_mutex_t mut; +}; + +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]; +static int dma_handle_count = 0; + +static int fastrpc_unmap_fd(void *buf, size_t size, int fd, int attr); +static __inline void try_map_buffer(struct mem_to_fd *tofd); +static __inline int try_unmap_buffer(struct mem_to_fd *tofd); + +int fastrpc_mem_init(void) { + int ii; + + pthread_mutex_init(&fdlist.mut, 0); + QList_Ctor(&fdlist.ql); + std_memset(dhandles, 0, sizeof(dhandles)); + for (ii = 0; ii < NUM_DOMAINS_EXTEND; ii++) { + QList_Ctor(&smaplst[ii].ql); + pthread_mutex_init(&smaplst[ii].mut, 0); + } + return 0; +} + +int fastrpc_mem_deinit(void) { + int ii; + + pthread_mutex_destroy(&fdlist.mut); + for (ii = 0; ii < NUM_DOMAINS_EXTEND; ii++) { + pthread_mutex_destroy(&smaplst[ii].mut); + } + return 0; +} + +static void *remote_register_fd_attr(int fd, size_t size, int attr) { + int nErr = AEE_SUCCESS; + void *po = NULL; + void *buf = (void *)-1; + struct mem_to_fd *tofd = 0; + + VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); + VERIFYC(fd >= 0, AEE_EBADPARM); + + VERIFYC(NULL != (tofd = calloc(1, sizeof(*tofd))), AEE_ENOMEMORY); + QNode_CtorZ(&tofd->qn); + VERIFYM((void *)-1 != (buf = mmap(0, size, PROT_NONE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)), + AEE_ERPC, "Error %x: mmap failed for fd %x, size %x\n", nErr, fd, + size); + tofd->buf = buf; + tofd->size = size; + tofd->fd = fd; + tofd->nova = 1; + tofd->attr = attr; + + pthread_mutex_lock(&fdlist.mut); + QList_AppendNode(&fdlist.ql, &tofd->qn); + pthread_mutex_unlock(&fdlist.mut); + + tofd = 0; + po = buf; + buf = (void *)-1; +bail: + if (buf != (void *)-1) + munmap(buf, size); + if (tofd) { + free(tofd); + tofd = NULL; + } + if (nErr != AEE_SUCCESS) { + if (0 == check_rpc_error(nErr)) { + FARF(ERROR, "Error 0x%x: remote register fd fails for fd %d, size %zu\n", + nErr, fd, size); + } + } + return po; +} + +void *remote_register_fd(int fd, int size) { + if (size < 0) { + FARF(ERROR, "Error: %s failed for invalid size %d", __func__, size); + return NULL; + } + return remote_register_fd_attr(fd, size, 0); +} + +void *remote_register_fd2(int fd, size_t size) { + return remote_register_fd_attr(fd, size, 0); +} + +static int remote_register_buf_common(void *buf, size_t size, int fd, + int attr) { + int nErr = 0; + + VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); + + VERIFYC(NULL != buf, AEE_EBADPARM); + VERIFYC(size != 0, AEE_EBADPARM); + + if (fd != -1) { + struct mem_to_fd *tofd; + int fdfound = 0; + QNode *pn, *pnn; + + pthread_mutex_lock(&fdlist.mut); + QLIST_NEXTSAFE_FOR_ALL(&fdlist.ql, pn, pnn) { + tofd = STD_RECOVER_REC(struct mem_to_fd, qn, pn); + if (tofd->buf == buf && tofd->size == size && tofd->fd == fd) { + fdfound = 1; + if (attr) + tofd->attr = attr; + tofd->refcount++; + break; + } + } + pthread_mutex_unlock(&fdlist.mut); + if (!fdfound) { + VERIFYC(NULL != (tofd = calloc(1, sizeof(*tofd))), AEE_ENOMEMORY); + QNode_CtorZ(&tofd->qn); + tofd->buf = buf; + tofd->size = size; + tofd->fd = fd; + if (attr) + tofd->attr = attr; + tofd->refcount++; + if (tofd->attr & FASTRPC_ATTR_TRY_MAP_STATIC) { + try_map_buffer(tofd); + } + pthread_mutex_lock(&fdlist.mut); + QList_AppendNode(&fdlist.ql, &tofd->qn); + pthread_mutex_unlock(&fdlist.mut); + } + } else { + QNode *pn, *pnn; + struct mem_to_fd *freefd = NULL; + pthread_mutex_lock(&fdlist.mut); + struct mem_to_fd *addr_match_fd = NULL; + QLIST_NEXTSAFE_FOR_ALL(&fdlist.ql, pn, pnn) { + struct mem_to_fd *tofd = STD_RECOVER_REC(struct mem_to_fd, qn, pn); + if (tofd->buf == buf) { + if (tofd->size == size) { + tofd->refcount--; + if (tofd->refcount <= 0) { + QNode_DequeueZ(&tofd->qn); + freefd = tofd; + tofd = NULL; + } + break; + } else { + addr_match_fd = tofd; + } + } + } + pthread_mutex_unlock(&fdlist.mut); + if (freefd) { + if (freefd->attr & FASTRPC_ATTR_KEEP_MAP) { + fastrpc_unmap_fd(freefd->buf, freefd->size, freefd->fd, freefd->attr); + } + if (freefd->attr & FASTRPC_ATTR_TRY_MAP_STATIC) { + try_unmap_buffer(freefd); + } + if (freefd->nova) { + munmap(freefd->buf, freefd->size); + } + free(freefd); + freefd = NULL; + } else if (addr_match_fd) { + /** + * When buf deregister size mismatch with register size, deregister buf + * fails leaving stale fd in fdlist. Bad fd can be attached to other + * shared buffers in next invoke calls. + */ + FARF(ERROR, + "FATAL: Size mismatch between deregister buf (%p) size (%zu) and " + "registered buf size (%zu) fd %d, bad fd can be attached to other " + "shared buffers. Use same buffer size as registered buffer", + buf, size, addr_match_fd->size, addr_match_fd->fd); + raise(SIGABRT); + } + } +bail: + if (nErr != AEE_SUCCESS) { + if (0 == check_rpc_error(nErr)) { + FARF(ERROR, + "Error 0x%x: remote_register_buf failed buf %p, size %zu, fd 0x%x", + nErr, buf, size, fd); + } + } + return nErr; +} + +void remote_register_buf(void *buf, int size, int fd) { + remote_register_buf_common(buf, (size_t)size, fd, 0); +} + +void remote_register_buf_attr(void *buf, int size, int fd, int attr) { + remote_register_buf_common(buf, (size_t)size, fd, attr); +} + +void remote_register_buf_attr2(void *buf, size_t size, int fd, int attr) { + remote_register_buf_common(buf, size, fd, attr); +} + +int remote_register_dma_handle_attr(int fd, uint32_t len, uint32_t attr) { + int nErr = AEE_SUCCESS, i; + int fd_found = 0; + + VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); + + if (attr && attr != FASTRPC_ATTR_NOMAP) { + FARF(ERROR, "Error: %s failed, unsupported attribute 0x%x", __func__, attr); + return AEE_EBADPARM; + } + VERIFYC(fd >= 0, AEE_EBADPARM); + VERIFYC(len >= 0, AEE_EBADPARM); + + pthread_mutex_lock(&fdlist.mut); + for (i = 0; i < dma_handle_count; i++) { + if (dhandles[i].used && dhandles[i].fd == fd) { + /* If fd already present in handle list, then just update attribute only + * if its zero */ + if (!dhandles[i].attr) { + dhandles[i].attr = attr; + } + fd_found = 1; + dhandles[i].used++; + break; + } + } + pthread_mutex_unlock(&fdlist.mut); + + if (fd_found) { + return AEE_SUCCESS; + } + + pthread_mutex_lock(&fdlist.mut); + for (i = 0; i < dma_handle_count; i++) { + if (!dhandles[i].used) { + dhandles[i].fd = fd; + dhandles[i].len = len; + dhandles[i].used = 1; + dhandles[i].attr = attr; + break; + } + } + if (i == dma_handle_count) { + if (dma_handle_count >= MAX_DMA_HANDLES) { + FARF(ERROR, "Error: %s: DMA handle list is already full (count %d)", + __func__, dma_handle_count); + nErr = AEE_EINVHANDLE; + } else { + dhandles[dma_handle_count].fd = fd; + dhandles[dma_handle_count].len = len; + dhandles[dma_handle_count].used = 1; + dhandles[dma_handle_count].attr = attr; + dma_handle_count++; + } + } + pthread_mutex_unlock(&fdlist.mut); + +bail: + if (nErr) { + if (0 == check_rpc_error(nErr)) { + FARF(ERROR, "Error 0x%x: %s failed for fd 0x%x, len %d, attr 0x%x", nErr, + __func__, fd, len, attr); + } + } + return nErr; +} + +int remote_register_dma_handle(int fd, uint32_t len) { + return remote_register_dma_handle_attr(fd, len, 0); +} + +void unregister_dma_handle(int fd, uint32_t *len, uint32_t *attr) { + int i, last_used = 0; + + *len = 0; + *attr = 0; + + pthread_mutex_lock(&fdlist.mut); + for (i = 0; i < dma_handle_count; i++) { + if (dhandles[i].used) { + if (dhandles[i].fd == fd) { + dhandles[i].used--; + *len = dhandles[i].len; + *attr = dhandles[i].attr; + if (i == (dma_handle_count - 1) && !dhandles[i].used) { + dma_handle_count = last_used + 1; + } + break; + } else { + last_used = i; + } + } + } + pthread_mutex_unlock(&fdlist.mut); +} + +int fdlist_fd_from_buf(void *buf, int bufLen, int *nova, void **base, int *attr, + int *ofd) { + QNode *pn; + int fd = -1; + pthread_mutex_lock(&fdlist.mut); + QLIST_FOR_ALL(&fdlist.ql, pn) { + if (fd != -1) { + break; + } else { + struct mem_to_fd *tofd = STD_RECOVER_REC(struct mem_to_fd, qn, pn); + if (STD_BETWEEN(buf, tofd->buf, (unsigned long)tofd->buf + tofd->size)) { + if (STD_BETWEEN((unsigned long)buf + bufLen - 1, tofd->buf, + (unsigned long)tofd->buf + tofd->size)) { + fd = tofd->fd; + *nova = tofd->nova; + *base = tofd->buf; + *attr = tofd->attr; + } else { + pthread_mutex_unlock(&fdlist.mut); + FARF(ERROR, + "Error 0x%x: Mismatch in buffer address(%p) or size(%x) to the " + "registered FD(0x%x), address(%p) and size(%zu)\n", + AEE_EBADPARM, buf, bufLen, tofd->fd, tofd->buf, tofd->size); + return AEE_EBADPARM; + } + } + } + } + *ofd = fd; + pthread_mutex_unlock(&fdlist.mut); + return 0; +} + +int fastrpc_mmap(int domain, int fd, void *vaddr, int offset, size_t length, + enum fastrpc_map_flags flags) { + struct fastrpc_map map = {0}; + int nErr = 0, dev = -1, iocErr = 0, attrs = 0, ref = 0; + uint64_t vaddrout = 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) { + PRINT_WARN_USE_DOMAINS(); + domain = get_current_domain(); + } + VERIFYC((domain >= 0) && (domain < NUM_DOMAINS_EXTEND), 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) { + tNode = STD_RECOVER_REC(struct static_map, qn, pn); + if (tNode->map.fd == fd) { + break; + } + } + pthread_mutex_unlock(&smaplst[domain].mut); + + // Raise error if map found already + if (tNode) { + VERIFYM(tNode->map.fd != fd, AEE_EALREADY, "Error: Map already present."); + } + + // map not found, allocate memory for adding to static map list. + VERIFYC(NULL != (mNode = calloc(1, sizeof(*mNode))), AEE_ENOMEMORY); + + // Map buffer to DSP process and return limited errors to user + map.version = 0; + map.m.fd = fd; + map.m.offset = offset; + map.m.flags = flags; + map.m.vaddrin = (uintptr_t)vaddr; + map.m.length = (size_t)length; + map.m.attrs = attrs; + map.m.vaddrout = 0; + mNode->map = map.m; + iocErr = ioctl_mmap(dev, MEM_MAP, flags, attrs, fd, offset, length, + (uint64_t)vaddr, &vaddrout); + if (!iocErr) { + 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); + mNode = NULL; + } else if (errno == ENOTTY || + iocErr == (int)(DSP_AEE_EOFFSET | AEE_EUNSUPPORTED)) { + nErr = AEE_EUNSUPPORTED; + goto bail; + } else { + nErr = AEE_EFAILED; + goto bail; + } +bail: + 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, " + "domain %d, flags 0x%x, ioctl ret 0x%x, errno %s", + nErr, __func__, fd, vaddr, length, domain, flags, iocErr, + strerror(errno)); + } + if (mNode) { + free(mNode); + mNode = NULL; + } + 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; + QNode *pn, *pnn; + + VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); + + FARF(RUNTIME_RPC_HIGH, "%s: domain %d fd %d vaddr %p length 0x%zx", __func__, + domain, fd, vaddr, length); + if (domain == -1) { + PRINT_WARN_USE_DOMAINS(); + domain = get_current_domain(); + } + VERIFYC(fd >= 0 && (domain >= 0) && (domain < NUM_DOMAINS_EXTEND), + AEE_EBADPARM); + FASTRPC_GET_REF(domain); + VERIFY(AEE_SUCCESS == (nErr = fastrpc_session_dev(domain, &dev))); + /** + * Search for mapping in current static map list using only file descriptor. + * Virtual address and length can be used for precise find with additional + * flags in future. + */ + 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.fd == fd) { + FARF(RUNTIME_RPC_HIGH, "%s: unmap found for fd %d domain %d", __func__, + fd, domain); + break; + } + } + VERIFYC(mNode && mNode->map.fd == fd, AEE_ENOSUCHMAP); + if (mNode->refs > 1) { + FARF(ERROR, "%s: Attempt to unmap FD %d with %d outstanding references", + __func__, fd, 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, 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 fd %d, vaddr %p, length 0x%zx, domain %d, " + "ioctl ret 0x%x, errno %s", + nErr, __func__, fd, vaddr, 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; + int dev = -1, ref = 0; + uint64_t vaddrout = 0; + + 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); + + VERIFYC(fd >= 0, AEE_EBADPARM); + VERIFYC(size >= 0, AEE_EBADPARM); + VERIFYC(flags >= 0 && flags < REMOTE_MAP_MAX_FLAG && raddr != NULL, + AEE_EBADPARM); + if (domain == -1) { + PRINT_WARN_USE_DOMAINS(); + domain = get_current_domain(); + } + VERIFYC((domain >= 0) && (domain < NUM_DOMAINS_EXTEND), AEE_EBADPARM); + + FASTRPC_GET_REF(domain); + VERIFY(AEE_SUCCESS == (nErr = fastrpc_session_dev(domain, &dev))); + + nErr = ioctl_mmap(dev, MMAP_64, flags, 0, fd, 0, size, vaddr, &vaddrout); + *raddr = vaddrout; +bail: + FASTRPC_PUT_REF(domain); + if (nErr) { + 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", + nErr, __func__, fd, vaddr, size, domain, flags, strerror(errno)); + } + } + return nErr; +} + +int remote_mem_unmap(int domain, uint64_t raddr, size_t size) { + int nErr = 0, dev = -1, ref = 0; + + VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); + + 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); + if (domain == -1) { + PRINT_WARN_USE_DOMAINS(); + domain = get_current_domain(); + } + VERIFYC((domain >= 0) && (domain < NUM_DOMAINS_EXTEND), AEE_EBADPARM); + + FASTRPC_GET_REF(domain); + VERIFY(AEE_SUCCESS == (nErr = fastrpc_session_dev(domain, &dev))); + + nErr = ioctl_munmap(dev, MUNMAP_64, 0, 0, -1, size, raddr); +bail: + FASTRPC_PUT_REF(domain); + if (nErr) { + 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", + nErr, __func__, raddr, size, domain, strerror(errno)); + } + } + return nErr; +} + +int remote_mmap64_internal(int fd, uint32_t flags, uint64_t vaddrin, + int64_t size, uint64_t *vaddrout) { + int dev, domain = DEFAULT_DOMAIN_ID, nErr = AEE_SUCCESS, ref = 0; + uint64_t vaout = 0; + + VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); + + domain = get_current_domain(); + VERIFYC((domain >= 0) && (domain < NUM_DOMAINS_EXTEND), AEE_EBADDOMAIN); + 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); + *vaddrout = vaout; +bail: + FASTRPC_PUT_REF(domain); + 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", + nErr, __func__, fd, size, flags, vaddrin, strerror(errno)); + } + return nErr; +} + +int remote_mmap64(int fd, uint32_t flags, uint64_t vaddrin, int64_t size, + uint64_t *vaddrout) { + int nErr = AEE_SUCCESS, log = 1; + + VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); + + PRINT_WARN_USE_DOMAINS(); + if (flags != 0) { + nErr = AEE_EBADPARM; + goto bail; + } + VERIFYC(size >= 0, AEE_EBADPARM); + VERIFYC(fd >= 0, AEE_EBADPARM); + VERIFYC(NULL != vaddrout, AEE_EBADPARM); + nErr = remote_mmap64_internal(fd, flags, vaddrin, size, vaddrout); + if (nErr == AEE_EBADDOMAIN) + nErr = AEE_ERPC; // override error code for user + log = 0; // so that we wont print error message twice +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", + nErr, __func__, fd, size, flags, vaddrin); + } + return nErr; +} + +int remote_mmap(int fd, uint32_t flags, uint32_t vaddrin, int size, + uint32_t *vaddrout) { + uint64_t vaddrout_64 = 0; + int nErr = 0; + + VERIFYC(NULL != vaddrout, AEE_EBADPARM); + nErr = + remote_mmap64(fd, flags, (uintptr_t)vaddrin, (int64_t)size, &vaddrout_64); + *vaddrout = (uint32_t)vaddrout_64; +bail: + return nErr; +} + +int remote_munmap64(uint64_t vaddrout, int64_t size) { + int dev, domain = DEFAULT_DOMAIN_ID, nErr = AEE_SUCCESS, ref = 0; + + VERIFY(AEE_SUCCESS == (nErr = fastrpc_init_once())); + + domain = get_current_domain(); + VERIFYC((domain >= 0) && (domain < NUM_DOMAINS_EXTEND), AEE_ERPC); + + /* 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); +bail: + FASTRPC_PUT_REF(domain); + 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)); + } + return nErr; +} + +int remote_munmap(uint32_t vaddrout, int size) { + PRINT_WARN_USE_DOMAINS(); + return remote_munmap64((uintptr_t)vaddrout, (int64_t)size); +} + +static int fastrpc_unmap_fd(void *buf, size_t size, int fd, int attr) { + int nErr = 0; + int ii, dev = -1; + + for (ii = 0; ii < NUM_DOMAINS_EXTEND; ii++) { + nErr = fastrpc_session_get(ii); + if(!nErr) + continue; + nErr = fastrpc_session_dev(ii, &dev); + if(!nErr) { + fastrpc_session_put(ii); + continue; + } + nErr = ioctl_munmap(dev, MUNMAP_FD, attr, buf, fd, size, 0); + if (nErr) + FARF(RUNTIME_RPC_LOW, + "unmap_fd: device found %d for domain %d returned %d", dev, ii, + nErr); + fastrpc_session_put(ii); + } + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed for size %zu fd %d errno %s\n", nErr, + __func__, size, fd, strerror(errno)); + } + return nErr; +} + +/** + * Map buffer on all domains with open remote session + * + * Args: + * @tofd : Data structure of the buffer to map + * + * Returns : None + */ +static __inline void try_map_buffer(struct mem_to_fd *tofd) { + int nErr = 0, domain = 0, errcnt = 0; + + FARF(RUNTIME_RPC_HIGH, "%s: fd %d", __func__, tofd->fd); + + /** + * Tries to create static mapping on remote process of all open sessions. + * Ignore errors in case of failure + */ + for (domain = 0; domain < NUM_DOMAINS_EXTEND; domain++) { + nErr = fastrpc_mmap(domain, tofd->fd, tofd->buf, 0, tofd->size, + FASTRPC_MAP_STATIC); + if (!nErr) { + tofd->mapped[domain] = true; + } else { + errcnt++; + } + } + if (errcnt) { + FARF(ERROR, "Error 0x%x: %s failed for fd %d buf %p size 0x%zx errcnt %d", + nErr, __func__, tofd->fd, tofd->buf, tofd->size, errcnt); + } +} + +/** + * Unmap buffer on all domains with open remote session + * + * Args: + * @tofd : Data structure of the buffer to map + * + * Returns : None + */ +static __inline int try_unmap_buffer(struct mem_to_fd *tofd) { + int nErr = 0, domain = 0, errcnt = 0; + + FARF(RUNTIME_RPC_HIGH, "%s: fd %d", __func__, tofd->fd); + + /* Remove static mapping of a buffer for all domains */ + for (domain = 0; domain < NUM_DOMAINS_EXTEND; domain++) { + if (tofd->mapped[domain] == false) { + continue; + } + nErr = fastrpc_munmap(domain, tofd->fd, tofd->buf, tofd->size); + if (!nErr) { + tofd->mapped[domain] = false; + } else { + errcnt++; + //@TODO: Better way to handle error? probably prevent same FD getting + //re-used with FastRPC library. + } + } + if (errcnt) { + FARF(ERROR, "Error 0x%x: %s failed for fd %d buf %p size 0x%zx errcnt %d", + nErr, __func__, tofd->fd, tofd->buf, tofd->size, errcnt); + } + return errcnt; +} + +int fastrpc_mem_open(int domain) { + int nErr = 0; + QNode *pn, *pnn; + struct mem_to_fd *tofd = NULL; + + /** + * Initialize fastrpc session specific informaiton of the fastrpc_mem module + */ + FARF(RUNTIME_RPC_HIGH, "%s for domain %d", __func__, domain); + VERIFYC((domain >= 0) && (domain < NUM_DOMAINS_EXTEND), AEE_EBADPARM); + + /* Map buffers with TRY_MAP_STATIC attribute that were allocated + * and registered before a session was opened on a given domain. + */ + pthread_mutex_lock(&fdlist.mut); + QLIST_NEXTSAFE_FOR_ALL(&fdlist.ql, pn, pnn) { + tofd = STD_RECOVER_REC(struct mem_to_fd, qn, pn); + if (tofd->attr & FASTRPC_ATTR_TRY_MAP_STATIC && + tofd->mapped[domain] == false) { + nErr = fastrpc_mmap(domain, tofd->fd, tofd->buf, 0, tofd->size, + FASTRPC_MAP_STATIC); + if (!nErr) { + tofd->mapped[domain] = true; + } + } + } + nErr = 0; // Try mapping is optional. Ignore error + pthread_mutex_unlock(&fdlist.mut); +bail: + if (nErr) { + FARF(ERROR, "Error 0x%x: %s failed for domain %d", nErr, __func__, domain); + } + return nErr; +} + +int fastrpc_mem_close(int domain) { + int nErr = 0; + struct static_map *mNode; + struct mem_to_fd *tofd = NULL; + QNode *pn, *pnn; + + FARF(RUNTIME_RPC_HIGH, "%s for domain %d", __func__, domain); + VERIFYC((domain >= 0) && (domain < NUM_DOMAINS_EXTEND), AEE_EBADPARM); + + /** + * Destroy fastrpc session specific information of the fastrpc_mem module. + * Remove all static mappings of a session + */ + pthread_mutex_lock(&smaplst[domain].mut); + do { + mNode = NULL; + QLIST_NEXTSAFE_FOR_ALL(&smaplst[domain].ql, pn, pnn) { + mNode = STD_RECOVER_REC(struct static_map, qn, pn); + QNode_DequeueZ(&mNode->qn); + free(mNode); + mNode = NULL; + } + } while (mNode); + pthread_mutex_unlock(&smaplst[domain].mut); + + // Remove mapping status of static buffers + pthread_mutex_lock(&fdlist.mut); + QLIST_NEXTSAFE_FOR_ALL(&fdlist.ql, pn, pnn) { + tofd = STD_RECOVER_REC(struct mem_to_fd, qn, pn); + /* This function is called only when remote session is being closed. + * So no need to do "fastrpc_munmap" here. + */ + if (tofd->mapped[domain]) { + tofd->mapped[domain] = false; + } + } + pthread_mutex_unlock(&fdlist.mut); +bail: + return nErr; +} + +int fastrpc_buffer_ref(int domain, int fd, int ref, void **va, size_t *size) { + + int nErr = 0; + struct static_map *map = NULL; + QNode *pn, *pnn; + + if ((domain < 0) || (domain >= NUM_DOMAINS_EXTEND)) { + FARF(ERROR, "%s: invalid domain %d", __func__, domain); + return AEE_EBADPARM; + } + pthread_mutex_lock(&smaplst[domain].mut); + + // Find buffer in the domain's static mapping list + QLIST_NEXTSAFE_FOR_ALL(&smaplst[domain].ql, pn, pnn) { + struct static_map *m = STD_RECOVER_REC(struct static_map, qn, pn); + if (m->map.fd == fd) { + map = m; + break; + } + } + VERIFYC(map != NULL, AEE_ENOSUCHMAP); + VERIFYC(map->refs > 0, AEE_ERPC); + + // Populate output + if (va) { + *va = (void *)map->map.vaddrin; + } + if (size) { + *size = map->map.length; + } + + // Handle refcount + if (ref == 1) { + map->refs++; + } else if (ref == -1) { + if (map->refs == 1) { + FARF(ERROR, + "%s: Attempting to remove last reference to buffer %d on domain %d", + __func__, fd, domain); + nErr = AEE_EBADPARM; + goto bail; + } + map->refs--; + } else { + VERIFYC(ref == 0, AEE_ERPC); + } + +bail: + pthread_mutex_unlock(&smaplst[domain].mut); + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed (domain %d, fd %d, ref %d)", nErr, + __func__, domain, fd, ref); + } + return nErr; +} diff --git a/src/fastrpc_notif.c b/src/fastrpc_notif.c new file mode 100644 index 0000000..18e8118 --- /dev/null +++ b/src/fastrpc_notif.c @@ -0,0 +1,242 @@ +// 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_common.h" +#include "fastrpc_notif.h" +#include "platform_libs.h" +#include "verify.h" + +struct notif_config { + pthread_t thread; + int init_done; + int deinit_started; +}; + +// Fastrpc client notification request node to be queued to +struct fastrpc_notif { + QNode qn; + remote_rpc_notif_register_t notif; +}; + +struct other_handle_list { // For non-domain and reverse handle list + QList ql; +}; + +/* Mutex to protect notif_list */ +static pthread_mutex_t update_notif_list_mut; +static struct notif_config lnotifinfo[NUM_DOMAINS_EXTEND]; +/* List of all clients who registered for process status notification */ +static struct other_handle_list notif_list; + +void fastrpc_cleanup_notif_list(); + +static void *notif_fastrpc_thread(void *arg) { + struct notif_config *me = (struct notif_config *)arg; + int nErr = AEE_SUCCESS, domain = (int)(me - &lnotifinfo[0]); + + do { + nErr = get_remote_notif_response(domain); + if (nErr) + goto bail; + } while (1); +bail: + dlerror(); + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error 0x%x: %s FastRPC notification worker thread exited " + "for domain %d (errno %s), notif_domain_deinit started %d", + nErr, __func__, domain, strerror(errno), me->deinit_started); + } + return (void *)(uintptr_t)nErr; +} + +/* This function gets called in the thread context when thread has been + * interrupted with SIGUSR1 */ +void notif_thread_exit_handler(int sig) { + FARF(ALWAYS, "Notification FastRPC worker thread exiting with signal %d\n", + sig); + pthread_exit(0); +} + +void fastrpc_notif_init() { + QList_Ctor(¬if_list.ql); + pthread_mutex_init(&update_notif_list_mut, 0); +} + +void fastrpc_notif_deinit() { + fastrpc_cleanup_notif_list(); + pthread_mutex_destroy(&update_notif_list_mut); +} + +void fastrpc_notif_domain_deinit(int domain) { + struct notif_config *me = &lnotifinfo[domain]; + int err = 0; + + if (me->thread) { + FARF(ALWAYS, "%s: Waiting for FastRPC notification worker thread to join", + __func__); + me->deinit_started = 1; + err = fastrpc_exit_notif_thread(domain); + if (err) { + pthread_kill(me->thread, SIGUSR1); + } + pthread_join(me->thread, 0); + me->thread = 0; + FARF(ALWAYS, "%s: Fastrpc notification worker thread joined", __func__); + } + me->init_done = 0; + return; +} + +int fastrpc_notif_domain_init(int domain) { + struct notif_config *me = &lnotifinfo[domain]; + int nErr = AEE_SUCCESS; + struct sigaction siga; + + if (me->init_done) { + goto bail; + } + me->thread = 0; + VERIFY(AEE_SUCCESS == + (nErr = pthread_create(&me->thread, 0, notif_fastrpc_thread, + (void *)me))); + // Register signal handler to interrupt thread, while thread is waiting in + // kernel + memset(&siga, 0, sizeof(siga)); + siga.sa_flags = 0; + siga.sa_handler = notif_thread_exit_handler; + VERIFY(AEE_SUCCESS == (nErr = sigaction(SIGUSR1, &siga, NULL))); + me->init_done = 1; + me->deinit_started = 0; + FARF(ALWAYS, "%s: FastRPC notification worker thread launched\n", __func__); +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error 0x%x: %s failed (errno %s)\n", nErr, __func__, + strerror(errno)); + fastrpc_notif_domain_deinit(domain); + } + return nErr; +} + +int fastrpc_notif_register(int domain, + struct remote_rpc_notif_register *notif) { + int nErr = AEE_SUCCESS; + struct fastrpc_notif *lnotif = NULL; + + // Initialize fastrpc structures, if in case this is the first call to library + VERIFYC((domain >= 0) && (domain < NUM_DOMAINS_EXTEND), AEE_EBADPARM); + + // Allocate client notification request node + VERIFYC(NULL != (lnotif = calloc(1, sizeof(struct fastrpc_notif))), + AEE_ENOMEMORY); + QNode_CtorZ(&lnotif->qn); + memcpy(&lnotif->notif, notif, sizeof(remote_rpc_notif_register_t)); + + // Add client node to notification list + pthread_mutex_lock(&update_notif_list_mut); + QList_AppendNode(¬if_list.ql, &lnotif->qn); + pthread_mutex_unlock(&update_notif_list_mut); + +bail: + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed for domain %d", nErr, __func__, domain); + } + return nErr; +} + +/* Internal function to notify clients, if there is any notification request */ +static int fastrpc_notify_status(int domain, int session, int status) { + QNode *pn, *pnn; + struct fastrpc_notif *lnotif = NULL; + int nErr = AEE_SUCCESS; + + pthread_mutex_lock(&update_notif_list_mut); + if (!QList_IsEmpty(¬if_list.ql)) { + QLIST_NEXTSAFE_FOR_ALL(¬if_list.ql, pn, pnn) { + lnotif = STD_RECOVER_REC(struct fastrpc_notif, qn, pn); + if (lnotif && (lnotif->notif.domain == domain)) { + lnotif->notif.notifier_fn(lnotif->notif.context, domain, session, + status); + } + } + } + pthread_mutex_unlock(&update_notif_list_mut); + return nErr; +} + +void fastrpc_cleanup_notif_list() { + QNode *pn = NULL, *pnn = NULL; + struct fastrpc_notif *lnotif = NULL; + + pthread_mutex_lock(&update_notif_list_mut); + if (!QList_IsEmpty(¬if_list.ql)) { + QLIST_NEXTSAFE_FOR_ALL(¬if_list.ql, pn, pnn) { + lnotif = STD_RECOVER_REC(struct fastrpc_notif, qn, pn); + if (lnotif) { + free(lnotif); + lnotif = NULL; + } + } + } + pthread_mutex_unlock(&update_notif_list_mut); +} + +/* Function to wait in kernel for an update in remote process status */ +int get_remote_notif_response(int domain) { + int nErr = AEE_SUCCESS, dev; + int dom = -1, session = -1, status = -1; + + VERIFY(AEE_SUCCESS == (nErr = fastrpc_session_dev(domain, &dev))); + nErr = ioctl_invoke2_notif(dev, &dom, &session, &status); + if (nErr) { + nErr = convert_kernel_to_user_error(nErr, errno); + goto bail; + } + FARF(ALWAYS, "%s: received status notification %u for domain %d, session %d", + __func__, status, dom, session); + fastrpc_notify_status(dom, session, status); +bail: + if (nErr && (errno != EBADF) && (nErr != AEE_EEXPIRED)) { + FARF(ERROR, + "Error 0x%x: %s failed to get notification response data errno %s", + nErr, __func__, strerror(errno)); + } + return nErr; +} + +// Make IOCTL call to exit notif thread +int fastrpc_exit_notif_thread(int domain) { + int nErr = AEE_SUCCESS, dev; + + VERIFY(AEE_SUCCESS == (nErr = fastrpc_session_dev(domain, &dev))); + nErr = ioctl_control(dev, DSPRPC_NOTIF_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_perf.c b/src/fastrpc_perf.c new file mode 100644 index 0000000..cee10aa --- /dev/null +++ b/src/fastrpc_perf.c @@ -0,0 +1,342 @@ +// 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 + +#ifndef VERIFY_PRINT_WARN +#define VERIFY_PRINT_WARN +#endif // VERIFY_PRINT_WARN + +#define FARF_ERROR 1 + +#include +#include +#include +#include +#include +#include +#include + +#include "AEEStdErr.h" +#include "AEEstd.h" +#include "HAP_farf.h" +#include "adsp_perf.h" +#include "adsp_perf1.h" +#include "fastrpc_common.h" +#include "fastrpc_internal.h" +#include "fastrpc_trace.h" +#include "fastrpc_cap.h" +#include "fastrpc_perf.h" +#include "remote.h" +#include "rpcmem_internal.h" +#include "verify.h" + + +#define PERF_MODE 2 +#define PERF_OFF 0 +#define PERF_KERNEL_MASK (0x1) +#define PERF_ADSP_MASK (0x2) +#define PERF_KEY_STR_MAX (2 * 1024) +#define PERF_MAX_NUM_KEYS 64 +#define PERF_KERNEL_NUM_KEYS 9 + +#define PERF_NS_TO_US(n) ((n) / 1000) + +#define IS_KEY_ENABLED(name) \ + (!std_strncmp((name), "perf_invoke_count", 17) || \ + !std_strncmp((name), "perf_mod_invoke", 15) || \ + !std_strncmp((name), "perf_rsp", 8) || \ + !std_strncmp((name), "perf_hdr_sync_flush", 19) || \ + !std_strncmp((name), "perf_sync_flush", 15) || \ + !std_strncmp((name), "perf_hdr_sync_inv", 17) || \ + !std_strncmp((name), "perf_clean_cache", 16) || \ + !std_strncmp((name), "perf_sync_inv", 13)) + +#define PERF_CAPABILITY_CHECK (1 << 1) + + +extern boolean fastrpc_config_is_perfkernel_enabled(void); +extern boolean fastrpc_config_is_perfdsp_enabled(void); + +int perf_v2_kernel = 0; +int perf_v2_dsp = 0; + +struct perf_keys { + int64 data[PERF_MAX_NUM_KEYS]; + int numKeys; + int maxLen; + int enable; + char *keys; +}; + +struct fastrpc_perf { + int count; + int freq; + int perf_on; + int process_trace_enabled; + struct perf_keys kernel; + struct perf_keys dsp; + remote_handle64 adsp_perf_handle; +}; +struct fastrpc_perf gperf = {0}; + +void check_perf_v2_enabled(int domain) { + int nErr = 0; + fastrpc_capability cap = {0}; + cap.domain = domain; + cap.attribute_ID = PERF_V2_DRIVER_SUPPORT; + + nErr = fastrpc_get_cap(cap.domain, cap.attribute_ID, &cap.capability); + if (nErr == 0) { + perf_v2_kernel = (cap.capability == PERF_CAPABILITY_CHECK) ? 1 : 0; + } + cap.attribute_ID = PERF_V2_DSP_SUPPORT; + nErr = fastrpc_get_cap(cap.domain, cap.attribute_ID, &cap.capability); + if (nErr == 0) { + perf_v2_dsp = (cap.capability == PERF_CAPABILITY_CHECK) ? 1 : 0; + } +} + +bool is_kernel_perf_enabled() { return perf_v2_kernel; } +bool is_dsp_perf_enabled(int domain) { return perf_v2_dsp; } +bool is_perf_v2_enabled() { return (perf_v2_kernel == 1 && perf_v2_dsp == 1); } + +inline int is_systrace_enabled() { return gperf.process_trace_enabled; } + +static int perf_kernel_getkeys(int dev) { + int nErr = 0, numkeys = 0; + struct fastrpc_perf *p = &gperf; + char *token; + char *saveptr; + + VERIFYC(p->kernel.keys, AEE_ERPC); + VERIFY(0 == (nErr = ioctl_getperf(dev, 1, p->kernel.keys, &numkeys))); + FARF(RUNTIME_RPC_HIGH, "adsprpc:apps:keys: numkeys %d keys: %s", numkeys, + p->kernel.keys); + p->kernel.numKeys = numkeys; + token = strtok_r(p->kernel.keys, ":", &saveptr); + while (token) { + FARF(RUNTIME_RPC_LOW, "key: %s", token); + token = strtok_r(NULL, ":", &saveptr); + } +bail: + if (nErr) { + VERIFY_WPRINTF("Warning: %s: Failed to get kernel keys, nErr 0x%x\n", + __func__, nErr); + } + return nErr; +} +/* +C: PERF_COUNT +F: PERF_FLUSH +M: PERF_MAP +CP: PERF_COPY +L: PERF_LINK +G: PERF_GETARGS +P: PERF_PUTARGS +INV: PERF_INVARGS +INVOKE: PERF_INVOKE +*/ + +static void get_perf_kernel(int dev, remote_handle handle, uint32_t sc) { + int nErr = 0, numkeys = 0; + struct fastrpc_perf *p = &gperf; + char *token; + + VERIFYC(dev != -1, AEE_ERPC); + + VERIFY(0 == (nErr = ioctl_getperf(dev, 0, p->kernel.data, &numkeys))); + token = p->kernel.keys; + + VERIFYC(token, AEE_ERPC); + switch (numkeys) { + case PERF_KERNEL_NUM_KEYS: + FARF(ALWAYS, + "RPCPERF-K H:0x%x SC:0x%x C:%" PRId64 " F:%" PRId64 " ns M:%" PRId64 + " ns CP:%" PRId64 " ns L:%" PRId64 " ns G:%" PRId64 " ns P:%" PRId64 + " ns INV:%" PRId64 " ns INVOKE:%" PRId64 " ns\n", + handle, sc, p->kernel.data[0], p->kernel.data[1], p->kernel.data[2], + p->kernel.data[3], p->kernel.data[4], p->kernel.data[5], + p->kernel.data[6], p->kernel.data[7], p->kernel.data[8]); + break; + default: + FARF(ALWAYS, "RPCPERF-K H:0x%x SC:0x%x \n", handle, sc); + break; + } +bail: + if (nErr) + VERIFY_WPRINTF( + "Warning: %s: Failed to get perf data from kernel, nErr 0x%x\n", + __func__, nErr); + return; +} + +static void get_perf_adsp(remote_handle handle, uint32_t sc) { + int nErr = 0; + struct perf_keys *pdsp = &gperf.dsp; + int ii; + char *token; + + char *keystr = pdsp->keys; + if (gperf.adsp_perf_handle != INVALID_HANDLE) { + VERIFY(0 == (nErr = adsp_perf1_get_usecs(gperf.adsp_perf_handle, pdsp->data, + PERF_MAX_NUM_KEYS))); + } else { + VERIFY(0 == (nErr = adsp_perf_get_usecs(pdsp->data, PERF_MAX_NUM_KEYS))); + } + VERIFYC(pdsp->maxLen < PERF_KEY_STR_MAX, AEE_ERPC); + VERIFYC(pdsp->numKeys < PERF_MAX_NUM_KEYS, AEE_ERPC); + FARF(ALWAYS, "\nFastRPC dsp perf for handle 0x%x sc 0x%x\n", handle, sc); + for (ii = 0; ii < pdsp->numKeys; ii++) { + token = keystr; + keystr += strlen(token) + 1; + VERIFYC(token, AEE_ERPC); + if (!pdsp->data[ii]) + continue; + if (!std_strncmp(token, "perf_invoke_count", 17)) { + FARF(ALWAYS, "fastrpc.dsp.%-20s : %" PRId64 " \n", token, pdsp->data[ii]); + } else { + FARF(ALWAYS, "fastrpc.dsp.%-20s : %" PRId64 " us\n", token, + pdsp->data[ii]); + } + } +bail: + if (nErr) + VERIFY_WPRINTF("Warning: %s: Failed to get perf data from dsp, nErr 0x%x\n", + __func__, nErr); + return; +} + +void fastrpc_perf_update(int dev, remote_handle handle, uint32_t sc) { + struct fastrpc_perf *p = &gperf; + + if (!(p->perf_on && !IS_STATIC_HANDLE(handle) && p->freq > 0)) + return; + + p->count++; + if (p->count % p->freq != 0) + return; + + if (p->kernel.enable && !perf_v2_kernel) + get_perf_kernel(dev, handle, sc); + + if (p->dsp.enable && !perf_v2_dsp) + get_perf_adsp(handle, sc); + + return; +} + +static int perf_dsp_enable(int domain) { + int nErr = 0; + int numKeys = 0, maxLen = 0; + char *keys = NULL; + int ii; + + keys = + (char *)rpcmem_alloc_internal(0, RPCMEM_HEAP_DEFAULT, PERF_KEY_STR_MAX); + VERIFYC(gperf.dsp.keys = keys, AEE_ERPC); + std_memset(keys, 0, PERF_KEY_STR_MAX); + + VERIFY(0 == (nErr = adsp_perf_get_keys(keys, PERF_KEY_STR_MAX, &maxLen, + &numKeys))); + if ((gperf.adsp_perf_handle = get_adsp_perf1_handle(domain)) != + INVALID_HANDLE) { + nErr = adsp_perf1_get_keys(gperf.adsp_perf_handle, keys, PERF_KEY_STR_MAX, + &maxLen, &numKeys); + if (nErr) { + FARF(ALWAYS, + "Warning 0x%x: %s: adsp_perf1 domains not supported for domain %d\n", + nErr, __func__, domain); + fastrpc_update_module_list(DOMAIN_LIST_DEQUEUE, domain, gperf.adsp_perf_handle, NULL); + gperf.adsp_perf_handle = INVALID_HANDLE; + VERIFY(0 == (nErr = adsp_perf_get_keys(keys, PERF_KEY_STR_MAX, &maxLen, + &numKeys))); + } + } + VERIFYC(maxLen < PERF_KEY_STR_MAX && maxLen >= 0, AEE_ERPC); + VERIFYC(numKeys < PERF_MAX_NUM_KEYS && numKeys >= 0, AEE_ERPC); + gperf.dsp.maxLen = maxLen; + gperf.dsp.numKeys = numKeys; + for (ii = 0; ii < numKeys; ii++) { + char *name = keys; + keys += strlen(name) + 1; + if (IS_KEY_ENABLED(name)) { + if (gperf.adsp_perf_handle != INVALID_HANDLE) { + VERIFY(0 == (nErr = adsp_perf1_enable(gperf.adsp_perf_handle, ii))); + } else { + VERIFY(0 == (nErr = adsp_perf_enable(ii))); + } + } + } + FARF(RUNTIME_RPC_HIGH, "keys enable done maxLen %d numKeys %d", maxLen, + numKeys); +bail: + if (nErr) { + VERIFY_WPRINTF("Warning: %s: Failed to enable perf on dsp, nErr 0x%x\n", + __func__, nErr); + } + return nErr; +} + +int fastrpc_perf_init(int dev, int domain) { + int nErr = 0; + struct fastrpc_perf *p = &gperf; + struct perf_keys *pk = &gperf.kernel; + struct perf_keys *pd = &gperf.dsp; + + pk->enable = fastrpc_get_property_int(FASTRPC_PERF_KERNEL, 0) || + fastrpc_config_is_perfkernel_enabled(); + pd->enable = fastrpc_get_property_int(FASTRPC_PERF_ADSP, 0) || + fastrpc_config_is_perfdsp_enabled(); + + p->perf_on = (pk->enable || pd->enable) ? PERF_MODE : PERF_OFF; + p->freq = fastrpc_get_property_int(FASTRPC_PERF_FREQ, 1000); + VERIFYC(p->freq > 0, AEE_ERPC); + p->process_trace_enabled = + fastrpc_get_property_int(FASTRPC_ENABLE_SYSTRACE, 0); + if (p->perf_on) { + check_perf_v2_enabled(domain); + } + p->count = 0; + if (pk->enable) { + VERIFY(0 == (nErr = ioctl_setmode(dev, PERF_MODE))); + if (!perf_v2_kernel) { + VERIFYC(NULL != + (pk->keys = (char *)calloc(sizeof(char), PERF_KEY_STR_MAX)), + AEE_ENOMEMORY); + VERIFY(0 == (nErr = perf_kernel_getkeys(dev))); + } + } + + if (pd->enable && (!perf_v2_dsp)) + perf_dsp_enable(domain); +bail: + if (nErr) { + FARF(ERROR, + "fastrpc perf init failed, nErr 0x%x (kernel %d, dsp %d) with " + "frequency %d", + nErr, pk->enable, pd->enable, p->freq); + p->perf_on = 0; + } else { + FARF(ALWAYS, + "%s: enabled systrace 0x%x and RPC traces (kernel %d, dsp %d) with " + "frequency %d", + __func__, p->process_trace_enabled, pk->enable, pd->enable, p->freq); + } + return nErr; +} + +void fastrpc_perf_deinit(void) { + struct fastrpc_perf *p = &gperf; + if (p->kernel.keys) { + free(p->kernel.keys); + p->kernel.keys = NULL; + } + if (p->dsp.keys) { + rpcmem_free_internal(p->dsp.keys); + p->dsp.keys = NULL; + } + return; +} diff --git a/src/fastrpc_pm.c b/src/fastrpc_pm.c new file mode 100644 index 0000000..edb4ed7 --- /dev/null +++ b/src/fastrpc_pm.c @@ -0,0 +1,217 @@ +// 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 "AEEstd.h" +#include "AEEStdErr.h" +#include "AEEatomic.h" +#include "HAP_farf.h" +#include "verify.h" + + +#define WAKE_LOCK_FILE "/sys/power/wake_lock" +#define WAKE_UNLOCK_FILE "/sys/power/wake_unlock" + +#define WAKELOCK_NAME_LEN 50 + +struct wake_lock { + char wake_lock_name[WAKELOCK_NAME_LEN]; + int lock; + int unlock; + pthread_mutex_t wmut; + unsigned int count; + bool init_done; + bool deinit_started; +}; + +static struct wake_lock wakelock; +static uint32 wakelock_wmut_int = 0; + +int fastrpc_wake_lock() { + int nErr = AEE_SUCCESS, ret = 0; + + if (!wakelock.init_done) { + nErr = AEE_ERPC; + FARF(ERROR, "Error 0x%x : %s failed for wakelock is not initialized\n", + nErr, __func__); + return nErr; + } + + pthread_mutex_lock(&wakelock.wmut); + if (wakelock.deinit_started) { + nErr = AEE_ERPC; + FARF(ERROR, "Warning 0x%x : %s failed for wakelock as deinit started\n", + nErr, __func__); + goto bail; + } + if (!wakelock.count && wakelock.lock > 0) + VERIFYC(0 < (ret = write(wakelock.lock, wakelock.wake_lock_name, + strlen(wakelock.wake_lock_name))), + AEE_ERPC); + wakelock.count++; +bail: + pthread_mutex_unlock(&wakelock.wmut); + if (nErr) { + FARF(ERROR, "Error 0x%x (%d): %s failed for %s, fd %d (errno %s)\n", nErr, + ret, __func__, WAKE_LOCK_FILE, wakelock.lock, strerror(errno)); + } + return nErr; +} + +int fastrpc_wake_unlock() { + int nErr = AEE_SUCCESS, ret = 0; + + if (!wakelock.init_done) { + nErr = AEE_ERPC; + FARF(ERROR, "Error 0x%x : %s failed for wakelock is not initialized\n", + nErr, __func__); + return nErr; + } + + pthread_mutex_lock(&wakelock.wmut); + if (!wakelock.count) + goto bail; + wakelock.count--; + if (!wakelock.count && wakelock.unlock > 0) + VERIFYC(0 < (ret = write(wakelock.unlock, wakelock.wake_lock_name, + strlen(wakelock.wake_lock_name))), + AEE_ERPC); +bail: + if (nErr) { + wakelock.count++; + FARF(ERROR, "Error 0x%x (%d): %s failed for %s, fd %d (errno %s)\n", nErr, + ret, __func__, WAKE_UNLOCK_FILE, wakelock.unlock, strerror(errno)); + } + pthread_mutex_unlock(&wakelock.wmut); + return nErr; +} + +static void fastrpc_wake_lock_release() { + int nErr = AEE_SUCCESS; + + while (wakelock.count) { + VERIFY(AEE_SUCCESS == (nErr = fastrpc_wake_unlock())); + } +bail: + return; +} + +int fastrpc_wake_lock_init() { + int nErr = AEE_SUCCESS, ret = 0; + const unsigned int TMPSTR_LEN = WAKELOCK_NAME_LEN / 2; + char pid_str[TMPSTR_LEN], prog_name_str[TMPSTR_LEN]; + + if (wakelock.init_done) + return nErr; + + wakelock.deinit_started = 0; + + if (1 == atomic_CompareAndExchange(&wakelock_wmut_int, 1, 0)) { + VERIFY(AEE_SUCCESS == (nErr = pthread_mutex_init(&wakelock.wmut, 0))); + } + pthread_mutex_lock(&wakelock.wmut); + + VERIFYC(0 < (ret = snprintf(pid_str, TMPSTR_LEN, ":%d", getpid())), AEE_ERPC); + if (0 >= (ret = snprintf(prog_name_str, TMPSTR_LEN, "%s", __progname))) { + nErr = AEE_ERPC; + goto bail; + } + + std_strlcpy(wakelock.wake_lock_name, prog_name_str, WAKELOCK_NAME_LEN); + std_strlcat(wakelock.wake_lock_name, pid_str, WAKELOCK_NAME_LEN); + + VERIFYC(0 < (wakelock.lock = open(WAKE_LOCK_FILE, O_RDWR | O_CLOEXEC)), + AEE_ERPC); + VERIFYC(0 < (wakelock.unlock = open(WAKE_UNLOCK_FILE, O_RDWR | O_CLOEXEC)), + AEE_ERPC); + +bail: + if (nErr) { + FARF(ERROR, "Error 0x%x (%d): %s failed (errno %s)\n", nErr, ret, __func__, + strerror(errno)); + if ((nErr == AEE_ERPC) && (errno == ENOENT)) { + nErr = AEE_EUNSUPPORTEDAPI; + } + if (wakelock.lock > 0) { + ret = close(wakelock.lock); + if (ret) { + FARF(ERROR, "Error %d: %s: failed to close %s with fd %d (errno %s)", + ret, __func__, WAKE_LOCK_FILE, wakelock.lock, strerror(errno)); + } else { + wakelock.lock = 0; + } + } + if (wakelock.unlock > 0) { + ret = close(wakelock.unlock); + if (ret) { + FARF(ERROR, "Error %d: %s: failed to close %s with fd %d (errno %s)", + ret, __func__, WAKE_UNLOCK_FILE, wakelock.unlock, strerror(errno)); + } else { + wakelock.unlock = 0; + } + } + pthread_mutex_unlock(&wakelock.wmut); + pthread_mutex_destroy(&wakelock.wmut); + } else { + wakelock.init_done = true; + pthread_mutex_unlock(&wakelock.wmut); + FARF(ALWAYS, "%s done for %s", __func__, wakelock.wake_lock_name); + } + return nErr; +} + +int fastrpc_wake_lock_deinit() { + int nErr = AEE_SUCCESS; + + if (!wakelock.init_done) + return nErr; + + pthread_mutex_lock(&wakelock.wmut); + wakelock.deinit_started = 1; + pthread_mutex_unlock(&wakelock.wmut); + fastrpc_wake_lock_release(); + pthread_mutex_lock(&wakelock.wmut); + if (wakelock.lock > 0) { + nErr = close(wakelock.lock); + if (nErr) { + FARF(ERROR, "Error %d: %s: failed to close %s with fd %d (errno %s)", + nErr, __func__, WAKE_LOCK_FILE, wakelock.lock, strerror(errno)); + } else { + wakelock.lock = 0; + } + } + if (wakelock.unlock > 0) { + nErr = close(wakelock.unlock); + if (nErr) { + FARF(ERROR, "Error %d: %s: failed to close %s with fd %d (errno %s)", + nErr, __func__, WAKE_UNLOCK_FILE, wakelock.unlock, strerror(errno)); + } else { + wakelock.unlock = 0; + } + } + wakelock.init_done = false; + pthread_mutex_unlock(&wakelock.wmut); + + if (nErr) + FARF(ERROR, "Error 0x%x (%d): %s failed (errno %s)\n", nErr, __func__, + strerror(errno)); + else + FARF(ALWAYS, "%s done", __func__); + return nErr; +} diff --git a/src/fastrpc_procbuf.c b/src/fastrpc_procbuf.c new file mode 100644 index 0000000..08b5963 --- /dev/null +++ b/src/fastrpc_procbuf.c @@ -0,0 +1,260 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#include +#include + +#include "AEEstd.h" +#include "AEEStdErr.h" +#include "verify.h" +#include "fastrpc_procbuf.h" +#include "apps_std_internal.h" +#include "fastrpc_config.h" +#include "fastrpc_internal.h" //TODO: Bharath +#include "rpcmem_internal.h" +#include "fastrpc_common.h" +#include "HAP_farf_internal.h" +#include "fastrpc_process_attributes.h" + +/* size of buffer used to share the inital config params to dsp */ +#define PROC_SHAREDBUF_SIZE (4*1024) +#define ENV_PATH_LEN 256 +#define WORD_SIZE 4 + +extern struct handle_list *hlist; + +int proc_sharedbuf_init(int dev, int domain) { + int proc_sharedbuf_size = PROC_SHAREDBUF_SIZE, sharedbuf_kernel_support = 1; + int nErr = AEE_SUCCESS, ioErr = 0; + void *proc_sharedbuf = NULL; + struct fastrpc_proc_sharedbuf_info sharedbuf_info; + + errno = 0; + VERIFYC(NULL != (proc_sharedbuf = rpcmem_alloc_internal(0, RPCMEM_HEAP_DEFAULT, (size_t)proc_sharedbuf_size)), AEE_ENORPCMEMORY); + hlist[domain].proc_sharedbuf = proc_sharedbuf; + VERIFYC(-1 != (sharedbuf_info.buf_fd = rpcmem_to_fd_internal(proc_sharedbuf)), AEE_ERPC); + sharedbuf_info.buf_size = proc_sharedbuf_size; + + ioErr = ioctl_sharedbuf(dev, &sharedbuf_info); + if (ioErr) { + if (errno == ENOTTY) { + sharedbuf_kernel_support = 0; + FARF(ERROR, "Error 0x%x: %s: sharedbuff capability not supported by kernel (errno %d, %s).", + nErr, __func__, errno, strerror(errno)); + } else { + nErr = convert_kernel_to_user_error(nErr, errno); + } + } +bail: + if (proc_sharedbuf && (nErr || !sharedbuf_kernel_support)) { + rpcmem_free_internal(proc_sharedbuf); + proc_sharedbuf = NULL; + hlist[domain].proc_sharedbuf = NULL; + } + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed for domain %d, errno %s, ioErr %d\n", + nErr, __func__, domain, strerror(errno), ioErr); + } + return nErr; +} + +/* + * Function to pack the shared buffer with list of shared objects in custom DSP_LIBRARY_PATH. + * @lib_names : List of the shared objects present in the custom DSP_SEARCH_PATH set by user. + * @buffer_size : Number of characters to be packed. + * Updated lib_names at the end (example) : lib1.so;lib2.so;lib3.so; + */ + +static int get_non_preload_lib_names (char** lib_names, size_t* buffer_size, int domain) +{ + int nErr = AEE_SUCCESS, env_list_len = 0; + char* data_paths = NULL; + char *saveptr = NULL; + VERIFYC(NULL != (data_paths = calloc(1, sizeof(char) * ENV_PATH_LEN)), AEE_ENOMEMORY); + VERIFY(AEE_SUCCESS == (nErr = apps_std_getenv(DSP_LIBRARY_PATH, data_paths, ENV_PATH_LEN, &env_list_len))); + + char* path = strtok_r(data_paths, ":", &saveptr); + while (path != NULL) + { + struct dirent *entry; + DIR *dir = opendir(path); + VERIFYC(NULL != dir, AEE_EBADPARM); + + while ((entry = readdir(dir)) != NULL) { + if ( entry -> d_type == DT_REG) { + char* file = entry->d_name; + if ( strstr (file, ".so") != NULL) { + size_t new_len = *buffer_size + std_strlen(file) + 1; + VERIFYC(NULL != (*lib_names = realloc (*lib_names, new_len)), AEE_ENOMEMORY); + std_strlcat(*lib_names, file, new_len); + std_strlcat(*lib_names, ";", new_len); + *buffer_size = new_len; + } + } + } + closedir(dir); + path = strtok_r(NULL,":", &saveptr); + } + (*lib_names)[*buffer_size - 1] = '\0'; + *buffer_size = std_strlen(*lib_names) + 1; + +bail: + if (nErr) { + FARF(ERROR, "Error 0x%x: %s Failed for domain %d (%s)\n", + nErr, __func__, domain, strerror(errno)); + } + return nErr; +} + +/* Internal function to pack the process config parameters in shared buffer + * + * shared buffer 4K + * +-------------------------+ + * proc_sharedbuf addr--------------->| Total no of id's packed | + * +-------------------------+ + * ID1 addr=proc_sharedbuf addr+1---->| ID1 | data payload size| + * +-------------------------+ + * ID1 data addr=ID1 addr+1---------->| ID1 data | + * +-------------------------+ + * ID2 addr=ID1 data addr+data size-->| ID2 | data payload size| + * +-------------------------+ + * ID2 data addr=ID2 addr+1---------->| ID2 data | + * +-------------------------+ + * ...... |.........................| + * +-------------------------+ + * ...... |......|..................| + * +-------------------------+ + * proc_sharedbuf end addr----------->|.........................| + * +-------------------------+ + * 8bits | 24bits + * + * @ domain: domain to retrieve the process shared buffer address + * @ param_id: unique process parameter id should match with dsp id to unpack + * @ param_addr: address of the process parameters to write into shared buffer + * @ param_size: size of the process parameters to pack + * returns 0 on success + */ + +static int pack_proc_shared_buf_params(int domain, uint32_t param_id, + void *param_addr, uint32_t param_size) +{ + uint32_t *buf_start_addr = (uint32_t*)hlist[domain].proc_sharedbuf; + uint32_t align_param_size = param_size; + /* Params pack address */ + uint32_t *buf_write_addr = (uint32_t*)hlist[domain].proc_sharedbuf_cur_addr, + *buf_last_addr = buf_start_addr + PROC_SHAREDBUF_SIZE; + + if (param_addr == NULL || param_size <= 0 || param_id < 0 || + param_id >= PROC_ATTR_BUF_MAX_ID) { + FARF(ERROR, "Error: %s: invalid param %u or size %u or addr 0x%x", + __func__, param_id, param_size, param_addr); + return AEE_EBADPARM; + } + if (buf_write_addr == NULL) { + /* + * Total no of param ids (4 bytes) are packed at shared buffer initial address, + * so add 4 bytes to start pack process params + */ + buf_write_addr = (uint32_t*)((char*)buf_start_addr + WORD_SIZE); + } + /* Align the params size in multiple of 4 bytes (word) for easy unpacking at DSP */ + align_param_size = ALIGN_B(param_size, WORD_SIZE); + + if (buf_last_addr < (uint32_t*)((char*)buf_write_addr + align_param_size + sizeof(param_id))) { + FARF(ERROR, "Error: %s: proc shared buffer exhausted to pack param_id:%u params", + __func__, param_id); + return AEE_ERPC; + } + /* Write param_id */ + *buf_write_addr = param_id; + + /* Shift param_id to first 8 bits */ + *buf_write_addr = (*buf_write_addr) << PROC_ATTR_BUF_ID_POS; + + /* Write param size in last 24 bits */ + *buf_write_addr = (*buf_write_addr) + (PROC_ATTR_BUF_ID_SIZE_MASK & align_param_size); + buf_write_addr++; + + std_memscpy(buf_write_addr, (buf_last_addr - buf_write_addr), param_addr, param_size); + buf_write_addr = (uint32_t*)((char*)buf_write_addr + align_param_size); + hlist[domain].proc_sharedbuf_cur_addr = buf_write_addr; + + /* Increase the number of ids in start address */ + (*buf_start_addr)++; + return AEE_SUCCESS; +} + +/* Internal function to send the process config parameters for packing + * + * @ dev: device id + * @ domain: domain to retrieve the process shared buffer address + * returns none + */ +void fastrpc_process_pack_params(int dev, int domain) { + int nErr = AEE_SUCCESS, sess_id = GET_SESSION_ID_FROM_DOMAIN_ID(domain); + struct err_codes* err_codes_to_send = NULL; + size_t buffer_size = 0; + char *lib_names = NULL; + pid_t pid = getpid(); + + if (AEE_SUCCESS != proc_sharedbuf_init(dev, domain)) { + return; + } + if (!hlist[domain].proc_sharedbuf) { + return; + } + nErr = pack_proc_shared_buf_params(domain, HLOS_PID_ID, + &pid, sizeof(pid)); + if (nErr) { + FARF(ERROR, "Error 0x%x: %s: Failed to pack process id in shared buffer", + nErr, __func__); + } + nErr = pack_proc_shared_buf_params(domain, THREAD_PARAM_ID, + &hlist[domain].th_params, sizeof(hlist[domain].th_params)); + if (nErr) { + FARF(ERROR, "Error 0x%x: %s: Failed to pack thread parameters in shared buffer", + nErr, __func__); + } + nErr = pack_proc_shared_buf_params(domain, PROC_ATTR_ID, + &hlist[domain].procattrs, sizeof(hlist[domain].procattrs)); + if (nErr) { + FARF(ERROR, "Error 0x%x: %s: Failed to pack process config parameters in shared buffer", + nErr, __func__); + } + err_codes_to_send = fastrpc_config_get_errcodes(); + if (err_codes_to_send) { + nErr = pack_proc_shared_buf_params(domain, PANIC_ERR_CODES_ID, + err_codes_to_send, sizeof(*err_codes_to_send)); + if (nErr) { + FARF(ERROR, "Error 0x%x: %s: Failed to pack panic error codes in shared buffer", + nErr, __func__); + } + } + nErr = pack_proc_shared_buf_params(domain, HLOS_PROC_EFFEC_DOM_ID, + &domain, sizeof(domain)); + if (nErr) { + FARF(ERROR, "Error 0x%x: %s: Failed to pack effective domain id %d in shared buffer", + nErr, __func__, domain); + } + if (AEE_SUCCESS != get_non_preload_lib_names(&lib_names, &buffer_size, domain)){ + return; + } + nErr = pack_proc_shared_buf_params(domain, CUSTOM_DSP_SEARCH_PATH_LIBS_ID, + lib_names, buffer_size); + if (nErr) { + FARF(ERROR, "Error 0x%x: %s: Failed to pack the directory list in shared buffer", + nErr, __func__); + } + nErr = pack_proc_shared_buf_params(domain, HLOS_PROC_SESS_ID, + &sess_id, sizeof(sess_id)); + if (nErr) { + FARF(ERROR, "Error 0x%x: %s: Failed to pack session id %d in shared buffer", + nErr, __func__, sess_id); + } + if (lib_names){ + free(lib_names); + lib_names = NULL; + } +} diff --git a/src/gpls.c b/src/gpls.c new file mode 100644 index 0000000..0d69ef5 --- /dev/null +++ b/src/gpls.c @@ -0,0 +1,52 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#include "HAP_farf.h" +#include "HAP_pls.h" +#include "adsp_pls.h" +#include "platform_libs.h" +#include "pls.h" +#include "version.h" + +static struct pls_table gpls; +const char pls_version[] = VERSION_STRING; +int gpls_init(void) { + pls_ctor(&gpls, 1); + return 0; +} + +void gpls_deinit(void) { pls_thread_deinit(&gpls); } + +int HAP_pls_add(uintptr_t type, uintptr_t key, int size, + int (*ctor)(void *ctx, void *data), void *ctx, + void (*dtor)(void *), void **ppo) { + return pls_add(&gpls, type, key, size, ctor, ctx, dtor, ppo); +} + +int HAP_pls_add_lookup(uintptr_t type, uintptr_t key, int size, + int (*ctor)(void *ctx, void *data), void *ctx, + void (*dtor)(void *), void **ppo) { + return pls_add_lookup_singleton(&gpls, type, key, size, ctor, ctx, dtor, ppo); +} + +int HAP_pls_lookup(uintptr_t type, uintptr_t key, void **ppo) { + return pls_lookup(&gpls, type, key, ppo); +} + +int adsp_pls_add(uintptr_t type, uintptr_t key, int size, + int (*ctor)(void *ctx, void *data), void *ctx, + void (*dtor)(void *), void **ppo) { + return pls_add(&gpls, type, key, size, ctor, ctx, dtor, ppo); +} + +int adsp_pls_add_lookup(uintptr_t type, uintptr_t key, int size, + int (*ctor)(void *ctx, void *data), void *ctx, + void (*dtor)(void *), void **ppo) { + return pls_add_lookup_singleton(&gpls, type, key, size, ctor, ctx, dtor, ppo); +} + +int adsp_pls_lookup(uintptr_t type, uintptr_t key, void **ppo) { + return pls_lookup(&gpls, type, key, ppo); +} + +PL_DEFINE(gpls, gpls_init, gpls_deinit) diff --git a/src/listener_android.c b/src/listener_android.c new file mode 100644 index 0000000..cf00be8 --- /dev/null +++ b/src/listener_android.c @@ -0,0 +1,469 @@ +// 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_HIGH 1 +#define FARF_LOW 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AEEStdErr.h" +#include "AEEstd.h" +#include "HAP_farf.h" +#include "rpcmem_internal.h" +#include "adsp_listener.h" +#include "adsp_listener1.h" +#include "fastrpc_common.h" +#include "fastrpc_internal.h" +#include "listener_buf.h" +#include "mod_table.h" +#include "platform_libs.h" +#include "rpcmem.h" +#include "shared.h" +#include "verify.h" + +struct listener { + pthread_t thread; + int eventfd; + int update_requested; + int params_updated; + sem_t *r_sem; + int domain; + remote_handle64 adsp_listener1_handle; +}; + +static struct listener linfo[NUM_DOMAINS_EXTEND]; + +extern void set_thread_context(int domain); + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_remotectl_open)(const char *name, uint32 *handle, char *dlStr, + int dlerrorLen, + int *dlErr) __QAIC_IMPL_ATTRIBUTE { + int domain = get_current_domain(); + int nErr = AEE_SUCCESS; + remote_handle64 local; + VERIFY(AEE_SUCCESS == + (nErr = mod_table_open(name, handle, dlStr, dlerrorLen, dlErr))); + VERIFY(AEE_SUCCESS == + (nErr = fastrpc_update_module_list( + REVERSE_HANDLE_LIST_PREPEND, domain, (remote_handle)*handle, &local))); +bail: + return nErr; +} + +__QAIC_IMPL_EXPORT int +__QAIC_IMPL(apps_remotectl_close)(uint32 handle, char *errStr, int errStrLen, + int *dlErr) __QAIC_IMPL_ATTRIBUTE { + int domain = get_current_domain(); + int nErr = AEE_SUCCESS; + + if (AEE_SUCCESS != + (nErr = mod_table_close(handle, errStr, errStrLen, dlErr))) { + if(!is_process_exiting(domain)) { + FARF(ERROR, + "Error 0x%x: %s: mod_table_close failed for handle:0x%x (dlErr %s)", + nErr, __func__, handle, (char *)dlErr); + } + goto bail; + } + VERIFY(AEE_SUCCESS == + (nErr = fastrpc_update_module_list( + REVERSE_HANDLE_LIST_DEQUEUE, domain, (remote_handle)handle, NULL))); +bail: + return nErr; +} + +#define RPC_FREEIF(buf) \ + do { \ + if (buf) { \ + rpcmem_free_internal(buf); \ + buf = 0; \ + } \ + } while (0) + +static __inline void *rpcmem_realloc(int heapid, uint32 flags, void *buf, + int oldsize, size_t size) { + void *bufnew = rpcmem_alloc_internal(heapid, flags, size); + if (buf && bufnew) { + memmove(bufnew, buf, STD_MIN(oldsize, size)); + rpcmem_free_internal(buf); + buf = NULL; + } + return bufnew; +} + +#define MIN_BUF_SIZE 0x1000 +#define ALIGNB(sz) ((sz) == 0 ? MIN_BUF_SIZE : _SBUF_ALIGN((sz), MIN_BUF_SIZE)) + +static void listener(struct listener *me) { + int nErr = AEE_SUCCESS, i = 0, domain = me->domain, ref = 0; + adsp_listener1_invoke_ctx ctx = 0; + uint8 *outBufs = 0; + int outBufsLen = 0, outBufsCapacity = 0; + uint8 *inBufs = 0; + int inBufsLen = 0, inBufsLenReq = 0; + int result = -1, bufs_len = 0; + adsp_listener1_remote_handle handle = -1; + uint32 sc = 0; + const char *eheap = getenv("ADSP_LISTENER_HEAP_ID"); + int heapid = eheap == 0 ? -1 : atoi(eheap); + const char *eflags = getenv("ADSP_LISTENER_HEAP_FLAGS"); + uint32 flags = eflags == 0 ? 0 : (uint32)atoi(eflags); + const char *emin = getenv("ADSP_LISTENER_MEM_CACHE_SIZE"); + int cache_size = emin == 0 ? 0 : atoi(emin); + remote_arg args[512]; + struct sbuf buf; + eventfd_t event = 0xff; + + FARF(ALWAYS, "%s thread starting\n", __func__); + 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); + } + + do { + invoke: + sc = 0xffffffff; + if (result != 0) { + outBufsLen = 0; + } + FARF(RUNTIME_RPC_HIGH, + "%s responding 0x%x for ctx 0x%x, handle 0x%x, sc 0x%x", __func__, + result, ctx, handle, sc); + FASTRPC_PUT_REF(domain); + if (me->adsp_listener1_handle != INVALID_HANDLE) { + nErr = __QAIC_HEADER(adsp_listener1_next2)( + me->adsp_listener1_handle, ctx, result, outBufs, outBufsLen, &ctx, + &handle, &sc, inBufs, inBufsLen, &inBufsLenReq); + } else { + nErr = __QAIC_HEADER(adsp_listener_next2)( + ctx, result, outBufs, outBufsLen, &ctx, &handle, &sc, inBufs, + inBufsLen, &inBufsLenReq); + } + if (nErr) { + if (nErr == AEE_EINTERRUPTED) { + goto invoke; + } + if (me->adsp_listener1_handle != INVALID_HANDLE) { + nErr = __QAIC_HEADER(adsp_listener1_next2)( + me->adsp_listener1_handle, ctx, nErr, 0, 0, &ctx, &handle, &sc, + inBufs, inBufsLen, &inBufsLenReq); + } else { + nErr = __QAIC_HEADER(adsp_listener_next2)(ctx, nErr, 0, 0, &ctx, + &handle, &sc, inBufs, + inBufsLen, &inBufsLenReq); + } + if (nErr) { + FARF(RUNTIME_HIGH, + "Error 0x%x: %s response with result 0x%x for ctx 0x%x, handle " + "0x%x, sc 0x%x failed\n", + nErr, __func__, result, ctx, handle, sc); + goto bail; + } + } + FASTRPC_GET_REF(domain); + if (__builtin_smul_overflow(inBufsLenReq, 2, &bufs_len)) { + FARF(ERROR, + "Error: %s: overflow occurred while multiplying input buffer size: " + "%d * 2 = %d for handle 0x%x, sc 0x%x", + __func__, inBufsLenReq, bufs_len, handle, sc); + result = AEE_EBADSIZE; + goto invoke; + } + if (ALIGNB(bufs_len) < inBufsLen && inBufsLen > cache_size) { + void *buf; + int size = ALIGNB(bufs_len); + if (NULL == + (buf = rpcmem_realloc(heapid, flags, inBufs, inBufsLen, size))) { + result = AEE_ENORPCMEMORY; + FARF(RUNTIME_RPC_HIGH, "rpcmem_realloc shrink failed"); + goto invoke; + } + inBufs = buf; + inBufsLen = size; + } + if (inBufsLenReq > inBufsLen) { + void *buf; + int req; + int oldLen = inBufsLen; + int size = _SBUF_ALIGN(inBufsLenReq, MIN_BUF_SIZE); + if (AEE_SUCCESS == + (buf = rpcmem_realloc(heapid, flags, inBufs, inBufsLen, size))) { + result = AEE_ENORPCMEMORY; + FARF(ERROR, "rpcmem_realloc failed"); + goto invoke; + } + inBufs = buf; + inBufsLen = size; + if (me->adsp_listener1_handle != INVALID_HANDLE) { + result = __QAIC_HEADER(adsp_listener1_get_in_bufs2)( + me->adsp_listener1_handle, ctx, oldLen, inBufs + oldLen, + inBufsLen - oldLen, &req); + } else { + result = __QAIC_HEADER(adsp_listener_get_in_bufs2)( + ctx, oldLen, inBufs + oldLen, inBufsLen - oldLen, &req); + } + if (AEE_SUCCESS != result) { + FARF(RUNTIME_RPC_HIGH, "adsp_listener_invoke_get_in_bufs2 failed %x", + result); + goto invoke; + } + if (req > inBufsLen) { + result = AEE_EBADPARM; + FARF(RUNTIME_RPC_HIGH, + "adsp_listener_invoke_get_in_bufs2 failed, size is invalid req %d " + "inBufsLen %d result %d %x", + req, inBufsLen, result); + goto invoke; + } + } + if (REMOTE_SCALARS_INHANDLES(sc) + REMOTE_SCALARS_OUTHANDLES(sc) > 0) { + result = AEE_EBADPARM; + goto invoke; + } + + sbuf_init(&buf, 0, inBufs, inBufsLen); + unpack_in_bufs(&buf, args, REMOTE_SCALARS_INBUFS(sc)); + unpack_out_lens(&buf, args + REMOTE_SCALARS_INBUFS(sc), + REMOTE_SCALARS_OUTBUFS(sc)); + + sbuf_init(&buf, 0, 0, 0); + pack_out_bufs(&buf, args + REMOTE_SCALARS_INBUFS(sc), + REMOTE_SCALARS_OUTBUFS(sc)); + outBufsLen = sbuf_needed(&buf); + + if (__builtin_smul_overflow(outBufsLen, 2, &bufs_len)) { + FARF(ERROR, + "%s: Overflow occured while multiplying output buffer size: %d * 2 " + "= %d", + __func__, outBufsLen, bufs_len); + result = AEE_EBADSIZE; + goto invoke; + } + if (ALIGNB(bufs_len) < outBufsCapacity && outBufsCapacity > cache_size) { + void *buf; + int size = ALIGNB(bufs_len); + if (NULL == (buf = rpcmem_realloc(heapid, flags, outBufs, outBufsCapacity, + size))) { + result = AEE_ENORPCMEMORY; + FARF(RUNTIME_RPC_HIGH, "listener rpcmem_realloc shrink failed"); + goto invoke; + } + outBufs = buf; + outBufsCapacity = size; + } + if (outBufsLen > outBufsCapacity) { + void *buf; + int size = ALIGNB(outBufsLen); + if (NULL == (buf = rpcmem_realloc(heapid, flags, outBufs, outBufsCapacity, + size))) { + result = AEE_ENORPCMEMORY; + FARF(ERROR, "listener rpcmem_realloc failed"); + goto invoke; + } + outBufs = buf; + outBufsLen = size; + outBufsCapacity = size; + } + sbuf_init(&buf, 0, outBufs, outBufsLen); + pack_out_bufs(&buf, args + REMOTE_SCALARS_INBUFS(sc), + REMOTE_SCALARS_OUTBUFS(sc)); + result = mod_table_invoke(handle, sc, args); + if (result && is_process_exiting(domain)) + result = AEE_EBADSTATE; // override result as process is exiting + } while (1); +bail: + me->adsp_listener1_handle = INVALID_HANDLE; + RPC_FREEIF(outBufs); + RPC_FREEIF(inBufs); + if (nErr != AEE_SUCCESS) { + if(!is_process_exiting(domain)) { + FARF(ERROR, + "Error 0x%x: %s response with result 0x%x for ctx 0x%x, handle 0x%x, " + "sc 0x%x failed : listener thread exited (errno %s)", + nErr, __func__, result, ctx, handle, sc, strerror(errno)); + } + } + for (i = 0; i < RETRY_WRITE; i++) { + if (AEE_SUCCESS == (nErr = eventfd_write(me->eventfd, event))) { + break; + } + // Sleep for 1 sec before retry writing + sleep(1); + } + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF( + "Error 0x%x : Writing to listener event_fd %d failed (errno %s)", nErr, + me->eventfd, strerror(errno)); + } + dlerror(); +} + +extern int apps_remotectl_skel_invoke(uint32 _sc, remote_arg *_pra); +extern int apps_std_skel_invoke(uint32 _sc, remote_arg *_pra); +extern int apps_mem_skel_invoke(uint32 _sc, remote_arg *_pra); +extern int adspmsgd_apps_skel_invoke(uint32_t _sc, remote_arg *_pra); +extern int fastrpc_set_remote_uthread_params(int domain); + +PL_DEP(mod_table); +PL_DEP(apps_std); + +static void *listener_start_thread(void *arg) { + int nErr = AEE_SUCCESS; + struct listener *me = (struct listener *)arg; + int domain = me->domain; + remote_handle64 adsp_listener1_handle = INVALID_HANDLE; + + /* + * Need to set TLS key of listener thread to right domain. + * Otherwise, the init2() call will go to default domain. + */ + set_thread_context(domain); + adsp_listener1_handle = get_adsp_listener1_handle(domain); + nErr = __QAIC_HEADER(adsp_listener1_init2)(adsp_listener1_handle); + if (nErr) { + FARF(ERROR, "Error 0x%x: %s domains support not available in listener", + nErr, __func__); + fastrpc_update_module_list(DOMAIN_LIST_DEQUEUE, domain, adsp_listener1_handle, NULL); + VERIFY(AEE_SUCCESS == (nErr = __QAIC_HEADER(adsp_listener_init2)())); + } else { + me->adsp_listener1_handle = adsp_listener1_handle; + } + + if (me->update_requested) { + /* Update parameters on DSP and signal main thread to proceed */ + me->params_updated = fastrpc_set_remote_uthread_params(domain); + sem_post(me->r_sem); + VERIFY(AEE_SUCCESS == (nErr = me->params_updated)); + } + listener(me); +bail: + me->adsp_listener1_handle = INVALID_HANDLE; + if (nErr != AEE_SUCCESS) { + sem_post(me->r_sem); + VERIFY_EPRINTF("Error 0x%x: %s failed for domain %d\n", nErr, __func__, + domain); + } + return (void *)(uintptr_t)nErr; +} + +void listener_android_deinit(void) { + PL_DEINIT(mod_table); + PL_DEINIT(apps_std); +} + +int listener_android_init(void) { + int nErr = 0; + int i; + + // initializing all event fd's + for (i = 0; i < NUM_DOMAINS_EXTEND; i++) + linfo[i].eventfd = -1; + + VERIFY(AEE_SUCCESS == (nErr = PL_INIT(mod_table))); + VERIFY(AEE_SUCCESS == (nErr = PL_INIT(apps_std))); + VERIFY(AEE_SUCCESS == (nErr = mod_table_register_const_handle( + 0, "apps_remotectl", apps_remotectl_skel_invoke))); + VERIFY(AEE_SUCCESS == + (nErr = mod_table_register_static("apps_std", apps_std_skel_invoke))); + VERIFY(AEE_SUCCESS == + (nErr = mod_table_register_static("apps_mem", apps_mem_skel_invoke))); + VERIFY(AEE_SUCCESS == (nErr = mod_table_register_static( + "adspmsgd_apps", adspmsgd_apps_skel_invoke))); +bail: + if (nErr != AEE_SUCCESS) { + listener_android_deinit(); + VERIFY_EPRINTF("Error %x: fastrpc listener initialization error", nErr); + } + return nErr; +} + +void listener_android_domain_deinit(int domain) { + struct listener *me = &linfo[domain]; + + FARF(RUNTIME_RPC_HIGH, "fastrpc listener joining to exit"); + if (me->thread) { + pthread_join(me->thread, 0); + me->thread = 0; + } + FARF(RUNTIME_RPC_HIGH, "fastrpc listener joined"); + me->adsp_listener1_handle = INVALID_HANDLE; + if (me->eventfd != -1) { + close(me->eventfd); + FARF(RUNTIME_RPC_HIGH, "Closed Listener event_fd %d for domain %d\n", + me->eventfd, domain); + me->eventfd = -1; + } +} + +int listener_android_domain_init(int domain, int update_requested, + sem_t *r_sem) { + struct listener *me = &linfo[domain]; + int nErr = AEE_SUCCESS; + + VERIFYC(-1 != (me->eventfd = eventfd(0, 0)), AEE_EBADPARM); + FARF(RUNTIME_RPC_HIGH, "Opened Listener event_fd %d for domain %d\n", + me->eventfd, domain); + me->update_requested = update_requested; + me->r_sem = r_sem; + me->adsp_listener1_handle = INVALID_HANDLE; + me->domain = domain; + VERIFY(AEE_SUCCESS == + (nErr = pthread_create(&me->thread, 0, listener_start_thread, + (void *)me))); + + if (me->update_requested) { + /* + * Semaphore initialized to 0. If main thread reaches wait first, + * then it will wait for listener to increment semaphore to 1. + * If listener posted semaphore first, then this wait will decrement + * semaphore to 0 and proceed. + */ + sem_wait(me->r_sem); + VERIFY(AEE_SUCCESS == (nErr = me->params_updated)); + } + +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error 0x%x: %s failed for domain %d\n", nErr, __func__, + domain); + listener_android_domain_deinit(domain); + } + return nErr; +} + +int close_reverse_handle(remote_handle64 h, char *dlerr, int dlerrorLen, + int *dlErr) { + return apps_remotectl_close((uint32)h, dlerr, dlerrorLen, dlErr); +} + +int listener_android_geteventfd(int domain, int *fd) { + struct listener *me = &linfo[domain]; + int nErr = 0; + + VERIFYC(-1 != me->eventfd, AEE_EBADPARM); + *fd = me->eventfd; +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: listener android getevent file descriptor failed " + "for domain %d\n", + nErr, domain); + } + return nErr; +} + +PL_DEFINE(listener_android, listener_android_init, listener_android_deinit) diff --git a/src/log_config.c b/src/log_config.c new file mode 100644 index 0000000..4ea451e --- /dev/null +++ b/src/log_config.c @@ -0,0 +1,731 @@ +// 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 + +#ifndef VERIFY_PRINT_ERROR_ALWAYS +#define VERIFY_PRINT_ERROR_ALWAYS +#endif // VERIFY_PRINT_ERROR_ALWAYS + +#ifndef VERIFY_PRINT_WARN +#define VERIFY_PRINT_WARN +#endif // VERIFY_PRINT_WARN + +#define FARF_ERROR 1 + +#include "AEEStdErr.h" +#include "AEEstd.h" +#include "HAP_farf.h" +#include "adsp_current_process.h" +#include "adsp_current_process1.h" +#include "adspmsgd_adsp.h" +#include "adspmsgd_adsp1.h" +#include "adspmsgd_internal.h" +#include "apps_std_internal.h" +#include "fastrpc_common.h" +#include "fastrpc_internal.h" +#include "rpcmem.h" +#include "verify.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define EVENT_SIZE (sizeof(struct inotify_event)) +#define EVENT_BUF_LEN (1024 * (EVENT_SIZE + 16)) +#ifndef AEE_EUNSUPPORTED +#define AEE_EUNSUPPORTED 20 // API is not supported 50 +#endif +#define DEFAULT_ADSPMSGD_MEMORY_SIZE 8192 +#define INVALID_HANDLE (remote_handle64)(-1) +#define ERRNO (errno == 0 ? -1 : errno) +#define ADSPMSGD_FILTER \ + 0x1f001f // Filter passed to adspmsgd init API to push DSP messages to logcat + +#define MAX_FARF_FILE_SIZE (511) + +/* + * Depending on the operating system, the default DSP_SEARCH_PATH gets fetched. + * e.g:- _WIN32 : DSP_SEARCH_PATH=";c:\\Program + * Files\\Qualcomm\\RFSA\\aDSP;"; LE_ENABLE : + * DSP_SEARCH_PATH=";/usr/lib/rfsa/adsp;/dsp;"; This is the maximum possible + * length of the DSP_SEARCH_PATH. + */ +#define ENV_PATH_LEN 256 + +struct log_config_watcher_params { + int fd; + int event_fd; // Duplicate fd to quit the poll + _cstring1_t *paths; + int *wd; + uint32 numPaths; + pthread_attr_t attr; + pthread_t thread; + unsigned char stopThread; + int asidToWatch; + char *fileToWatch; + char *asidFileToWatch; + char *pidFileToWatch; + boolean adspmsgdEnabled; + boolean file_watcher_init_flag; +}; + +static struct log_config_watcher_params log_config_watcher[NUM_DOMAINS_EXTEND]; +extern const char *__progname; +void set_runtime_logmask(uint32_t); + +const char *get_domain_str(int domain); + +static int parseLogConfig(int dom, unsigned int mask, char *filenames) { + _cstring1_t *filesToLog = NULL; + int filesToLogLen = 0; + char *tempFiles = NULL; + int nErr = AEE_SUCCESS; + char *saveptr = NULL; + char *path = NULL; + char delim[] = {','}; + int maxPathLen = 0; + int i = 0; + remote_handle64 handle; + + VERIFYC(filenames != NULL, AEE_ERPC); + + VERIFYC(NULL != + (tempFiles = malloc(sizeof(char) * (std_strlen(filenames) + 1))), + AEE_ENOMEMORY); + std_strlcpy(tempFiles, filenames, std_strlen(filenames) + 1); + + // Get the number of folders and max size needed + path = strtok_r(tempFiles, delim, &saveptr); + while (path != NULL) { + maxPathLen = STD_MAX(maxPathLen, (int)std_strlen(path)) + 1; + filesToLogLen++; + path = strtok_r(NULL, delim, &saveptr); + } + + VERIFY_IPRINTF("%s: #files: %d max_len: %d\n", + log_config_watcher[dom].fileToWatch, filesToLogLen, + maxPathLen); + + // Allocate memory + VERIFYC(NULL != (filesToLog = malloc(sizeof(_cstring1_t) * filesToLogLen)), + AEE_ENOMEMORY); + for (i = 0; i < filesToLogLen; ++i) { + VERIFYC(NULL != (filesToLog[i].data = malloc(sizeof(char) * maxPathLen)), + AEE_ENOMEMORY); + filesToLog[i].dataLen = maxPathLen; + } + + // Get the number of folders and max size needed + std_strlcpy(tempFiles, filenames, std_strlen(filenames) + 1); + i = 0; + path = strtok_r(tempFiles, delim, &saveptr); + while (path != NULL) { + VERIFYC((filesToLog != NULL) && (filesToLog[i].data != NULL) && + filesToLog[i].dataLen >= (int)strlen(path), + AEE_ERPC); + std_strlcpy(filesToLog[i].data, path, filesToLog[i].dataLen); + VERIFY_IPRINTF("%s: %s\n", log_config_watcher[dom].fileToWatch, + filesToLog[i].data); + path = strtok_r(NULL, delim, &saveptr); + i++; + } + + handle = get_adsp_current_process1_handle(dom); + if (handle != INVALID_HANDLE) { + if (AEE_SUCCESS != (nErr = adsp_current_process1_set_logging_params2( + handle, mask, filesToLog, filesToLogLen))) { + VERIFY(AEE_SUCCESS == (nErr = adsp_current_process1_set_logging_params( + handle, mask, filesToLog, filesToLogLen))); + } + } else { + if (AEE_SUCCESS != (nErr = adsp_current_process_set_logging_params2( + mask, filesToLog, filesToLogLen))) { + VERIFY(AEE_SUCCESS == (nErr = adsp_current_process_set_logging_params( + mask, filesToLog, filesToLogLen))); + } + } + +bail: + if (filesToLog) { + for (i = 0; i < filesToLogLen; ++i) { + if (filesToLog[i].data != NULL) { + free(filesToLog[i].data); + filesToLog[i].data = NULL; + } + } + free(filesToLog); + filesToLog = NULL; + } + + if (tempFiles) { + free(tempFiles); + tempFiles = NULL; + } + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error 0x%x: parse log config failed. domain %d, mask %x, " + "filename %s\n", + nErr, dom, mask, filenames); + } + return nErr; +} + +// Read log config given the filename +static int readLogConfigFromPath(int dom, const char *base, const char *file) { + int nErr = 0; + apps_std_FILE fp = -1; + uint64 len; + byte *buf = NULL; + int readlen = 0, eof; + unsigned int mask = 0; + char *path = NULL; + char *filenames = NULL; + boolean fileExists = FALSE; + int buf_addr = 0; + remote_handle64 handle; + uint64_t farf_logmask = 0; + + len = std_snprintf(0, 0, "%s/%s", base, file) + 1; + VERIFYC(NULL != (path = malloc(sizeof(char) * len)), AEE_ENOMEMORY); + std_snprintf(path, (int)len, "%s/%s", base, file); + VERIFY(AEE_SUCCESS == (nErr = apps_std_fileExists(path, &fileExists))); + if (fileExists == FALSE) { + FARF(RUNTIME_RPC_HIGH, "%s: Couldn't find file: %s\n", + log_config_watcher[dom].fileToWatch, path); + nErr = AEE_ENOSUCHFILE; + goto bail; + } + if (log_config_watcher[dom].adspmsgdEnabled == FALSE) { + handle = get_adspmsgd_adsp1_handle(dom); + if (handle != INVALID_HANDLE) { + if ((nErr = adspmsgd_init(handle, ADSPMSGD_FILTER)) == + (int)(AEE_EUNSUPPORTED + DSP_AEE_EOFFSET)) + adspmsgd_adsp1_init2(handle); + } else if ((nErr = adspmsgd_adsp_init2()) == + (int)(AEE_EUNSUPPORTED + DSP_AEE_EOFFSET)) { + nErr = adspmsgd_adsp_init(0, RPCMEM_HEAP_DEFAULT, 0, + DEFAULT_ADSPMSGD_MEMORY_SIZE, &buf_addr); + } + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("adspmsgd not supported. nErr=%x\n", nErr); + } else { + log_config_watcher[dom].adspmsgdEnabled = TRUE; + } + VERIFY_EPRINTF("Found %s. adspmsgd enabled \n", + log_config_watcher[dom].fileToWatch); + } + + VERIFY(AEE_SUCCESS == (nErr = apps_std_fopen(path, "r", &fp))); + VERIFY(AEE_SUCCESS == (nErr = apps_std_flen(fp, &len))); + + VERIFYM(len <= MAX_FARF_FILE_SIZE, AEE_ERPC, + "len greater than %d for path %s (%s)\n", nErr, MAX_FARF_FILE_SIZE, + path, strerror(ERRNO)); + VERIFYC(NULL != (buf = calloc(1, sizeof(byte) * (len + 1))), + AEE_ENOMEMORY); // extra 1 byte for null character + VERIFYC(NULL != (filenames = malloc(sizeof(byte) * len)), AEE_ENOMEMORY); + VERIFY(AEE_SUCCESS == (nErr = apps_std_fread(fp, buf, len, &readlen, &eof))); + VERIFYC((int)len == readlen, AEE_ERPC); + + FARF(RUNTIME_RPC_HIGH, "%s: Config file %s contents: %s\n", + log_config_watcher[dom].fileToWatch, path, buf); + + // Parse farf file to get logmasks. + len = sscanf((const char *)buf, "0x%lx %511s", &farf_logmask, filenames); + + if (farf_logmask == LLONG_MAX || farf_logmask == (uint64_t)LLONG_MIN || + farf_logmask == 0) { + VERIFY_EPRINTF("Error : Invalid FARF logmask!"); + } + /* + * Parsing logmask to get userspace and kernel space masks. + * Example: For farf_logmask = 0x001f001f001f001f, this enables all Runtime + * levels + * + * i.e.: 0x 001f001f 001f001f + * |__________| |__________| + * Userspace DSP space + */ + mask = farf_logmask & 0xffffffff; + set_runtime_logmask(farf_logmask >> 32); + switch (len) { + case 1: + FARF(RUNTIME_RPC_HIGH, "%s: Setting log mask:0x%x", + log_config_watcher[dom].fileToWatch, mask); + handle = get_adsp_current_process1_handle(dom); + if (handle != INVALID_HANDLE) { + if (AEE_SUCCESS != (nErr = adsp_current_process1_set_logging_params2( + handle, mask, NULL, 0))) { + VERIFY(AEE_SUCCESS == (nErr = adsp_current_process1_set_logging_params( + handle, mask, NULL, 0))); + } + } else { + if (AEE_SUCCESS != + (nErr = adsp_current_process_set_logging_params2(mask, NULL, 0))) { + VERIFY(AEE_SUCCESS == + (nErr = adsp_current_process_set_logging_params(mask, NULL, 0))); + } + } + break; + case 2: + VERIFY(AEE_SUCCESS == (nErr = parseLogConfig(dom, mask, filenames))); + FARF(RUNTIME_RPC_HIGH, "%s: Setting log mask:0x%x, filename:%s", + log_config_watcher[dom].fileToWatch, mask, filenames); + break; + default: + VERIFY_EPRINTF("Error : %s: No valid data found in config file %s", + log_config_watcher[dom].fileToWatch, path); + nErr = AEE_EUNSUPPORTED; + goto bail; + } + +bail: + if (buf != NULL) { + free(buf); + buf = NULL; + } + + if (filenames != NULL) { + free(filenames); + filenames = NULL; + } + + if (fp != -1) { + apps_std_fclose(fp); + } + + if (path != NULL) { + free(path); + path = NULL; + } + + if (nErr != AEE_SUCCESS && nErr != AEE_ENOSUCHFILE) { + VERIFY_EPRINTF("Error 0x%x: fopen failed for %s/%s. (%s)\n", nErr, base, + file, strerror(ERRNO)); + } + return nErr; +} + +// Read log config given the watch descriptor +static int readLogConfigFromEvent(int dom, struct inotify_event *event) { + int i = 0; + + // Ensure we are looking at the right file + for (i = 0; i < (int)log_config_watcher[dom].numPaths; ++i) { + if (log_config_watcher[dom].wd[i] == event->wd) { + if (std_strcmp(log_config_watcher[dom].fileToWatch, event->name) == 0) { + return readLogConfigFromPath(dom, log_config_watcher[dom].paths[i].data, + log_config_watcher[dom].fileToWatch); + } else if (std_strcmp(log_config_watcher[dom].asidFileToWatch, + event->name) == 0) { + return readLogConfigFromPath(dom, log_config_watcher[dom].paths[i].data, + log_config_watcher[dom].asidFileToWatch); + } else if (std_strcmp(log_config_watcher[dom].pidFileToWatch, + event->name) == 0) { + return readLogConfigFromPath(dom, log_config_watcher[dom].paths[i].data, + log_config_watcher[dom].pidFileToWatch); + } + } + } + VERIFY_IPRINTF("%s: Watch descriptor %d not valid for current process", + log_config_watcher[dom].fileToWatch, event->wd); + return AEE_SUCCESS; +} + +// Read log config given the watch descriptor +static int resetLogConfigFromEvent(int dom, struct inotify_event *event) { + int i = 0; + remote_handle64 handle; + + // Ensure we are looking at the right file + for (i = 0; i < (int)log_config_watcher[dom].numPaths; ++i) { + if (log_config_watcher[dom].wd[i] == event->wd) { + if ((std_strcmp(log_config_watcher[dom].fileToWatch, event->name) == 0) || + (std_strcmp(log_config_watcher[dom].asidFileToWatch, event->name) == + 0) || + (std_strcmp(log_config_watcher[dom].pidFileToWatch, event->name) == + 0)) { + if (log_config_watcher[dom].adspmsgdEnabled == TRUE) { + adspmsgd_stop(dom); + log_config_watcher[dom].adspmsgdEnabled = FALSE; + handle = get_adspmsgd_adsp1_handle(dom); + if (handle != INVALID_HANDLE) { + adspmsgd_adsp1_deinit(handle); + } else { + adspmsgd_adsp_deinit(); + } + } + handle = get_adsp_current_process1_handle(dom); + if (handle != INVALID_HANDLE) { + return adsp_current_process1_set_logging_params(handle, 0, NULL, 0); + } else { + return adsp_current_process_set_logging_params(0, NULL, 0); + } + } + } + } + VERIFY_IPRINTF("%s: Watch descriptor %d not valid for current process", + log_config_watcher[dom].fileToWatch, event->wd); + return AEE_SUCCESS; +} + +static void *file_watcher_thread(void *arg) { + int dom = (int)(uintptr_t)arg; + int ret = 0, current_errno = 0, env_list_len = 0; + int length = 0; + int nErr = AEE_SUCCESS; + int i = 0; + char buffer[EVENT_BUF_LEN]; + struct pollfd pfd[] = {{log_config_watcher[dom].fd, POLLIN, 0}, + {log_config_watcher[dom].event_fd, POLLIN, 0}}; + const char *fileExtension = ".farf"; + int len = 0; + remote_handle64 handle; + int file_found = 0; + char *data_paths = NULL; + + FARF(ALWAYS, "%s starting for domain %d\n", __func__, dom); + // Check for the presence of the .farf file at bootup + for (i = 0; i < (int)log_config_watcher[dom].numPaths; ++i) { + if (0 == readLogConfigFromPath(dom, log_config_watcher[dom].paths[i].data, + log_config_watcher[dom].fileToWatch)) { + file_found = 1; + VERIFY_IPRINTF("%s: Log config File %s found.\n", + log_config_watcher[dom].fileToWatch, + log_config_watcher[dom].paths[i].data); + break; + } + } + if (!file_found) { + // Allocate single buffer for all the paths. + data_paths = calloc(1, sizeof(char) * ENV_PATH_LEN); + if (data_paths) { + current_errno = errno; + // Get DSP_LIBRARY_PATH env variable path set by the user. + ret = apps_std_getenv(DSP_LIBRARY_PATH, data_paths, ENV_PATH_LEN, + &env_list_len); + errno = current_errno; + // User has not set the env variable. Get default search paths. + if (ret != 0) + std_memmove(data_paths, DSP_SEARCH_PATH, std_strlen(DSP_SEARCH_PATH)); + VERIFY_WPRINTF("%s: Couldn't find file %s, errno (%s) at %s\n", __func__, + log_config_watcher[dom].fileToWatch, strerror(errno), + data_paths); + } else { + VERIFY_WPRINTF( + "%s: Calloc failed for %d bytes. Couldn't find file %s, errno (%s)\n", + __func__, ENV_PATH_LEN, log_config_watcher[dom].fileToWatch, + strerror(errno)); + } + } + + while (log_config_watcher[dom].stopThread == 0) { + // Block forever + ret = poll(pfd, 2, -1); + if (ret < 0) { + VERIFY_EPRINTF("Error : %s: Error polling for file change. Runtime FARF " + "will not work for this process. errno=%x !", + log_config_watcher[dom].fileToWatch, errno); + break; + } else if (pfd[1].revents & POLLIN) { // Check for exit + VERIFY_WPRINTF("Warning: %s received exit for domain %d, file %s\n", + __func__, dom, log_config_watcher[dom].fileToWatch); + break; + } else { + length = read(log_config_watcher[dom].fd, buffer, EVENT_BUF_LEN); + i = 0; + while (i < length) { + struct inotify_event *event = (struct inotify_event *)&buffer[i]; + if (event->len) { + // Get the asiD for the current process + // Do it once only + if (log_config_watcher[dom].asidToWatch == -1) { + handle = get_adsp_current_process1_handle(dom); + if (handle != INVALID_HANDLE) { + VERIFY( + AEE_SUCCESS == + (nErr = adsp_current_process1_getASID( + handle, + (unsigned int *)&log_config_watcher[dom].asidToWatch))); + } else { + VERIFY( + AEE_SUCCESS == + (nErr = adsp_current_process_getASID( + (unsigned int *)&log_config_watcher[dom].asidToWatch))); + } + len = strlen(fileExtension) + strlen(__TOSTR__(INT_MAX)); + VERIFYC(NULL != (log_config_watcher[dom].asidFileToWatch = + malloc(sizeof(char) * len)), + AEE_ENOMEMORY); + snprintf(log_config_watcher[dom].asidFileToWatch, len, "%d%s", + log_config_watcher[dom].asidToWatch, fileExtension); + VERIFY_IPRINTF("%s: Watching ASID file %s\n", + log_config_watcher[dom].fileToWatch, + log_config_watcher[dom].asidFileToWatch); + } + + VERIFY_IPRINTF("%s: %s %d.\n", log_config_watcher[dom].fileToWatch, + event->name, event->mask); + if ((event->mask & IN_CREATE) || (event->mask & IN_MODIFY)) { + VERIFY_IPRINTF("%s: File %s created.\n", + log_config_watcher[dom].fileToWatch, event->name); + if (0 != readLogConfigFromEvent(dom, event)) { + VERIFY_EPRINTF("Error : %s: Error reading config file %s", + log_config_watcher[dom].fileToWatch, + log_config_watcher[dom].paths[i].data); + } + } else if (event->mask & IN_DELETE) { + VERIFY_IPRINTF("%s: File %s deleted.\n", + log_config_watcher[dom].fileToWatch, event->name); + if (0 != resetLogConfigFromEvent(dom, event)) { + VERIFY_EPRINTF( + "Error : %s: Error resetting FARF runtime log config", + log_config_watcher[dom].fileToWatch); + } + } + } + + i += EVENT_SIZE + event->len; + } + } + } +bail: + if (data_paths) { + free(data_paths); + data_paths = NULL; + } + + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error 0x%x: %s exited. Runtime FARF will not work for this " + "process. filename %s (errno %s)\n", + nErr, __func__, log_config_watcher[dom].fileToWatch, + strerror(errno)); + } else { + FARF(ALWAYS, "%s exiting for domain %d\n", __func__, dom); + } + return NULL; +} + +void deinitFileWatcher(int dom) { + int i = 0; + uint64 stop = 10; + remote_handle64 handle; + ssize_t sz = 0; + + if (log_config_watcher[dom].file_watcher_init_flag) { + log_config_watcher[dom].stopThread = 1; + if (0 <= log_config_watcher[dom].event_fd) { + for (i = 0; i < RETRY_WRITE; i++) { + VERIFY_IPRINTF( + "Writing to file_watcher_thread event_fd %d for domain %d\n", + log_config_watcher[dom].event_fd, dom); + sz = write(log_config_watcher[dom].event_fd, &stop, sizeof(uint64)); + if ((sz < (ssize_t)sizeof(uint64)) || (sz == -1 && errno == EAGAIN)) { + VERIFY_WPRINTF("Warning: Written %zd bytes on event_fd %d for domain " + "%d (errno = %s): Retrying ...\n", + sz, log_config_watcher[dom].event_fd, dom, + strerror(errno)); + continue; + } else { + break; + } + } + } + if (sz != sizeof(uint64) && 0 <= log_config_watcher[dom].event_fd) { + VERIFY_EPRINTF("Error: Written %zd bytes on event_fd %d for domain %d: " + "Cannot set exit flag to watcher thread (errno = %s)\n", + sz, log_config_watcher[dom].event_fd, dom, + strerror(errno)); + // When deinitFileWatcher fail to write dupfd, file watcher thread hangs + // on poll. Abort in this case. + raise(SIGABRT); + } + } + if (log_config_watcher[dom].thread) { + pthread_join(log_config_watcher[dom].thread, NULL); + log_config_watcher[dom].thread = 0; + } + if (log_config_watcher[dom].fileToWatch) { + free(log_config_watcher[dom].fileToWatch); + log_config_watcher[dom].fileToWatch = 0; + } + if (log_config_watcher[dom].asidFileToWatch) { + free(log_config_watcher[dom].asidFileToWatch); + log_config_watcher[dom].asidFileToWatch = 0; + } + if (log_config_watcher[dom].pidFileToWatch) { + free(log_config_watcher[dom].pidFileToWatch); + log_config_watcher[dom].pidFileToWatch = 0; + } + if (log_config_watcher[dom].wd) { + for (i = 0; i < (int)log_config_watcher[dom].numPaths; ++i) { + // On success, inotify_add_watch() returns a nonnegative integer watch + // descriptor + if (log_config_watcher[dom].wd[i] >= 0) { + inotify_rm_watch(log_config_watcher[dom].fd, + log_config_watcher[dom].wd[i]); + } + } + free(log_config_watcher[dom].wd); + log_config_watcher[dom].wd = NULL; + } + if (log_config_watcher[dom].paths) { + for (i = 0; i < (int)log_config_watcher[dom].numPaths; ++i) { + if (log_config_watcher[dom].paths[i].data) { + free(log_config_watcher[dom].paths[i].data); + log_config_watcher[dom].paths[i].data = NULL; + } + } + free(log_config_watcher[dom].paths); + log_config_watcher[dom].paths = NULL; + } + if (log_config_watcher[dom].fd != 0) { + close(log_config_watcher[dom].fd); + VERIFY_IPRINTF("Closed file watcher fd %d for domain %d\n", + log_config_watcher[dom].fd, dom); + log_config_watcher[dom].fd = 0; + } + if (log_config_watcher[dom].adspmsgdEnabled == TRUE) { + adspmsgd_stop(dom); + handle = get_adspmsgd_adsp1_handle(dom); + if (handle != INVALID_HANDLE) { + adspmsgd_adsp1_deinit(handle); + } else { + adspmsgd_adsp_deinit(); + } + log_config_watcher[dom].adspmsgdEnabled = FALSE; + } + if (log_config_watcher[dom].file_watcher_init_flag && + (log_config_watcher[dom].event_fd != -1)) { + close(log_config_watcher[dom].event_fd); + VERIFY_IPRINTF("Closed file watcher eventfd %d for domain %d\n", + log_config_watcher[dom].event_fd, dom); + log_config_watcher[dom].event_fd = -1; + } + log_config_watcher[dom].file_watcher_init_flag = FALSE; + log_config_watcher[dom].numPaths = 0; +} + +int initFileWatcher(int dom) { + int nErr = AEE_SUCCESS; + const char *fileExtension = ".farf"; + uint32 len = 0; + uint16 maxPathLen = 0; + int i = 0; + char *name = NULL; + + memset(&log_config_watcher[dom], 0, sizeof(struct log_config_watcher_params)); + log_config_watcher[dom].asidToWatch = 0; + log_config_watcher[dom].event_fd = -1; + + VERIFYC(NULL != (name = std_basename(__progname)), AEE_EBADPARM); + + len = strlen(name) + strlen(fileExtension) + 1; + VERIFYC(NULL != (log_config_watcher[dom].fileToWatch = + malloc(sizeof(char) * len)), + AEE_ENOMEMORY); + snprintf(log_config_watcher[dom].fileToWatch, len, "%s%s", name, + fileExtension); + + len = strlen(fileExtension) + strlen(__TOSTR__(INT_MAX)); + VERIFYC(NULL != (log_config_watcher[dom].pidFileToWatch = + malloc(sizeof(char) * len)), + AEE_ENOMEMORY); + snprintf(log_config_watcher[dom].pidFileToWatch, len, "%d%s", getpid(), + fileExtension); + + VERIFY_IPRINTF("%s: Watching PID file: %s\n", + log_config_watcher[dom].fileToWatch, + log_config_watcher[dom].pidFileToWatch); + + log_config_watcher[dom].fd = inotify_init(); + if (log_config_watcher[dom].fd < 0) { + nErr = AEE_ERPC; + VERIFY_EPRINTF("Error 0x%x: inotify_init failed, invalid fd errno = %s\n", + nErr, strerror(errno)); + goto bail; + } + + // Duplicate the fd, so we can use it to quit polling + log_config_watcher[dom].event_fd = eventfd(0, 0); + if (log_config_watcher[dom].event_fd < 0) { + nErr = AEE_ERPC; + VERIFY_EPRINTF("Error 0x%x: eventfd in dup failed, invalid fd errno %s\n", + nErr, strerror(errno)); + goto bail; + } + log_config_watcher[dom].file_watcher_init_flag = TRUE; + VERIFY_IPRINTF("Opened file watcher fd %d eventfd %d for domain %d\n", + log_config_watcher[dom].fd, log_config_watcher[dom].event_fd, + dom); + + // Get the required size + apps_std_get_search_paths_with_env(ADSP_LIBRARY_PATH, ";", NULL, 0, + &log_config_watcher[dom].numPaths, + &maxPathLen); + + maxPathLen += +1; + + // Allocate memory + VERIFYC(NULL != (log_config_watcher[dom].paths = malloc( + sizeof(_cstring1_t) * log_config_watcher[dom].numPaths)), + AEE_ENOMEMORY); + VERIFYC(NULL != (log_config_watcher[dom].wd = + malloc(sizeof(int) * log_config_watcher[dom].numPaths)), + AEE_ENOMEMORY); + + for (i = 0; i < (int)log_config_watcher[dom].numPaths; ++i) { + VERIFYC(NULL != (log_config_watcher[dom].paths[i].data = + malloc(sizeof(char) * maxPathLen)), + AEE_ENOMEMORY); + log_config_watcher[dom].paths[i].dataLen = maxPathLen; + } + + // Get the paths + VERIFY(AEE_SUCCESS == + (nErr = apps_std_get_search_paths_with_env( + ADSP_LIBRARY_PATH, ";", log_config_watcher[dom].paths, + log_config_watcher[dom].numPaths, &len, &maxPathLen))); + + maxPathLen += 1; + + VERIFY_IPRINTF("%s: Watching folders:\n", + log_config_watcher[dom].fileToWatch); + for (i = 0; i < (int)log_config_watcher[dom].numPaths; ++i) { + // Watch for creation, deletion and modification of files in path + VERIFY_IPRINTF("log file watcher: %s: %s\n", + log_config_watcher[dom].fileToWatch, + log_config_watcher[dom].paths[i].data); + if ((log_config_watcher[dom].wd[i] = inotify_add_watch( + log_config_watcher[dom].fd, log_config_watcher[dom].paths[i].data, + IN_CREATE | IN_DELETE)) < 0) { + VERIFY_EPRINTF( + "Error : Unable to add watcher for folder %s : errno is %s\n", + log_config_watcher[dom].paths[i].data, strerror(ERRNO)); + } + } + + // Create a thread to watch for file changes + log_config_watcher[dom].asidToWatch = -1; + log_config_watcher[dom].stopThread = 0; + pthread_create(&log_config_watcher[dom].thread, NULL, file_watcher_thread, + (void *)(uintptr_t)dom); +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error 0x%x: Failed to register with inotify file %s. " + "Runtime FARF will not work for the process %s! errno %d", + nErr, log_config_watcher[dom].fileToWatch, name, errno); + deinitFileWatcher(dom); + } + + return nErr; +} diff --git a/src/mod_table.c b/src/mod_table.c new file mode 100644 index 0000000..54009ee --- /dev/null +++ b/src/mod_table.c @@ -0,0 +1,1102 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef FARF_ERROR +#define FARF_ERROR 1 +#endif +#define FARF_LOW 1 + +#ifndef VERIFY_PRINT_ERROR_ALWAYS +#define VERIFY_PRINT_ERROR_ALWAYS +#endif // VERIFY_PRINT_ERROR_ALWAYS + +#include "mod_table.h" +#include "AEEStdErr.h" +#include "AEEstd.h" +#include "HAP_farf.h" +#include "HAP_pls.h" +#include "fastrpc_trace.h" +#include "mutex.h" +#include "platform_libs.h" +#include "remote64.h" +#include "sbuf_parser.h" +#include "uthash.h" +#include "verify.h" +#include +#include + +/* + * Handle size needed is about ~250 bytes + * Allocating 256 bytes per handle to avoid misalignment memory access error + * and for cache alignment performance. + */ +#define MAX_REV_HANDLES 20 +#define REV_HANDLE_SIZE 256 +static uint8 rev_handle_table[MAX_REV_HANDLES][REV_HANDLE_SIZE]; +RW_MUTEX_T rev_handle_table_lock; +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#ifdef WINNT +#include +#include +#include + +#define RTLD_NOW 0 + +static __inline HMODULE DLOPEN(LPCSTR name, int mode) { + UNREFERENCED_PARAMETER(mode); + return LoadLibraryExA(name, 0, 0); +} + +static __inline FARPROC DLSYM(LPVOID handle, LPCSTR name) { + return GetProcAddress((HMODULE)handle, name); +} + +static __inline int DLCLOSE(LPVOID handle) { + int nErr = AEE_SUCCESS; + + VERIFYC(0 < FreeLibrary((HMODULE)handle), AEE_EBADPARM); + +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: dlclose failed for %x\n", nErr, handle); + } + return nErr; +} + +static __inline const char *DLERROR(VOID) { + static const char errMsg[] = "dl Error"; + return errMsg; +} +#else +#include + +#define DLOPEN dlopen +#define DLCLOSE dlclose +#define DLSYM dlsym +#define DLERROR dlerror +#endif + +extern int errno; + +/** + * structure for the mod table + * + * you need to define a rw_mutex type and its read/write lock/unlock api's + * which are under the RW_MUTEX namespace. + * + * this library defines 2 functions for opening modules, open_static and + * open_dynamic. Both return a handle that should be closed via close. + * + * you can also register a const handle, an invoke function for a known handle + * value. since handle keys are allocated, you should pick handle values that + * are not going to be returned by malloc (0, or odd). + */ +struct static_mod_table { + RW_MUTEX_T mut; + struct static_mod *staticModOverrides; + struct static_mod *staticMods; + struct const_mod *constMods; + boolean bInit; +}; + +struct open_mod_table { + RW_MUTEX_T mut; + struct open_mod *openMods; + struct static_mod_table *smt; +}; + +typedef int (*invoke_fn)(uint32, remote_arg *); +typedef int (*handle_invoke_fn)(remote_handle64, uint32, remote_arg *); +struct static_mod { + invoke_fn invoke; + handle_invoke_fn handle_invoke; + UT_hash_handle hh; + char uri[1]; +}; + +struct const_mod { + invoke_fn invoke; + handle_invoke_fn handle_invoke; + uint32 key; + remote_handle64 h64; + UT_hash_handle hh; + char uri[1]; +}; + +struct parsed_uri { + const char *file; + const char *sym; + const char *ver; + int filelen; + int symlen; + int verlen; +}; + +struct open_mod { + void *dlhandle; + invoke_fn invoke; + handle_invoke_fn handle_invoke; + uint64 key; + UT_hash_handle hh; + remote_handle64 h64; + struct parsed_uri vals; + int refs; + char uri[1]; +}; + +static int static_mod_table_ctor(struct static_mod_table *me) { + if (me->bInit == 0) { + RW_MUTEX_CTOR(me->mut); + RW_MUTEX_CTOR(rev_handle_table_lock); + me->staticMods = 0; + me->staticModOverrides = 0; + me->bInit = 1; + } + return 0; +} + +static void static_mod_table_dtor_imp(struct static_mod_table *me) { + struct static_mod *sm, *stmp; + struct const_mod *dm, *ftmp; + if (me->bInit != 0) { + if (me->staticMods || me->constMods || me->staticModOverrides) { + RW_MUTEX_LOCK_WRITE(me->mut); + HASH_ITER(hh, me->staticMods, sm, stmp) { + if (me->staticMods) { + HASH_DEL(me->staticMods, sm); + } + free(sm); + sm = NULL; + } + HASH_ITER(hh, me->staticModOverrides, sm, stmp) { + if (me->staticModOverrides) { + HASH_DEL(me->staticModOverrides, sm); + } + free(sm); + sm = NULL; + } + HASH_ITER(hh, me->constMods, dm, ftmp) { + if (me->constMods) { + HASH_DEL(me->constMods, dm); + } + free(dm); + dm = NULL; + } + RW_MUTEX_UNLOCK_WRITE(me->mut); + } + RW_MUTEX_DTOR(me->mut); + RW_MUTEX_DTOR(rev_handle_table_lock); + me->staticMods = 0; + me->staticModOverrides = 0; + me->bInit = 0; + } +} + +static int open_mod_table_ctor_imp(void *ctx, void *data) { + struct open_mod_table *me = (struct open_mod_table *)data; + RW_MUTEX_CTOR(me->mut); + me->openMods = 0; + me->smt = (struct static_mod_table *)ctx; + return 0; +} + +static int open_mod_handle_close(struct open_mod *mod, remote_handle64 h); + +static void open_mod_table_dtor_imp(void *data) { + struct open_mod_table *me = (struct open_mod_table *)data; + struct open_mod *dm, *ftmp; + if (me->openMods) { + RW_MUTEX_LOCK_WRITE(me->mut); + HASH_ITER(hh, me->openMods, dm, ftmp) { + if (me->openMods) { + HASH_DEL(me->openMods, dm); + } + if (dm->h64) { + (void)open_mod_handle_close(dm, dm->h64); + } + if (dm->dlhandle) { + DLCLOSE(dm->dlhandle); + } + FARF(ALWAYS, "%s: closed reverse module %s with handle 0x%x", __func__, + dm->uri, (uint32)dm->key); + dm->key = 0; + } + RW_MUTEX_UNLOCK_WRITE(me->mut); + } + RW_MUTEX_DTOR(me->mut); + me->openMods = 0; +} +static int open_mod_table_open_from_static(struct open_mod_table *me, + struct static_mod **tbl, + const char *uri, + remote_handle *handle); + +static int open_mod_table_open_static_override(struct open_mod_table *me, + const char *uri, + remote_handle *handle) { + FARF(RUNTIME_RPC_HIGH, "open_mod_table_open_static_override"); + return open_mod_table_open_from_static(me, &me->smt->staticModOverrides, uri, + handle); +} + +static int open_mod_table_open_static(struct open_mod_table *me, + const char *uri, remote_handle *handle) { + FARF(RUNTIME_RPC_HIGH, "open_mod_table_open_static"); + return open_mod_table_open_from_static(me, &me->smt->staticMods, uri, handle); +} + +static int static_mod_add(struct static_mod_table *me, struct static_mod **tbl, + const char *uri, + int (*invoke)(uint32 sc, remote_arg *pra), + int (*handle_invoke)(remote_handle64, uint32 sc, + remote_arg *pra)) { + int nErr = AEE_SUCCESS; + struct static_mod *sm = 0; + int len = std_strlen(uri) + 1; + VERIFYC(NULL != (sm = ((struct static_mod *)calloc( + 1, sizeof(struct static_mod) + len))), + AEE_ENOMEMORY); + std_strlcpy(sm->uri, uri, len); + sm->invoke = invoke; + sm->handle_invoke = handle_invoke; + RW_MUTEX_LOCK_WRITE(me->mut); + HASH_ADD_STR(*tbl, uri, sm); + RW_MUTEX_UNLOCK_WRITE(me->mut); +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: static module addition failed\n", nErr); + if (sm) { + free(sm); + sm = NULL; + } + } + return nErr; +} + +static int static_mod_table_register_static_override( + struct static_mod_table *me, const char *uri, + int (*pfn)(uint32 sc, remote_arg *pra)) { + return static_mod_add(me, &me->staticModOverrides, uri, pfn, 0); +} +static int static_mod_table_register_static_override1( + struct static_mod_table *me, const char *uri, + int (*pfn)(remote_handle64, uint32 sc, remote_arg *pra)) { + return static_mod_add(me, &me->staticModOverrides, uri, 0, pfn); +} +static int +static_mod_table_register_static(struct static_mod_table *me, const char *uri, + int (*pfn)(uint32 sc, remote_arg *pra)) { + return static_mod_add(me, &me->staticMods, uri, pfn, 0); +} +static int static_mod_table_register_static1( + struct static_mod_table *me, const char *uri, + int (*pfn)(remote_handle64, uint32 sc, remote_arg *pra)) { + return static_mod_add(me, &me->staticMods, uri, 0, pfn); +} + +static int static_mod_table_register_const_handle( + struct static_mod_table *me, remote_handle local, remote_handle64 remote, + const char *uri, int (*invoke)(uint32 sc, remote_arg *pra), + int (*handle_invoke)(remote_handle64, uint32 sc, remote_arg *pra)) { + int nErr = AEE_SUCCESS; + int len = std_strlen(uri) + 1; + struct const_mod *dm = 0, *dmOld; + VERIFYC(NULL != (dm = ((struct const_mod *)calloc(1, sizeof(struct open_mod) + + len))), + AEE_ENOMEMORY); + dm->key = local; + dm->invoke = invoke; + dm->handle_invoke = handle_invoke; + dm->h64 = remote; + std_strlcpy(dm->uri, uri, len); + + RW_MUTEX_LOCK_WRITE(me->mut); + HASH_FIND_INT(me->constMods, &local, dmOld); + if (dmOld == 0) { + HASH_ADD_INT(me->constMods, key, dm); + } + RW_MUTEX_UNLOCK_WRITE(me->mut); + nErr = dmOld != 0 ? -1 : nErr; +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: failed to register const handle in modtable\n", + nErr); + if (dm) { + free(dm); + dm = NULL; + } + } + return nErr; +} + +static int open_mod_handle_open(struct open_mod *mod, const char *name, + remote_handle64 *ph) { + int nErr = AEE_SUCCESS; + remote_arg args[3] = {0}; + int32_t len = strlen(name) + 1; + args[0].buf.pv = &len; + args[0].buf.nLen = sizeof(len); + args[1].buf.pv = (void *)name; + args[1].buf.nLen = len; + nErr = mod->handle_invoke(0, REMOTE_SCALARS_MAKEX(0, 0, 2, 0, 0, 1), args); + if (!nErr) { + *ph = args[2].h64; + } + FARF(RUNTIME_RPC_HIGH, "allocated %x", *ph); + return nErr; +} + +static int open_mod_handle_close(struct open_mod *mod, remote_handle64 h) { + int nErr; + remote_arg args[1] = {0}; + args[0].h64 = h; + FARF(RUNTIME_RPC_HIGH, "releasing %x", h); + nErr = mod->handle_invoke(0, REMOTE_SCALARS_MAKEX(0, 1, 0, 0, 1, 0), args); + return nErr; +} + +static int notqmark(struct sbuf *buf) { return sbuf_notchar(buf, '?'); } +static int notandoreq(struct sbuf *buf) { return sbuf_notchars(buf, "&="); } +static int notand(struct sbuf *buf) { return sbuf_notchar(buf, '&'); } + +static int parse_uri(const char *uri, int urilen, struct parsed_uri *out) { + // "file:///librhtest_skel.so?rhtest_skel_handle_invoke&_modver=1.0" + int nErr = 0; + char *name, *value; + int nameLen, valueLen; + struct sbuf buf; + FARF(RUNTIME_RPC_HIGH, "parse_uri %s %d", uri, urilen); + memset(out, 0, sizeof(*out)); + // initialize + sbuf_parser_init(&buf, uri, urilen); + + // parse until question mark + VERIFYC(sbuf_string(&buf, "file://"), AEE_EBADPARM); + + // ignore the starting / + (void)sbuf_string(&buf, "/"); + + out->file = sbuf_cur(&buf); + VERIFY(sbuf_many1(&buf, notqmark)); + out->filelen = sbuf_cur(&buf) - out->file; + FARF(RUNTIME_RPC_HIGH, "file:%.*s %d", out->filelen, out->file, out->filelen); + VERIFY(sbuf_char(&buf, '?')); + out->sym = sbuf_cur(&buf); + VERIFY(sbuf_many1(&buf, notand)); + out->symlen = sbuf_cur(&buf) - out->sym; + assert(out->sym + out->symlen <= uri + urilen); + FARF(RUNTIME_RPC_HIGH, "sym:%.*s %d", out->symlen, out->sym, out->symlen); + + if (!sbuf_end(&buf) && sbuf_char(&buf, '&')) { + // parse each query + while (!sbuf_end(&buf)) { + // record where the name starts + name = sbuf_cur(&buf); + + // name is valid until '=' or '&' + VERIFY(sbuf_many1(&buf, notandoreq)); + nameLen = sbuf_cur(&buf) - name; + + value = 0; + valueLen = 0; + // if the next char is a '=' then we also get a value + if (sbuf_char(&buf, '=')) { + value = sbuf_cur(&buf); + + // value is until the next query that starts with '&' + VERIFY(sbuf_many1(&buf, notand)); + valueLen = sbuf_cur(&buf) - value; + } + // expect '&' or end + sbuf_char(&buf, '&'); + if (!std_strncmp(name, "_modver", nameLen)) { + out->ver = value; + out->verlen = valueLen; + } + } + } +bail: + if (out->filelen) { + FARF(RUNTIME_RPC_HIGH, "parse_uri file: %.*s", out->filelen, out->file); + } + if (out->symlen) { + FARF(RUNTIME_RPC_HIGH, "parse_uri sym: %.*s", out->symlen, out->sym); + } + if (out->verlen) { + FARF(RUNTIME_RPC_HIGH, "parse_uri version: %.*s", out->verlen, out->ver); + } + FARF(RUNTIME_RPC_HIGH, "parse_uri done: %s %d err:%x", uri, urilen, nErr); + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: parseuri failed for uri %s, urilen %d\n", nErr, + uri, urilen); + } + return nErr; +} + +/* + * Iterate through the list of reverse handles and search for the next available + * handle. 'key' is only set when handle have been taken and is set to 0 when + * handle is free. Returns 0 if it found a free handle, otherwise return -1 if + * it fails. + */ +static inline int next_available_rev_handle(uint32 *handle_idx) { + int nErr = AEE_EUNKNOWN; + struct open_mod *dm = 0; + unsigned int ii; + + for (ii = 0; ii < MAX_REV_HANDLES; ++ii) { + dm = (struct open_mod *)&(rev_handle_table[ii][0]); + if (dm->key == 0) { + *handle_idx = ii; + nErr = 0; + break; + } + } + if (nErr) + FARF(ERROR, + "Error 0x%x: %s: max number of reverse RPC handles (%u) open already", + nErr, __func__, MAX_REV_HANDLES); + return nErr; +} + +uint32 is_reverse_handle_opened(struct open_mod_table *me, + remote_handle *handle, const char *uri) { + int ii = 0; + uint32 keyfound = 0; + struct open_mod *dmOld; + RW_MUTEX_LOCK_WRITE(me->mut); + for (ii = 0; ii < MAX_REV_HANDLES; ++ii) { + dmOld = (struct open_mod *)&(rev_handle_table[ii][0]); + if (dmOld->key != 0) { + if (!std_strncmp(dmOld->uri, uri, MAX(strlen(dmOld->uri), strlen(uri)))) { + keyfound = 1; + break; + } + } + } + if (keyfound) { + *handle = dmOld->key; + dmOld->refs++; + FARF( + ALWAYS, + "%s: reverse module %s already found with handle 0x%x (idx %u) refs %d", + __func__, uri, *handle, ii, dmOld->refs); + } + RW_MUTEX_UNLOCK_WRITE(me->mut); + return keyfound; +} + +static int open_mod_table_open_dynamic(struct open_mod_table *me, + const char *uri, remote_handle *handle, + char *dlStr, int dlerrorLen, + int *pdlErr) { + int nErr = AEE_SUCCESS, dlErr = 0; + struct open_mod *dm = 0, *dmOld; + int len = strlen(uri); + int tmplen = len * 2 + + sizeof("file:///lib_skel.so?_skel_handle_invoke&_modver=1.0") + + 1; + char *tmp = 0; + uint32 handle_idx = 0, keyfound = 0; + int lock = 0; + + FARF(RUNTIME_RPC_HIGH, "open_mod_table_open_dynamic uri %s", uri); + VERIFYC(NULL != (tmp = calloc(1, tmplen)), AEE_ENOMEMORY); + VERIFYC((REV_HANDLE_SIZE >= sizeof(struct open_mod) + len + 1), + AEE_ENOMEMORY); + RW_MUTEX_LOCK_WRITE(rev_handle_table_lock); + lock = 1; + keyfound = is_reverse_handle_opened(me, handle, uri); + if (keyfound) { + goto bail; + } + + VERIFYC(0 == (nErr = next_available_rev_handle(&handle_idx)), AEE_EINVHANDLE); + VERIFYC(handle_idx < MAX_REV_HANDLES, AEE_EINVHANDLE); + dm = (struct open_mod *)&(rev_handle_table[handle_idx][0]); + memset(dm, 0, REV_HANDLE_SIZE); + std_memmove(dm->uri, uri, len + 1); + FARF(RUNTIME_RPC_HIGH, "calling parse_uri"); + (void)parse_uri(dm->uri, len, &dm->vals); + FARF(RUNTIME_RPC_HIGH, "done calling parse_uri"); + FARF(RUNTIME_RPC_HIGH, "vals %d %d %d", dm->vals.filelen, dm->vals.symlen, + dm->vals.verlen); + if (dm->vals.filelen) { + int rv = std_snprintf(tmp, tmplen, "%.*s", dm->vals.filelen, dm->vals.file); + VERIFYC((rv > 0) && (tmplen >= rv), AEE_EBADPARM); + } else { + int rv; + rv = std_snprintf(tmp, tmplen, "lib%s_skel.so", uri); + VERIFYC((rv > 0) && (tmplen >= rv), AEE_EBADPARM); + } + + FARF(RUNTIME_RPC_HIGH, "calling dlopen for %s", tmp); + errno = 0; + dm->dlhandle = DLOPEN(tmp, RTLD_NOW); + + // Only check for system library if original library was not found + if ((dlErr = dm->dlhandle == 0 ? AEE_EINVHANDLE : 0) && errno == ENOENT) { + int str_len, ii, rv; + + FARF(RUNTIME_RPC_HIGH, "Couldn't find %s", tmp); + str_len = strlen(tmp); + VERIFYC(str_len <= tmplen, AEE_EBADPARM); + for (ii = str_len - 1; ii >= 0; ii--) { + + // Find index of last character before the extension ".so" starts + if (tmp[ii] == '.') { + tmp[ii] = '\0'; + break; + } + } + rv = std_snprintf(tmp, tmplen, "%s_system.so", tmp); + VERIFYC((rv > 0) && (tmplen >= rv), AEE_EBADPARM); + FARF(RUNTIME_RPC_HIGH, "calling dlopen for %s", tmp); + dm->dlhandle = DLOPEN(tmp, RTLD_NOW); + dlErr = dm->dlhandle == 0 ? AEE_EINVHANDLE : 0; + if (dlErr == 0) + FARF(ALWAYS, "system library %s successfully loaded", tmp); + } + FARF(RUNTIME_RPC_HIGH, "got DL handle %p for %s", dm->dlhandle, tmp); + VERIFY(!(nErr = dlErr)); + + if (dm->vals.symlen) { + int rv = std_snprintf(tmp, tmplen, "%.*s", dm->vals.symlen, dm->vals.sym); + VERIFYC((rv > 0) && (tmplen >= rv), AEE_EBADPARM); + } else { + int rv = std_snprintf(tmp, tmplen, "%s_skel_invoke", uri); + VERIFYC((rv > 0) && (tmplen >= rv), AEE_EBADPARM); + } + + FARF(RUNTIME_RPC_HIGH, "calling dlsym for %s", tmp); + if (dm->vals.verlen && + 0 == std_strncmp(dm->vals.ver, "1.0", dm->vals.verlen)) { + dm->handle_invoke = (handle_invoke_fn)DLSYM(dm->dlhandle, tmp); + } else { + dm->invoke = (invoke_fn)DLSYM(dm->dlhandle, tmp); + } + FARF(RUNTIME_RPC_HIGH, "dlsym returned %p %p", dm->invoke, dm->handle_invoke); + VERIFYC(!(dlErr = dm->invoke || dm->handle_invoke ? 0 : AEE_ENOSUCHSYMBOL), + AEE_ENOSUCHSYMBOL); + + dm->key = (uint32)(uintptr_t)dm; + dm->refs = 1; + if (dm->handle_invoke) { + VERIFY(AEE_SUCCESS == (nErr = open_mod_handle_open(dm, uri, &dm->h64))); + } + + RW_MUTEX_LOCK_WRITE(me->mut); + if (!keyfound) { + do { + HASH_FIND_INT(me->openMods, &dm->key, dmOld); + if (dmOld) { + dm->key++; + } + } while (dmOld); + RW_MUTEX_LOCK_WRITE(me->smt->mut); + HASH_FIND_INT(me->smt->constMods, &dm->key, dmOld); + RW_MUTEX_UNLOCK_WRITE(me->smt->mut); + if (dmOld == 0) { + HASH_ADD_INT(me->openMods, key, dm); + } + nErr = dmOld != 0 ? -1 : nErr; + if (nErr == 0) { + *handle = dm->key; + } + } + RW_MUTEX_UNLOCK_WRITE(me->mut); +bail: + if (lock) { + lock = 0; + RW_MUTEX_UNLOCK_WRITE(rev_handle_table_lock); + } + if (nErr == AEE_SUCCESS) { + FARF(ALWAYS, + "%s: dynamic reverse module %s opened with handle 0x%x (idx %u)", + __func__, uri, *handle, handle_idx); + } else { + if (dlErr) { + const char *dlerr = DLERROR(); + if (dlerr != 0) { + std_strlcpy(dlStr, dlerr, dlerrorLen); + } + FARF(RUNTIME_RPC_HIGH, "dlerror:0x%x:%s", dlErr, dlerr == 0 ? "" : dlerr); + nErr = 0; + } + if (pdlErr) { + *pdlErr = dlErr; + } + if (dm && dm->h64) { + (void)open_mod_handle_close(dm, dm->h64); + } + if (dm && dm->dlhandle) { + DLCLOSE(dm->dlhandle); + } + if (dm) { + dm->key = 0; + dm = NULL; + } + VERIFY_EPRINTF("Error 0x%x: %s failed for %s, dlerr 0x%x", nErr, __func__, + uri, dlErr); + } + + FARF(RUNTIME_RPC_HIGH, + "done open_mod_table_open_dynamic for %s rv %x handle: %p %x", uri, nErr, + *handle, dlErr); + if (tmp) { + free(tmp); + tmp = NULL; + } + return nErr; +} + +static int open_mod_table_open_from_static(struct open_mod_table *me, + struct static_mod **tbl, + const char *uri, + remote_handle *handle) { + int nErr = AEE_SUCCESS; + struct static_mod *sm = 0; + struct open_mod *dm = 0; + int len = std_strlen(uri); + int sz = len * 2 + + sizeof("file:///lib_skel.so?_skel_handle_invoke&_modver=1.0") + 1; + uint32 handle_idx = 0, keyfound = 0; + int lock = 0; + + VERIFYC((REV_HANDLE_SIZE >= sizeof(struct open_mod) + sz), AEE_ENOMEMORY); + + RW_MUTEX_LOCK_WRITE(rev_handle_table_lock); + lock = 1; + keyfound = is_reverse_handle_opened(me, handle, uri); + if (keyfound) { + goto bail; + } + VERIFYC(0 == (nErr = next_available_rev_handle(&handle_idx)), AEE_EINVHANDLE); + VERIFYC(handle_idx < MAX_REV_HANDLES, AEE_EINVHANDLE); + dm = (struct open_mod *)&(rev_handle_table[handle_idx][0]); + memset(dm, 0, REV_HANDLE_SIZE); + RW_MUTEX_LOCK_READ(me->mut); + HASH_FIND_STR(*tbl, uri, sm); + RW_MUTEX_UNLOCK_READ(me->mut); + std_memmove(dm->uri, uri, len); + if (sm == 0) { + VERIFY(AEE_SUCCESS == (nErr = parse_uri(uri, len, &dm->vals))); + FARF(RUNTIME_RPC_HIGH, "file %.*s %d", dm->vals.filelen, dm->vals.file, + dm->vals.filelen); + FARF(RUNTIME_RPC_HIGH, "sym %.*s %d", dm->vals.symlen, dm->vals.sym, + dm->vals.symlen); + FARF(RUNTIME_RPC_HIGH, "version %.*s %d", dm->vals.verlen, dm->vals.ver, + dm->vals.verlen); + if (dm->vals.verlen) { + int rv = std_snprintf(dm->uri, sz, "file:///%.*s?%.*s&_modver=%.*s", + dm->vals.filelen, dm->vals.file, dm->vals.symlen, + dm->vals.sym, dm->vals.verlen, dm->vals.ver); + VERIFYC((rv > 0) && (sz >= rv), AEE_EBADPARM); + } else { + int rv = std_snprintf(dm->uri, sz, "file://%.*s?%.*s", dm->vals.filelen, + dm->vals.file, dm->vals.symlen, dm->vals.sym); + VERIFYC((rv > 0) && (sz >= rv), AEE_EBADPARM); + } + FARF(RUNTIME_RPC_HIGH, "dm->uri:%s", dm->uri); + + RW_MUTEX_LOCK_READ(me->mut); + HASH_FIND_STR(*tbl, dm->uri, sm); + RW_MUTEX_UNLOCK_READ(me->mut); + } + VERIFYM(0 != sm, AEE_ENOSUCHMOD, "Error %x: static mod is not initialized\n", + nErr); + assert(sm->handle_invoke || sm->invoke); + dm->handle_invoke = sm->handle_invoke; + dm->invoke = sm->invoke; + dm->key = (uint32)(uintptr_t)dm; + dm->refs = 1; + if (dm->handle_invoke) { + VERIFY(AEE_SUCCESS == (nErr = open_mod_handle_open(dm, uri, &dm->h64))); + } + + RW_MUTEX_LOCK_WRITE(me->mut); + if (!keyfound) { + HASH_ADD_INT(me->openMods, key, dm); + *handle = dm->key; + } + RW_MUTEX_UNLOCK_WRITE(me->mut); +bail: + if (lock) { + lock = 0; + RW_MUTEX_UNLOCK_WRITE(rev_handle_table_lock); + } + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error 0x%x: %s failed for %s", nErr, __func__, uri); + } else { + FARF(RUNTIME_RPC_HIGH, "%s: reverse module %s opened with handle 0x%x (idx %u)", + __func__, uri, *handle, handle_idx); + } + if (nErr && dm) { + if (dm->h64) { + (void)open_mod_handle_close(dm, dm->h64); + } + dm->key = 0; + dm = NULL; + } + return nErr; +} + +static int open_mod_table_open(struct open_mod_table *me, const char *uri, + remote_handle *handle, char *dlerr, + int dlerrorLen, int *pdlErr) { + int nErr = AEE_SUCCESS, dlErr = 0; + if (pdlErr) { + *pdlErr = 0; + } + if (0 != open_mod_table_open_static_override(me, uri, handle)) { + VERIFY(AEE_SUCCESS == (nErr = open_mod_table_open_dynamic( + me, uri, handle, dlerr, dlerrorLen, &dlErr))); + if (dlErr != 0) { + FARF(RUNTIME_RPC_HIGH, "dynammic open failed, trying static"); + if (0 != open_mod_table_open_static(me, uri, handle)) { + if (pdlErr) { + *pdlErr = dlErr; + } + } + } + } +bail: + FARF(RUNTIME_RPC_HIGH, "done open for %s rv %d handle: %p", uri, nErr, + *handle); + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: open modtable failed\n", nErr); + } + return nErr; +} + +static void open_mod_close(struct open_mod_table *me, struct open_mod *dm) { + RW_MUTEX_LOCK_WRITE(me->mut); + FARF(RUNTIME_RPC_HIGH, "%s: uri:%s, refs:%d", __func__, dm->uri, dm->refs); + dm->refs--; + if (dm->refs == 0) { + HASH_DEL(me->openMods, dm); + } else { + FARF(RUNTIME_RPC_HIGH, "%s : module %s has pending invokes ref count %d", + __func__, dm->uri, dm->refs); + dm = 0; + } + RW_MUTEX_UNLOCK_WRITE(me->mut); + if (dm) { + if (dm->h64) { + (void)open_mod_handle_close(dm, dm->h64); + } + if (dm->dlhandle) { + DLCLOSE(dm->dlhandle); + } + FARF(ALWAYS, "%s: closed reverse module %s with handle 0x%x", __func__, + dm->uri, (uint32)dm->key); + dm->key = 0; + dm = NULL; + } +} +static int open_mod_table_close(struct open_mod_table *me, + remote_handle64 handle, char *errStr, + int errStrLen, int *pdlErr) { + int nErr = AEE_SUCCESS; + struct open_mod *dm, *del = 0; + int dlErr = 0, locked = 0; + // First ensure that the handle is valid + RW_MUTEX_LOCK_WRITE(me->mut); + HASH_FIND_INT(me->openMods, &handle, dm); + locked = 1; + VERIFYC(dm, AEE_ENOSUCHMOD); + if (dm) { + dm->refs--; + if (dm->refs == 0) { + del = dm; + FARF(RUNTIME_RPC_HIGH, "deleting %s %p %d", del->uri, del, dm->refs); + HASH_DEL(me->openMods, dm); + del->key = 0; + } else { + FARF(RUNTIME_RPC_HIGH, "%s: pending ref: dm->refs %d, for uri: %s", + __func__, dm->refs, dm->uri); + dm = 0; + } + } + RW_MUTEX_UNLOCK_WRITE(me->mut); + locked = 0; + if (del) { + if (del->h64) { + (void)open_mod_handle_close(dm, dm->h64); + } + if (del->dlhandle) { + dlErr = DLCLOSE(del->dlhandle); + } + FARF(ALWAYS, "%s: closed reverse module %s with handle 0x%x", __func__, + del->uri, (uint32)handle); + del = NULL; + } +bail: + if (locked) { + locked = 0; + RW_MUTEX_UNLOCK_WRITE(me->mut); + } + if (dlErr) { + const char *error = DLERROR(); + nErr = dlErr; + if (error != 0) { + std_strlcpy(errStr, error, errStrLen); + } + VERIFY_EPRINTF("Error %x: open modtable close failed. dlerr %s\n", nErr, + error); + } + if (pdlErr) { + *pdlErr = dlErr; + } + return nErr; +} + +static struct open_mod *open_mod_table_get_open(struct open_mod_table *me, + remote_handle handle) { + struct open_mod *om = 0; + RW_MUTEX_LOCK_WRITE(me->mut); + HASH_FIND_INT(me->openMods, &handle, om); + if (0 != om) { + om->refs++; + FARF(RUNTIME_RPC_HIGH, "%s: module %s, increament refs %d", __func__, + om->uri, om->refs); + } + RW_MUTEX_UNLOCK_WRITE(me->mut); + return om; +} +static struct const_mod *open_mod_table_get_const(struct open_mod_table *me, + remote_handle handle) { + struct const_mod *cm = 0; + RW_MUTEX_LOCK_READ(me->smt->mut); + HASH_FIND_INT(me->smt->constMods, &handle, cm); + RW_MUTEX_UNLOCK_READ(me->smt->mut); + return cm; +} + +static int open_mod_table_handle_invoke(struct open_mod_table *me, + remote_handle handle, uint32 sc, + remote_arg *pra) { + int nErr = AEE_SUCCESS; + struct open_mod *om = 0; + struct const_mod *cm = 0; + remote_handle64 h = 0; + invoke_fn invoke = 0; + handle_invoke_fn handle_invoke = 0; + cm = open_mod_table_get_const(me, handle); + + FASTRPC_ATRACE_BEGIN_L("%s called with handle 0x%x , scalar 0x%x", __func__, + handle, sc); + if (cm) { + invoke = cm->invoke; + handle_invoke = cm->handle_invoke; + h = cm->h64; + } else { + VERIFYC(0 != (om = open_mod_table_get_open(me, handle)), AEE_ENOSUCHMOD); + invoke = om->invoke; + handle_invoke = om->handle_invoke; + h = om->h64; + } + if (invoke) { + VERIFY(AEE_SUCCESS == (nErr = invoke(sc, pra))); + } else { + VERIFY(AEE_SUCCESS == (nErr = handle_invoke(h, sc, pra))); + } +bail: + if (om) { + open_mod_close(me, om); + } + if (nErr != AEE_SUCCESS) { + FARF(ERROR, "Error 0x%x: %s failed for handle:0x%x, sc:0x%x", nErr, + __func__, handle, sc); + } + FASTRPC_ATRACE_END(); + return nErr; +} + +struct mod_table { + struct static_mod_table smt; + struct open_mod_table omt; +}; + +// mod_table object +static struct static_mod_table static_mod_table_obj; + +/** + * register a static component for invocations + * this can be called at any time including from a static constructor + * + * overrides will be tried first, then dynamic modules, then regular + * static modules. + * + * name, name of the interface to register + * pfn, function pointer to the skel invoke function + * + * for example: + * __attribute__((constructor)) static void my_module_ctor(void) { + * mod_table_register_static("my_module", my_module_skel_invoke); + * } + * + */ +int mod_table_register_static_override(const char *name, + int (*pfn)(uint32 sc, remote_arg *pra)) { + if (0 == static_mod_table_ctor(&static_mod_table_obj)) { + return static_mod_table_register_static_override(&static_mod_table_obj, + name, pfn); + } + return AEE_EUNKNOWN; +} + +int mod_table_register_static_override1(const char *name, + int (*pfn)(remote_handle64, uint32 sc, + remote_arg *pra)) { + if (0 == static_mod_table_ctor(&static_mod_table_obj)) { + return static_mod_table_register_static_override1(&static_mod_table_obj, + name, pfn); + } + return AEE_EUNKNOWN; +} + +/** + * register a static component for invocations + * this can be called at any time including from a static constructor + * + * name, name of the interface to register + * pfn, function pointer to the skel invoke function + * + * for example: + * __attribute__((constructor)) static void my_module_ctor(void) { + * mod_table_register_static("my_module", my_module_skel_invoke); + * } + * + */ +int mod_table_register_static(const char *name, + int (*pfn)(uint32 sc, remote_arg *pra)) { + if (0 == static_mod_table_ctor(&static_mod_table_obj)) { + return static_mod_table_register_static(&static_mod_table_obj, name, pfn); + } + return AEE_EUNKNOWN; +} + +int mod_table_register_static1(const char *name, + int (*pfn)(remote_handle64, uint32 sc, + remote_arg *pra)) { + if (0 == static_mod_table_ctor(&static_mod_table_obj)) { + return static_mod_table_register_static1(&static_mod_table_obj, name, pfn); + } + return AEE_EUNKNOWN; +} + +/** + * Open a module and get a handle to it + * + * uri, name of module to open + * handle, Output handle + * dlerr, Error String (if an error occurs) + * dlerrorLen, Length of error String (if an error occurs) + * pdlErr, Error identifier + */ +int mod_table_open(const char *uri, remote_handle *handle, char *dlerr, + int dlerrorLen, int *pdlErr) { + int nErr = AEE_SUCCESS; + struct open_mod_table *pomt = 0; + + VERIFYC(NULL != uri, AEE_EBADPARM); + FASTRPC_ATRACE_BEGIN_L("%s for %s", __func__, uri); + FARF(RUNTIME_RPC_HIGH, "mod_table_open for %s", uri); + VERIFY(AEE_SUCCESS == + (nErr = HAP_pls_add_lookup((uintptr_t)open_mod_table_ctor_imp, 0, + sizeof(*pomt), open_mod_table_ctor_imp, + (void *)&static_mod_table_obj, + open_mod_table_dtor_imp, (void **)&pomt))); + VERIFY(AEE_SUCCESS == (nErr = open_mod_table_open(pomt, uri, handle, dlerr, + dlerrorLen, pdlErr))); +bail: + FARF(RUNTIME_RPC_HIGH, "mod_table_open for %s nErr: %x", uri, nErr); + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: modtable open failed\n", nErr); + } + if (uri) { + FASTRPC_ATRACE_END(); + } + return nErr; +} +/** + * invoke a handle in the mod table + * + * handle, handle to invoke + * sc, scalars, see remote.h for documentation. + * pra, args, see remote.h for documentation. + */ +int mod_table_invoke(remote_handle handle, uint32 sc, remote_arg *pra) { + int nErr = AEE_SUCCESS; + struct open_mod_table *pomt = 0; + VERIFY(AEE_SUCCESS == + (nErr = HAP_pls_add_lookup((uintptr_t)open_mod_table_ctor_imp, 0, + sizeof(*pomt), open_mod_table_ctor_imp, + (void *)&static_mod_table_obj, + open_mod_table_dtor_imp, (void **)&pomt))); + VERIFY(AEE_SUCCESS == + (nErr = open_mod_table_handle_invoke(pomt, handle, sc, pra))); +bail: + return nErr; +} + +/** + * Closes a handle in the mod table + * + * handle, handle to close + * errStr, Error String (if an error occurs) + * errStrLen, Length of error String (if an error occurs) + * pdlErr, Error identifier + */ +int mod_table_close(remote_handle handle, char *errStr, int errStrLen, + int *pdlErr) { + int nErr = AEE_SUCCESS; + struct open_mod_table *pomt = 0; + + FASTRPC_ATRACE_BEGIN_L("%s called with handle 0x%x", __func__, (int)handle); + VERIFY(AEE_SUCCESS == + (nErr = HAP_pls_lookup((uintptr_t)open_mod_table_ctor_imp, 0, + (void **)&pomt))); + VERIFY(AEE_SUCCESS == (nErr = open_mod_table_close(pomt, handle, errStr, + errStrLen, pdlErr))); +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: modtable close failed\n", nErr); + } + FASTRPC_ATRACE_END(); + return nErr; +} + +/** + * internal use only + */ +int mod_table_register_const_handle(remote_handle remote, const char *uri, + int (*pfn)(uint32 sc, remote_arg *pra)) { + if (0 == static_mod_table_ctor(&static_mod_table_obj)) { + return static_mod_table_register_const_handle(&static_mod_table_obj, remote, + 0, uri, pfn, 0); + } + return AEE_EUNKNOWN; +} +int mod_table_register_const_handle1(remote_handle remote, + remote_handle64 local, const char *uri, + int (*pfn)(remote_handle64, uint32 sc, + remote_arg *pra)) { + if (0 == static_mod_table_ctor(&static_mod_table_obj)) { + return static_mod_table_register_const_handle(&static_mod_table_obj, remote, + local, uri, 0, pfn); + } + return AEE_EUNKNOWN; +} + +// Constructor and destructor +static int mod_table_ctor(void) { + return static_mod_table_ctor(&static_mod_table_obj); +} +static void mod_table_dtor(void) { + static_mod_table_dtor_imp(&static_mod_table_obj); + return; +} + +PL_DEFINE(mod_table, mod_table_ctor, mod_table_dtor); diff --git a/src/pl_list.c b/src/pl_list.c new file mode 100644 index 0000000..97a404a --- /dev/null +++ b/src/pl_list.c @@ -0,0 +1,10 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#include "platform_libs.h" + +PL_DEP(gpls) +PL_DEP(listener_android) + +struct platform_lib *(*pl_list[])(void) = {PL_ENTRY(gpls), + PL_ENTRY(listener_android), 0}; diff --git a/src/platform_libs.c b/src/platform_libs.c new file mode 100644 index 0000000..d59e62a --- /dev/null +++ b/src/platform_libs.c @@ -0,0 +1,99 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#define FARF_ERROR 1 +#include "platform_libs.h" +#include "AEEStdErr.h" +#include "AEEatomic.h" +#include "AEEstd.h" +#include "HAP_farf.h" +#include "verify.h" +#include +#include + +extern struct platform_lib *(*pl_list[])(void); +static uint32 atomic_IfNotThenAdd(uint32 *volatile puDest, uint32 uCompare, + int nAdd); + +int pl_lib_init(struct platform_lib *(*plf)(void)) { + int nErr = AEE_SUCCESS; + struct platform_lib *pl = plf(); + if (1 == atomic_Add(&pl->uRefs, 1)) { + if (pl->init) { + FARF(RUNTIME_RPC_HIGH, "calling init for %s", pl->name); + nErr = pl->init(); + FARF(RUNTIME_RPC_HIGH, "init for %s returned %x", pl->name, nErr); + } + pl->nErr = nErr; + } + if (pl->nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: %s init failed", nErr, pl->name); + } + return pl->nErr; +} + +void pl_lib_deinit(struct platform_lib *(*plf)(void)) { + struct platform_lib *pl = plf(); + if (1 == atomic_IfNotThenAdd(&pl->uRefs, 0, -1)) { + if (pl->deinit && pl->nErr == 0) { + pl->deinit(); + } + } + return; +} + +static int pl_init_lst(struct platform_lib *(*lst[])(void)) { + int nErr = AEE_SUCCESS; + int ii; + for (ii = 0; lst[ii] != 0; ++ii) { + nErr = pl_lib_init(lst[ii]); + if (nErr != 0) { + break; + } + } + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: plinit failed\n", nErr); + } + return nErr; +} +int pl_init(void) { + int nErr = pl_init_lst(pl_list); + return nErr; +} + +static void pl_deinit_lst(struct platform_lib *(*lst[])(void)) { + int size, ii; + for (size = 0; lst[size] != 0; ++size) { + ; + } + for (ii = size - 1; ii >= 0; --ii) { + pl_lib_deinit(lst[ii]); + } + return; +} + +void pl_deinit(void) { + pl_deinit_lst(pl_list); + return; +} + +static uint32 atomic_IfNotThenAdd(uint32 *volatile puDest, uint32 uCompare, + int nAdd) { + uint32 uPrev; + uint32 uCurr; + uint32 sum; + do { + // check puDest + uCurr = *puDest; + uPrev = uCurr; + // see if we need to update it + if (uCurr != uCompare) { + // update it + __builtin_add_overflow(uCurr, nAdd, &sum); + uPrev = atomic_CompareAndExchange(puDest, sum, uCurr); + } + // verify that the value was the same during the update as when we decided + // to update + } while (uCurr != uPrev); + return uPrev; +} diff --git a/src/remotectl1_stub.c b/src/remotectl1_stub.c new file mode 100644 index 0000000..0a5ca6c --- /dev/null +++ b/src/remotectl1_stub.c @@ -0,0 +1,408 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _REMOTECTL1_STUB_H +#define _REMOTECTL1_STUB_H +#include "remotectl1.h" +#include +#ifndef _WIN32 +#include "HAP_farf.h" +#endif //_WIN32 for HAP_farf +#include +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include +#include + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc((size_t)size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + (size_t)size) < (uintptr_t)me->stack + (size_t)me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _REMOTECTL1_SLIM_H +#define _REMOTECTL1_SLIM_H +#include + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Type types[2]; +static const Type types[2] = {{0x1,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x1},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4}}; +static const Parameter parameters[8] = {{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)0x0,0}}, 4,SLIM_IFPTR32(0x4,0x8),0,0},{SLIM_IFPTR32(0x4,0x8),{{(const uintptr_t)0xdeadc0de,(const uintptr_t)0}}, 0,SLIM_IFPTR32(0x4,0x8),3,0},{SLIM_IFPTR32(0x4,0x8),{{(const uintptr_t)0xdeadc0de,(const uintptr_t)0}}, 0,SLIM_IFPTR32(0x4,0x8),0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[0]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8),3,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[1]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8),0,0}}; +static const Parameter* const parameterArrays[14] = {(&(parameters[0])),(&(parameters[3])),(&(parameters[4])),(&(parameters[3])),(&(parameters[5])),(&(parameters[4])),(&(parameters[3])),(&(parameters[5])),(&(parameters[7])),(&(parameters[6])),(&(parameters[6])),(&(parameters[0])),(&(parameters[1])),(&(parameters[2]))}; +static const Method methods[6] = {{REMOTE_SCALARS_MAKEX(0,0,0x2,0x0,0x0,0x1),0x4,0x0,2,2,(&(parameterArrays[11])),0x4,0x1},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x0,0x1,0x0),0x0,0x0,1,1,(&(parameterArrays[13])),0x1,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x2,0x2,0x0,0x0),0x8,0x8,6,4,(&(parameterArrays[0])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x2,0x0,0x0),0x8,0x4,5,3,(&(parameterArrays[4])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0x8,0x0,2,2,(&(parameterArrays[9])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x2,0x0,0x0,0x0),0x8,0x0,3,2,(&(parameterArrays[7])),0x4,0x0}}; +static const Method* const methodArrays[6] = {&(methods[0]),&(methods[1]),&(methods[2]),&(methods[3]),&(methods[4]),&(methods[5])}; +static const char strings[103] = "set_param\0grow_heap\0phyAddr\0dlerror\0params\0close1\0handle\0reqID\0nSize\0open1\0close\0nErr\0name\0open\0uri\0h\0"; +static const uint16_t methodStrings[20] = {69,86,50,28,81,43,50,28,81,0,57,36,10,20,63,91,96,100,75,100}; +static const uint16_t methodStringsArrays[6] = {15,18,0,5,12,9}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(remotectl1_slim) = {6,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_REMOTECTL1_SLIM_H + + +#ifdef __cplusplus +extern "C" { +#endif +__QAIC_STUB_EXPORT int __QAIC_STUB(remotectl1_open)(const char* uri, remote_handle64* h) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle64_open)(uri, h); +} +__QAIC_STUB_EXPORT int __QAIC_STUB(remotectl1_close)(remote_handle64 h) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle64_close)(h); +} +static __inline int _stub_method(remote_handle64 _handle, uint32_t _mid, char* _in0[1], uint32_t _rout1[1], char* _rout2[1], uint32_t _rout2Len[1], uint32_t _rout3[1]) { + uint32_t _in0Len[1] = {0}; + int _numIn[1] = {0}; + remote_arg _pra[4] = {0}; + uint32_t _primIn[2]= {0}; + uint32_t _primROut[2]= {0}; + remote_arg* _praIn = 0; + remote_arg* _praROut = 0; + int _nErr = 0; + _numIn[0] = 1; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _pra[(_numIn[0] + 1)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 1)].buf.nLen = sizeof(_primROut); + _in0Len[0] = (uint32_t)(1 + strlen(_in0[0])); + _COPY(_primIn, 0, _in0Len, 0, 4); + _praIn = (_pra + 1); + _praIn[0].buf.pv = (void*) _in0[0]; + _praIn[0].buf.nLen = (1 * _in0Len[0]); + _COPY(_primIn, 4, _rout2Len, 0, 4); + _praROut = (_praIn + _numIn[0] + 1); + _praROut[0].buf.pv = _rout2[0]; + _praROut[0].buf.nLen = (1 * _rout2Len[0]); + _TRY_FARF(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 2, 2, 0, 0), _pra)); + _COPY(_rout1, 0, _primROut, 0, 4); + _COPY(_rout3, 0, _primROut, 4, 4); + _CATCH_FARF(_nErr) { + _QAIC_FARF(RUNTIME_ERROR, "ERROR 0x%x: handle=0x%"PRIx64", scalar=0x%x, method ID=%d: %s failed\n", _nErr , _handle, REMOTE_SCALARS_MAKEX(0, _mid, 2, 2, 0, 0), _mid, __func__); + } + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(remotectl1_open1)(remote_handle64 _handle, const char* name, int* handle, char* dlerror, int dlerrorLen, int* nErr) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 2; + return _stub_method(_handle, _mid, (char**)&name, (uint32_t*)handle, (char**)&dlerror, (uint32_t*)&dlerrorLen, (uint32_t*)nErr); +} +static __inline int _stub_method_1(remote_handle64 _handle, uint32_t _mid, uint32_t _in0[1], char* _rout1[1], uint32_t _rout1Len[1], uint32_t _rout2[1]) { + int _numIn[1] = {0}; + remote_arg _pra[3] = {0}; + uint32_t _primIn[2]= {0}; + uint32_t _primROut[1]= {0}; + remote_arg* _praIn = 0; + remote_arg* _praROut = 0; + int _nErr = 0; + _numIn[0] = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _pra[(_numIn[0] + 1)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 1)].buf.nLen = sizeof(_primROut); + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _rout1Len, 0, 4); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 1); + _praROut[0].buf.pv = _rout1[0]; + _praROut[0].buf.nLen = (1 * _rout1Len[0]); + _TRY_FARF(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 2, 0, 0), _pra)); + _COPY(_rout2, 0, _primROut, 0, 4); + _CATCH_FARF(_nErr) { + _QAIC_FARF(RUNTIME_ERROR, "ERROR 0x%x: handle=0x%"PRIx64", scalar=0x%x, method ID=%d: %s failed\n", _nErr , _handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 2, 0, 0), _mid, __func__); + } + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(remotectl1_close1)(remote_handle64 _handle, int handle, char* dlerror, int dlerrorLen, int* nErr) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 3; + return _stub_method_1(_handle, _mid, (uint32_t*)&handle, (char**)&dlerror, (uint32_t*)&dlerrorLen, (uint32_t*)nErr); +} +static __inline int _stub_method_2(remote_handle64 _handle, uint32_t _mid, uint32_t _in0[1], uint32_t _in1[1]) { + remote_arg _pra[1] = {0}; + uint32_t _primIn[2]= {0}; + int _nErr = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _in1, 0, 4); + _TRY_FARF(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 0, 0, 0), _pra)); + _CATCH_FARF(_nErr) { + _QAIC_FARF(RUNTIME_ERROR, "ERROR 0x%x: handle=0x%"PRIx64", scalar=0x%x, method ID=%d: %s failed\n", _nErr , _handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 0, 0, 0), _mid, __func__); + } + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(remotectl1_grow_heap)(remote_handle64 _handle, uint32 phyAddr, uint32 nSize) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 4; + return _stub_method_2(_handle, _mid, (uint32_t*)&phyAddr, (uint32_t*)&nSize); +} +static __inline int _stub_method_3(remote_handle64 _handle, uint32_t _mid, uint32_t _in0[1], char* _in1[1], uint32_t _in1Len[1]) { + remote_arg _pra[2] = {0}; + uint32_t _primIn[2]= {0}; + remote_arg* _praIn = 0; + int _nErr = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _in1Len, 0, 4); + _praIn = (_pra + 1); + _praIn[0].buf.pv = (void*) _in1[0]; + _praIn[0].buf.nLen = (4 * _in1Len[0]); + _TRY_FARF(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 2, 0, 0, 0), _pra)); + _CATCH_FARF(_nErr) { + _QAIC_FARF(RUNTIME_ERROR, "ERROR 0x%x: handle=0x%"PRIx64", scalar=0x%x, method ID=%d: %s failed\n", _nErr , _handle, REMOTE_SCALARS_MAKEX(0, _mid, 2, 0, 0, 0), _mid, __func__); + } + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(remotectl1_set_param)(remote_handle64 _handle, int reqID, const uint32* params, int paramsLen) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 5; + return _stub_method_3(_handle, _mid, (uint32_t*)&reqID, (char**)¶ms, (uint32_t*)¶msLen); +} +#ifdef __cplusplus +} +#endif +#endif //_REMOTECTL1_STUB_H diff --git a/src/remotectl_stub.c b/src/remotectl_stub.c new file mode 100644 index 0000000..8b55482 --- /dev/null +++ b/src/remotectl_stub.c @@ -0,0 +1,674 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef _REMOTECTL_STUB_H +#define _REMOTECTL_STUB_H +#include "remotectl.h" +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#include + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef _ATTRIBUTE_VISIBILITY + +#ifdef _WIN32 +#define _ATTRIBUTE_VISIBILITY +#else +#define _ATTRIBUTE_VISIBILITY __attribute__ ((visibility("default"))) +#endif + +#endif // _ATTRIBUTE_VISIBILITY + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i = 0; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#endif + + +#endif // _QAIC_ENV_H + +#include +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include +#include + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = malloc((size_t)size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + (size_t)size) < (uintptr_t)me->stack + (size_t)me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + free(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _REMOTECTL_SLIM_H +#define _REMOTECTL_SLIM_H +#include + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Type types[2]; +static const Type types[2] = {{0x1,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x1},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4}}; +static const Parameter parameters[6] = {{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)0x0,0}}, 4,SLIM_IFPTR32(0x4,0x8),0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,3,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[0]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8),3,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{0x4,{{(const uintptr_t)0,(const uintptr_t)1}}, 2,0x4,0,0},{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)&(types[1]),(const uintptr_t)0x0}}, 9,SLIM_IFPTR32(0x4,0x8),0,0}}; +static const Parameter* const parameterArrays[11] = {(&(parameters[0])),(&(parameters[1])),(&(parameters[2])),(&(parameters[1])),(&(parameters[3])),(&(parameters[2])),(&(parameters[1])),(&(parameters[3])),(&(parameters[5])),(&(parameters[4])),(&(parameters[4]))}; +static const Method methods[4] = {{REMOTE_SCALARS_MAKEX(0,0,0x2,0x2,0x0,0x0),0x8,0x8,6,4,(&(parameterArrays[0])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x2,0x0,0x0),0x8,0x4,5,3,(&(parameterArrays[4])),0x4,0x4},{REMOTE_SCALARS_MAKEX(0,0,0x1,0x0,0x0,0x0),0x8,0x0,2,2,(&(parameterArrays[9])),0x4,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x2,0x0,0x0,0x0),0x8,0x0,3,2,(&(parameterArrays[7])),0x4,0x0}}; +static const Method* const methodArrays[4] = {&(methods[0]),&(methods[1]),&(methods[2]),&(methods[3])}; +static const char strings[84] = "set_param\0grow_heap\0phyAddr\0dlerror\0params\0handle\0reqID\0nSize\0close\0nErr\0name\0open\0"; +static const uint16_t methodStrings[15] = {78,73,43,28,68,62,43,28,68,0,50,36,10,20,56}; +static const uint16_t methodStringsArrays[4] = {0,5,12,9}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(remotectl_slim) = {4,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_REMOTECTL_SLIM_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _const_remotectl_handle +#define _const_remotectl_handle ((remote_handle)-1) +#endif //_const_remotectl_handle + +static void _remotectl_pls_dtor(void* data) { + remote_handle* ph = (remote_handle*)data; + if(_const_remotectl_handle != *ph) { + (void)__QAIC_REMOTE(remote_handle_close)(*ph); + *ph = _const_remotectl_handle; + } +} + +static int _remotectl_pls_ctor(void* ctx, void* data) { + remote_handle* ph = (remote_handle*)data; + *ph = _const_remotectl_handle; + if(*ph == (remote_handle)-1) { + return __QAIC_REMOTE(remote_handle_open)((const char*)ctx, ph); + } + return 0; +} + +#if (defined __qdsp6__) || (defined __hexagon__) +#pragma weak adsp_pls_add_lookup +extern int adsp_pls_add_lookup(uint32_t type, uint32_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* ctx), void** ppo); +#pragma weak HAP_pls_add_lookup +extern int HAP_pls_add_lookup(uint32_t type, uint32_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* ctx), void** ppo); + +__QAIC_STUB_EXPORT remote_handle _remotectl_handle(void) { + remote_handle* ph = 0; + if(adsp_pls_add_lookup) { + if(0 == adsp_pls_add_lookup((uint32_t)_remotectl_handle, 0, sizeof(*ph), _remotectl_pls_ctor, "remotectl", _remotectl_pls_dtor, (void**)&ph)) { + return *ph; + } + return (remote_handle)-1; + } else if(HAP_pls_add_lookup) { + if(0 == HAP_pls_add_lookup((uint32_t)_remotectl_handle, 0, sizeof(*ph), _remotectl_pls_ctor, "remotectl", _remotectl_pls_dtor, (void**)&ph)) { + return *ph; + } + return (remote_handle)-1; + } + return(remote_handle)-1; +} + +#else //__qdsp6__ || __hexagon__ + +uint32_t _remotectl_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare); + +#ifdef _WIN32 +#ifdef _USRDLL +#include "Windows.h" +#else +#include "ntddk.h" +#endif //_USRDLL +uint32_t _remotectl_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare) { + return (uint32_t)InterlockedCompareExchange((volatile LONG*)puDest, (LONG)uExchange, (LONG)uCompare); +} +#elif __GNUC__ +uint32_t _remotectl_atomic_CompareAndExchange(uint32_t * volatile puDest, uint32_t uExchange, uint32_t uCompare) { + return __sync_val_compare_and_swap(puDest, uCompare, uExchange); +} +#endif //_WIN32 + + +__QAIC_STUB_EXPORT remote_handle _remotectl_handle(void) { + static remote_handle handle = _const_remotectl_handle; + if((remote_handle)-1 != handle) { + return handle; + } else { + remote_handle tmp; + int nErr = _remotectl_pls_ctor("remotectl", (void*)&tmp); + if(nErr) { + return (remote_handle)-1; + } + if(((remote_handle)-1 != handle) || ((remote_handle)-1 != (remote_handle)_remotectl_atomic_CompareAndExchange((uint32_t*)&handle, (uint32_t)tmp, (uint32_t)-1))) { + _remotectl_pls_dtor(&tmp); + } + return handle; + } +} + +#endif //__qdsp6__ + +#ifdef __cplusplus +} +#endif + + +#ifdef __cplusplus +extern "C" { +#endif +static __inline int _stub_method(remote_handle _handle, uint32_t _mid, char* _in0[1], uint32_t _rout1[1], char* _rout2[1], uint32_t _rout2Len[1], uint32_t _rout3[1]) { + uint32_t _in0Len[1] = {0}; + int _numIn[1] = {0}; + remote_arg _pra[4] = {0}; + uint32_t _primIn[2]= {0}; + uint32_t _primROut[2]= {0}; + remote_arg* _praIn = 0; + remote_arg* _praROut = 0; + int _nErr = 0; + _numIn[0] = 1; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _pra[(_numIn[0] + 1)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 1)].buf.nLen = sizeof(_primROut); + _in0Len[0] = (uint32_t)(1 + strlen(_in0[0])); + _COPY(_primIn, 0, _in0Len, 0, 4); + _praIn = (_pra + 1); + _praIn[0].buf.pv = (void*) _in0[0]; + _praIn[0].buf.nLen = (1 * _in0Len[0]); + _COPY(_primIn, 4, _rout2Len, 0, 4); + _praROut = (_praIn + _numIn[0] + 1); + _praROut[0].buf.pv = _rout2[0]; + _praROut[0].buf.nLen = (1 * _rout2Len[0]); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 2, 2, 0, 0), _pra)); + _COPY(_rout1, 0, _primROut, 0, 4); + _COPY(_rout3, 0, _primROut, 4, 4); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(remotectl_open)(const char* name, int* handle, char* dlerror, int dlerrorLen, int* nErr) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 0; + remote_handle _handle = _remotectl_handle(); + if (_handle != (remote_handle)-1) + { + return _stub_method(_handle, _mid, (char**)&name, (uint32_t*)handle, (char**)&dlerror, (uint32_t*)&dlerrorLen, (uint32_t*)nErr); + } + else + { + return AEE_EINVHANDLE; + } +} +static __inline int _stub_method_1(remote_handle _handle, uint32_t _mid, uint32_t _in0[1], char* _rout1[1], uint32_t _rout1Len[1], uint32_t _rout2[1]) { + int _numIn[1] = {0}; + remote_arg _pra[3] = {0}; + uint32_t _primIn[2]= {0}; + uint32_t _primROut[1]= {0}; + remote_arg* _praIn = 0; + remote_arg* _praROut = 0; + int _nErr = 0; + _numIn[0] = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _pra[(_numIn[0] + 1)].buf.pv = (void*)_primROut; + _pra[(_numIn[0] + 1)].buf.nLen = sizeof(_primROut); + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _rout1Len, 0, 4); + _praIn = (_pra + 1); + _praROut = (_praIn + _numIn[0] + 1); + _praROut[0].buf.pv = _rout1[0]; + _praROut[0].buf.nLen = (1 * _rout1Len[0]); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 2, 0, 0), _pra)); + _COPY(_rout2, 0, _primROut, 0, 4); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(remotectl_close)(int handle, char* dlerror, int dlerrorLen, int* nErr) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 1; + remote_handle _handle = _remotectl_handle(); + if (_handle != (remote_handle)-1) + { + return _stub_method_1(_handle, _mid, (uint32_t*)&handle, (char**)&dlerror, (uint32_t*)&dlerrorLen, (uint32_t*)nErr); + } + else + { + return AEE_EINVHANDLE; + } +} +static __inline int _stub_method_2(remote_handle _handle, uint32_t _mid, uint32_t _in0[1], uint32_t _in1[1]) { + remote_arg _pra[1] = {0}; + uint32_t _primIn[2]= {0}; + int _nErr = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _in1, 0, 4); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 1, 0, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(remotectl_grow_heap)(uint32 phyAddr, uint32 nSize) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 2; + remote_handle _handle = _remotectl_handle(); + if (_handle != (remote_handle)-1) + { + return _stub_method_2(_handle, _mid, (uint32_t*)&phyAddr, (uint32_t*)&nSize); + } + else + { + return AEE_EINVHANDLE; + } +} +static __inline int _stub_method_3(remote_handle _handle, uint32_t _mid, uint32_t _in0[1], char* _in1[1], uint32_t _in1Len[1]) { + remote_arg _pra[2] = {0}; + uint32_t _primIn[2]= {0}; + remote_arg* _praIn = 0; + int _nErr = 0; + _pra[0].buf.pv = (void*)_primIn; + _pra[0].buf.nLen = sizeof(_primIn); + _COPY(_primIn, 0, _in0, 0, 4); + _COPY(_primIn, 4, _in1Len, 0, 4); + _praIn = (_pra + 1); + _praIn[0].buf.pv = (void*) _in1[0]; + _praIn[0].buf.nLen = (4 * _in1Len[0]); + _TRY(_nErr, __QAIC_REMOTE(remote_handle_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 2, 0, 0, 0), _pra)); + _CATCH(_nErr) {} + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(remotectl_set_param)(int reqID, const uint32* params, int paramsLen) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 3; + remote_handle _handle = _remotectl_handle(); + if (_handle != (remote_handle)-1) + { + return _stub_method_3(_handle, _mid, (uint32_t*)&reqID, (char**)¶ms, (uint32_t*)¶msLen); + } + else + { + return AEE_EINVHANDLE; + } +} +#ifdef __cplusplus +} +#endif +#endif //_REMOTECTL_STUB_H diff --git a/src/rpcmem_linux.c b/src/rpcmem_linux.c new file mode 100644 index 0000000..0ac801b --- /dev/null +++ b/src/rpcmem_linux.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define FARF_LOW 1 + +#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 "apps_std.h" +#include "fastrpc_common.h" +#include "rpcmem.h" +#include "verify.h" + +#define PAGE_SIZE 4096 + +#ifndef PAGE_MASK +#define PAGE_MASK ~((uintptr_t)PAGE_SIZE - 1) +#endif + +struct dma_heap_allocation_data { + __u64 len; + __u32 fd; + __u32 fd_flags; + __u64 heap_flags; +}; + +#define DMA_HEAP_IOC_MAGIC 'H' +#define DMA_HEAP_IOCTL_ALLOC \ + _IOWR(DMA_HEAP_IOC_MAGIC, 0x0, struct dma_heap_allocation_data) +#define DMA_HEAP_NAME "/dev/dma_heap/system" +static int dmafd = -1; +static QList rpclst; +static pthread_mutex_t rpcmt; +struct rpc_info { + QNode qn; + void *buf; + void *aligned_buf; + int size; + int fd; + int dma; +}; + +struct fastrpc_alloc_dma_buf { + int fd; /* fd */ + uint32_t flags; /* flags to map with */ + uint64_t size; /* size */ +}; + +void rpcmem_init() { + QList_Ctor(&rpclst); + pthread_mutex_init(&rpcmt, 0); + pthread_mutex_lock(&rpcmt); + + dmafd = open(DMA_HEAP_NAME, O_RDONLY | O_CLOEXEC); + if (dmafd < 0) { + FARF(ERROR, "Error %d: Unable to open %s\n", errno, DMA_HEAP_NAME); + } + pthread_mutex_unlock(&rpcmt); +} + +void rpcmem_deinit() { + pthread_mutex_lock(&rpcmt); + if (dmafd != -1) + close(dmafd); + pthread_mutex_unlock(&rpcmt); + pthread_mutex_destroy(&rpcmt); +} + +int rpcmem_to_fd_internal(void *po) { + struct rpc_info *rinfo, *rfree = 0; + QNode *pn, *pnn; + + pthread_mutex_lock(&rpcmt); + QLIST_NEXTSAFE_FOR_ALL(&rpclst, pn, pnn) { + rinfo = STD_RECOVER_REC(struct rpc_info, qn, pn); + if (rinfo->aligned_buf == po) { + rfree = rinfo; + break; + } + } + pthread_mutex_unlock(&rpcmt); + + if (rfree) + return rfree->fd; + + return -1; +} + +int rpcmem_to_fd(void *po) { return rpcmem_to_fd_internal(po); } + +void *rpcmem_alloc_internal(int heapid, uint32 flags, size_t size) { + struct rpc_info *rinfo; + int nErr = 0; + struct dma_heap_allocation_data dmabuf = { + .len = size, + .fd_flags = O_RDWR | O_CLOEXEC, + }; + + if (dmafd == -1 || size <= 0) + return NULL; + + VERIFY(0 != (rinfo = calloc(1, sizeof(*rinfo)))); + + nErr = ioctl(dmafd, DMA_HEAP_IOCTL_ALLOC, &dmabuf); + if (nErr) { + FARF(ERROR, + "Error %d: Unable to allocate memory dmaheap fd %d, heapid %d, size " + "%zu, flags %u", + errno, dmafd, heapid, size, flags); + goto bail; + } + VERIFY(0 != (rinfo->buf = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, + dmabuf.fd, 0))); + rinfo->fd = dmabuf.fd; + rinfo->aligned_buf = + (void *)(((uintptr_t)rinfo->buf /*+ PAGE_SIZE*/) & PAGE_MASK); + rinfo->aligned_buf = rinfo->buf; + rinfo->size = size; + pthread_mutex_lock(&rpcmt); + QList_AppendNode(&rpclst, &rinfo->qn); + pthread_mutex_unlock(&rpcmt); + FARF(RUNTIME_RPC_HIGH, "Allocted memory from DMA heap fd %d ptr %p orig ptr %p\n", + rinfo->fd, rinfo->aligned_buf, rinfo->buf); + return rinfo->aligned_buf; +bail: + if (nErr) { + if (rinfo) { + if (rinfo->buf) { + free(rinfo->buf); + } + free(rinfo); + } + } + return NULL; +} + +void rpcmem_free_internal(void *po) { + struct rpc_info *rinfo, *rfree = 0; + QNode *pn, *pnn; + + pthread_mutex_lock(&rpcmt); + QLIST_NEXTSAFE_FOR_ALL(&rpclst, pn, pnn) { + rinfo = STD_RECOVER_REC(struct rpc_info, qn, pn); + if (rinfo->aligned_buf == po) { + rfree = rinfo; + QNode_Dequeue(&rinfo->qn); + break; + } + } + pthread_mutex_unlock(&rpcmt); + if (rfree) { + munmap(rfree->buf, rfree->size); + close(rfree->fd); + free(rfree); + } + return; +} + +void rpcmem_free(void *po) { rpcmem_free_internal(po); } + +void *rpcmem_alloc(int heapid, uint32 flags, int size) { + return rpcmem_alloc_internal(heapid, flags, size); +} + +void rpcmem_deinit_internal() { rpcmem_deinit(); } + +void rpcmem_init_internal() { rpcmem_init(); } diff --git a/src/smath.c b/src/smath.c new file mode 100644 index 0000000..f16c9b4 --- /dev/null +++ b/src/smath.c @@ -0,0 +1,28 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#include "AEEStdDef.h" +#include "AEEsmath.h" + + +static int32 ToInt(int64 a) +{ + return (a > MAX_INT32 ? MAX_INT32 : + a < MIN_INT32 ? MIN_INT32 : + (int32)a); +} + +int smath_Add(int a, int b) +{ + return ToInt((int64)a + (int64)b); +} + +int smath_Sub(int a, int b) +{ + return ToInt((int64)a - (int64)b); +} + +int smath_Mul(int a, int b) +{ + return ToInt((int64)a * (int64)b); +} diff --git a/src/std.c b/src/std.c new file mode 100644 index 0000000..5466bff --- /dev/null +++ b/src/std.c @@ -0,0 +1,534 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +// +// someday, drop this #include, implement our own memmove() +// +#include +#include "AEEstd.h" +#include "version.h" + +int std_getversion(char *pcDst, int nDestSize) +{ + return std_strlcpy(pcDst, VERSION_STRING, nDestSize); +} + + +char std_tolower(char c) +{ + if ((c >= 'A') && (c <= 'Z')) { + c |= 32; + } + return c; +} + +char std_toupper(char c) +{ + if ((c >= 'a') && (c <= 'z')) { + c &= ~32; + } + return c; +} + + +static __inline int x_casecmp(unsigned char c1, unsigned char c2) +{ + int diff = c1 - c2; + if (c1 >= 'A' && c1 <= 'Z') { + diff += 32; + } + if (c2 >= 'A' && c2 <= 'Z') { + diff -= 32; + } + return diff; +} + + +int std_strncmp(const char* s1, const char* s2, int n) +{ + if (n > 0) { + int i = 0; + + do { + unsigned char c1 = (unsigned char)s1[i]; + unsigned char c2 = (unsigned char)s2[i]; + int diff = c1 - c2; + + if (diff) { + return diff; + } + + if ('\0' == c1) { + break; + } + i++; + } while (i < n); + } + + return 0; +} + +int std_strcmp(const char* s1, const char* s2) +{ + return std_strncmp(s1, s2, MAX_INT32); +} + +int std_strnicmp(const char* s1, const char* s2, int n) +{ + if (n > 0) { + int i = -n; + + s1 += n; + s2 += n; + + do { + unsigned char c1 = (unsigned char)s1[i]; + unsigned char c2 = (unsigned char)s2[i]; + + int diff = x_casecmp(c1,c2); + if (diff) { + return diff; + } + if ('\0' == c1) { + break; + } + } while (++i); + } + return 0; +} + +int std_stricmp(const char* s1, const char* s2) +{ + return std_strnicmp(s1, s2, MAX_INT32); +} + +int std_strlcpy(char* pcDst, const char* cpszSrc, int nDestSize) +{ + int nLen = std_strlen(cpszSrc); + + if (0 < nDestSize) { + int n; + + n = STD_MIN(nLen, nDestSize - 1); + (void)std_memmove(pcDst, cpszSrc, n); + + pcDst[n] = 0; + } + + return nLen; +} + +int std_strlcat(char* pcDst, const char* cpszSrc, int nDestSize) +{ + int nLen = 0; + + while ((nLen < nDestSize) && (0 != pcDst[nLen])) { + ++nLen; + } + + return nLen + std_strlcpy(pcDst+nLen, cpszSrc, nDestSize-nLen); +} + +char* std_strstr(const char* cpszHaystack, const char* cpszNeedle) +{ + /* Check the empty needle string as a special case */ + if ('\0' == *cpszNeedle ) { + return (char*)cpszHaystack; + } + + while ('\0' != *cpszHaystack) { + /* Find the first character of the needle string in the haystack string */ + if (*cpszHaystack == *cpszNeedle) { + /* check if the rest of the string matches */ + const char* pHaystack = cpszHaystack; + const char* pNeedle = cpszNeedle; + do { + if ('\0' == *++pNeedle) { + /* Found a match */ + return (char*)cpszHaystack; + } + } while (*++pHaystack == *pNeedle); + } + cpszHaystack++; + } + + return 0; +} + + +int std_memcmp(const void* p1, const void* p2, int length) +{ + const unsigned char *cpc1 = p1; + const unsigned char *cpc2 = p2; + + while (length-- > 0) { + int diff = *cpc1++ - *cpc2++; + + if (0 != diff) { + return diff; + } + } + return 0; +} + +int std_wstrlen(const AECHAR* s) +{ + const AECHAR *sEnd = s; + + if (! *sEnd) + return 0; + + do { + ++sEnd; + } while (*sEnd); + + return sEnd - s; +} + + +int std_wstrlcpy(AECHAR* pwcDst, const AECHAR* cpwszSrc, int nDestSize) +{ + int nLen = std_wstrlen(cpwszSrc); + + if (0 < nDestSize) { + int n; + + n = STD_MIN(nLen, nDestSize - 1); + /* call memmove, in case n is larger than 1G */ + (void)std_memsmove(pwcDst, nDestSize*sizeof(AECHAR), + cpwszSrc, ((size_t)n)*sizeof(AECHAR)); + + pwcDst[n] = 0; + } + + return nLen; +} + +int std_wstrlcat(AECHAR* pwcDst, const AECHAR* cpwszSrc, int nDestSize) +{ + int nLen = 0; + + while ((nLen < nDestSize) && (0 != pwcDst[nLen])) { + ++nLen; + } + + return nLen + std_wstrlcpy(pwcDst+nLen, cpwszSrc, nDestSize-nLen); +} + +char* std_strchrend(const char* cpsz, char c) +{ + while (*cpsz && *cpsz != c) { + ++cpsz; + } + return (char*)cpsz; +} + +char* std_strchr(const char* cpszSrch, int c) +{ + const char *pc = std_strchrend(cpszSrch, (char)c); + + return (*pc == c ? (char*)pc : 0); +} + +void* std_memstr(const char* cpHaystack, const char* cpszNeedle, + int nHaystackLen) +{ + int nLen = 0; + + /* Handle empty needle string as a special case */ + if ('\0' == *cpszNeedle ) { + return (char*)cpHaystack; + } + + /* Find the first character of the needle string in the haystack string */ + while (nLen < nHaystackLen) { + if (cpHaystack[nLen] == *cpszNeedle) { + /* check if the rest of the string matches */ + const char* cpNeedle = cpszNeedle; + int nRetIndex = nLen; + do { + if ('\0' == *++cpNeedle) { + /* Found a match */ + return (void*)(cpHaystack + nRetIndex); + } + nLen++; + } while(cpHaystack[nLen] == *cpNeedle); + } + else { + nLen++; + } + } + + return 0; +} + +void* std_memchrend(const void* p, int c, int nLen) +{ + const char* cpc = (const char*)p + nLen; + int i = -nLen; + + if (nLen > 0) { + do { + if (cpc[i] == c) { + break; + } + } while (++i); + } + return (void*) (cpc + i); +} + +void* std_memchr(const void* s, int c, int n) +{ + const char *pEnd = (const char*)std_memchrend(s,c,n); + int nEnd = pEnd - (const char*)s; + + if (nEnd < n) { + return (void*)pEnd; + } + return 0; +} + +void* std_memrchr(const void* p, int c, int nLen) +{ + const char* cpc = (const char*)p - 1; + + if (nLen > 0) { + do { + if (cpc[nLen] == c) { + return (void*) (cpc + nLen); + } + } while (--nLen); + } + + return 0; +} + + +char* std_strrchr(const char* cpsz, int c) +{ + return std_memrchr(cpsz, c, std_strlen(cpsz) + 1); +} + + +void* std_memrchrbegin(const void* p, int c, int n) +{ + void *pOut = std_memrchr(p, c, n); + + return (pOut ? pOut : (void*)p); +} + + +// x_scanbytes: internal function; WARNING: nLen must be >0 +// +// cStop = character at which to stop (in addition to cpszChars[...]) +// +// Using a bit mask provides a constant-time check for a terminating +// character: 10 instructions for inner loop on ADS12arm9. Initialization +// overhead is increased, but this is quickly made up for as searching begins. +// +// +static char *x_scanbytes(const char *pcBuf, const char* cpszChars, + int nLen, unsigned char cStop, boolean bTestEqual) +{ + int n; + unsigned a[8]; + + // Initialize bit mask based on the input flag that specifies whether + // we are looking for a character that matches "any" or "none" + // of the characters in the search string + + #define ENTRY(c) a[((c)&7)] // c's bit lives here + #define SHIFT(c) ((c)>>3) // c's bit is shifted by this much + + if (bTestEqual) { + std_memset(a, 0, STD_SIZEOF(a)); + do { + ENTRY(cStop) |= (0x80000000U >> SHIFT(cStop)); + cStop = (unsigned char)*cpszChars++; + } while (cStop); + } + else { + std_memset(a, 0xFF, STD_SIZEOF(a)); + + while (0 != (cStop = (unsigned char)*cpszChars++)) { + ENTRY(cStop) ^= (0x80000000U >> SHIFT(cStop)); + } + } + + + // Search buffer + + pcBuf += nLen; + n = -nLen; + do { + unsigned char uc = (unsigned char)pcBuf[n]; + // testing for negative after shift is quicker than comparison + if ( (int)(ENTRY(uc) << SHIFT(uc)) < 0) { + break; + } + } while (++n); + + return (char*)(pcBuf+n); +} + + +void* std_memchrsend(const void* pBuf, const char* cpszChars, int nLen) +{ + if (nLen <= 0) { + return (void*)pBuf; + } + if ('\0' == *cpszChars) { + return (char*)pBuf + nLen; + } + + return x_scanbytes((const char*)pBuf, cpszChars+1, nLen, + (unsigned char)*cpszChars, TRUE); +} + + +char* std_strchrsend(const char* cpszSrch, const char* cpszChars) +{ + return x_scanbytes(cpszSrch, cpszChars, MAX_INT32, '\0', TRUE); +} + + +char *std_strchrs(const char* cpszSrch, const char* cpszChars) +{ + const char *pc = std_strchrsend(cpszSrch, cpszChars); + + return (*pc ? (char*)pc : 0); +} + + +char* std_striends(const char* cpsz, const char* cpszSuffix) +{ + int nOffset = std_strlen(cpsz) - std_strlen(cpszSuffix); + + if ((0 <= nOffset) && + (0 == std_stricmp(cpsz+nOffset, cpszSuffix))) { + + return (char*)(cpsz+nOffset); + } + + return 0; +} + + +char* std_strends(const char* cpsz, const char* cpszSuffix) +{ + int nOffset = std_strlen(cpsz) - std_strlen(cpszSuffix); + + if ((0 <= nOffset) && + (0 == std_strcmp(cpsz+nOffset, cpszSuffix))) { + + return (char*)(cpsz + nOffset); + } + + return 0; +} + +char* std_strbegins(const char* cpsz, const char* cpszPrefix) +{ + for (;;) { + if ('\0' == *cpszPrefix) { + return (char*)cpsz; + } + + if (*cpszPrefix != *cpsz) { + return 0; + } + + ++cpszPrefix; + ++cpsz; + } + // not reached +} + +char* std_stribegins(const char* cpsz, const char* cpszPrefix) +{ + for (;;) { + if ('\0' == *cpszPrefix) { + return (char*)cpsz; + } + + if (x_casecmp((unsigned char)*cpszPrefix, (unsigned char)*cpsz)) { + return 0; + } + + ++cpszPrefix; + ++cpsz; + } + // not reached +} + +int std_strcspn(const char* cpszSrch, const char* cpszChars) +{ + const char *pc = x_scanbytes(cpszSrch, cpszChars, MAX_INT32, '\0', TRUE); + + return (pc - cpszSrch); +} + +int std_strspn(const char* cpszSrch, const char* cpszChars) +{ + const char *pc = x_scanbytes(cpszSrch, cpszChars, MAX_INT32, '\0', FALSE); + + return (pc - cpszSrch); +} + +int std_wstrncmp(const AECHAR* s1, const AECHAR* s2, int nLen) +{ + if (nLen > 0) { + int i; + + s1 += nLen; + s2 += nLen; + i = -nLen; + do { + AECHAR c1 = s1[i]; + AECHAR c2 = s2[i]; + int diff = c1 - c2; + + if (diff) { + return diff; + } + + if ('\0' == c1) { + break; + } + } while (++i); + } + + return 0; +} + +int std_wstrcmp(const AECHAR* s1, const AECHAR* s2) +{ + return std_wstrncmp(s1, s2, MAX_INT32); +} + +AECHAR* std_wstrchr(const AECHAR* cpwszText, AECHAR ch) +{ + for (; ; cpwszText++) { + AECHAR chn = *cpwszText; + + if (chn == ch) { + return (AECHAR *)cpwszText; + } + else if ( chn == (AECHAR)0 ) { + return 0; + } + } +} + +AECHAR* std_wstrrchr(const AECHAR* cpwszText, AECHAR ch) +{ + const AECHAR* p = 0; + + do { + if (*cpwszText == ch) { + p = cpwszText; + } + } while (*cpwszText++ != (AECHAR)0); + + return (AECHAR*)p; +} diff --git a/src/std_SwapBytes.c b/src/std_SwapBytes.c new file mode 100644 index 0000000..2f2ef70 --- /dev/null +++ b/src/std_SwapBytes.c @@ -0,0 +1,169 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#include "AEEstd.h" +#include "AEEsmath.h" + + + +static int xMinSize(int a, int b) +{ + if (b < a) { + a = b; + } + return (a >= 0 ? a : 0); +} + + +static void xMoveBytes(byte *pbDest, const byte *pbSrc, int cb) +{ + if (pbDest != pbSrc) { + (void) std_memmove(pbDest, pbSrc, cb); + } +} + + +#ifdef AEE_BIGENDIAN +# define STD_COPY std_CopyBE +# define STD_COPY_SWAP std_CopyLE +#else +# define STD_COPY std_CopyLE +# define STD_COPY_SWAP std_CopyBE +#endif + + +// See std_CopyLE/BE for documentation. This function implements the case +// where host ordering != target byte ordering. +// +int STD_COPY_SWAP(void * pvDest, int nDestSize, + const void *pvSrc, int nSrcSize, + const char *pszFields) +{ + byte* pbDest = (byte*)pvDest; + byte* pbSrc = (byte*)pvSrc; + int cbCopied = xMinSize(nDestSize, nSrcSize); + const char * pszNextField; + int cb, nSize; + + nSize = 0; // avoid warning when using RVCT2.2 with -O1 + + pszNextField = pszFields; + + for (cb = cbCopied; cb > 0; cb -= nSize) { + char ch; + + ch = *pszNextField++; + if ('\0' == ch) { + ch = *pszFields; + pszNextField = pszFields+1; + } + + if (ch == 'S') { + + // S = 2 bytes + + nSize = 2; + if (cb < nSize) { + break; + } else { + byte by = pbSrc[0]; + pbDest[0] = pbSrc[1]; + pbDest[1] = by; + } + } else if (ch == 'L') { + + // L = 4 bytes + + nSize = 4; + if (cb < nSize) { + break; + } else { + byte by = pbSrc[0]; + pbDest[0] = pbSrc[3]; + pbDest[3] = by; + by = pbSrc[1]; + pbDest[1] = pbSrc[2]; + pbDest[2] = by; + } + } else if (ch == 'Q') { + + // Q = 8 bytes + + nSize = 8; + if (cb < nSize) { + break; + } else { + byte by = pbSrc[0]; + pbDest[0] = pbSrc[7]; + pbDest[7] = by; + by = pbSrc[1]; + pbDest[1] = pbSrc[6]; + pbDest[6] = by; + by = pbSrc[2]; + pbDest[2] = pbSrc[5]; + pbDest[5] = by; + by = pbSrc[3]; + pbDest[3] = pbSrc[4]; + pbDest[4] = by; + } + } else { + + // None of the above => read decimal and copy without swap + + if (ch >= '0' && ch <= '9') { + nSize = (int) (ch - '0'); + while ( (ch = *pszNextField) >= '0' && ch <= '9') { + nSize = nSize*10 + (int)(ch - '0'); + ++pszNextField; + } + // Check bounds & ensure progress + if (nSize > cb || nSize <= 0) { + nSize = cb; + } + } else { + // Unexpected character: copy rest of data + nSize = cb; + } + + xMoveBytes(pbDest, pbSrc, nSize); + } + + pbDest += nSize; + pbSrc += nSize; + } + + if (cb > 0) { + + // Swap could not be completed: 0 < cb < nSize <= 8 + + byte byBuf[8]; + + // If entire value is available in source, use swapped version + if (nSrcSize - (pbSrc - (byte*)pvSrc) >= nSize) { + int i; + for (i=0; i 0xFFFF ) * 16; ulVal >>= uTmp, uRet -= uTmp; + uTmp = ( ulVal > 0xFF ) * 8; ulVal >>= uTmp, uRet -= uTmp; + uTmp = ( ulVal > 0xF ) * 4; ulVal >>= uTmp, uRet -= uTmp; + return uRet + ( ( 0x55AF >> ( ulVal * 2 ) ) & 3 ); + } +} + +static __inline +uint32 std_dtoa_clz64( uint64 ulVal ) +// +// This function returns the number of leading zeroes in a uint64. +// +{ + uint32 ulCount = 0; + + if( !( ulVal >> 32 ) ) + { + ulCount += 32; + } + else + { + ulVal >>= 32; + } + + return ulCount + std_dtoa_clz32( (uint32)ulVal ); +} + +double fp_pow_10( int nPow ) +{ + double dRet = 1.0; + int nI = 0; + boolean bNegative = FALSE; + double aTablePos[] = { 0, 1e1, 1e2, 1e4, 1e8, 1e16, 1e32, 1e64, 1e128, + 1e256 }; + double aTableNeg[] = { 0, 1e-1, 1e-2, 1e-4, 1e-8, 1e-16, 1e-32, 1e-64, 1e-128, + 1e-256 }; + double* pTable = aTablePos; + int nTableSize = STD_ARRAY_SIZE( aTablePos ); + + if( 0 == nPow ) + { + return 1.0; + } + + if( nPow < 0 ) + { + bNegative = TRUE; + nPow = -nPow; + pTable = aTableNeg; + nTableSize = STD_ARRAY_SIZE( aTableNeg ); + } + + for( nI = 1; nPow && (nI < nTableSize); nI++ ) + { + if( nPow & 1 ) + { + dRet *= pTable[nI]; + } + + nPow >>= 1; + } + + if( nPow ) + { + // Overflow. Trying to compute a large power value. + uint64 ulInf = STD_DTOA_FP_POSITIVE_INF; + dRet = bNegative ? 0 : UINT64_TO_DOUBLE( ulInf ); + } + + return dRet; +} + +double fp_round( double dNumber, int nPrecision ) +// +// This functions rounds dNumber to the specified precision nPrecision. +// For example: +// fp_round(2.34553, 3) = 2.346 +// fp_round(2.34553, 4) = 2.3455 +// +{ + double dResult = dNumber; + double dRoundingFactor = FP_POW_10( -nPrecision ) * 0.5; + + if( dNumber < 0 ) + { + dResult = dNumber - dRoundingFactor; + } + else + { + dResult = dNumber + dRoundingFactor; + } + + return dResult; +} + +int fp_log_10( double dNumber ) +// +// This function finds the integer part of the log_10( dNumber ). +// The function assumes that dNumber != 0. +// +{ + // Absorb the negative sign + if( dNumber < 0 ) + { + dNumber = -dNumber; + } + + return (int)( floor( log10( dNumber ) ) ); +} + +int fp_check_special_cases( double dNumber, FloatingPointType* pNumberType ) +// +// This function evaluates the input floating-point number dNumber to check for +// following special cases: NaN, +/-Infinity. +// The evaluation is based on the IEEE Standard 754 for Floating Point Numbers +// +{ + int nError = AEE_SUCCESS; + FloatingPointType NumberType = FP_TYPE_UNKOWN; + uint64 ullValue = 0; + uint64 ullSign = 0; + int64 n64Exponent = 0; + uint64 ullMantissa = 0; + + ullValue = DOUBLE_TO_UINT64( dNumber ); + + // Extract the sign, exponent and mantissa + ullSign = FP_SIGN( ullValue ); + n64Exponent = FP_EXPONENT_BIASED( ullValue ); + ullMantissa = FP_MANTISSA_DENORM( ullValue ); + + // + // Rules for special cases are listed below: + // For Infinity, the following needs to be true: + // 1. Exponent should have all bits set to 1. + // 2. Mantissa should have all bits set to 0. + // + // For NaN, the following needs to be true: + // 1. Exponent should have all bits set to 1. + // 2. Mantissa should be non-zero. + // Note that we do not differentiate between QNaNs and SNaNs. + // + if( STD_DTOA_DP_INFINITY_EXPONENT_ID == n64Exponent ) + { + if( 0 == ullMantissa ) + { + // Inifinity. + if( ullSign ) + { + NumberType = FP_TYPE_NEGATIVE_INF; + } + else + { + NumberType = FP_TYPE_POSITIVE_INF; + } + } + else + { + // NaN + NumberType = FP_TYPE_NAN; + } + } + else + { + // A normal number + NumberType = FP_TYPE_GENERAL; + } + + // Set the output value + *pNumberType = NumberType; + + return nError; +} + +int std_dtoa_decimal( double dNumber, int nPrecision, + char acIntegerPart[ STD_DTOA_FORMAT_INTEGER_SIZE ], + char acFractionPart[ STD_DTOA_FORMAT_FRACTION_SIZE ] ) +{ + int nError = AEE_SUCCESS; + boolean bNegativeNumber = FALSE; + double dIntegerPart = 0.0; + double dFractionPart = 0.0; + double dTempIp = 0.0; + double dTempFp = 0.0; + int nMaxIntDigs = STD_DTOA_FORMAT_INTEGER_SIZE; + uint32 ulI = 0; + int nIntStartPos = 0; + + // Optimization: Special case an input of 0 + if( 0.0 == dNumber ) + { + acIntegerPart[0] = '0'; + acIntegerPart[1] = '\0'; + + for( ulI = 0; (ulI < STD_DTOA_FORMAT_FRACTION_SIZE - 1) && (nPrecision > 0); + ulI++, nPrecision-- ) + { + acFractionPart[ulI] = '0'; + } + acFractionPart[ ulI ] = '\0'; + + goto bail; + } + + // Absorb the negative sign + if( dNumber < 0 ) + { + acIntegerPart[0] = '-'; + nIntStartPos = 1; + dNumber = -dNumber; + bNegativeNumber = TRUE; + } + + // Split the input number into it's integer and fraction parts + dFractionPart = modf( dNumber, &dIntegerPart ); + + // First up, convert the integer part + if( 0.0 == dIntegerPart ) + { + acIntegerPart[ nIntStartPos ] = '0'; + } + else + { + double dRoundingConst = FP_POW_10( -STD_DTOA_PRECISION_ROUNDING_VALUE ); + int nIntDigs = 0; + int nI = 0; + + // Compute the number of digits in the integer part of the number + nIntDigs = fp_log_10( dIntegerPart ) + 1; + + // For negative numbers, a '-' sign has already been written. + if( TRUE == bNegativeNumber ) + { + nIntDigs++; + } + + // Check for overflow + if( nIntDigs >= nMaxIntDigs ) + { + // Overflow! + // Note that currently, we return a simple AEE_EFAILED for all + // errors. + nError = AEE_EFAILED; + goto bail; + } + + // Null Terminate the string + acIntegerPart[ nIntDigs ] = '\0'; + + for( nI = nIntDigs - 1; nI >= nIntStartPos; nI-- ) + { + dIntegerPart = dIntegerPart / 10.0; + dTempFp = modf( dIntegerPart, &dTempIp ); + + // Round it to the a specific precision + dTempFp = dTempFp + dRoundingConst; + + // Convert the digit to a character + acIntegerPart[ nI ] = (int)( dTempFp * 10 ) + '0'; + if( !MY_ISDIGIT( acIntegerPart[ nI ] ) ) + { + // Overflow! + // Note that currently, we return a simple AEE_EFAILED for all + // errors. + nError = AEE_EFAILED; + goto bail; + } + dIntegerPart = dTempIp; + } + } + + // Just a double check for integrity sake. This should ideally never happen. + // Out of bounds scenario. That is, the integer part of the input number is + // too large. + if( dIntegerPart != 0.0 ) + { + // Note that currently, we return a simple AEE_EFAILED for all + // errors. + nError = AEE_EFAILED; + goto bail; + } + + // Now, convert the fraction part + for( ulI = 0; ( nPrecision > 0 ) && ( ulI < STD_DTOA_FORMAT_FRACTION_SIZE - 1 ); + nPrecision--, ulI++ ) + { + if( 0.0 == dFractionPart ) + { + acFractionPart[ ulI ] = '0'; + } + else + { + double dRoundingValue = FP_POW_10( -( nPrecision + + STD_DTOA_PRECISION_ROUNDING_VALUE ) ); + acFractionPart[ ulI ] = (int)( ( dFractionPart + dRoundingValue ) * 10.0 ) + '0'; + if( !MY_ISDIGIT( acFractionPart[ ulI ] ) ) + { + // Overflow! + // Note that currently, we return a simple AEE_EFAILED for all + // errors. + nError = AEE_EFAILED; + goto bail; + } + + dFractionPart = ( dFractionPart * 10.0 ) - + (int)( ( dFractionPart + FP_POW_10( -nPrecision - 6 ) ) * 10.0 ); + } + } + + +bail: + + return nError; +} + +int std_dtoa_hex( double dNumber, int nPrecision, char cFormat, + char acIntegerPart[ STD_DTOA_FORMAT_INTEGER_SIZE ], + char acFractionPart[ STD_DTOA_FORMAT_FRACTION_SIZE ], + int* pnExponent ) +{ + int nError = AEE_SUCCESS; + uint64 ullMantissa = 0; + uint64 ullSign = 0; + int64 n64Exponent = 0; + static const char HexDigitsU[] = "0123456789ABCDEF"; + static const char HexDigitsL[] = "0123456789abcde"; + boolean bFirstDigit = TRUE; + int nI = 0; + int nF = 0; + uint64 ullValue = DOUBLE_TO_UINT64( dNumber ); + int nManShift = 0; + const char *pcDigitArray = ( cFormat == 'A' ) ? HexDigitsU : HexDigitsL; + boolean bPrecisionSpecified = TRUE; + + // If no precision is specified, then set the precision to be fairly + // large. + if( nPrecision < 0 ) + { + nPrecision = STD_DTOA_FORMAT_FRACTION_SIZE; + bPrecisionSpecified = FALSE; + } + else + { + bPrecisionSpecified = TRUE; + } + + // Extract the sign, exponent and mantissa + ullSign = FP_SIGN( ullValue ); + n64Exponent = FP_EXPONENT( ullValue ); + ullMantissa = FP_MANTISSA( ullValue ); + + // Write out the sign + if( ullSign ) + { + acIntegerPart[ nI++ ] = '-'; + } + + // Optimization: Special case an input of 0 + if( 0.0 == dNumber ) + { + acIntegerPart[0] = '0'; + acIntegerPart[1] = '\0'; + + for( nF = 0; (nF < STD_DTOA_FORMAT_FRACTION_SIZE - 1) && (nPrecision > 0); + nF++, nPrecision-- ) + { + acFractionPart[nF] = '0'; + } + acFractionPart[nF] = '\0'; + + goto bail; + } + + // The mantissa is in lower 53 bits (52 bits + an implicit 1). + // If we are dealing with a denormalized number, then the implicit 1 + // is absent. The above macros would have then set that bit to 0. + // Shift the mantisaa on to the highest bits. + + if( 0 == ( n64Exponent + STD_DTOA_DP_EXPONENT_BIAS ) ) + { + // DENORMALIZED NUMBER. + // A denormalized number is of the form: + // 0.bbb...bbb x 2^Exponent + // Shift the mantissa to the higher bits while discarding the leading 0 + ullMantissa <<= 12; + + // Lets update the exponent so as to make sure that the first hex value + // in the mantissa is non-zero, i.e., at least one of the first 4 bits is + // non-zero. + nManShift = std_dtoa_clz64( ullMantissa ) - 3; + if( nManShift > 0 ) + { + ullMantissa <<= nManShift; + n64Exponent -= nManShift; + } + } + else + { + // NORMALIZED NUMBER. + // A normalized number has the following form: + // 1.bbb...bbb x 2^Exponent + // Shift the mantissa to the higher bits while retaining the leading 1 + ullMantissa <<= 11; + } + + // Now, lets get the decimal point out of the picture by shifting the + // exponent by 1. + n64Exponent++; + + // Read the mantissa four bits at a time to form the hex output + for( nI = 0, nF = 0, bFirstDigit = TRUE; ullMantissa != 0; + ullMantissa <<= 4 ) + { + uint64 ulHexVal = ullMantissa & 0xF000000000000000uLL; + ulHexVal >>= 60; + if( bFirstDigit ) + { + // Write to the integral part of the number + acIntegerPart[ nI++ ] = pcDigitArray[ulHexVal]; + bFirstDigit = FALSE; + } + else if( nF < nPrecision ) + { + // Write to the fractional part of the number + acFractionPart[ nF++ ] = pcDigitArray[ulHexVal]; + } + } + + // Pad the fraction with trailing zeroes upto the specified precision + for( ; bPrecisionSpecified && (nF < nPrecision); nF++ ) + { + acFractionPart[ nF ] = '0'; + } + + // Now the output is of the form; + // h.hhh x 2^Exponent + // where h is a non-zero hexadecimal number. + // But we were dealing with a binary fraction 0.bbb...bbb x 2^Exponent. + // Therefore, we need to subtract 4 from the exponent (since the shift + // was to the base 16 and the exponent is to the base 2). + n64Exponent -= 4; + *pnExponent = (int)n64Exponent; + +bail: + return nError; +} diff --git a/src/std_mem.c b/src/std_mem.c new file mode 100644 index 0000000..40ff777 --- /dev/null +++ b/src/std_mem.c @@ -0,0 +1,81 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +/* +======================================================================= + +FILE: std_mem.c + +SERVICES: apiOne std lib memory operations stuff + +*/ + +#include +#include "AEEstd.h" +#include "AEEStdErr.h" + +#if defined __hexagon__ +#include "stringl/stringl.h" + +//Add a weak reference so shared objects work with older images +#pragma weak memscpy +#pragma weak memsmove +#endif /*__hexagon__*/ + +void* std_memset(void* p, int c, int nLen) +{ + if (nLen < 0) { + return p; + } + return memset(p, c, (size_t)nLen); +} + +void* std_memmove(void* pTo, const void* cpFrom, int nLen) +{ + if (nLen <= 0) { + return pTo; + } +#ifdef __hexagon__ + std_memsmove(pTo, (size_t)nLen, cpFrom, (size_t)nLen); + return pTo; +#else + return memmove(pTo, cpFrom, (size_t)nLen); +#endif +} + +int std_memscpy(void *dst, int dst_size, const void *src, int src_size){ + size_t copy_size = 0; + + if(dst_size <0 || src_size <0){ + return AEE_ERPC; + } + +#if defined (__hexagon__) + if (memscpy){ + return memscpy(dst,dst_size,src,src_size); + } +#endif + + copy_size = (dst_size <= src_size)? dst_size : src_size; + memcpy(dst, src, copy_size); + return copy_size; +} + +int std_memsmove(void *dst, int dst_size, const void *src, int src_size){ + size_t copy_size = 0; + + if(dst_size <0 || src_size <0){ + return AEE_ERPC; + } + +#if defined (__hexagon__) + if (memsmove){ + return memsmove(dst,dst_size,src,src_size); + } +#endif + + copy_size = (dst_size <= src_size)? dst_size : src_size; + memmove(dst, src, copy_size); + return copy_size; +} + diff --git a/src/std_path.c b/src/std_path.c new file mode 100644 index 0000000..b68cf9b --- /dev/null +++ b/src/std_path.c @@ -0,0 +1,139 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +/* +======================================================================= + +FILE: std_path.c + +======================================================================= +======================================================================= +*/ + +#include "AEEstd.h" +#include "AEEBufBound.h" +#include +/*=========================================================================== + +===========================================================================*/ +int std_makepath(const char* cpszDir, const char* cpszFile, + char* pszOut, int nOutLen) +{ + BufBound bb; + + BufBound_Init(&bb, pszOut, nOutLen); + + BufBound_Puts(&bb, cpszDir); + + if (('\0' != cpszDir[0]) && /* non-empty dir */ + ('/' != cpszDir[std_strlen(cpszDir)-1])) { /* no slash at end of dir */ + BufBound_Putc(&bb, '/'); + } + if ('/' == cpszFile[0]) { + cpszFile++; + } + + BufBound_Puts(&bb, cpszFile); + + BufBound_ForceNullTerm(&bb); + + return BufBound_Wrote(&bb) - 1; + +} + +/*=========================================================================== + +===========================================================================*/ +char* std_splitpath(const char* cpszPath, const char* cpszDir) +{ + const char* cpsz = cpszPath; + + while ( ! ('\0' == cpszDir[0] || + ('/' == cpszDir[0] && '\0' == cpszDir[1])) ){ + + if (*cpszDir != *cpsz) { + return 0; + } + + ++cpsz; + ++cpszDir; + } + + /* Found the filename part of the path. + It should begin with a '/' unless there is no filename */ + if ('/' == *cpsz) { + cpsz++; + } + else if ('\0' != *cpsz) { + cpsz = 0; + } + + return (char*)cpsz; +} + +char* std_cleanpath(char* pszPath) +{ + char* pszStart = pszPath; + char* pc; + char* pcEnd = pszStart+std_strlen(pszStart); + + /* preserve leading slash */ + if ('/' == pszStart[0]) { + pszStart++; + } + + pc = pszStart; + + while ((char*)0 != (pc = std_strstr(pc, "/."))) { + char* pcDelFrom; + + if ('/' == pc[2] || '\0' == pc[2]) { + /* delete "/." */ + pcDelFrom = pc; + pc += 2; + } else if ('.' == pc[2] && ('/' == pc[3] || '\0' == pc[3])) { + /* delete "/element/.." */ + pcDelFrom = std_memrchrbegin(pszStart, '/', pc - pszStart); + pc += 3; + } else { + pc += 2; + continue; + } + + std_memmove(pcDelFrom, pc, pcEnd-pcDelFrom); + + pc = pcDelFrom; + } + + /* eliminate leading "../" */ + while (pszStart == std_strstr(pszStart, "../")) { + std_memmove(pszStart, pszStart+2, pcEnd-pszStart); + } + + /* eliminate leading "./" */ + while (pszStart == std_strstr(pszStart, "./")) { + std_memmove(pszStart, pszStart+1, pcEnd-pszStart); + } + + if (!strncmp(pszStart,"..",2) || !strncmp(pszStart,".",1)) { + pszStart[0] = '\0'; + } + + /* whack double '/' */ + while ((char*)0 != (pc = std_strstr(pszPath, "//"))) { + std_memmove(pc, pc+1, pcEnd-pc); + } + + return pszPath; +} + +char* std_basename(const char* cpszFile) +{ + const char* cpsz; + + if ((char*)0 != (cpsz = std_strrchr(cpszFile,'/'))) { + cpszFile = cpsz+1; + } + + return (char*)cpszFile; +} diff --git a/src/std_strlprintf.c b/src/std_strlprintf.c new file mode 100644 index 0000000..cced450 --- /dev/null +++ b/src/std_strlprintf.c @@ -0,0 +1,733 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +#include "AEEstd.h" +#include "AEEBufBound.h" +#include "AEEsmath.h" +#include "AEEStdErr.h" +#include "std_dtoa.h" +//#include "math.h" + +//============================================================================== +// Macro definitions +//============================================================================== + +#define ISDIGIT(c) ( (c) >= '0' && (c) <= '9') +#define TOLOWER(c) ( (c) | 32 ) // works only for letters +#define FAILED(b) ( (b) != AEE_SUCCESS ? TRUE : FALSE ) +#define CLEANUP_ON_ERROR(b,l) if( FAILED( b ) ) { goto l; } +#define ROUND(d, p) fp_round( d, p ) +#define FP_POW_10(n) fp_pow_10(n) + +//============================================================================== +// Type definitions +//============================================================================== + + +// Formatting flags + +#define FF_PLUS 1 // '+' +#define FF_MINUS 2 // '-' +#define FF_POUND 4 // '#' +#define FF_BLANK 8 // ' ' +#define FF_ZERO 16 // '0' + +typedef struct { + + // Parsed values (from "%..." expression) + + int flags; // FF_PLUS, FF_MINUS, etc. + char cType; // d, s, c, x, X, etc. + int32 nWidth; // number preceding '.' : controls padding + int32 nPrecision; // number following '.' (-1 if not given) + + // Computed values + + const char * pszStr; // string holding prefix + value + int nPrefix; // # of numeric prefix bytes in pszStr[] + int nLen; // length of string (after prefix) + int nNumWidth; // minimum numeric value size (pad with '0') + +} FieldFormat; + +typedef int (*pfnFormatFloat)(FieldFormat* me, double dNumber, char* pcBuffer); + +//============================================================================== +// Function definitions +//============================================================================== + +// Read an unsigned decimal integer +// +static int ScanDecimal(const char **ppsz) +{ + int n = 0; + const char *psz; + + for (psz = *ppsz; ISDIGIT(*psz); ++psz) { + n = n*10 + (int) (*psz - '0'); + } + *ppsz = psz; + return n; +} + + +#define FORMATNUMBER_SIZE 24 // octal: 22 + '0' + null ; decimal: 20 + sign + null + + +// Convert number to string, setting computed fields in FieldFormat. +// +// pcBuf[] must have room for at least FORMATNUMBER_SIZE characters +// return value: length of string. +// +static __inline void +FormatNumber(FieldFormat *me, char pcBuf[FORMATNUMBER_SIZE], uint64 uNum64) +{ + char cType = me->cType; + const char *cpszDigits; + char *pc = pcBuf; + int nBase; + char *pcRev; + + if (cType == 'p') { + cType = 'X'; + me->nPrecision = 8; + } + + if (me->nPrecision >= 0) { + me->nNumWidth = me->nPrecision; + // Odd thing: '0' flag is ignored for numbers when precision is + // specified. + me->flags &= ~FF_ZERO; + } else { + me->nNumWidth = 1; + } + + // Output prefix + + if (( 'd' == cType || 'i' == cType)) { + if ((int64)uNum64 < 0) { + *pc++ = '-'; + uNum64 = (uint64)-(int64)uNum64; + } else if (me->flags & FF_PLUS) { + *pc++ = '+'; + } else if (me->flags & FF_BLANK) { + *pc++ = ' '; + } + } + + if ((me->flags & FF_POUND) && 0 != uNum64) { + if ('x' == TOLOWER(cType)) { + *pc++ = '0'; + *pc++ = cType; + } else if ('o' == cType) { + *pc++ = '0'; + // Odd thing about libc printf: "0" prefix counts as part of minimum + // width, but "0x" prefix does not. + --me->nNumWidth; + } + } + me->nPrefix = pc - pcBuf; + + // Output unsigned numeric value + + nBase = ('o' == cType ? 8 : + 'x' == TOLOWER(cType) ? 16 : + 10); + cpszDigits = ((cType == 'X') ? "0123456789ABCDEF" + : "0123456789abcdef"); + + pcRev = pc; + + while (uNum64) { + *pc++ = cpszDigits[uNum64 % (unsigned)nBase]; + uNum64 /= (unsigned)nBase; + } + + *pc = '\0'; + + me->pszStr = pcBuf; + me->nLen = pc - pcRev; + + // Reverse string + + --pc; + for (; pcRev < pc; ++pcRev, --pc) { + char c = *pc; + *pc = *pcRev; + *pcRev = c; + } +} + +// +// This function converts the input floating point number dNumber to an +// ASCII string using either %f or %F formatting. This functions assumes +// that dNumer is a valid floating point number (i.e., dNumber is NOT +// +/-INF or NaN). The size of the output buffer pcBuffer should be at +// least STD_DTOA_FORMAT_FLOAT_SIZE. +// +static int ConvertFloat(FieldFormat* me, double dNumber, char* pcBuffer, + int nBufSize) +{ + int nError = AEE_SUCCESS; + int32 nPrecision = 0; + int nIndex = 0; + BufBound OutBuf; + char szIntegerPart[STD_DTOA_FORMAT_INTEGER_SIZE] = {0}; + char szFractionPart[STD_DTOA_FORMAT_FRACTION_SIZE] = {0}; + int nExponent = 0; + char cType = TOLOWER(me->cType); + + // Set the precision for conversion + nPrecision = me->nPrecision; + if (nPrecision < 0) { + // No precision was specified, set it to the default value if the + // format specifier is not %a + if (cType != 'a') { + nPrecision = STD_DTOA_DEFAULT_FLOAT_PRECISION; + } + } + else if ((0 == nPrecision) && ('g' == cType)) { + nPrecision = 1; + } + + if (cType != 'a') { + // For %g, check whether to use %e of %f formatting style. + // Also, set the precision value accordingly since in this case the user + // specified value is really the number of significant digits. + // These next few steps should be skipped if the input number is 0. + if (dNumber != 0.0) { + nExponent = fp_log_10(dNumber); + if ('g' == cType) { + if ((nExponent < -4) || (nExponent >= nPrecision)) { + cType = 'e'; + nPrecision = nPrecision - 1; + } + else { + cType = 'f'; + nPrecision = nPrecision - nExponent - 1; + } + } + + // For %e, convert the number to the form d.ddd + if ('e' == cType) { + dNumber = dNumber / FP_POW_10(nExponent); + } + + // Now, round the number to the specified precision + dNumber = ROUND(dNumber, nPrecision); + + // For %e, the rounding operation may have resulted in a number dd.ddd + // Reconvert it to the form d.ddd + if (('e' == cType) && ((dNumber >= 10.0) || (dNumber <= -10.0))) { + dNumber = dNumber / 10.0; + nExponent++; + } + } + + // Convert the decmial number to string + nError = std_dtoa_decimal(dNumber, nPrecision, szIntegerPart, szFractionPart); + CLEANUP_ON_ERROR(nError, bail); + } + else + { + // Conver the hex floating point number to string + nError = std_dtoa_hex(dNumber, nPrecision, me->cType, szIntegerPart, + szFractionPart, &nExponent); + CLEANUP_ON_ERROR(nError, bail); + } + + + // + // Write the output as per the specified format. + // First: Check for any prefixes that need to be added to the output. + // The only possible prefixes are '-', '+' or ' '. The following rules + // are applicable: + // 1. One and only one prefix will be applicable at any time. + // 2. If the number is negative, then '+' and ' ' are not applicable. + // 3. For positive numbers, the prefix '+' takes precedence over ' '. + // + // In addition, we were dealing with a hex floating point number (%a), + // then we need to write of the 0x prefix. + // + BufBound_Init(&OutBuf, pcBuffer, nBufSize); + if (dNumber < 0.0) { + // The '-' sign would have already been added to the szIntegerPart by + // the conversion function. + me->nPrefix = 1; + } + if (dNumber >= 0.0){ + if (me->flags & FF_PLUS) { + BufBound_Putc(&OutBuf, '+'); + me->nPrefix = 1; + } + else if(me->flags & FF_BLANK) { + BufBound_Putc(&OutBuf, ' '); + me->nPrefix = 1; + } + } + + // For %a, write out the 0x prefix + if ('a' == cType) { + BufBound_Putc(&OutBuf, '0'); + BufBound_Putc(&OutBuf, ('a' == me->cType) ? 'x' : 'X'); + me->nPrefix += 2; + } + + // Second: Write the integer part + BufBound_Puts(&OutBuf, szIntegerPart); + + // Third: Write the decimal point followed by the fraction part. + // For %g, we need to truncate the trailing zeros in the fraction. + // Skip this if the '#' flag is specified + if (!(me->flags & FF_POUND) && ('g' == TOLOWER(me->cType))) { + for (nIndex = std_strlen(szFractionPart) - 1; + (nIndex >= 0) && (szFractionPart[nIndex] == '0'); nIndex--) { + szFractionPart[nIndex] = '\0'; + } + } + + // The decimal point is specified only if there are some decimal digits. + // However, if the '#' format specifier is present then the decimal point + // will be present. + if ((me->flags & FF_POUND) || (*szFractionPart != 0)) { + BufBound_Putc(&OutBuf, '.'); + + // Write the fraction part + BufBound_Puts(&OutBuf, szFractionPart); + } + + // For %e and %a, write out the exponent + if (('e' == cType) || ('a' == cType)) { + char* pcExpStart = NULL; + char* pcExpEnd = NULL; + char cTemp = 0; + + if ('a' == me->cType) { + BufBound_Putc(&OutBuf, 'p'); + } + else if ('A' == me->cType) { + BufBound_Putc(&OutBuf, 'P'); + } + else if (('e' == me->cType) || ('g' == me->cType)) { + BufBound_Putc(&OutBuf, 'e'); + } + else { + BufBound_Putc(&OutBuf, 'E'); + } + + // Write the exponent sign + if (nExponent < 0) { + BufBound_Putc(&OutBuf, '-'); + nExponent = -nExponent; + } + else { + BufBound_Putc(&OutBuf, '+'); + } + + // Write out the exponent. + // For %e, the exponent should at least be two digits. + // The exponent to be written will be at most 4 digits as any + // overflow would have been take care of by now. + if (BufBound_Left(&OutBuf) >= 4) { + if ('e' == cType) { + if (nExponent < 10) { + BufBound_Putc(&OutBuf, '0'); + } + } + + pcExpStart = OutBuf.pcWrite; + do { + BufBound_Putc(&OutBuf, '0' + (nExponent % 10)); + nExponent /= 10; + } while (nExponent); + pcExpEnd = OutBuf.pcWrite - 1; + + // Reverse the exponent + for (; pcExpStart < pcExpEnd; pcExpStart++, pcExpEnd--) { + cTemp = *pcExpStart; + *pcExpStart = *pcExpEnd; + *pcExpEnd = cTemp; + } + } + } + + // Null-terminate the string + BufBound_ForceNullTerm(&OutBuf); + + // Set the output parameters + // We do not care if there was enough space in the output buffer or not. + // The output would be truncated to a maximum length of + // STD_DTOA_FORMAT_FLOAT_SIZE. + me->pszStr = OutBuf.pcBuf; + me->nLen = BufBound_ReallyWrote(&OutBuf) - me->nPrefix - 1; + +bail: + + return nError; +} + +// +// This is a wrapper function that converts an input floating point number +// to a string based on a given format specifier %e, %f or %g. It first checks +// if the specified number is a valid floating point number before calling +// the function that does the conversion. +// +// The size of the output buffer pcBuffer should be at least STD_DTOA_FORMAT_FLOAT_SIZE. +// +static int FormatFloat(FieldFormat* me, double dNumber, + char pcBuffer[STD_DTOA_FORMAT_FLOAT_SIZE]) +{ + int nError = AEE_SUCCESS; + FloatingPointType NumberType = FP_TYPE_UNKOWN; + + // Check for error conditions + if (NULL == pcBuffer) { + nError = AEE_EBADPARM; + goto bail; + } + + // Initialize the output params first + me->nLen = 0; + me->nPrefix = 0; + + // Check for special cases such as NaN and Infinity + nError = fp_check_special_cases(dNumber, &NumberType); + CLEANUP_ON_ERROR(nError, bail); + + switch(NumberType) { + case FP_TYPE_NEGATIVE_INF: + + if (('E' == me->cType) || ('F' == me->cType) || ('G' == me->cType)) { + me->nLen = std_strlcpy(pcBuffer, STD_DTOA_NEGATIVE_INF_UPPER_CASE, + STD_DTOA_FORMAT_FLOAT_SIZE); + } + else { + me->nLen = std_strlcpy(pcBuffer, STD_DTOA_NEGATIVE_INF_LOWER_CASE, + STD_DTOA_FORMAT_FLOAT_SIZE); + } + + // Don't pad with 0's + me->flags &= ~FF_ZERO; + + break; + + case FP_TYPE_POSITIVE_INF: + + if (('E' == me->cType) || ('F' == me->cType) || ('G' == me->cType)) { + me->nLen = std_strlcpy(pcBuffer, STD_DTOA_POSITIVE_INF_UPPER_CASE, + STD_DTOA_FORMAT_FLOAT_SIZE); + } + else { + me->nLen = std_strlcpy(pcBuffer, STD_DTOA_POSITIVE_INF_LOWER_CASE, + STD_DTOA_FORMAT_FLOAT_SIZE); + } + + // Don't pad with 0's + me->flags &= ~FF_ZERO; + + break; + + case FP_TYPE_NAN: + + if (('E' == me->cType) || ('F' == me->cType) || ('G' == me->cType)) { + me->nLen = std_strlcpy(pcBuffer, STD_DTOA_NAN_UPPER_CASE, + STD_DTOA_FORMAT_FLOAT_SIZE); + } + else + { + me->nLen = std_strlcpy(pcBuffer, STD_DTOA_NAN_LOWER_CASE, + STD_DTOA_FORMAT_FLOAT_SIZE); + } + + // Don't pad with 0's + me->flags &= ~FF_ZERO; + + break; + + case FP_TYPE_GENERAL: + + nError = ConvertFloat(me, dNumber, pcBuffer, + STD_DTOA_FORMAT_FLOAT_SIZE); + CLEANUP_ON_ERROR(nError, bail); + + break; + + default: + + // This should only happen if this function has been modified + // to support other special cases and this block has not been + // updated. + nError = AEE_EFAILED; + goto bail; + } + + // Set the output parameters + me->pszStr = pcBuffer; + + +bail: + + return nError; +} + +static int std_strlprintf_inner(char *pszDest, int nDestSize, + const char *cpszFmt, AEEVaList args, + pfnFormatFloat pfnFormatFloatFunc) +{ + BufBound bb; + const char *pcIn = cpszFmt; + + BufBound_Init(&bb, pszDest, nDestSize); + + for (;;) { + FieldFormat ff; + const char *pcEsc; + char achBuf[FORMATNUMBER_SIZE]; + char achBuf2[STD_DTOA_FORMAT_FLOAT_SIZE]; + char cType; + boolean bLong = 0; + + pcEsc = std_strchrend(pcIn, '%'); + BufBound_Write(&bb, pcIn, pcEsc-pcIn); + + if (0 == *pcEsc) { + break; + } + pcIn = pcEsc+1; + + //---------------------------------------------------- + // Consume "%..." specifiers: + // + // %[FLAGS] [WIDTH] [.PRECISION] [{h | l | I64 | L}] + //---------------------------------------------------- + + std_memset(&ff, 0, sizeof(FieldFormat)); + ff.nPrecision = -1; + + // Consume all flags + for (;;) { + int f; + + f = (('+' == *pcIn) ? FF_PLUS : + ('-' == *pcIn) ? FF_MINUS : + ('#' == *pcIn) ? FF_POUND : + (' ' == *pcIn) ? FF_BLANK : + ('0' == *pcIn) ? FF_ZERO : 0); + + if (0 == f) { + break; + } + + ff.flags |= f; + ++pcIn; + } + + // Consume width + if ('*' == *pcIn) { + AEEVA_ARG(args, ff.nWidth, int32); + pcIn++; + } else { + ff.nWidth = ScanDecimal(&pcIn); + } + if ((ff.flags & FF_MINUS) && ff.nWidth > 0) { + ff.nWidth = -ff.nWidth; + } + + // Consume precision + if ('.' == *pcIn) { + pcIn++; + if ('*' == *pcIn) { // Can be *... (given in int * param) + AEEVA_ARG(args, ff.nPrecision, int32); + pcIn++; + } else { + ff.nPrecision = ScanDecimal(&pcIn); + } + } + + // Consume size designator + { + static const struct { + char szPre[3]; + boolean b64; + } a[] = { + { "l", 0, }, + { "ll", 1, }, + { "L", 1, }, + { "j", 1, }, + { "h", 0, }, + { "hh", 0, }, + { "z", 0 } + }; + + int n = STD_ARRAY_SIZE(a); + + while (--n >= 0) { + const char *psz = std_strbegins(pcIn, a[n].szPre); + if ((const char*)0 != psz) { + pcIn = psz; + bLong = a[n].b64; + break; + } + } + } + + //---------------------------------------------------- + // + // Format output values + // + //---------------------------------------------------- + + ff.cType = cType = *pcIn++; + + if ('s' == cType) { + + // String + char *psz; + + AEEVA_ARG(args, psz, char*); + ff.pszStr = psz; + ff.nLen = std_strlen(psz); + if (ff.nPrecision >= 0 && ff.nPrecision < ff.nLen) { + ff.nLen = ff.nPrecision; + } + + } else if ('c' == cType) { + + // char + AEEVA_ARG(args, achBuf[0], int); + achBuf[1] = '\0'; + ff.pszStr = achBuf; + ff.nLen = 1; + + } else if ('u' == cType || + 'o' == cType || + 'd' == cType || + 'i' == cType || + 'p' == cType || + 'x' == TOLOWER(cType) ) { + + // int + uint64 uArg64; + + if (bLong) { + AEEVA_ARG(args, uArg64, int64); // See how much room needed + } else { + uint32 uArg32; + AEEVA_ARG(args, uArg32, int32); // See how much room needed + uArg64 = uArg32; + if ('d' == cType || 'i' == cType) { + uArg64 = (uint64)(int64)(int32)uArg32; + } + } + + FormatNumber(&ff, achBuf, uArg64); + + } else if (pfnFormatFloatFunc && + ('e' == TOLOWER(cType) || + 'f' == TOLOWER(cType) || + 'g' == TOLOWER(cType) || + 'a' == TOLOWER(cType))) { + + // float + int nError = AEE_SUCCESS; + double dNumber; + + AEEVA_ARG(args, dNumber, double); + nError = pfnFormatFloatFunc(&ff, dNumber, achBuf2); + if (FAILED(nError)) { + continue; + } + + } else if ('\0' == cType) { + + // premature end + break; + + } else { + // Unknown type + BufBound_Putc(&bb, cType); + continue; + } + + // FieldFormat computed variables + nWidth controls output + + if (ff.flags & FF_ZERO) { + ff.nNumWidth = ff.nWidth - ff.nPrefix; + } + + { + int nLen1 = ff.nLen; + int nLen2 = STD_MAX(ff.nNumWidth, nLen1) + ff.nPrefix; + + // Putnc() safely ignores negative sizes + BufBound_Putnc(&bb, ' ', smath_Sub(ff.nWidth,nLen2)); + BufBound_Write(&bb, ff.pszStr, ff.nPrefix); + BufBound_Putnc(&bb, '0', smath_Sub(ff.nNumWidth, nLen1)); + BufBound_Write(&bb, ff.pszStr+ff.nPrefix, nLen1); + BufBound_Putnc(&bb, ' ', smath_Sub(-nLen2, ff.nWidth)); + } + } + + AEEVA_END(args); + + BufBound_ForceNullTerm(&bb); + + /* Return number of bytes required regardless if buffer bound was reached */ + + /* Note that we subtract 1 because the NUL byte which was added in + BufBound_ForceNullTerm() is counted as a written byte; the semantics + of both the ...printf() functions and the strl...() functions call for + the NUL byte to be excluded from the count. */ + + return BufBound_Wrote(&bb)-1; +} + +int std_vstrlprintf(char *pszDest, int nDestSize, + const char *cpszFmt, + AEEVaList args) +{ + return std_strlprintf_inner(pszDest, nDestSize, cpszFmt, args, NULL); +} + +int std_vsnprintf(char *pszDest, int nDestSize, + const char *cpszFmt, + AEEVaList args) +/* + Same as std_vstrlprintf with the additional support of floating point + conversion specifiers - %e, %f, %g and %a +*/ +{ + return std_strlprintf_inner(pszDest, nDestSize, cpszFmt, args, FormatFloat); +} + +int std_strlprintf(char *pszDest, int nDestSize, const char *pszFmt, ...) +{ + int nRet; + AEEVaList args; + + AEEVA_START(args, pszFmt); + + nRet = std_vstrlprintf(pszDest, nDestSize, pszFmt, args); + + AEEVA_END(args); + + return nRet; +} + +int std_snprintf(char *pszDest, int nDestSize, const char *pszFmt, ...) +/* + Same as std_strlprintf with the additional support of floating point + conversion specifiers - %e, %f, %g and %a +*/ +{ + int nRet; + AEEVaList args; + + AEEVA_START(args, pszFmt); + + nRet = std_vsnprintf(pszDest, nDestSize, pszFmt, args); + + AEEVA_END(args); + + return nRet; +} diff --git a/src/symbols.lst b/src/symbols.lst new file mode 100644 index 0000000..5e64155 --- /dev/null +++ b/src/symbols.lst @@ -0,0 +1,55 @@ +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause + +{ + global: + remote_handle_open; + remote_handle_invoke; + remote_handle_close; + remote_handle_control; + remote_session_control; + fastrpc_mmap; + fastrpc_munmap; + remote_mmap; + remote_munmap; + remote_mmap64; + remote_munmap64; + remote_mem_map; + remote_mem_unmap; + remote_register_buf; + remote_register_buf_attr; + remote_register_buf_attr2; + remote_register_fd; + remote_register_fd2; + remote_register_dma_handle; + remote_register_dma_handle_attr; + remote_set_mode; + remote_handle64_open; + remote_handle64_invoke; + remote_handle64_close; + remote_handle64_control; + rpcmem_init; + rpcmem_deinit; + rpcmem_alloc; + 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; + dspqueue_close; + dspqueue_export; + dspqueue_write_noblock; + dspqueue_write; + dspqueue_read_noblock; + dspqueue_read; + dspqueue_peek_noblock; + dspqueue_peek; + dspqueue_write_early_wakeup_noblock; + dspqueue_get_stat; + HAP_debug_v2; + HAP_debug_runtime; + local: *; +};