pax_global_header00006660000000000000000000000064151234570540014520gustar00rootroot0000000000000052 comment=cff7d44c4f1a2a9657514eecc0348caa3f455de4 fastrpc-1.0.2/000077500000000000000000000000001512345705400131625ustar00rootroot00000000000000fastrpc-1.0.2/.github/000077500000000000000000000000001512345705400145225ustar00rootroot00000000000000fastrpc-1.0.2/.github/actions/000077500000000000000000000000001512345705400161625ustar00rootroot00000000000000fastrpc-1.0.2/.github/actions/aws_s3_helper/000077500000000000000000000000001512345705400207205ustar00rootroot00000000000000fastrpc-1.0.2/.github/actions/aws_s3_helper/action.yml000066400000000000000000000110521512345705400227170ustar00rootroot00000000000000name: AWS S3 Helper description: Upload and download files from AWS S3 inputs: s3_bucket: description: S3 Bucket Name required: true local_file: description: Local file paths. For 'multi-upload', this should be a path to a file containing a list of local file paths (one per line). For 'single-upload', it's a single local file path. required: false default: ../artifacts/file_list.txt download_file: description: S3 path of the file to download (e.g., path/to/your/file.txt). Used only in 'download' mode. required: false default: '' download_location: description: Local directory where the downloaded file should be placed. Used only in 'download' mode. required: false default: . mode: description: Mode of operation (single-upload, multi-upload, download) required: true default: single-upload deviceTree: description: Target device Tree name or identifier, used to organize uploads in S3. type: string required: true outputs: presigned_url: description: Pre-signed URL for the single uploaded file (only available in 'single-upload' mode). value: ${{ steps.sync-data.outputs.presigned_url }} runs: using: "composite" steps: - name: Sync Data id: sync-data shell: bash env: UPLOAD_LOCATION: ${{ github.repository_owner }}/${{ github.event.repository.name }}/${{ github.workflow }}/${{ github.head_ref != '' && github.head_ref || github.run_id }}/${{ inputs.deviceTree }}/ run: | echo "::group::$(printf '__________ %-100s' 'Process' | tr ' ' _)" case "${{ inputs.mode }}" in multi-upload) echo "Uploading files to S3 bucket..." first_line=true # Start the JSON object mkdir -p "${{ github.workspace }}/${{ inputs.deviceTree }}" echo "{" > ${{ github.workspace }}/${{ inputs.deviceTree }}/presigned_urls_${{ inputs.deviceTree }}.json while IFS= read -r file; do if [ -f "$file" ]; then echo "Uploading $file..." aws s3 cp "$file" s3://${{ inputs.s3_bucket }}/${{ env.UPLOAD_LOCATION }} echo "Uploaded $file to s3://${{ inputs.s3_bucket }}/${{ env.UPLOAD_LOCATION }}" echo "Creating Pre-signed URL for $file..." filename=$(basename "$file") presigned_url=$(aws s3 presign s3://${{ inputs.s3_bucket }}/${{ env.UPLOAD_LOCATION }}$filename --expires-in 259200) if [ "$first_line" = true ]; then first_line=false else echo "," >> ${{ github.workspace }}/${{ inputs.deviceTree }}/presigned_urls_${{ inputs.deviceTree }}.json fi # Append the pre-signed URL to the file echo " \"${file}\": \"${presigned_url}\"" >> ${{ github.workspace }}/${{ inputs.deviceTree }}/presigned_urls_${{ inputs.deviceTree }}.json echo "Pre-signed URL for $file: $presigned_url" else echo "Warning: $file does not exist or is not a regular file." fi done < "${{ inputs.local_file }}" # Close the JSON object echo "}" >> ${{ github.workspace }}/${{ inputs.deviceTree }}/presigned_urls_${{ inputs.deviceTree }}.json ;; single-upload) echo "Uploading single file to S3 bucket..." aws s3 cp "${{ inputs.local_file }}" s3://${{ inputs.s3_bucket }}/${{ env.UPLOAD_LOCATION }} echo "Uploaded ${{ inputs.local_file }} to s3://${{ inputs.s3_bucket }}/${{ env.UPLOAD_LOCATION }}" echo "Creating Pre-signed URL for ${{ inputs.local_file }}..." presigned_url=$(aws s3 presign s3://${{ inputs.s3_bucket }}/${{ env.UPLOAD_LOCATION }}${{ inputs.local_file }} --expires-in 259200) echo "presigned_url=${presigned_url}" >> "$GITHUB_OUTPUT" ;; download) #Download The required file from s3 echo "Downloading files from S3 bucket..." aws s3 cp s3://${{ inputs.s3_bucket }}/${{ inputs.download_file }} ${{ inputs.download_location }} ;; *) echo "Invalid mode. Use 'upload' or 'download'." exit 1 ;; esac - name: Upload artifacts if: ${{ inputs.mode == 'multi-upload' }} uses: actions/upload-artifact@v4 with: name: presigned_urls_${{ inputs.deviceTree }}.json path: ${{ github.workspace }}/${{ inputs.deviceTree }}/presigned_urls_${{ inputs.deviceTree }}.json retention-days: 3 fastrpc-1.0.2/.github/actions/build/000077500000000000000000000000001512345705400172615ustar00rootroot00000000000000fastrpc-1.0.2/.github/actions/build/action.yml000066400000000000000000000060541512345705400212660ustar00rootroot00000000000000name: Build workspace description: | Builds and packages the FastRPC workspace. This composite action compiles the FastRPC source code and kernel modules using a specified Docker image, verifies the compilation artifacts, and then packages the resulting binaries, libraries, and kernel modules into a gzipped CPIO ramdisk. It also includes steps to copy firmware files and test binaries into the ramdisk. Finally, it unpacks the generated ramdisk for inspection and verification. inputs: docker_image: description: Docker image required: true default: fastrpc-image:latest workspace_path: description: Workspace path required: true runs: using: "composite" steps: - name: Compile fastrpc code using Docker Image shell: bash run: | cd ${{ inputs.workspace_path }} echo "::group::$(printf '__________ %-100s' 'Compile fastrpc' | tr ' ' _)" docker run -i --rm \ --user $(id -u):$(id -g) \ --workdir="$PWD" \ -v "$(dirname $PWD)":"$(dirname $PWD)" \ ${{ inputs.docker_image }} bash -c " ./gitcompile --host=aarch64-linux-gnu make install DESTDIR=${{ inputs.workspace_path }}/artifacts/ramdisk_fastrpc " echo "::endgroup::" - name: Build kernel using Docker Image shell: bash run: | cd ${{ inputs.workspace_path }}/kernel echo "::group::$(printf '__________ %-100s' 'Compile kernel' | tr ' ' _)" docker run -i --rm \ --user $(id -u):$(id -g) \ --workdir="$PWD" \ -v "$(dirname $PWD)":"$(dirname $PWD)" \ ${{ inputs.docker_image }} bash -c " make O=../kobj defconfig make O=../kobj -j$(nproc) make O=../kobj -j$(nproc) dir-pkg INSTALL_MOD_STRIP=1 " echo "::endgroup::" - name: Package Files into ramdisk shell: bash run: | echo "Package FastRPC firmware files" cp -r ${{ inputs.workspace_path }}/firmware_dir/* ${{ inputs.workspace_path }}/artifacts/ramdisk_fastrpc/ echo "Package DLKM into ramdisk" cd ${{ inputs.workspace_path }}/kobj/tar-install cp -r lib/* ${{ inputs.workspace_path }}/artifacts/ramdisk_fastrpc/usr/lib/ ls -la ${{ inputs.workspace_path }}/artifacts/ramdisk_fastrpc/usr/lib/ cd ${{ inputs.workspace_path }}/artifacts/ cd ramdisk_fastrpc find . | cpio -o -H newc > ../ramdisk_fastrpc.cpio cd .. gzip -9 ramdisk_fastrpc.cpio mv ramdisk_fastrpc.cpio.gz ramdisk_fastrpc.gz - name: Unpack and inspect ramdisk shell: bash run: | echo "Unpack and mount ramdisk" cd ${{ inputs.workspace_path }}/artifacts mkdir -p ramdisk_test gunzip -c ramdisk_fastrpc.gz > ramdisk_test/ramdisk echo "Unpacking ramdisk" cd ramdisk_test # Use safer syntax to avoid broken pipe cpio -idmv < ramdisk || echo "cpio unpack failed" # Inspect contents ls -ltr usr/lib | grep rpc || true ls -ltr usr/bin | grep rpc || true fastrpc-1.0.2/.github/actions/build_docker_image/000077500000000000000000000000001512345705400217525ustar00rootroot00000000000000fastrpc-1.0.2/.github/actions/build_docker_image/action.yml000066400000000000000000000044541512345705400237610ustar00rootroot00000000000000name: Build fastrpc docker image description: | Build fastrpc docker image This GitHub Action builds the fastrpc Docker image using a multi-step process: Checks out the fastrpc-image repository to obtain the Dockerfile. Sets up Docker Buildx for advanced build capabilities. Captures the current user's UID, GID, and username for use as Docker build arguments. Builds the Docker image with caching enabled, tagging it as 'fastrpc-image:latest'. Outputs a success message and the image name after the build. Re-checks out the main repository for any subsequent workflow steps. inputs: image: description: The docker image to Build required: true default: fastrpc-image:latest runs: using: "composite" steps: # Checkout fastrpc-image repository to get the Dockerfile - name: Checkout fastrpc-image repo for Dockerfile uses: actions/checkout@v4 with: fetch-depth: 0 repository: qualcomm/fastrpc-image ref: main - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Pre-Build Docker Image id: pre-build shell: bash run: | uid=$(id -u) gid=$(id -g) user=$(whoami) echo "uid=$uid" >> "$GITHUB_OUTPUT" echo "gid=$gid" >> "$GITHUB_OUTPUT" echo "user=$user" >> "$GITHUB_OUTPUT" echo "Running as user: $user (UID: $uid, GID: $gid)" - name: Build fastrpc Docker Image id: build uses: docker/build-push-action@v6 with: context: . push: false load: true tags: fastrpc-image:latest build-args: | "USER=${{ steps.pre-build.outputs.user }}" "UID=${{ steps.pre-build.outputs.uid }}" "GID=${{ steps.pre-build.outputs.gid }}" cache-from: type=gha cache-to: type=gha,mode=max - name: Post-Build Docker Image id: post-build shell: bash run: | echo "Docker image fastrpc-image:latest built successfully." echo "image_name=fastrpc-image:latest" >> $GITHUB_OUTPUT # Checkout the main repo again for later steps - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 ref: ${{ github.ref }}fastrpc-1.0.2/.github/actions/lava_job_render/000077500000000000000000000000001512345705400212765ustar00rootroot00000000000000fastrpc-1.0.2/.github/actions/lava_job_render/action.yml000066400000000000000000000166341512345705400233100ustar00rootroot00000000000000name: Test Action description: | This GitHub Action composite action prepares data for LAVA job definitions. It reads presigned URLs from a JSON file, creates a metadata.json file, uploads it to S3, and then populates a cloudData.json file with various artifact URLs (image, vmlinux, firmware, modules, dtb, metadata, ramdisk). Finally, it generates a LAVA job definition using these populated data files. inputs: docker_image: description: Docker image required: true default: fastrpc-image:latest runs: using: "composite" steps: - name: Process presigned_urls.json id: process_urls uses: actions/github-script@v7 with: script: | const fs = require('fs'); const p = require('path'); // Helper function to find URL by filename function findUrlByFilename(filename) { for (const [path, url] of Object.entries(data)) { if (path.endsWith(filename)) { return url; } } return null; } const filePath = p.join( process.env.GITHUB_WORKSPACE, `presigned_urls_${process.env.DEVICE_TREE}.json` ); if (fs.existsSync(filePath)) { console.log("File exists"); } else { console.log("File does not exist"); core.setFailed(`File not found: ${filePath}`); } // Read the JSON file const data = JSON.parse(fs.readFileSync(filePath, 'utf-8')); // Extract URLs into variables const modulesTarUrl = findUrlByFilename('modules.tar.xz'); const imageUrl = findUrlByFilename('Image'); const vmlinuxUrl = findUrlByFilename('vmlinux'); const firmwareUrl = findUrlByFilename('ramdisk_fastrpc.gz'); const dtbFilename = `${process.env.DEVICE_TREE}.dtb`; const dtbUrl = findUrlByFilename(dtbFilename); // Set outputs core.setOutput('modules_url', modulesTarUrl); core.setOutput('image_url', imageUrl); core.setOutput('vmlinux_url', vmlinuxUrl); core.setOutput('firmware_url', firmwareUrl); core.setOutput('dtb_url', dtbUrl); console.log(`Modules URL: ${modulesTarUrl}`); console.log(`Image URL: ${imageUrl}`); console.log(`Vmlinux URL: ${vmlinuxUrl}`); console.log(`Ramdisk FastRPC URL: ${firmwareUrl}`); console.log(`Dtb URL: ${dtbUrl}`); - name: Create metadata.json id: create_metadata shell: bash run: | echo "Creating job dtb definition" # Create the job definition using the processed URLs cd ../job_render docker run -i --rm \ --user "$(id -u):$(id -g)" \ --workdir="$PWD" \ -v "$(dirname "$PWD")":"$(dirname "$PWD")" \ -e dtb_url="${{ steps.process_urls.outputs.dtb_url }}" \ ${{ inputs.docker_image }} \ jq '.artifacts["dtbs/qcom/${{ env.DEVICE_TREE }}.dtb"] = env.dtb_url' data/metadata.json > temp.json && mv temp.json data/metadata.json - name: Upload metadata.json id: upload_metadata uses: qualcomm/fastrpc/.github/actions/aws_s3_helper@development with: local_file: ../job_render/data/metadata.json s3_bucket: qli-prd-fastrpc-gh-artifacts mode: single-upload - name: Create cloudData json shell: bash run: | echo "Creating job metadata definition" metadata_url="${{ steps.upload_metadata.outputs.presigned_url }}" ramdisk_url="${{ steps.process_urls.outputs.ramdisk_url }}" firmware_url="${{ steps.process_urls.outputs.firmware_url }}" vmlinux_url="${{ steps.process_urls.outputs.vmlinux_url }}" image_url="${{ steps.process_urls.outputs.image_url }}" modules_url="${{ steps.process_urls.outputs.modules_url }}" # Create the job definition using the processed URLs cd ../job_render echo "Creating metadata_url ${metadata_url}" # using metadata_url docker run -i --rm \ --user "$(id -u):$(id -g)" \ --workdir="$PWD" \ -v "$(dirname "$PWD")":"$(dirname "$PWD")" \ -e metadata_url="$metadata_url" \ ${{ inputs.docker_image }} \ jq '.artifacts.metadata = env.metadata_url' data/cloudData.json > temp.json && mv temp.json data/cloudData.json echo "Creating image_url ${image_url}" # using image_url docker run -i --rm \ --user "$(id -u):$(id -g)" \ --workdir="$PWD" \ -v "$(dirname "$PWD")":"$(dirname "$PWD")" \ -e image_url="$image_url" \ ${{ inputs.docker_image }} \ jq '.artifacts.kernel = env.image_url' data/cloudData.json > temp.json && mv temp.json data/cloudData.json echo "Creating vmlinux_url ${vmlinux_url}" # using vmlinux_url docker run -i --rm \ --user "$(id -u):$(id -g)" \ --workdir="$PWD" \ -v "$(dirname "$PWD")":"$(dirname "$PWD")" \ -e vmlinux_url="$vmlinux_url" \ ${{ inputs.docker_image }} \ jq '.artifacts.vmlinux = env.vmlinux_url' data/cloudData.json > temp.json && mv temp.json data/cloudData.json echo "Creating FastRPC firmware_url ${firmware_url}" # using firmware_url - ramdisk_fastrpc docker run -i --rm \ --user "$(id -u):$(id -g)" \ --workdir="$PWD" \ -v "$(dirname "$PWD")":"$(dirname "$PWD")" \ -e firmware_url="$firmware_url" \ ${{ inputs.docker_image }} \ jq '.artifacts.firmware = env.firmware_url' data/cloudData.json > temp.json && mv temp.json data/cloudData.json echo "Creating modules_url ${modules_url}" # using modules_url docker run -i --rm \ --user "$(id -u):$(id -g)" \ --workdir="$PWD" \ -v "$(dirname "$PWD")":"$(dirname "$PWD")" \ -e modules_url="$modules_url" \ ${{ inputs.docker_image }} \ jq '.artifacts.modules = env.modules_url' data/cloudData.json > temp.json && mv temp.json data/cloudData.json - name: Update firmware to cloudData shell: bash run: | cd ../job_render ramdisk_url="$(aws s3 presign s3://qli-prd-fastrpc-gh-artifacts/meta-qcom/initramfs-kerneltest-full-image-qcom-armv8a.cpio.gz --expires 7600)" echo "Updating ramdisk_url ${ramdisk_url}" # using ramdisk_url docker run -i --rm \ --user "$(id -u):$(id -g)" \ --workdir="$PWD" \ -v "$(dirname "$PWD")":"$(dirname "$PWD")" \ -e ramdisk_url="$ramdisk_url" \ ${{ inputs.docker_image }} \ jq '.artifacts.ramdisk = env.ramdisk_url' data/cloudData.json > temp.json && mv temp.json data/cloudData.json - name: Create lava_job_definition shell: bash run: | cd ../job_render mkdir -p renders docker run -i --rm \ --user "$(id -u):$(id -g)" \ --workdir="$PWD" \ -v "$(dirname "$PWD")":"$(dirname "$PWD")" \ -e TARGET="${{ env.LAVA_DEVICE_NAME }}" \ -e TARGET_DTB="${{ env.DEVICE_TREE }}" \ ${{ inputs.docker_image }} \ sh -c 'export BOOT_METHOD=fastboot && \ export TARGET=${TARGET} && \ export TARGET_DTB=${TARGET_DTB} && \ python3 lava_Job_definition_generator.py --localjson ./data/cloudData.json --fastrpc-premerge' fastrpc-1.0.2/.github/actions/loading/000077500000000000000000000000001512345705400175775ustar00rootroot00000000000000fastrpc-1.0.2/.github/actions/loading/action.yml000066400000000000000000000035661512345705400216110ustar00rootroot00000000000000name: Load Parameters description: | This composite action loads build parameters from a `MACHINES.json` file. It parses the JSON file to create two matrices: - `build_matrix`: A complete matrix containing 'deviceTree', 'linuxFirmware', 'lavaDeviceName' and 'hexDSPBinary' It expects the `MACHINES.json` file to be located at `ci/MACHINES.json` relative to the workspace root. outputs: build_matrix: description: Build matrix value: ${{ steps.set-matrix.outputs.build_matrix }} runs: using: "composite" steps: - name: Set Build Matrix id: set-matrix uses: actions/github-script@v7 with: script: | const fs = require('fs'); const path = require('path'); const filePath = path.join(process.env.GITHUB_WORKSPACE, 'ci', 'MACHINES.json'); let fileData; try { if (!fs.existsSync(filePath)) { core.setFailed(`Error: MACHINES.json not found at ${filePath}`); return; } fileData = JSON.parse(fs.readFileSync(filePath, 'utf-8')); } catch (err) { core.setFailed(`Error loading or parsing MACHINES.json: ${err.message}`); return; } // fileData is an object, not an array const matrix = Object.values(fileData) .filter(item => typeof item === 'object' && item !== null && 'deviceTree' in item && 'linuxFirmware' in item && 'lavaDeviceName' in item && 'hexDSPBinary' in item ) .map(({ deviceTree, linuxFirmware, lavaDeviceName, hexDSPBinary }) => ({ deviceTree, linuxFirmware, lavaDeviceName, hexDSPBinary })); core.setOutput('build_matrix', JSON.stringify(matrix)); console.log("Generated build_matrix:"); console.log(matrix); fastrpc-1.0.2/.github/actions/sync/000077500000000000000000000000001512345705400171365ustar00rootroot00000000000000fastrpc-1.0.2/.github/actions/sync/action.yml000066400000000000000000000114371512345705400211440ustar00rootroot00000000000000name: Sync workspace description: | This composite action synchronizes a workspace by cleaning it up,checking out necessary code repositories, and preparing a linux Firmware directory with required binaries. It clones and copies FastRPC hexagon DSP binaries and Linux firmware (specifically QCOM firmware) based on the provided `hexDSPBinary` and `linuxFirmware` input. It also clones the `qualcomm-linux/kernel` repository. The action sets an output `workspace_path` to the GitHub workspace directory. inputs: linuxFirmware: description: Linux Firmware identifier type: string required: true hexDSPBinary: description: Hexagon DSP binaries identifier type: string required: true outputs: workspace_path: description: Sync workspace path value: ${{ steps.set-workspace.outputs.workspace }} runs: using: "composite" steps: - name: Clean workspace shell: bash run: | echo "Cleaning up workspace..." rm -rf ${{ github.workspace }}/* echo "Workspace cleaned successfully!" - name: Checkout fastrpc code uses: actions/checkout@v4 - name: Clone FastRPC hexagon DSP binaries repositories and copy Firmware shell: bash run: | cd ${{ github.workspace }} mkdir -p firmware_dir/usr/lib/dsp/ echo "Cloning FastRPC hexagon DSP binaries..." git clone https://github.com/linux-msm/hexagon-dsp-binaries.git cd hexagon-dsp-binaries git fetch --all --tags --prune TARGET="${{ inputs.hexDSPBinary }}" DSP_REF="" CONFIG="config.txt" echo "Searching FastRPC hexagon DSP binaries for target: $TARGET" if [ ! -f "$CONFIG" ]; then echo "Error: $CONFIG file not found in hexagon-dsp-binaries directory." exit 1 fi while read -r _ subdir dsp version; do echo "DSP binaries for $dsp in $subdir - $version" # match anywhere in the path if [[ "${subdir,,}" == *"${TARGET,,}/"* ]]; then echo "Found matching DSP binaries for target '$TARGET': $subdir - $version" echo "Copying DSP binaries for $dsp in $subdir/$version" mkdir -p "../firmware_dir/usr/lib/dsp/${dsp}" cp -rf "$subdir/$version/"* "../firmware_dir/usr/lib/dsp/${dsp}/" echo "Copied DSP binaries for $dsp in ../firmware_dir/usr/lib/dsp/${dsp}" DSP_REF="$version" echo "${dsp}:${subdir}////${version}" fi done < <(grep "^Install:" "$CONFIG") echo "DSP binaries copied successfully!" - name: Clone Firmware binaries repositories and copy Firmware shell: bash run: | cd ${{ github.workspace }} git clone https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git TARGET="${{ inputs.hexDSPBinary }}" LINUX_FIRMWARE="${{ inputs.linuxFirmware }}" # Construct the source path for qcom firmware in the cloned linux-firmware repo # It's usually under /qcom/ LINUX_FIRMWARE_QCOM_PATH="linux-firmware/qcom/${TARGET}" # Check if the target qcom firmware directory exists in the cloned repo if [ ! -d "$LINUX_FIRMWARE_QCOM_PATH" ]; then echo "ERROR: Directory '$LINUX_FIRMWARE_QCOM_PATH' not found in linux_firmware repo." exit -1 else # Create the destination directory in firmware_dir mkdir -p "${{ github.workspace }}/firmware_dir/usr/lib/firmware/qcom/${LINUX_FIRMWARE}" # Copy the contents of the qcom target directory # Use trailing slashes to copy contents, not the directory itself cp -rf "${LINUX_FIRMWARE_QCOM_PATH}/"* "${{ github.workspace }}/firmware_dir/usr/lib/firmware/qcom/${LINUX_FIRMWARE}/" echo "Copied QCOM firmware from '${LINUX_FIRMWARE_QCOM_PATH}' to '${{ github.workspace }}/firmware_dir/usr/lib/firmware/qcom/${LINUX_FIRMWARE}/' successfully!" fi - name: List all subdirectories and files in firmware_dir shell: bash run: | cd ${{ github.workspace }} echo "Listing contents of firmware_dir recursively..." find firmware_dir -type d -print find firmware_dir -type f -print - name: Configure git shell: bash run: | git config --global user.name "github-actions" git config --global user.email "github-actions@github.com" - name: Clone kernel repositories shell: bash run: | cd ${{ github.workspace }} git clone https://github.com/qualcomm-linux/kernel.git cd kernel git fetch origin git checkout qcom-next - name: Set workspace path id: set-workspace shell: bash run: | echo "workspace=${{ github.workspace }}" >> "$GITHUB_OUTPUT" fastrpc-1.0.2/.github/dependabots.yaml000066400000000000000000000010321512345705400176720ustar00rootroot00000000000000# To get started with Dependabot version updates, you'll need to specify which # package ecosystems to update and where the package manifests are located. # Please see the documentation for all configuration options: # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file version: 2 updates: - package-ecosystem: "github-actions" # See documentation for possible values directory: "/" # This points to .github/workflows schedule: interval: "daily" fastrpc-1.0.2/.github/workflows/000077500000000000000000000000001512345705400165575ustar00rootroot00000000000000fastrpc-1.0.2/.github/workflows/abi-compat.yml000066400000000000000000000175241512345705400213270ustar00rootroot00000000000000# ============================================================================= # ABI/API Compatibility Check Workflow # ============================================================================= # Ensures that PR changes don't break binary compatibility for existing apps # by comparing shared library ABIs between PR and development branch versions name: ABI/API Compatibility Check on: pull_request: branches: [development, main] # Cross-compilation environment for AArch64 (ARM64) architecture env: CC: aarch64-linux-gnu-gcc CXX: aarch64-linux-gnu-g++ AS: aarch64-linux-gnu-as LD: aarch64-linux-gnu-ld RANLIB: aarch64-linux-gnu-ranlib STRIP: aarch64-linux-gnu-strip # -fno-eliminate-unused-debug-types prevents GCC from optimizing away debug info # that abi-dumper needs to extract complete type information from shared libraries CFLAGS: "-g -Og -fno-eliminate-unused-debug-types" CXXFLAGS: "-g -Og -fno-eliminate-unused-debug-types" jobs: abi: runs-on: ubuntu-latest steps: # ------------------------------------------------------------------------- # Setup Phase: Prepare environment and install dependencies # ------------------------------------------------------------------------- - name: Checkout PR (new) uses: actions/checkout@v4 with: # fetch-depth: 0 required for git worktree to access development branch # without full history, worktree creation will fail fetch-depth: 0 - name: Configure APT for amd64 + arm64 (ports) and update shell: bash run: | set -euxo pipefail # Detect Ubuntu codename CODENAME="$(. /etc/os-release; echo "${VERSION_CODENAME}")" : "${CODENAME:?Failed to read VERSION_CODENAME from /etc/os-release}" echo "Detected Ubuntu codename: ${CODENAME}" # 1) Enable ARM64 multiarch sudo dpkg --add-architecture arm64 # 2) Overwrite main sources to be amd64-only (archive + security) sudo tee /etc/apt/sources.list > /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null <> "$GITHUB_OUTPUT" if [[ "${{ github.event_name }}" == "pull_request_target" ]]; then echo "head_sha=${{ github.event.pull_request.head.sha }}" >> "$GITHUB_OUTPUT" echo "base_sha=${{ github.event.pull_request.base.sha }}" >> "$GITHUB_OUTPUT" echo "branch_name=${{ github.event.pull_request.base.ref }}" >> "$GITHUB_OUTPUT" elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then echo "head_sha=${{ inputs.head-sha }}" >> "$GITHUB_OUTPUT" echo "base_sha=${{ inputs.base-sha }}" >> "$GITHUB_OUTPUT" echo "branch_name=${{ inputs.branch-name }}" >> "$GITHUB_OUTPUT" else # push echo "head_sha=${{ github.event.after }}" >> "$GITHUB_OUTPUT" echo "base_sha=${{ github.event.before }}" >> "$GITHUB_OUTPUT" echo "branch_name=${{ github.ref_name }}" >> "$GITHUB_OUTPUT" fi echo "ref=${{ github.ref }}" >> "$GITHUB_OUTPUT" echo "repo=${{ github.repository }}" >> "$GITHUB_OUTPUT" - name: Run ARMOR Tool uses: qualcomm/armor@main with: event-name: ${{ steps.ev.outputs.event_name }} head-sha: ${{ steps.ev.outputs.head_sha }} base-sha: ${{ steps.ev.outputs.base_sha }} ref: ${{ steps.ev.outputs.ref }} repo: ${{ steps.ev.outputs.repo }} branch-name: ${{ steps.ev.outputs.branch_name }}fastrpc-1.0.2/.github/workflows/stale-issues.yaml000066400000000000000000000013321512345705400220630ustar00rootroot00000000000000name: 'Close stale issues and pull requests with no recent activity' on: schedule: - cron: "30 1 * * *" permissions: issues: write pull-requests: write jobs: stale: runs-on: ubuntu-latest steps: - uses: actions/stale@v9 with: stale-issue-message: 'This issue has been marked as stale due to 60 days of inactivity.' stale-pr-message: 'This pull request has been marked as stale due to 60 days of inactivity.' exempt-issue-labels: bug,enhancement exempt-pr-labels: bug,enhancement days-before-stale: 60 days-before-close: -1 remove-stale-when-updated: true remove-issue-stale-when-updated: true remove-pr-stale-when-updated: true fastrpc-1.0.2/.github/workflows/sync_build.yml000066400000000000000000000105331512345705400214370ustar00rootroot00000000000000name: Sync and build description: | This reusable workflow syncs and builds FastRPC code for a specified machine and firmware using a Docker image. It performs code checkout, Docker image build, workspace sync, kernel compilation, and artifact packaging. Key build outputs (Image, ramdisk, modules, DTB) are uploaded to S3, and the runner workspace is cleaned to manage disk usage. A summary of the build status is added to the GitHub Actions summary. on: workflow_call: inputs: docker_image: description: Docker image type: string required: true deviceTree: description: device Tree name type: string required: true linuxFirmware: description: Linux Firmware identifier type: string required: true hexDSPBinary: description: Hexagon DSP binaries identifier type: string required: true jobs: build: runs-on: group: GHA-fastrpc-Prd-SelfHosted-RG labels: [ self-hosted, fastrpc-prd-u2404-x64-large-od-ephem ] steps: - name: Checkout code uses: actions/checkout@v4 with: # fetch-depth: 1 is generally sufficient for builds and is faster than 0 (full history). # Change to 0 if your build process strictly requires the full Git history. fetch-depth: 1 - name: Build fastrpc docker image uses: qualcomm/fastrpc/.github/actions/build_docker_image@development with: image: ${{ inputs.docker_image }} - name: Sync codebase id: sync uses: qualcomm/fastrpc/.github/actions/sync@development with: linuxFirmware: ${{ inputs.linuxFirmware }} hexDSPBinary: ${{ inputs.hexDSPBinary }} - name: Build workspace id: build_workspace uses: qualcomm/fastrpc/.github/actions/build@development with: docker_image: ${{ inputs.docker_image }} workspace_path: ${{ steps.sync.outputs.workspace_path }} - name: Create file list for artifacts upload run: | workspace=${{ steps.sync.outputs.workspace_path }} # Create the tarball in the root of the GitHub workspace cd "$workspace/kobj/tar-install" tar -cJf "${{ github.workspace }}/modules.tar.xz" lib/modules/ # Populate the file_list.txt with paths to artifacts cat < "$workspace/artifacts/file_list.txt" ${{ github.workspace }}/modules.tar.xz $workspace/kobj/arch/arm64/boot/Image $workspace/kobj/vmlinux $workspace/artifacts/ramdisk_fastrpc.gz $workspace/kobj/arch/arm64/boot/dts/qcom/${{ inputs.deviceTree }}.dtb EOF echo "Generated artifact list:" cat "$workspace/artifacts/file_list.txt" - name: Upload artifacts uses: qualcomm/fastrpc/.github/actions/aws_s3_helper@development with: s3_bucket: qli-prd-fastrpc-gh-artifacts # local_file points to the list of files to upload local_file: ${{ steps.sync.outputs.workspace_path }}/artifacts/file_list.txt mode: multi-upload deviceTree: ${{ inputs.deviceTree }} - name: Clean up # This step is crucial for self-hosted runners to manage disk space. run: | rm -rf "${{ steps.sync.outputs.workspace_path }}/artifacts" || true rm -rf "${{ steps.sync.outputs.workspace_path }}/fastrpc_libs" || true rm -rf "${{ steps.sync.outputs.workspace_path }}/gcc-linaro-7.5.0-2019.12-i686_aarch64-linux-gnu" || true rm -rf "${{ steps.sync.outputs.workspace_path }}/kobj" || true rm -f "${{ github.workspace }}/modules.tar.xz" || true # Clean up the tarball from the root workspace - name: Update summary # This step always runs to provide feedback on the build status. if: success() || failure() shell: bash run: | if [ "${{ steps.build_workspace.outcome }}" == 'success' ]; then echo "Build was successful" summary=":heavy_check_mark: Build Success" else echo "Build failed" summary=":x: Build Failed" fi SUMMARY='
Build Summary '${summary}'
' echo -e "$SUMMARY" >> "$GITHUB_STEP_SUMMARY" fastrpc-1.0.2/.github/workflows/test.yml000066400000000000000000000116661512345705400202730ustar00rootroot00000000000000name: test description: | Run tests on LAVA for a specified target using a Docker image. This reusable GitHub Actions workflow executes FastRPC tests on LAVA infrastructure. It leverages a Docker image for test execution and supports multi-target builds via a matrix strategy. The workflow automates job creation, submission, and result validation on LAVA, providing a streamlined testing process. Designed to be triggered by other workflows, it offers a summary of test outcomes with direct links to LAVA job results, enhancing traceability and debugging. on: workflow_call: inputs: docker_image: description: Docker image type: string required: true default: fastrpc-image:latest build_matrix: description: Build matrix for multi target builds type: string required: true jobs: test: runs-on: group: GHA-fastrpc-Prd-SelfHosted-RG labels: [ self-hosted, fastrpc-prd-u2404-x64-large-od-ephem ] strategy: fail-fast: false matrix: build_matrix: ${{ fromJson(inputs.build_matrix) }} steps: - name: Checkout code uses: actions/checkout@v4 with: ref: ${{ github.ref }} fetch-depth: 0 - name: Build fastrpc docker image uses: qualcomm/fastrpc/.github/actions/build_docker_image@development with: image: ${{ inputs.docker_image }} - name: Download URLs list uses: actions/download-artifact@v4 with: name: presigned_urls_${{ matrix.build_matrix.deviceTree }}.json merge-multiple: true path: ${{ github.workspace }} - name: Clone lava job render scripts run: cd .. && git clone https://github.com/qualcomm-linux/job_render - name: Create fastrpc - lava job definition uses: qualcomm/fastrpc/.github/actions/lava_job_render@development id: create_job_definition with: docker_image: ${{ inputs.docker_image }} env: FIRMWARE: ${{ matrix.build_matrix.linuxFirmware }} DEVICE_TREE: ${{ matrix.build_matrix.deviceTree }} LAVA_DEVICE_NAME: ${{ matrix.build_matrix.lavaDeviceName }} - name: Submit lava job id: submit_job run: | cd ../job_render job_id=$(docker run -i --rm --workdir="$PWD" -v "$(dirname $PWD)":"$(dirname $PWD)" ${{ inputs.docker_image }} sh -c "lavacli identities add --token ${{ secrets.LAVA_OSS_TOKEN }} --uri https://lava-oss.qualcomm.com/RPC2 --username ${{ secrets.LAVA_OSS_USER }} production && lavacli -i production jobs submit ./renders/lava_job_definition.yaml") job_url="https://lava-oss.qualcomm.com/scheduler/job/$job_id" echo "job_id=$job_id" >> $GITHUB_OUTPUT echo "job_url=$job_url" >> $GITHUB_OUTPUT echo "Lava Job: $job_url" echo "JOB_ID=$job_id" >> $GITHUB_ENV - name: Check lava job results id: check_job run: | STATE="" while [ "$STATE" != "Finished" ]; do state=$(docker run -i --rm --workdir="$PWD" -v "$(dirname $PWD)":"$(dirname $PWD)" ${{ inputs.docker_image }} sh -c "lavacli identities add --token ${{ secrets.LAVA_OSS_TOKEN }} --uri https://lava-oss.qualcomm.com/RPC2 --username ${{ secrets.LAVA_OSS_USER }} production && lavacli -i production jobs show $JOB_ID" | grep state) STATE=$(echo "$state" | cut -d':' -f2 | sed 's/^ *//;s/ *$//') echo "Current status: $STATE" sleep 30 done health=$(docker run -i --rm --workdir="$PWD" -v "$(dirname $PWD)":"$(dirname $PWD)" ${{ inputs.docker_image }} sh -c "lavacli identities add --token ${{ secrets.LAVA_OSS_TOKEN }} --uri https://lava-oss.qualcomm.com/RPC2 --username ${{ secrets.LAVA_OSS_USER }} production && lavacli -i production jobs show $JOB_ID" | grep Health) HEALTH=$(echo "$health" | cut -d':' -f2 | sed 's/^ *//;s/ *$//') if [[ "$HEALTH" == "Complete" ]]; then echo "Lava job passed." summary=":heavy_check_mark: Lava job passed." echo "summary=$summary" >> $GITHUB_OUTPUT exit 0 else echo "Lava job failed." summary=":x: Lava job failed." echo "summary=$summary" >> $GITHUB_OUTPUT exit 1 fi - name: Update summary if: success() || failure() shell: bash run: | if [ "${{ steps.create_job_definition.conclusion }}" == 'failure' ]; then status=":x: Test job failed" else status="${{ steps.check_job.outputs.summary }}" job_url="${{ steps.submit_job.outputs.job_url }}" job_id="${{ steps.submit_job.outputs.job_id }}" fi SUMMARY='
'${status}'
JOB ID: '${job_id}'
' echo -e "$SUMMARY" >> $GITHUB_STEP_SUMMARY fastrpc-1.0.2/.gitignore000066400000000000000000000006601512345705400151540ustar00rootroot00000000000000# Build system artifacts autom4te.cache/ m4/ Makefile.in aclocal.m4 compile config.guess config.h.in config.sub configure configure~ depcomp install-sh ltmain.sh missing test-driver # build time artifacts Makefile config.h config.log config.status libtool stamp-h1 .deps/ .libs/ # Compiled objects *.o *.lo *.la # Compiled programs src/adsprpcd src/cdsprpcd src/sdsprpcd test/fastrpc_test # make dist tarballs fastrpc-*.tar.gz fastrpc-1.0.2/CODE-OF-CONDUCT.md000066400000000000000000000127101512345705400156160ustar00rootroot00000000000000# 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 fastrpc-1.0.2/CONTRIBUTING.md000066400000000000000000000147751512345705400154310ustar00rootroot00000000000000## 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. - [Before you begin](#before-you-begin) - [Guidelines](#guidelines) - [Branching strategy](#branching-strategy) - [Setup](#setup) - [Get code](#get-code) - [Development](#development) * [Build](#build) * [Test](#test) * [Commit](#commit) * [Branch update](#branch-update) * [Branch cleanup](#branch-cleanup) - [Submission](#submission) ## Before you begin - Please read our [Code of Conduct](CODE-OF-CONDUCT.md) and [License](LICENSE) and ensure that you agree to abide by them. - For every new feature or bug fix, always start a new issue on https://github.com/quic/fastrpc/issues. - To contribute a bug-fix, please follow the steps in the next sections without any further discussion. - To contribute new features, extensions, utility functions or other significant changes, please describe and discuss the change with us via the GitHub issue that you created above. **A pull request (PR) submitted without discussion and agreement with the project maintainers may be subject to rejection, or significant changes may be requested prior to its acceptance.** ## Guidelines Please follow the guidelines below to increase the likelihood and speed of your PR acceptance: - Follow the existing style in the file or folder where possible. - Keep your change as focused as possible. If you want to make multiple independent changes, consider submitting them as separate PRs. - Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). - Every commit must be signed with the [Developer Certificate of Origin](https://developercertificate.org) (by adding the `-s` option to your `git commit` command). - Each PR submission will trigger a build, test, code quality check and static analysis processes. Submitters are required to fix all failures and warnings prior to acceptance. ## Branching strategy Contributors should develop on [their own fork](https://help.github.com/en/github/getting-started-with-github/fork-a-repo) on branches based off of the `development` branch and then pull requests should be made into the [upstream `development` branch](https://github.com/quic/fastrpc/tree/development). ## Setup Go to https://github.com/quic/fastrpc and fork the repo using [these instructions](https://help.github.com/en/github/getting-started-with-github/fork-a-repo). ## Get code [Sync your fork](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/syncing-a-fork) with the latest from the upstream repository. Get the fastrpc code as follows: ``` git clone https://github.com/YOUR_USERNAME/fastrpc.git cd fastrpc ``` *IMPORTANT:* Setup your pre-commit and commit-msg hook using the following way: ``` cd fastrpc ln -s $(realpath -s .githooks/pre-commit) .git/hooks/pre-commit ln -s $(realpath -s .githooks/commit-msg) .git/hooks/commit-msg ``` ## Development Start a new issue on https://github.com/quic/fastrpc/issues. Create a branch for your feature ``` git checkout -b branch_short_feature_description ``` Now you may begin development. Once your development is complete, please ensure that the code builds successfully and that all tests pass using the instructions in the next sections. ### Build Follow these steps to [build the code](https://github.com/quic/fastrpc/tree/development?tab=readme-ov-file#build--installation). Verify that build artifacts got created here: ``` ls ./src/libs/ ``` ### Test Run [unit tests](https://github.com/quic/fastrpc/tree/development?tab=readme-ov-file#testing). ### Commit Commit the code and checkpoint it on your branch using the following procedure. To display the files that you modified or added: ``` git status ``` To stage new (untracked) or existing files or folders for commit, do the following for each file or folder name that was added or changed: ``` git add ``` To commit your changes: ``` git commit -s -m "Commit message" ``` >*IMPORTANT:* The -s option is required during the commit step (DCO signoff). To push your branch to the remote: ``` git push origin branch_short_feature_description ``` ### Branch update Before merging, it is recommended that you update your branch to the latest on development using the following steps: ``` git fetch git checkout development git pull origin development git checkout branch_short_feature_description ``` Rebase your changes: ``` git rebase development ``` Fix any conflicts that may arise. Then complete the rebasing procedure as follows: ``` git status # Run the next 2 commands ONLY IF you needed to fix any conflicts. # Run this for each file that you changed git add git rebase --continue ``` Re-build the code on your branch and run all tests. Then update your remote branch: ``` git push origin branch_short_feature_description --force-with-lease ``` ### Branch cleanup It is recommended that you commit code to your branches often. Prior to pushing the code and submitting PRs, please try to clean up your branch by squashing multiple commits together and amending commit messages as appropriate. See these pages for details: https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History ## Submission When you're ready to submit your code, issue a pull request from the branch on your FORK into the develop branch on the upstream repository using these [instructions](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request-from-a-fork). 1. Go to your forked repo page `https://github.com/YOUR_USERNAME/fastrpc` and click "New Pull Request". 1. Under "*compare changes*", select the base (destination) repository as `quic/fastrpc` and the branch as `base:development` to the left of the arrow. 1. Under "*compare changes*", select the head (source) repository as `YOUR_USERNAME/fastrpc` and the branch as `base:branch_short_feature_description` to the right of the arrow. 1. Click "*Create Pull Request*" which will initiate the PR and take you to the [PR page](https://github.com/quic/fastrpc/pulls). - In the PR page, click *Reviewers* on the top left and select one. He/she will receive an email notification. - In the PR page, click *Assignee* on the top left and select one. This person can be the reviewer or someone else or even the code submitter. 1. Wait for the outcome of the continuous integration (CI) build and test job, and for any review feedback from the project maintainers.fastrpc-1.0.2/Docs/000077500000000000000000000000001512345705400140525ustar00rootroot00000000000000fastrpc-1.0.2/Docs/adspmsgd.md000066400000000000000000000060021512345705400161740ustar00rootroot00000000000000# Low-Level Design Document for ADSPMSGD ## 1. Introduction This document provides a detailed low-level design for the adspmsgd module. It outlines the implementation details, data structures, algorithms, and interactions with other components. ## 2. Module Overview **Module Name**: adspmsgd **Description**: The adspmsgd framework is a crucial component that bridges the communication between the DSP skel libraries and the application’s logging framework (for example logcat/printf). It essentially enables the skel libraries to log their messages directly into the application’s log framework. This is beneficial for developers because they typically focus on the application logs when debugging, making it easier for them to track and resolve issues. This mechanism enhances the efficiency of the debugging process. **Responsibilities**: - Establishes a shared buffer between the DSP and APSS. - Enables the DSP to inscribe messages into this buffer. - Permits the APPS to extract these messages from the buffer and relay them to the application’s logging framework. ## 3. Data Structures ```c typedef struct { volatile int threadStop; // variable to stop the adspmsgd reader thread unsigned int bufferSize; // size of shared buffer unsigned int readIndex; // the index from which reader 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 printing messages in application logging framework pthread_t msgreader_thread; // thread data structure FILE *log_file_fd; // file descriptor to save runtime farf logs, if set } msgd; ``` ## 4. Msg/Packet format In ADSPMSGD, the shared buffer contains multiple string messages from DSP. Each message is stored in the buffer and is ended with a null character to indicate its conclusion. This format allows the system to efficiently store, read, and manage multiple messages within a single shared buffer. ![Design](Docs/images/adspmsgd_msg_format.png) currentIndex: 21 In this example, the shared buffer contains three message: “Hello”, “World”, and “ADSPMSGD”. Each message is terminated by a null character (\0). The currentIndex is now pointing to the index after the last null character in the buffer. This is typically the position where a new message would start to be stored. ## 5. Design Diagram ![Design](Docs/images/adspmsgd.png) ## 6. Function Definitions **Initialization Function**: ```c int adspmsgd_init(remote_handle64 handle, int filter); ``` **Message Handling Function**: ```c void readMessage(int domain); ``` **Logger Thread**: ```c static void *adspmsgd_reader(void *arg) ``` ## 7. Interface Definitions Although this module doesn’t define any public interfaces, clients can still access its features. All they need to do is create a .FARF file in the application’s running directory and input the appropriate runtime FARF mask values, as specified in the Hexagon SDK. fastrpc-1.0.2/Docs/apps_mem.md000066400000000000000000000121661512345705400162030ustar00rootroot00000000000000# Design Document for apps_mem ## Overview apps_mem is an interface specifically designed to execute memory-related operations on APPS from DSP. These operations could include requests for memory allocation and mapping them on SMMU for DSP usage. The requests from DSP could be for either allocating & mapping a buffer or utilizing a file descriptor. Typically, the interface file is designed for communication from APPS to DSP. However, in this unique scenario, this interface file facilitates communication from DSP to APSS. ## Interface Structure module apps { interface mem { long request_map(in long heapid, in uint32 ion_flags, in uint32 rflags, in uint32 vin, in int32 len, rout uint32 vapps, rout uint32 vadsp); long request_unmap(in uint32 vadsp, in int32 len); long request_map64(in long heapid, in uint32 ion_flags, in uint32 rflags, in uint64 vin, in int64 len, rout uint64 vapps, rout uint64 vadsp); long request_unmap64(in uint64 vadsp, in int64 len); long share_map(in long fd, in long size, rout uint64 vapps, rout uint64 vadsp); long share_unmap(in uint64 vadsp, in long size); }; }; This interface is compiled using the QAIC compiler. The generated stub/skel files are utilized on APPS and DSP. In this particular case, the generated skel file is linked to the APPS library and the stub is linked to DSP. The implementation file includes the implementation to allocate memory, map them on SMMU, and transmit it to DSP. The behavior of different APIs varies based on their implementation. ## API Structure ```c int apps_mem_request_map(int heapid, uint32 lflags, uint32 rflags, uint32 vin, int32 len, uint32* vapps, uint32* vadsp); int apps_mem_request_map64(int heapid, uint32 ion_flags, uint32 rflags, uint64 vin, int64 len, uint64* vapps, uint64* vadsp); int apps_mem_request_unmap(uint32 vadsp, int32 len); int apps_mem_request_unmap64(uint64 vadsp, int64 len); ``` The apps_mem_request map and unmap APIs (both 32bit and 64bit) enable DSP to send heapid (ION heap id - in the case of ION heaps), lflags containing flags related to the heap, and rflags containing information related to the remote usage of this memory (for example, the memory is used for remote heap or dynamic loading or it should be a file descriptor or memory should be allocated from LLC). vin contains the virtual address of the memory on APPS, len is the total size of the memory allocated. vapps and vadsp are return values from kernel and DSP, which contains application space virtual address and DSP virtual address. ```c int apps_mem_share_map(int fd, int size, uint64* vapps, uint64* vadsp); int apps_mem_share_unmap(uint64 vadsp, int size); ``` The apps_mem_share APIs are an extension to the request APIs described above. These APIs enable DSP to work on file descriptors instead of an address to memory. ```c int apps_mem_dma_handle_map(int fd, int offset, int size); int apps_mem_dma_handle_unmap(int fd, int size); ``` The apps_mem_dma_handle APIs are an evolution from apps_mem_share APIs, where there is no need for the virtual address for DSP and APPS, and they completely rely on the file descriptor. ## Remote flags supported DSP supports five distinct flags, with some overlapping between them. Their primary function is to distinguish how this memory is utilized on the DSP. ### ADSP_MMAP_REMOTE_HEAP_ADDR This specific flag represents a request for memory by the Audio PD (Specifically) on the DSP for heap operations. When this flag is used, it’s assumed that the memory allocation takes place in the kernel space, not in the user space. The allocated memory is protected at stage 2 using the SMMU, to prevent any other masters from accessing this memory, with the exception of the DSP. ### ADSP_MMAP_HEAP_ADDR This flag is identical to the previously mentioned one, with the only difference being that it does not provide stage 2 protection at SMMU. ### ADSP_MMAP_ADD_PAGES ADD_PAGES indicates a memory request by a fastRPC signed/unsigned PD on the DSP for heap operations. Typically, memory is allocated in the user space for unsigned PD, while for signed PD, the allocation takes place in the kernel space. ### ADSP_MMAP_ADD_PAGES_LLC This flag enables clients to primarily allocate memory from the system’s L3 (LLC) as it offers low latency memory. Additionally, it allows clients to have memory accessible even in low power mode. This option is available only for priviledged applications. ### FASTRPC_ALLOC_HLOS_FD This flag primarily used in HAP APIs, which are exposed in the Hexagon SDK. Their main function is to allocate memory from the HLOS for different use cases of the clients. ## Application These APIs are typically used in scenarios where additional memory is required on DSP. For instance, the heap on DSP uses these APIs to bring additional memory from HLOS when the available memory on DSP heap hits a low threshold. In some cases, clients can also use these APIs to bring memory for their use case, but with the latest implementation, fastrpc_mmap is introduced thereby reducing the usage of these interfaces. ## Sequence diagram ### Map ![Map sequence](images/apps_mem_map.png) ### Unmap ![UnMap sequence](images/apps_mem_unmap.png) fastrpc-1.0.2/Docs/conf_guideline.md000066400000000000000000000060671512345705400173570ustar00rootroot00000000000000📄 **YAML Configuration Usage Guide** --- ### 🔧 **Purpose** The YAML configuration file enables **fastrpc** to set machine-specific configurations at runtime. Each machine entry corresponds to a specific hardware platform. - fastrpc supports reading YAML configuration files from a particular directory. Users should ensure all configuration files are stored in that same directory. - For Linux platforms: `/usr/share/qcom/conf.d/` - In case of multiple configuration files defining path for a single machine, the directory is parsed in lexicographical order and the latest one carrying the machine path is picked. - **Machine Name**: Obtain the machine name for your platform from: ``` /sys/firmware/devicetree/base/model ``` (fastrpc uses same path for matching machine names) --- ### 📄 **Current Properties** - **DSP_LIBRARY_PATH**: Specifies the path to DSP binaries and resources for the Machine. --- ### 📁 **Format Guidelines** The configuration uses YAML format with the following structure: ``` machines: "Machine Name": DSP_LIBRARY_PATH: "/relative/path/to/dsp/binaries/" ``` **Key Points:** - The root element is `machines:` - Each machine name is a quoted string key under `machines:` - Properties are indented under each machine name - Use proper YAML indentation - Paths should be quoted strings --- ### ✅ **Example Configuration** ``` machines: "Qualcomm Technologies, Inc. DB820c": DSP_LIBRARY_PATH: "/apq8096/Qualcomm/db820c/" "Thundercomm Dragonboard 845c": DSP_LIBRARY_PATH: "/sdm845/Thundercomm/db845c/" ``` --- ### ⚠️ **Important Notes** - Do **not** modify machine names unless adding a new supported Machine. - Ensure `DSP_LIBRARY_PATH` values: - Are enclosed in double quotes (`"..."`). - Are **relative to `/usr/share/qcom/`**. - Follow YAML syntax rules: - Use consistent indentation. - Ensure proper spacing after colons (`: `). - Quote strings containing special characters or spaces. - Avoid tabs (use spaces only). - Maintain: - Proper YAML structure and hierarchy. - Consistent formatting across entries. - When adding new properties: - Document their purpose **here**. - Follow the same indentation pattern. - Do **not** create duplicate Machine entries. - Validate YAML syntax before deployment to avoid parsing errors. --- ### ➕ **Adding New Platforms** To add a new Machine, follow the existing YAML format: ``` machines: "New Machine Name": DSP_LIBRARY_PATH: "/new_machine/path/" ``` Ensure the new entry is properly indented under the `machines:` root element and follows YAML syntax conventions. --- ### 📝 **File Naming** Configuration files should use the `.yaml` or `.yml` extension and be placed in the designated configuration directory (`/usr/share/qcom/conf.d/` on Linux platforms). ### ✅ Schema Validation To ensure the configuration file adheres to the required structure, validate it against the schema provided. Schema File Location: /Docs/schemas/fastrpc-config-schema.yaml Validation Command: Use Yamale for schema validation: yamale -s fastrpc-config-schema.yaml fastrpc-1.0.2/Docs/images/000077500000000000000000000000001512345705400153175ustar00rootroot00000000000000fastrpc-1.0.2/Docs/images/FastRPC_architecture.png000066400000000000000000002110271512345705400220340ustar00rootroot00000000000000PNG  IHDRQh sRGBgAMA a pHYs&?IDATx^ \UqN;Bǀ ((3qu`!ifQ/:#+ ӄ$BȾv:oO}O}R]}{~*[UՕ:u~w~'cDMMa3heWWWq$ɏOulmcvqb8[ vbbߟwj_c߻ľwm}X ((lٲ GƾrDˑ}Qysꩧ:{L۬}G3vY>vyo}[;A@@K."rtyd!hԶcJ]LNN5ۚl9[:geeً: `|]r%p㥭n;::@aOuz{]?fZ6]ϭҕ(`ɒ%3c_,Ή]Έ$`a~~ ꒗g:"d67b=^dl@FQm1Valн(pLC@PRdtɲ 0H4'X\\l/ $* |\++X$>}NF53V ?Ĉ … ͬYD~YrwyqgN>dhr{ylߙ5\cW׾6᤺elud4e~?G'pS@fQ}ŭ[ݽ"vbsy{@PD(-[lBKK999fʔ).0y&ѥ_~@K.qZ`sM7d88#Nk׮57|.;c{bh ]wYhk$#NVyyy\{}OiPSSs~gg磑H%@8F@n㏛vh< d6D{{{i3zs$W2s1'xeVy{LYY= &8 SYYi~x`駟n?#w6O=g'?ɞzFm+<ľ(x-zosO4kC׹;{l[&HG28qm755isl3/9^ pPDhGkkcͥiӦr3ƌwjEN?_b3u%K8 \bד ̐]"CHd(Sb<ϛ_} /BٯA%r/N:ey$#OYVT֢twwߓl޳EY /3[[[5m0Q`s%1Do0QY%xi@A+Sfi'=c6l`uQࣂu~%6UW]4(߻kX鏀P-9sغZ%v奚Üw}iFAA҉S}˝EG@TTTC=#ȢWcOtXt{b.%%%SƚVs.78RTʵj*"?;{ HK~~9—h8vypɒ%QKmmm}^)יzggg끱O:-cN:$2d Jt5gHM4YSY Z8j̙=Sc_hiiy)@#>TqLqxtgՊruQNk|v(̣,{=N`З׬YW.ɦ@/]tlQ_:28#l޼i͘1i 4u|{ϮON+;]9".#@ؘq%MdkJ83fϞ=N+.٪Σw26^]]L@^ZK+/_y^~Z)ZőH@@\u]7@ ';;XUvv#-⵴.g6 9]wlJ+cQGCS5~8NnI_2Ed%KN'֜ { 6={e]x檫raXRQX\ps4N" 3O)/]4{%F@)ɜD5hKTgzw2  sw5xw(cqɒ%*)gևLUTrHii]%v7pk+8\D"E&L0g϶%.2M\~g=zN ɼ'3Т-_ל8MiNe$#ZI=qD:;;\t眫!0(555WsFٕfƌ`@ZJbꫯ:4Ԍ>`=N̟Pv98{ #IiӦz]\ PDXt7W:SƯҜ л4;pY#o؊+V@cC}Mcc׷*cCMO;c{64B@ioٲe9D"׵)J2>ewAS oOv'?Ik1/WFouq9-}͝;7K[[[^n!iΞ`b2twogM'֠o =c6l`w<5X}Gw)X)`|ZDE+2iv-Eo喞O<Ѷ`GI%nP@t8m hƦf!Lwp{Cm 꼃AQaًKV|U͑ic= S+x*( `cfNĒ+jׯ?_O>dg/4Zrs<>(X,89$g[oV伮5 HK7p]]]wi@8 $ tI W_}7.ƥzlZ`"{I &߈ &>"}'O/cEظPDB-s H;Qw5g`A)]UY7`;oij+sɻRpi\]]yRc;w93GwH p籂yAC/7P Uw0ʜWYľHAD}>S&e4#Hw^O~s1F@ieɒ%'G"bJ3uT‹"q:٢]]]-q㹷vUS6nh &N0`"\^ʄ,17x1UE뮻n9ǚSJJJWSVVf=M' *wuu^)UEk*<kPՌDzxQFctvvTEe˖:gfΜLεLA9s|!]/K2"7W---w6@[d#Uk8>^*" 7H$rLT'_JJ={[6벥K^n0(b\>vuuXɓ'/M{6mmwww{ 7T"Ɯ&F"_.eZY0Tܮ E@cΩxRg̘?0L>[On0Q@@c|ol{"-z]d'FE؇jS70Ҽc~XSSs0(bLnb4}0֬n"`x)vww26-p0B(bL~=9SD"0u,U歧kz"Qlٲ }jS70V#ȿ_{UvPĨjii?͔b&Ɣ)*X{s0PĨRm*[Sک1-]4{PĨʺ7f+31//9 ,_lY0d1*jjjۜU(Spdeevg ƥJtFG|9 `(bĩmwwwSLk0aٷoKSR\K,iw 8U[-R^^`ch4Z01H,ؘ"F ۪ڪO·:Zi1*lH'-1sZ[[o EԞ:u-x @ 70"FD4}(R(駨L0AcZ0(bjjj}&Olcnc| pc4,Z¶;;;m"뮛uڞH{v,E;;D@ÒDى謒@F,;Rt3E jOi&Md}G"E Yvv"d7KQﺻ?a)PĐ,[lB*ݚd"w\~V~PĐ\Dʊ.d*ͺ;Zat8me˖n5+͛G@Q|r]x"ut}:쉵4w.c[LWWihQe)ʋhl ˔EMeiPe*JMnvĹ50|---fݺux`fl׹ @6w+"0,x(fNiWyggj++23+s̬\>07n4mPĠ8ىoŚSfϞmS  2C=d_A:ڱüŬzP6y]RarL^vwe"sczuDLGWFs{ԴwFLCk4dŶY@ԟ:5,oLq566 6(/??.Y@r1(K.H$S՗80V`,`Ŭ^|w ](K~uS?̥ibQTn*:LY'ȀPߜev5f\&dbѳMI?X^{@1(K,y,3c >0T ,PL?;scX-!fmDݱ>ms}y>מ`h4bg7Ȕ4YSc^=EdɒhtS$W5 ,PL%>L-k_g9fӾ\!hK&Yf$Ro|ι |}^myy9D `{y?1ml0 h?,d&LƋ-l>xd9~VRnLam{CO?:v֡ 91@eٍYkzQ^@}sm Edɒ5h9s昒(=xQemV3i-jȷ̎sG"'c eaU-/̡o3oγyQs"-^MMMfjY,˒%KNV01'';G4?6{ٞSfwfD (Xr&#C*[uҬl~[z?z`2yz@)2ScG5S94K>RXXhrss՜z=E/GiJRa 0ѻOc6h3di|@Q*8qv)i7< 2H@@ZlYA4`@p1CX<ϞS=ѳo%?V_>[og. ]]]xPĀ.m*.@ AZZxE}xU9qVɢ8T ,|My.**Ң---C@ݞto`@0C(8ส~QSmwĤMuu@ 3lЛDl0qҵ^[}&9G^ pc aknju:5 { lR=2>?^c_s-JEgS.]:@@^F/`2Uz`NeCLEa]hgO5붴:"baore=Hۦuiހ/`D߳L[G{!CM'Oχ߾e!率ccV{ѯ뮻nj$Ynb `$*{ Yck}(f6S1v9nB"8r 굍-oo6M8~V#%; W!/I0$ڐPDRFTMy,`#҂bnpM,&7->U$;%??dgg9:Eí0O0CldTUUݻw;{ Mz;V3kBs 3̟ҧ …:@/菭 Av".`H{yil ͟9bR]xL ۷!<<Ӟ#P?0#M-f6; 3l*-;:5Hgg0smLi~sFFan3ն} PDK.QA0ƂN՞;F>_tlݖVNDnnD"o0:GChmN /`06،6-^I),,N;~ˆ"z‰ ˞C+[-bN$N#r$Y`@PD]]]hK@1K 0ZVoj'ǴPY-K'᧗vmAYv‡X_3gδ[}~Wݣ0_j 뮻̾}k2wa 0wvƳ\'>BfR_`7x18Q$KAE?~bgEp?P `$҂$ނa 5`UVVڅ,"KA7|3i G?Q@$c也? >7'80He3Y%|: y眽z`1put4zd.{5ɽm=A?Yu*QM }[Wtx/:׌͛7;&TPQGhK+]=e5+))/ }̙zKI|ae#bቦ8?9 ٹs=8GhǾNs Q4XDZ?okOI>@' {SC2U0 k~D5 Z@ޖ$q%^?Ǣۧ??m#ٷٓdoimm5/9P CVwwtw ~8n[#Qӝ]ހ[_1jš w}RkV N1 ~5Q0S2eJct^Q_ny=7=F=l 85sH阂_r~$>F>=x_c>o0Qǧk;X4sz_/ݿ^d7LJGсs?\݅t4&rn5ZhL?;W׫y LT R@ᱢ0Rqt#$/ޏug#H„"h4Zl>ƒX.g~Ѡ+ yG+~V\>} {Q`龼+3T=IAP禁xXY y9wwШ/1`Oj^K_k,묋sk'lL^#\h:^P1pioJ)ߑN:$)C^Yhde調 ɉM Fjf'??,<-L^n7P?UUFhruo=fj{6+++>"P7 CVWWWv,N7ȥ`w{>@pS`JJ$ށnǑ2tR,ݗLwZ#OAA7cC44p/2#z:=;E;P`ƽwP{ܽ e^cI|uQ; vz)k_Ք0br9A V|o"}H6EW7\_r#^y{2*鏾}J"å;#bӦMNkd?5r,,("(r?`q}{V|;y0SnE~O#w`#~V\T K+5&@gΞPx@MV|]]s4Zj`k#ID7[Cd%GI-A$>_e0 ǁ&/A:~){˻H2*e@'Ɗ/^sb=!9ƪ Y[;GA_?B", aw衽eO֯_zy=`u &d2KX d%\ ~y335lNyGVr*z?LF,Tpu]}^K5Etf 0 Gs^,/ LU_߻8+`ryWP.++sZ  >U{q %7L|F{y[|.@1gxҒ/>P0[}߁[nuZZ`ӊ8١n7ןUV9x9U}́v@chlol~~X T[WEb.񢚶M z/ޓu_0҆r@;j` $(ŠD"x`f̱봒OwvygF9o IK2 olx9,BIUVڵƌ7E JXf gfGpT: 7^A6ٸm0Pߛ,PxNN'z*)۪FA4-֥žE. _}k8p^lYj+')1*** `d'ꛝj!t(@T01Sν(  f3g?k ʱ#Y?JkkJN})ڳEg_xf*& ԥ'?q~2<5+ Enn2 "mEK/v iJ)ЃXi4 e0я~t3M3{ [[2!( ~ ɻ0J*XT֞m[hdMQz_W^yi08?LyFhp3:J#1[L^[K[{p$j&f e]Q[AӻF{ˁ$rG: .q1Lqy v7m+1bXu9cx6hiM@ 3+ ƛ][?zfITH64PҴm׮]y7в4Yu)ǓnxW{^5v+^x眷Rj~Nϟ? gޢJ/W\qE]wQؖEY:7juDk֬qZ@|u[h)`}ǜidoie3xRb*z}{JJJdtB@9cul7|i@iTi,SQ:@mKZYe1}* =ꫯ:x>NEo^7=K/u NF9p?@ /3,N:i%/zPPM&omiW]uA.9T&3Mo AѾuvyN-:G}iŃ7unV@ӕ'p{*:~%..\hWrh]V@U6bbv(sG=.Wߤ$͙=/>Oo iǢ,3B)q`oހ@/ BwO;PA7`~(i~hxL/ӀkiZ+8z^ ~Tz5rR MI6ctvz500~ɥo⥓\ &ߪ{I}V!o{~v"-NQ?ޏ.z\޾2(Yzݽӥ! w78wUD}a?묳i_SH%2Nsi@筣;`q7𧁌7D@ଞ@4ޗPpɺāK-)fϞ=o}ߵ*@}F3ZSޔ:)`Q[t]wݕO~s}rK=J#ؖ~F]r}M0[DwEʮRE2~)l8D__ٶ5Lfulԩ=mx)@i~ 4 Дs=Snjn[ʎtWV.12>O Rtgs *{G4SITskΜ9?,J]3J:}֘VTqw8G塺O[K{P dtlݟcysiCڅfBY˱㡥74f-fͱf{]~vY0,oAFFGPL E,t"3vHgllyĤ3rmPL-E}WVSߜeۣ%v!)+bL^N)]J̴6SQa YxPDX1@R`hĜw"ϜO0C+;}̝:楩eqwZyuhi~3-M)SܴO 3Kz2[:Se3ݒOe3dFE.e/#qExInNo7x]2nvnߢ0^ʼTP)n?lz9@䓷zu]}Uo";ۛV &akc1/2]6{FThJ8*/1'ίpAx`d)mol:3uKD.+ެwY.M4}@QUYʞa *VNFZQZ׻uo޺E'&ӊ ,vt:P0{m]D'SSikE9R'\;8=vEr!JӺ#"*v) ,*cQɷr}}TCkcw8@۲ɣ67t+]:XQ"an=_=.P)sWL<_ `4-Y+`jXT2Gc064Le_q{,utLۑ ]ɂ:罍NީfN=SLs3`(}@){O?AQSf( "hya>I\`&q 4 x{m[:q$Tf7 RYP~#&h"L{G߅ZFJNv|`6Wv(k*|rNn>)8NOㄒ'ؔ Th"H{Gd<S3M{Y*pТ-+]$e,A!8¶Gj (@S&E9GROME7c [v8VTwL9߬WVklEEEJyk pK548{]4]y :y(p @P ilAD iAQb@PZzԁ[pƒg^~e7woAEO+AnJ& ()zДiOtirzY i0f*ЇOb\Tsy1Uv*eMx3 FoM;z~TPSܟQS?=U9SQR?]7kz龒=]tLz<~ֽ=2EPEPEPEPEPE PTTd=`PEۖvn"vc"@ˎ3`kljۼ.B@@8C`N@흝P]]n2 P(e׺-Toma rq WlIa@f  Pk'~]uvr B *t+)၀sȸLB@@Tvn{{-Q X}W]hE E7 {${$21XcϬ[ h5;U^f_nZvdЪP̋+t6c)'{69 cS5@@@KQSxw0C0h^[lP@0/71ǧW-4v6@diVUg *"))a:sê'ko9G`Xf[[m A@@`)KqzYihl6?|q?#ci~}/=p*a`'7zc -,G'K2 EvƞLŇ}|bLd Wl~{2hs*쥽fo޶ǹL &'m6~OdOhg5S[?_Vک6*x/x{po}Yq]޾WXNk6D0!߯,Y\Xzs Y4?Ծ'Ӌq*b555v[]]m;dz.gA1wlHw+DX+O[ZzY|׾W3}cusygoݟ;s9Ef 3,:+LT01 ПG]]-d( dbΛ_oN{N!(4]v5M`<=ޓzo8ќT`");YS ^VϿnnQF㩫˾{>fߧ,9 EXd(W2?2:as}x?k눘;ۻL'tl6sX`? 2Vd(d!rm<͔3ދzOޙM)ά A",2Ë E鄌ܹz{q @:? 2Vd("("("("("("("("@1---0~(dr㇀"("("("("("("("("@10>(dro>gq[wEd5[瘖ض#bڢ#n8ʎvnSe sL~kO)i8Cuv{Ivjs7*\gG߆o,<춶n CQߜe7OYbԬR`ؙgٛkv5f(.1/zџ֖'b; } d("C18f{T"/19y&csM4+n#Q4#Nf:춻ݴ0 7(1̚ /2:R#CgѷaзCd("Pl%w+m&ҪCYǘɇi\HIO~FIO>S+e|HoHoERXdPl4e/1%UL^QFOxS9cQl;DrTgb.1*656>YOYbpaT;*(@ c#1%LŌ|}mo6O'зaѷ@@hmڗkPbWT )w za\A4>4ٷ[s[ېN (-EtڪS>;-ozT{[ %B߆tFC@@ّo.zR66ޛXйF߆GB@@h*;*gϔ0r^L }2 }E"+ލ /0Ӯp ;@+Q6G29v=^mDm(yqcqO])7I+*5;E}2}d6>-=+^Wv|-,3󪓍 ې sPx9&ҪCl hH4슽‹ @"[n5,Ud. 4=L^ߞo'6}d&ms}-X d2s,+%.gaE߆oC@@P L鍅3lmdrLEEٳgoCз@! ꛳LCkDM~Is|EM4;.ư)9 TmY(m Rye7+(M- <XmQ //@M[V… AF"@jn}Y6{A('ľۢ=oCѷ@  S p450ɱZS@з! cDc6Bnqv{Q> <fa4fKϝ \P󼳗sag9jl<`~6SasMrz />cM>voV?mU+59̚\`WWQ~qmq&3wbyϴ&hf{.~~$E_rYx?sg^m遾mto? :[ ,8 BDҧ!ӊ? ,n:.)-6xd՗gl5I|:v0_{p2Y6Q'ia@8зeo@@@ wƿFYv2\*?xf;#M顁w~huҬŠ B64m(@Ԥ:|OӴ܋ʫn3Fu SM& Fx}y=uQ1xg{k$y'fv(cx@XѷGH CƒVaj>Nge*+@^mt[ovO52*RP䊱[YRތءo9mD@2[]uʤ /z4_깏sͫSroī;{뢢ChnV}amG U\L'WrZD68mtA@AIAꢌ /w맷:GҠB!פ ON%n"c=c_ΛeXi:/nO`(ٽY,{9N):86@Pq R]lsk4dF6='o{].=wfO'eo&_QjͥGԽ&0O deeNgH/mm iexAdwxF]|V/qimWLkn#z k_{ϔ0 UTT={Eߖ} SPqls}6eM0-}g:[?DD2zJ3G[>29ġΞ?2aWک;0A@2<.Tit{ :Q6"ZӥV|d;p>Hxg{sO{ղR,VnN kzz,F}[jmtD@22-4ɭ4Tḣg c*?Z%˄Ryy@}[_mLA@2AʴpiA5߭3C@)t|piO6fĩj?۶GMW.>sEK |iN+Mu;GNY|k?jo}9i՞rwdEK H5ӨF_Oa~}?&í7+h5Ћmѷ E0DGL]~ -̆d#I(Nq 5z }j\@ m# 0V(@ᴌYxhA5ؕ1VԀ!Y yfRgϘ[V][1g ov&MGË۝T8- T߭L,D:Ϛ\\ G+ 𑷝1UevJ 4@-V҄;ЀAWٟE-~V\2fݟ[8 fy*3^Z /WՏkqv5G6:c"dM4x K ~/ϯgzs(ʔ뢶{p}ޕo׻ݟ :WG,^?AW?;riP }o60FvRm w]:sӏVx&D BӠt ;x۰OƄ:ʦnk@}}_MifT> 52VWZzGQV50ooS;i#jjj춺nw,aU塺9-T;~n{IvO?9WP3/6E6𨫫Z‚ EPEPEPfΝ0>("("("("("("(""1N!VSScvczCuv[5xj/mPw_W^ )H`a*SDs{>6]VolRT`(d k.g{ s?Vj_1 ൶u*`L'y'Lv -N777:o^iWRF嵟8E@ Cdee9- x\|ـ9Ofɸ{Aذ7 yad)0D'WAE7^I`2ƒwtA@H)rJhr_/,pLun:o>iS[OY 7_1؞E:>P~nHΑʣǣ  *zb:dqy)Kqc >$i%4 ҪxKjf*: *ZS:%csiu3<_>iiWSKӊ},OE];l։.ZTuK=+g~+$lh wvYSt ;q]CVm!]T{Ok_ӊgy)åj-*;NhH{?c" %ziM ^ 8-cD g~^?RMr)sC?w%}z[))8xzoK) ,tO촌ͼΪ#>(|;ށ@Tޝ2%?&Kk:-cd4Z2AbK+eK}2p3'iQoM}, PÓp}6);:>eJTj,z3T+\zeݾ>Y0Rvjo2S-LދZĻ~zLE@ҷ~fNڤEiJW^v^c[hA*Tm`b@ TT @EDwgdӃ}, SP7Jړ@ESR4^;u  +Rί7؅@u s)0 $* R.c"`@*Į'5zMd|0@, iEMOv߹^r^lZ1YtK Di0Aϭ?]gUN z͢JTh l ybYi '{?T0S2 E8MiʦЪxk?]~l17'i⣧OsZڅwkhnwZ>V Z{W(cD7,Y;y}N˘A׼d.Vۧ i?X(@ m[N`ZER_G=n>ceN@S03EnB(J#K?us꫼SJoM@ E$`K 6e2|U$SQ+w,AsJcNZ2nHO W))jA:Vt %R>W^2},Dc6Bnqv{Q"jvF?9Om' ´f~lwȴle8h@$eض(DCѠp M>gШQ1DTy~6lm4Ú5ޗF%U{ʟo_v^xݢ^{oO^AϼƫoSJ+gn͟KTM.CT?{WUGF} BFuuuv[[[k@X?VK 9t4xO`ϽgeM D4uKށyɨY ~Eͽ/=>UVVtj}f'^iJ zw % &X@PҠKex=hQU;`h#a+HDmuʚH5Ȼ>6uzO\:Kd-q`'\z65POo5oMU}Clf_JB ;¶wַOm}mgoضWR Vskǜw 9}[qѷ2 E4}>e'ӠX'¯c~u?P_u ׇN촒@ ožl}y>6=>z}m2ymmE@2?2gР`:iJ,v%NKnFg~4삚͏w0su2OsZ}yizwJg%;1Tx} 0Ey fѷ2 ؁cE 8lߓDCHT~2f~}%}ޟMf#0;}hr6;i7ۂ#'r _yq2N+hjLDY'H;8杖ZuSzep1_NNioowU k$>з%зCc[(' @p NJwS{x9BZ3-F`(hh ے_ۂ5y4#'r 0yf 0 Gei<F}zBqf`(0$ojwJo_洒{~s*r 1=AFE߆jl1\|!,ykKMsZݩa)a;Jvx o81pT?c4}9ޟU WBXFOx̼ݩa)avZ}y3&:- 0 GnvĔeH{ 鋾 A5-1%,2 B.hvwǧ(e[]S>G=WXNkV]w~d 0H6FmyAE@@ `//Nhu savtί78?zɥ7cS&W]i69 =G=WN쭷ywmæp20Х3b4"}oܷ5Em T" |KhW@]M;uʭ$j똮?c3o{/w@۽Ѷ⽯[? ϔT46po9kopk(1ӸY>FҡSc ^+}}}[z{gosir9 W;i#jjj춺n>f3obY8-ϊo؝gVn)0laQ Xvn0-QSUؙ`|vG9zvqQK.1T 04}>m 9Fgз!2ok鈘-> AG@@ /-rJXL[S|JX&a(y_9 A}ۺdc, E=6+/4E]vLQ 66-vʢ̭ }IMroCPejߦrAo|Js‚">6;bR6bkN4bߑ ]Еg)/9I{-(8ܷiuؤl(E}m6kB-n9Gܰfp(CinEs40|(!5$TK A}Nߗ99 l(8H`S~|438Ҝى 0VtlѼ^9 mLVm+0]3f>'E Lux&tia ޢ=2VnZEa^`Kg]l f{Cٺ?9ڷ;mMorf`ky9sx&lɲoCԾM{i †6|H*h09aVFӼin`eLd mf6N =s ̴5+ g6dLVn-4 QSYep<~ma ~سѴJ*_{Ӱm>rRRSa<\=Yi_Y#8?6dLڝk/ʴ2fPGA܉mT}ךkT5f#bL mbI{o@SoC&Me;trL>||)uE)qLwB{ߍ҈J߹gu̮ `\sSo M}sm}2A&mʰ"Eiy5N (h0yϴ&{Q~߹twef]:އluOn1f"`H7=J/l,2-ȖoC:3b^XlGL33aF@/A)}snTovw;Ys`uwEvo^ٳ剳3z30s9=jߣAZ i%}NĘN)Jk (-s! Ξkؗ^[J 1A֞ͯ{1ݝ3< 0C:S<Ԯ4)+P+? }AP6P鎢Yr[ @@ uVeNw4єwΎv[j:s`V #+~JdyNh1E]Y6b&ctWc*LE6m-vA1}2'"A Lg:} n5 ;̾mkͮw^1 /MLKnY_BTDoh׻+b5vmfsJ`$ʞBAn솒TtѷaoS.R;K+b555v[]]m@mi5}iiSXN}~q }2nʶZo]`dt.xٚDwډYW_}MUUsõc_Y>eo* xзaom,[eDRWWgv EX1a,!4gi]ڣjdT|>7ŶjtlPZ:C7[ZVA oPo 1 2e0kVYEEX1Ta"8z^i0m@;rKF?MoV_]Ĩ ?("`XTSSggln,2kw;: TgJD >uXJ͙Ŷz{~kЗڧ/Y 56`@0?%%%h8BѓKM^N|?Qjey]=9#'S*rB@a񕗗gZ[[=yS̥gM0S&/ybB&@kn7gߊ,Ռ i,$~b0ĒlsǔؓeZ7JMA6.iК%}9)1]akc`1L<+0=s l9̣klgқco?3|{-7  u(*z҇Jt ,"'(Q < )+WuC~M}2wUOkKͪm9˹5Z kJmcKv= _;i#jjj춺nѲc_yvuYwA.3(k3eQcIwڋj%4 -b/^lϟxin6oj5+?TwIv9Iӽ1ۭ` ffۺhZ‚",k ,sPL_j7i1km1}b+4%y8t,}(sK'Źhes~N-a':GC@aE@E'`bl327wvKb`dUk/3+sȨǘ#""0`l0\3ӁN{{ m谙m>ns$Y[Gin%+R_?AVZ59Q3XlS^5Ue9Ÿ#""0`EEEX HV'"("("(d"c"@),,4MMM0("("("("("("("("(d|c"@)..6 0("("("("(-b555g0(sr@PTWW-HO˗/ŋ-?uuuv[[[k@X0oF@oF@o2H~~immuG@ g{F@oF@oF@oF@oF@oF@oF@oF@o/~a.{YbsrrrL{{=@@[N˘w}i2]yyٷo=?|O2rwb8p^= yG̎;[ #q{n7.Ϭ\3fƌN cw17twc^x\cl[||+_aj5!@@iMYq=g̕W^i8gM[nl߾s9|򓟴N:s1#`\^x9䓝=e3wu\`/W]u~`'O6'NE@iI5R&?qgcA5S<,..vRWFE%-͌SV޽{VܤIHwFmuuݎ6 鴲pBd-MT}>ehڵO]ŭs5R_TF׾5ȼ+gm3%_Z:?m-Zψn/ELDCmϚ5~O>iVZ'SPׂ ̙guQP9;ky7;{<Nkp*~#ۮyz~ot?{۩lذ^DC1~:FիmƗ%&Yb6BLAQe,^mSO=նdV@F*ow}/~aqEm{ꩧ̖-[l0.77׹n2l*0>fz``)O9{7k}nz5R0Z?ꫯeVo}ǣ1\ӗ~ko{ׇz)++s۵k *_J.-^ S6.¢i~fj.++ϥAe@DA/ptL y'e)fA.=G-8uw+Fܠ;Spe6 uM|_#q3[Eϻt Qۥޟ^zᇝc{ ӑk3=w뭷dj Mf tMO]xG)n`̵ݻwl4qt/?A; yFQ`QSvYg^z'H'h^ ~}_wEUޗZZZzrz 7CQ\{9gl7|fVVV:GSU(Hٌn}^B|饗K.ľ&^keiO?m{jz7EN;lݺվgqF眘MO?˺us߭LG E+21uA">qy]wJMAo<,LUO23+s 6ڊTϥdK *_6pVW^)OQ}CzT33uRMM=&Mo~glX=F=VvOSmMחG?}Nzt18rd0\ZĥT>]f ѴU?S>ـV2 s$NqEER?YE[ل٫ ,j5\t:p2{SѥơpZLD*6>f:OHO2zN PĸJ}{z"\7ovZ vUd( yQP-UpTf̘ᴒg$e)3PيE֔6~`;֬Y㴆hqgD4ELS?5ͦS]ܬR=^d{6+S`Q(OPq 'NtZɳ );R5@x~VOj*zwd:H Ztado:? .PK3^ӣǚ25uNWN](`UM-ʢH@=ƛ9 j{w7 @#ޅSJAA &8{;v,vI'r ۤ0oV4[NShS4x?5 Ǔ'{]>;?9n={8|ًךT]ǻᄏ_íi{{K\c"Ҏ@@+777;\S?2 a6m(VKAׯ6=paa2ipzg{vTOꫯv[P|7Vf6mӊ?L *ܹiڐ=/T 88o駟﨣rZ}_3gtZ9-"Ғ^q^Nk|\s5ŀ!{k]wqN` (ZlG xI\I+Uf@ӘV1XKN{_+;܅h$>>ob=Eգsp}_Zx2vuGyKNu m? ,*,[nYYݜx≶~wJ?=o}[^gMk#*|ًN ¨&C;cr%x­[o{S?unFeQ~QW p[o5ssd@XOQz `)0]CA܋U^Ѣ47G*o`.1785~k,C1]w}L}%[hEǴK,J>ǤjҢJ|(`ӧOwT {ܬN>e*`hZbn}Bope4޽ۼ⋶`M^ZR ߻wv6Ѩioo?(`~s%2͔)Sl/=SO=6x81\tE泟lEk>fG;;;;;?FkA=H$uxTkzo$|)h.|H^>czΟ?߾OJO?]8R30a3;SHLyFX1oF@oF@1c2fܹN d*FբE<`/ǝ SPEPE e:;;=`P fϞ=0("("("("("("(-b555v[]]mH? ]fViW{i;k eheUCc\ry= }*LB춶n bZżl4<wh9zvsCE@qhS}j "bywWyٲ'>D&^L4+n uuζضմ5՛֦^A)13+s>Чd鍀"Š@zamy}vANI\3q1_43֢ٹ*/UR5~,+;a|jyFOS#@6}ikFEf M~qͦL0}M 6S̳ͯ7mL*sNgЧ*ToS@̪wZL$+۔O>Me PVX6ŔO9deu[ZX\ TAG `< H3})/uԭi h65ѧT぀"T,כtCLvNs g7P&a[s 0tˆ>X#@ѧ+qҺfJH3pmumCA Si㨡ln=yEQH_Λe)r8G3[^ƾNU }*ѧ q~kXrna9|;dZ2f҄<"ɺ-ѧ>t8mXMMVWW-{*g&:G3[RS&/`֟5Oee]zLg/ͻ͎w/l\\s^ʤ;LCS[|]ywe;G{窷|n~ɹ&oN^&ڰ|+lf]VmgzS 3oJ)eQ$sWoTUU9G>u)ʝ3yevo5k60}a۰߹&919/6 x=3Y |a-Mgԯ哛s }I͌I,9k_/l~&ī;ͯE"ԱSWWgv oq C *(JrVzЗmw:GN7[? |Wd &ϛZd.u 69/' ??R{} _;U/W6O=ǽ?~ϥ[hFbǩ*~"?n}GwX.=.}O}~wLF#S}|_hTaE `PƑ=V *EFe{tU{\Vol . n}K?ソWg]@auKӗѢ{ y(Ͳ/_aSG+; R)pW+S۟,L/?oS0"$/dx}tC};^g==gyz7~McEZ;W-$}*ƔgXLyw,aUs PF7u:n/L?]~fkS~}CNIv/M/^mVK_5U(:ؿ^ Nfǎyeo/dH) b:ۿ#?i5'uwN+6MIK$y߯ᓦ㏜`o?~.{5?\uIޯ{ X^=SSVd(P>gՏ;rpُ40yn?ۯ``"ex }3uziP3|ޕ XS^ku>|/D' m?{ 2z3<8x\:y'u:w ~CPov2#RE@Ъ{nph`Zeu[XWև4MvϽZ?$qҢ(á~5{S|bT@ XhO =ًwQDޠNkt=ػN+nSC@@f}YU-{B!:/~~T[tM־{7Ч4q2P T4%giGWH|q ᭯_{ ߚ&UdDҔ)ҾW{O#=,;4=f~tzԯ2,L_9`~3ؽƺuvS,uމYf屢`c{ Ҋ2ZQ]8΀tG Rt?:4[{Bc8R1oz+0Z4.¢iTվriЩU-*V-u YĀl=G{J ޤzOݕs}feP+ >;?_Տ< })LE'L|<5b̪Of'zkzOox⫵wĂ9=߯5^FYT S}ME}zDtD Ez>16y{y=ε72iV ;gL n=~uj`ݿmJoHj{^C| bT}ﭿ{?ds>dIeGln3ui`,)NC>6^{NcNkx?xׇb,N+ ׭->nD ֟.ld >oNWwBn}WvQDTTupgAD Bn"FxƅqfdQQ%A=@HBt97[]y^un/յS: S6ㄇ5j+0~MAUs[Wa7~wW盕F@@W)#YoHg\Qp^K=0sK& AY(vJcʮ-`R'S-Ȗ HtII72/kJdU>s*Eg:mO~}IiI Tp4ެj;X:6L:>}a :GMp7TTzj ,v9[۰y:t2UqnV:X&[T6A%l]č2v[*@edۈZ ZO1aK ƣْ,?њG!F#[z7zua0TVlVz͵=6jѵӴN4ZZ ޶Vd۞6^"]MOm`u2Z~ *`vK, ۇʪ=-6ݪt')*2*!׭6PPLUQ)=[bDN=9LkvڽL%[q[VJwVtoiIEfYp_%8 uhf=E{fjsfmU>kk_eMo;j|@N{U Q߷+U o'o!^v/j/e8Jg(QfV#UcRSOŻJqx ꏞ櫊rM-,-Aے* h;Jz؛ F]H{͖IK0?NMJe;kBimkWk/A6Q5 \އMPI>iT6#b>k%551]eV}Pq:(˓Ho_'[Si;:nRT ѣS~=P6zF|꩸ƥ[%"ԾPl^WG"1#foX4/鉼J$@ >T\վxkm*j^V5A\~>v5롟l^龂ݪU`;ZSکmGX'vnKTuZޥY+˩ҟi淵g#`iJ^|*e`cd\7. RвS"nX h* iKQ|u\' öPP\?/5ꍹw߿e7OJ7`M1(Ȧn k}%.?U=>kzd^koSVST˚MզAEIo_i55O@P00>gX|RnKg(Un[7.z* v!lۄ :6VqS5A֠S跳rnG kЈB)Mc(* anJ{ S*l{͸[% 9@(LǶWP%ᔗbEOM˳Kr-6ݞqϖLm-P=EpLS*b2Jx zIH;T!JM'J)?{R߮kB\W9GZaV{Ƀ"a{m'ڈnX"[}teKHSc S/>U*5+fۗkajrұl}J@T*m`oiaʺۖb3ՆU z(L5SA@@k]F c[pe[ngE^m;R}gL|_wNznoX.]ٮRZ{6tÎnCq+<buJ٦IwiƼyUAE-ko75_ryGJ}Te_N`XP00l=wVV*գ zr)/zlrOgi6Hi6ۡjK=t* zVnoR(gMmOz۴*oUEi jP =V)/Y׶aݬlsؒis?~2S~[,˝ZGv(=DKAj:SږX=} | e'Lc͛7Ϗ=P?Fo|ʇx}@He(#5 emwr͘oCO"lp+(ᵾă桪wJ5(C7<bXP۹lo0˪~O^U(Co|YnpknB.:Y=sqY)69UGmff-njU/b~L\vvZ+۴@틩47Zz btNVnDW=i5{M&,g#矟p ӟޛ&vMk]jI_t-u $O6}еG׍_4=L5j F W'eH9ͮqPOGݸf mzݘ3k y ڞlvьe?>x-oXWfd9@l*:q#JCt5^tRkҍ^:@.?XICzM ^uuͷ2躙:)$Я4?/m7ZNaZۨFˬuWڤeоV<%Y6c:eOGz*TjTʇ*@5ޠ3%F@@n&w1yG@oPdbR*m8%r# 7r# 7r# 7r# 7r# 7r# 7r# 70@<䇋\5ztr~ۆW@N}~>M^@@ȶ[O=u'ʧWvq_dۥ@T +0ŝ&ч쐼e{'/>ljvH{^QTÊ"LqgN S*Lby^I4aA@L6l,Gؘ\hUOnJ[#~aC@o~_$o97Cof( =ciܼ֟"p! 7r+0!6oC+9ҏ1߶ɻ^ONm_S,}"Yw~,}ueK}!Ȍb>⿷#Gi~o_WN߻_ s'Ԣ™RQ7qdmGgEb_ZU,ʧި傯髓W͓^j^Yw>YV9>8O1}+%ocG&;o7O_g[Vk[2oIޛ/OV)=tz[]ƘNsG~{Ū ɍwL.kHS{[oQ?%t_Gi}ֈJ*4ꯞkʦtӦZ`yk=c!.70 v"t2|Ζ wəZG֫L} 楛 }G7UoL§K@EbK ^}ÃaB73q[zj}|dq&C|_?G0<b1SZ4_,JQ=_0ۄl60FzRbyg?u `*0[ҩu@(@(pCoGjIAVK}KZi[ׄi6بeXB)^OQP 6FJ[h}[~OYLmo}tB[âw><1T:}t^Udp5wSn?/s==H<]G"tѳ.L%˾_~MPT{Ujm yޡ;數h]f. |]!J}YQI_#)J3^} Slug=8՝KSP+_ͺP.m<*XTvwm㟻["]9]ڮgv='T`NqM=èVK5z6lug[S@zb~7K%~SȖlug7qo8fK)Իfff0$~NzIbG'*Qi) ]LG@~ ]rK [PP[ٖȢT 4+VtjyPuoj(tz"d;՞mugPTjG4 2Jڳ;Sq͵ @([>=;7{xy `PG*=W`ʦײZC\$%6Ui2mg[ٖ0Utm7q?=[՞mugW M;3C R("{sQ~m>ڳu*|Q[r莹s&O^S ErSpۇL pE՞mu_&{`* U#> &xք {Mnڳl;D Erղ0UR78iQP0Q7nbw~ZlISoau>:o9hBoԢ߳:$|ήJ+QZ myP j~Ӓ-Mj1ޯ`(}4gV,m۩J7?@78WwTr;/{v烉jK~՞TPIZ?uuծ=jZO丿ܹ7iR.^f=|oJc>C/`w^ݖq?KFF@__|1V>⇋WHStW̚Ǜ7s3WP鄣*' }[&:^.[jt]0JJY#dO<XFD18?קK十HhOtOcLS5rߣ[> 6.@Qbx?onl?zOo֮_?+z-DoPji;xt7<O7H?~_?Ϸfz-mW?&ᡴCiJN4^D,Cғ.Jw4k~PUz/xOd: o8z;eHSLy"0@fL/$';:4TF (C7A;ΩTKove.Di㺤ic4 ilfײJP9@בHS B b[F8!qB?UY%Vwv|`PPx\*(b(Pu'- %7E W.oӘfC"mڴ6h7SC"-^7ZQ*ʋ`zw=w^?::$ Hcj0PC"|;tDNP E@i @ B@ZQ%>a3r È" n:?bڵ~HE矺3`҉"BP իW}20(R䟼cQ #ǂ6BC@5]x ͺx>U;g n/C"* _xʕrC"*J_s&޴iSxO%cXE4hѢ{ 6՝o3ECg01@E44k֬J5yÆ U1߻^q/p(+_4Bpŋ("rw *SY,PS( PD. .-E֯_Z122"q[,HgTc|c(_u.WMFug Ep?KSڴi7_p7єXYSQ\('L@@M9snO>h`Pg,VRa###/H!̟??M?C5sywK<h̙3?[."`K͛7//@@M Oi.+4`RB^x(%cccꩍ)ƍ}>wS\t"Edŏ詍iK0=~\,/_hѽ5PD6o޼\.o"`ݿT^PELmJ hi;;K?"v-S+W:Lcccc=槧MFD 'hިr<#<~ ߹ n /h"V(|XRLtC@(m ,UOsTj>… _ EtDP8]75k« k҉Ϟ^EtD |M)E<. ֝@n13gdTZa߰-%>EM!?b^M- :h M6N,JgM!}!`< $jE/hEt'VZ^@=䓾g]_,hEtܢE- 5M-~}}б(PDW\.7E@s=z2.\;:"zb̙g 9voNַFxЇ>߻LkȕJ;FFFN / \(NTj ˗$ӟ 5.O>o & _uU~^dsOr[:PV9`G:묓B!9Tr1o͚5ɭޚx~lr!sd]v[ \q~Yz~tb},yӞO%E?OWɛ&+~_&_җy駷| {5ˮ:򔧄w:K.In?c.jw]w)ԡLD EԢE(JUL&* ֥^omAӷr~A+ &M~ɝw^i6(^dIJEf?oYvmc}f&~`"=sfӞ"IC?m,vI'}-՛1>0՜';?L=|J%yוvR80`"nґwtEў"DbhK>O%'|rWv~xꩧ;,G_괕^0Egt=#ztPKկA@T'n"]K i+>EA JE n6j P)hU\;S/]׿Sj{,`ٳ4yL}bq\p@PD,\KnX  ބ:\u1DŽ҆y\s5a*I) +=hPE[Rs\t˦Me˖vы[^Wϟnݺ_gtxO%T(RuVY=g?`ġx5KBF;?C|۰e$ځƪݕW^9>?S,>jOxi=/ӱJ^}~}|T/~)jЇ3H;0?]WxigwoIOuWm@j=:ꨆm]16t X $RGc-?fP'5mF>)Vf;n?׽uU=ǂc]zu]}U>h8;o-/ԢN>L5M1k֬=f`]A}v-܅eoذ!>Y @iя~ڣ~hTP|KE7yHꅸ$ YͿz &iZK.-h/To[V{~S30O'xݺu>XxRGǸ 5V@V~V i>=~ j&@jb;0z jK;sJ<DŽ-uګMV 7馉Y~'Q|cBAF0U :ie_yktUWt\5nc9Tc=f[wtM>t-mzjwr :j>8ѵEf;oJ)zzh%q3PX`*DAF%DWTI.K%T-U1ݠ7K7jG1NJDH,'|~7J(VҼri"]m)Zퟩڧ]4`(n~[Ynz _wbK5&_']DGzϦE!Ryi*fKi>Yy=;?[M}>=OMeU6t;l^w(Ohg~W*VNNWK_ "+:TdQW,J,\0_{%:"bv%ЦK@(056@" ,A≥<<?}+썻*c= @V86IcGtm;/VXz׻aUۼVJ80MKb JAZշuÖf}k=T{>SS&jPlugs+tRLVݯ~Gm6 i*R(N@PY`7]^M  J|SӁE/T.Own>LPLS4  "O?L%}*l<0Lek&p*[V,-՘G']Z^{Ǟ֢g=Z:Da'g] -.Ν݈ 뺑(U1Զ/=tj 7]_ ~%LH.q7:C.C\_*!J,*Қ'XOk(x:VCDT:,{V@4]t 69Kʲ-)G]j FA<A +Tb/zdAdKtK'KXDmqi 6ﹳ\.rtt"! ]bq QV"DA0U=3ƫNy?C%|ߝ̛7^WMZ磊ZAAlBA]T#ҌhgM6Ҽ`vFgNRRYE|mT1L TIh?pWO1\b7|ӦM>"AS{nVMnSڨ=lqYilZlSW̶1iiO(]U{՝m$t-6,1221\|PQW^]yJARkzum'_|xp@w*ٝ|_IUӿWk:dbL9JvQ2]-k bNAl@Q)n%w0}j3]u?՝80U[ֱXk?twɒ%L9sI o3xJ4Mbe˖3TCNR$VTK9^TAvKhKR2m9u]W"L5Sۮ_ҥ$ӟdIK[0V{VVwG m8s1a:ب{*,ݤ9m5g!I#TmnV<#a}0U Q̝dbwuWjm[oɒ%a*[/ F (H;T2{+:A9[}Sْv uQa/l^F*6u|R:wlugκf5{N.]4L@o){s.W:`{!I%tRI_Lx:O~hXZG7P*Po;TcvJ1RRW_}uHqO X?%/yIj^']қ7뮃޳SޫeRxݤEJ'tIa~RZqf5\w=^A:`EL:.QiӦT*n4 *el~ x@JS;J%+peFNbI;(^>Y^-{v]6ysT:%ϴYD 3m7 [_R`W%wW]uɶyꩧiy*hյ^ [U#U*K.ܿ]DG;::zQx6 qqǽe`u ͛6n8C7m]R( USPdll̗Q@$/c/W`!ݞvm~Z~o}[a*IN80U{ԵOz5 _B||EN;|bG%: ?]ڴw׮]SuW׿4JV7o)oۗ Ľ/lֺaCU\kKAz%̻SN~ӟ&#lc:h~D8Qƪdޱsgf1j/ynKyҎ6ֵ@:uˠ`-%z7Z>]#uBt+}&ftPܿq_OJ]TJo R{ʕ+X|X,po (J(brϦO *7ЮO>ٷf);ttӬ`b/J%}7^q4e *׽OwOMqZx3T7MUckviգYe.c#rm+!mW/g1!CZV{ VϢjq?h{N;Nl;]zr5.w)ux;Q?^7y%}:̳۸m{E]7je/cK˙g$A};kط7pbx 7 B n8ww Џp=:;SS鍂R˗+Q(Jw{W-\Om%1%\x̚5H7eՎP{`RD1y`p{5wIr>a}IXfƌSd̙]0tblOUp=Uq{|URi_7JOE EL9 .ҴiӎvmJ+c=SzȎD 0T*`ӧM0(bJZ`*:&?BT`kT#u^MK_sis'LVTyƔwYgFBh~89s}j;n؋5w28ptt3mE yo '݋OT"0PИ?u]T,ߣvdwOTjО1߶?^I<22r[0EPQB7UiEUyM:|˥RI׸af)"駟3ԫȈMcڲU+6l$_+Jg,Z?)"g};aܹnlV}D6mRͥRi:mtt 4zjvG|hA@5D|D=8E3g\օ(g]Us=ZP[v$j,RTA@H7ok7~d]w4ޛ~aJCɪU $ @8ݧMvV,nPT`qΜ9IPA5k|&ݻ|ֽxѢE@̟?MkӧOٳJ#*O$6mn͛7/ /@R`qÆ owouEG=B+8w\zccc]ĕ+W&>%7 |lr"t9s;X|/:b^J%_ QADUm6V˧Mt].?V6lx|K:vn;Xfmho@Kt[O *Jh*7ܽɘD@!Y~߸ܿ/ *jP ƙ3}2 W%c1 qXx#s(}rgFo}:tE ###hƍ>p  _v_]`핗;(sy;_&_wV[mU`c`jSPLy ?qO O"%j`T@1U=Zc tL.%We ׯ_k׮YVO O]'t(@1nF[yJ2ztdc@a bFe"AF@>yg!> =HύM_SQ^c,L5`)[h 6m)0(%>CE=1Rgpܝ.?~3D"0 Qp`wj3UULaRN|&l]&/~!ɞlCuɽH~qɟXʥk7N1;iGPڴ1۰&Y!?SxƉn3m[9g'bV,Jɵߖ˓Co ~P5o5gdrnɓ+K><#@2*8D2J{WX>%U2Dq{%[͜!+E5 Us`£^([iBn7h/7}oAPr\hV7;K`nyH CyC7\Ƙ>~ w阌2IlStMA=vr@Wnأ2ٴ cyfS P+pӬv)` |L$g̪L  W ov_޳+>{JoӜyz4PTMK鼵}mK;n -!.{0%JM9kp'@3r 1nPb|@iYzn KpǔtC̐jax+ђ ۄs yI<+}~k6-.l%ԨTs* FMRS|s;3nR4{n|rM\~7VAeq>8& :@@qڍ~tDe`X侫 zKU)09R&:l GιW0Y:5\AnIt:Nn"mJuڞC~WnG#M[ X29iø[%a10wI"dTled㆝>=WEȘ/Zw~ɺPswJT[Bןu70H.s)?l*wSjP 6 nEK3RVK3K>UJ7 ʿ<נ}:8,c;w%O'P{+s`8 VT^^ @*ã<snyzRO%!>]gy_?OU[`iLY_cCU]ܴ.WU/5{`\'u= RC͞{|G=5r?Qwx-Foȸ{M.urwNyRtz>XCǪ2|&Y>^{6?ܴγcϺhZ%8jrn1iopC1wl;?AOm0~^ohl^>(`ӎDkzG qzjvO8}g)-^Ǵ{=e_V7T}&=7s]9k;tѶUe;JTBOL ưEO[ :]DmCsI ':4?>D@Qz rU5zkkq~SC˚~A\Z'гOܤ2Z&{qҴ^S73׶~ղh}> MOz*~_rDe{w˽a<(lLZzx,cU3:&Sz X:wj o>L:ϲ3՘}zie\3=Poޑ~׮ݞ_W)ZVwqy.uk |W:Ot- "]t=O_cJn st^miƮq4,_UŽpc@>ZG۹ṕ\y=c=ocy,cq}AJK\ ec8~>rA.* K(篳pFwr[Z=co徯emӻy4ʯk)n9/8Bw;hPl],uEA4[RL7yJ :at٧}zz'{O'NxD2i^ @Q>ƋOL|pCM}F˭mb?F/rYmVG ¶ ߶.Pa̓p ѕjfEZkvi' \tSncQ; a5!76mǹ+pb& vi{*/k۴'?RG!.geSfyyW-ԑ+vؽAn̗$q+ɨrme۞=-cKypjهKh[Pwe?߲KήLf1mt>OQqM ۮV~]=o9u`}^/x3ƿ0h>r+?:IEFw#o"OMh3ʜTO v~s:)=};o}Ndcgtb3NJ2!>HgUri^^pa]ƃs2 z3a*[ݸ.8v<熘aetvѓ }F!>7y5~Wesg|6 aOOjQ8}מ_޷56lKzZˇܠmY={L*}{dNzYD߻ώ_H}=\~7s]2֣ѵ.sτ)/rƄsEgZV]?g;O.9ҏ#~ØgNk&}!}t>xz3Ztg{^U˕6[;aʫu͍7u1V3_>;mvy|hj>֥]7m2a[: }^+mJ2>kǺyLf͇g3Y{\C' Nos곑ֳA#w|GRQ훗g,CNXg9qkoavh)(t^Z|sZoDZ!L7nZg{j>S{>߈Oz> 93ּE$, kQjYv%-z[%w;xu/4Xǹ 75%:*|?}Z &Ἤwi7t*f{I}_>dfnjh'ea<;X<0sa,J@(Lfx[VenŷQUo&ømwle֓v@ײ.6{O C6 ȉ$_>?'34UoƋeKٌ [iQ+3q06'8ۆWfH1Fs\4:'T21tƢsaB00q=263Nn]{u4@/ b3lTIW6C47śJ݀ B">U,_i?)|3ׇq@uFoƹ}AȓFn7b.g׊Uְ͚⾣@ƥƅ߫ g1K7{P+i;gP3n_oyN9S<# FOޖ Ycɺ̭<^Nұc;~h]nԥ_o>3k.3o@y:)Q5(Vqz 6:la\S 78n cit=%K{#t+n]{dV"߆\nTc9Rh񚬛@3d2n[jpa,U2S~V*/iԦ\|͇$?EK2HvPPWNu-៮b@RҔt_νA.:gt =XIoNq"q? R^6uLkͳWRv `KpPlD+t f3DmgKN~6IDATC~d;ۧ-{ԭ~>E3dA\ڥ@Jrؒ5MS XڥtQ7N*Y22be2UM|jXQ'XT'\ *8do/QP-]suk41 w*zQJd/ vAt^=PP:[6Q72ޣQ)n!/=QcfVwO-@@q,#f2MuҐK< 1 mKV:zcL l O:{ی_,}d^N׸k@`Wts.zy0dOGYSi}>Ev)`g8zVC3tǮ6WM4{je-Ɨ (ᘊ-%j۰%FC}u*XF\W gtPPZIˁ.mώ=oě]Eny;V* >/S'ix79:;Qݔ'8܁Lo'v ^Qf/f,gþ&<6斳 _{an-B_S [?urLq?y:3X&dR{h 8;[ѩn7[дﵙOyioԣ=qUŞti߭,o_^!8 cPC{onm#޽WA߄ض\ZakRNׁP jU0=uʿ08nY3f0%qNW&'ǒTXz1VcV ppwLv;h7U/ XijjΦ`ky[P=)[' 19{1Ugo}tޠ] c [ѩn!SZT&[26n{4Kc7 P[6,{]y 95*7u+0;Jak;06n&^li*a~\*gL=F6=՝ݺꆞpF*~fy!}R}蘟Ƣu=H>% cV꤁QCvKk{So%NzQ:R77/ϑzsqCqS[qdq NQjc#+_m.}A:yomlGy=;ǭ)mOQ˺C=/m:gj߹^t㘶*m;[q>swAOJlMUF~6kဎEk=5z"X*sɧ@0aQ7CWBщLWՓ7Ls)`0q{5/j@;c4,#nja,gP:5=!2 'Y-nۏ*uuS k9#W&0s^ӱsGxQ}0&j*|=I ALUp#=ǘ])  UõH\͛FcY׬ݼylTZ7o -]>{Lx?nߪ}7m/&g^ORp]OZs[Ǭ]ݼes S^kC_@;b?y%EeEÜgtׄ”Wrh My Z_uqW+74J3j<;)a>}^]ͽߕ몛nL yxuinJFiJ O޼G[>7Rxv߳AhQϮ9LR>_xt\ȽA-7T*0w];ƷGyu͓!.kia{οZg>[y1n~Y rsyרN$ :u`­ E^{NuC޽@7(1wuQtօ]+_uC*+ zo}~K N>en!]5Yi^M{evYXl_gvjϯLnϻA]]\yq)QWU.F-ɦ1:j)o[=˕AvJ>fsZYǡfhx: :rmk\s< `jf]l^t=u3^{Uhvu6U+kuNN+y1YMW:v]vsCLOnPaui h}bb4Nyzc˨|b>ضM1. m"Glu4u 8[&/h)ﻡ#(Qk#+{s XNHע8_zοZ¶kv<3Ǵ{_I kB\礛{][Ώt~d׻~S/޸$)u{^l7gVxy0l۔.(m^0DS'tPa㧩;O-Wqǽ")N^MɊ{oJJI+?t]TtV>z2 ' zDUK!}c؆'T,x/n3)JAqo Sc7խ讘o\!]ָrUb94IJ|njk~?$w}2}B 愨=z-UBɕk$>Q3m^^@_P,_/. <8s9[Mŵk7$~7T.x˷>h0$ սB@|V3$=>2;)Nʿ j3Q՜U2QD!;>Jpg!0 J&-,ޯ^.W^Rэ@)Hr/޾\,^($%I1-ƴͪrO$|#yF (@=0(ȍ"(ȍ"(ȍ"(ȍ"(ȍ"(ȍ"(ȍ"(ȍ"(ȍ"(ȍ"(ȍ"(ȍ"stIENDB`fastrpc-1.0.2/Docs/images/FastRPC_workflow.png000066400000000000000000000773051512345705400212350ustar00rootroot00000000000000PNG  IHDR>sRGBgAMA a pHYs&?~ZIDATx^ S'a؇apqW[ҪzUz{k-VvqkjQ * ( >$}r!If2dy^$L~>yB&N>eeEÑ!nBH4[ EWJ1UWQ, oF B_{yF'F^NEUgzo|v4:'lL)@]kGD)7г!} " c Bxx vSf@_Wޭs)TbJ¦[W 솩GPx"RTVGLŎJe{YiٰuYyYn~MBj(z: Mz5fMqHPxɴ) u1GÌt+m?HOɸn1.d>ZVnUGgF̜p8zӼ'ks1 'qmu5nF{K"a$ }{*϶w?l-lvgG#CQO_?nȢ&F^>UwDCac;+60| MجJs ]չkӯ/7;+cۢѩE7[b7dAVnxw zx jSk;iQ ȕ]{Wg 7썆B7lwkn?yxQ)6C{ 6Aަ̼1%TtɌn#pˀ^eg3Caj37sa@X<'fD;M(4qOn&_1WWEBCǎiajf{G2եS9aTou{Y~&;ψ3= OqqQBBƄ5O7:=4}$ ˊ!s!=L6E&5~;m_wKKdxw֮e{Wm^̈́= /hMv& M,^ :-i'Գ-2O:ˎ >,Fǘ:qmy;~wUW{StP?VքMxaOoV}{A]mdeyqLӥ?v9rys,o7OMimywS 8<}|'yȖp8d n׋Lї슧&.P9Ny&JKKC>hf}{w%,_UTT{~kGv!=J,6u23MQ،&ha%~}=ѣӥKP;tބ\@kA P(piZ^|߫.]Wjzɦt)HA]L6JN<6fnEUgzkvhWRMٳgOlk,%I# 0^▱gfy׍7tw;~~oQRMS hݨר㫯+fǎ_jjMqP_RGS9,˭M 1g/SNe&܅_;͌7ij4~#Ϙ?6Qw7t}{ߣ:WSz%&HM2Qc |򏋣9z&y%3{e&{-~|جJ ¤LS7%{ZʖC 3l0;?x:4ȑ#m>u5pȄ3ee1WGӭ-g…Z=#5˹!Ct4k=n&M민-l2(4Bm5deDžp=ѯ{-Mw(6=uҹԎߔ)s͹{챶-7xî7}cIЫ- ۄ[FZ痦܍8jGNl6];5 [=]~ p߾ZsͤIL+!TCQeb+asH؄̡Z߫@K?iqSO5 @}4-7lJKKߍc%R]=5h?5y -v2H4Cu.hi'p-5Zs%\R/"./]pyW͝wa{:[W^iV^ﱟ?+W=_h7zd4jjHI;qNi'n8rhsp;o]wmfi׿nKx|%t%&L% x\LR93ԿPa&O?C>X3=g=? @zڕ2=() ۍ.nt1r*s7i?SN{dM\nL>_t$X a. 6{l[=8[ޮ*hpl1pcHI@bѩSmcmM|`}']sw(环 .[EM=c6)&~֮_tEώ;mٹsg[mJkaeݴJ7@(u)5C{h}=XJ9nJv|%KS\=iDShjH($qn =Ůr)9eM1qD64tю{9k׈&fh $ n_u+--4[x۔h{S'[ەX~5#\S 'hNQ#l7h%?}͖p2@ k "t}"n@H w D$ Rnp3 76n@H 7w"npW_ 7 $ k " -/9i8 Ձ~xf1v9wx#m۶{ۧ ͝7^W**@.]1u̙ kVȑ#Uhj͌g1^rIѿ6ʼ9k+ҧԸ /@v^Z4q{@zHHI I LV\i{+ѩS͝04nhi?: -2s.[3ū 0uYփ>ϛO?m=wi{tb̙ga{nk9v䧿OfG.~oh]HHIwp7z@M7pSGs淿CxVy2w<hn t$F%5Ɨk&ML?!OMnż+- ˾MsLiH@Sc.JKKM͟? k۹sgqFRn_jjC3N?{.?W֕W.n ~9y-tMy%]̳3f̙7x߫m ?8ʰa>\k30n ~7e+IwyV 5(% 9n{'̗/Pv-׭[gKH 7H/;  H|jzwajyvӫ-cpdۍ7d'oʔZC|@P\}Z[ H7Q0כ=1G}d>}uv2Gn9nvwm40[*roVR6emM7o6Ԍ:ڿia1&5lSC;>Mo.8vuo!kl\z ffӶ=6FE"94p8di.̠Qbk=_̝7΅yر)S|Q2פ3~n%&!2&]l 7?`fsYyhzumox sYƠfPܼ%˧5ͩDAkXOq[W^iIZCl:i8;Y1b6m4#Cr\5>yڋOj[]:sNdtp#5˧x!mgE:uԳM7V $f-"jNg;sf`ަsGӡC;S.AW6w5*vue+ט;v4fpqP}4oեf<(kКc_oPecSQq;Sҡ)iikE%&btph4b"L=fߞfέj}.ȱivYfצD&?o„M=6\4[Klغ>.nދOe^|*5ⶦȋO^hU{MTf؍9Wn{nE~~Cv61}zuע۷7$۱s6ko4+׬7[VxApšEǎkom1 MbRno1=쩬6;3cF4ChAeʵv%E/ 3-XBO%ڇŦ{\h6ӱӮcwYuػsٹuMmSd.=zP}nL;}?}O%LDz6 t3Î-+lMՠDL ?^vZjFvԟк۰ټ=CM< 6b AKŤ@'t>5'|HӦ%he;%c*"-XBBmnsɆVK=vl^ndR BM2~b]o_t:l@ܺڶ֮_q!Q4E| yAQ#5Vm:(xI(4\­ψ3oy' rM':j';idB͠}lc #v3e{9kPh5Ai|`#QۘKqуKm;tiߞ bS=fϜ~DQpCۇ6>u~X֏d@ڵM;Skd9ޅkw?QчVosNfŪģ!&5wLr[uYsz{Vuf;ꈙGvR4b &4Lzu6 ~5: 6!ZӿP|; 2 C^^lEO9`M١a GALB!kۛnvͣ݀Bs1䤚չa@}:bM0ؤ9Գ (46mRhl^h6;$Pϴilkfߊ\p1T#i6Ќ>lݳ( I(tpX1ޏyP4VѣF__n>b &\lu^(8Ki3$G: soWI; Çےx{$ycR`ZstGͻLNm>P eR,Z^oEkbMTT]l/*bS]KWk-듕O>,Poڴlڴdv2 ?%悋]bP>Vޕxc$ 9cR`n,hK5l9wf["Z5~ĚpIiC!6vK{kR $'۝&["3.H60h@x=$+&& Ӗ@!7;tv["|_5򊿥a`?bMi셏M%I%KmIlʾ_x|+͜9s- [~-ݿ R>p[n-z\?R?Cu'=P%yG~rdisz7+&&Rڹ-BֶmlR| BG<&ވ5~Ě\l*j֖@! mIljJ)nmӶ= |ޱ{-9TK'b4 ]I6$en룏>;1 دbR`n~CSl 5a&ވ5~Ě՘\l Œ@!+Ħںv&jn >y)\n*5"{I@!/1 دbR`n[w_,5D"Q["} 5pk5-#ěMP`f@MʴҟOs1Kے/}+nu&&lvn@@pˮݻ.̼ k<ޮ'.Ap˽+.}~g;- _$r#'gp@p?9_GMfm֖ԖP@oAmGwkڸ=ũfzx5d栾G޴\z{cwbgYLyS~klqƋ?(foeĬ޼ۼz?[k;Rs9MMibmJj.+Vm%ܨw]fyg̭?J%4QQQQMݩn3ksZθ=_?Ǜl6TdVqM.Ko6Ew_^'K%82Rbl}U;BCL͞{'(\1ueW:C+)&)6zLRr(df;'+w$7ns#ڮg[.n]8Ė<ԖP@4[b!kGcoBm~16٤D5?(Ԁ|̈́'^넚sRSC}V#O9^}|)߱n+ƌ8]u՘u%6UĎCrp%j[bquBO)FYT4 .m#L<'Vv%a3R|R,7펋J:z&mq͵G16E5Ibs@z^_;U#.] Nׅ=%mן@m\fW} DS1I%%۔t\?U_Ybba~~]oKd:/Nړ[4G--zԀn0=J@RSb)qid['aY nַl/;^f5v;=vQu汽Mm%۔;Y56(+4'%~rmfOJ6%[+k6Z]Jy/޳I,% .}%͔ScP<%tOL1P_wğαK7NF1XCbb.vj^WN Vד΋ 45f}]o?m CGK6]eTV^vֺtmflP 7 8z27cl %j>nVc&kVuvjo#bD[륞\ zz:PhEqkEI/56XVgX\[$yayvD?6쥒h=t#Cd6AB-}: "E @^@KC0>z1v0-Z=2DOMh?6 &jPv\C +Uk1ukD @Cv$ښ_qJ=~~9ۣ=m.xKk-/4F>-?]3٠z)&&~6 ]k!$ ss|v|S8 ;npzRC3jx@3l3kqi>dT9'3Q胻WWNo# o"A6"і}jְcJ^W妴}xZKcàX}mӰd!X5J57fGhu{:y-夓N"ҍSJ,)}t=.'QrqŮ kY&ㆻM5kv7?bEA*)?ocv5n׸$% (mMzLӐJD%:2[.c(YS۹tӧ^k=6Qw1jn+6iKѺ%buxv1lUe'&ݒJ}4dpXɴx~USWiY\|d 7ys4`$nhH\i[si pLjԺzJ[Ci_#6'$iTpWH wmLE߮$V h{)Hes6ITpD)Xzv׉6',Yo4UQNC6op7 _sJ쑧8om=oGƘ_\uhC?%R>v%( t77Fshgd)ӎe]|y3{yS]~oϹֵ8q oAks{i1ʞwj%G ՟4gXUۑ]$Fw%.Jn9VamVkvdBaܦrz e)Gi1Rcz5 %ES"?YrIcTn'Oũ_M: ?gk4ؤ].JV1Ws`w\q=dJ)IϠ3Z󪄓SC+^`k6$3%ؔROZYdoꉧ40[ޖNŮ*;0dSO;}9WM$}_uH^oQ5Yëp^Jx%;)]q172jv jVc{?TbMSO&WteKE$-p.Fi[zMbz}w6*sVB-Q|BT9 kmgDc72(ݏmXJiG 4U}otDf#.Ql:dGH /hhgk=rZQñgCMs'GSow⟼ ;ftGɹxvQcob %醖:4deJkHG ДěWCS^s<({ɛ(>aؖlJ?q52G={rR,UMPK-1!D=@*s_C RDU2ņV1ͣh{s ;r9ZW<ۣeK+k5&c5NsCC)V_t:~dvLX&6OҐ~u 9Oz 3S{KrpFEOΥܝG wsQd0\)m?'@c)95z$t9mq7&{Xtq׍--~IN/G w|oqyv=j|Vύގo?'\S̝SSz;@aV 5n8zoؒi"II)rSOI x yVwSi[kغ=KXa-<M:P*u-Ö꽕8{cIA7LeҺs]!sw&d,])GeS(wO94fySs)%c0W3ؖM4CVO< ϧ+|I0ƿĄK7*(Nr@A 0\SM󞭩g(xk7yl/~elHqIR8_hn:7\tR׼.'˧6RF [w gf=C7ai5ѿnXu汽~O+vqm꽡}!jVc}3G?Ѣϡyh]C`2$9K&o]hQIH%*8s&W s,f.iL9)i^:͇}-Ga+pt)j^׫1JߍOW5zo]ɥ uMxCfEh]U6qՐ7lYý۷9'-Kҿf^8gKE=:w~M{{k8 ]pr?3yטs-,v#}ECj"H53U_t5U`}A5Ml="@hȵ[l{[QZ%m̽?5*b 9r_m~jp^y}㨗3;R= {D˄gpHԋE>o{#xlScԊsGKҶ6oQ k6 6ѹhLT'XkěAFs_>N٥&i]gSԱ{wtл (@ꉡ=W[ac@OHiN =\=F x^tS|Ңzƫ;{u&~yu!z^_Sx{­慷7{Ƽ⽷WUG~ͷb.˫?2u}䖓\䧯ҋεekh(}r+^F?D8((bUy_z^ /f2׿֦ƚvoSw)t5V%#Ěpcl ޱ%i2'vgvrd3jh e̕C>sMoD=Od'lsp[$l$꥞,jLW[w2ӳ̓- w(QM9J~M{mG];Ix%m :#+UgKGC}*~4rP.*_,SF ";6:J#4Ű)ZRLк)H]͙2dnn5W1мJꕖH*SS9R[7Kb>gI^}t?3E~n2%oUuoXnOGZg~@!eņݶCm5 |tjPz ׮|ndWHƠ>׫@h(Ǎ{Ujx]'jV!Fu ;K}l޶ct$;'Ϣ NbMɿts*743Ȏt/rĭ߿e.>ndCQ|5C:v.%漓ٸ h}t%ufCׁz1=5^?*zJ7k)4ʡnB1HA;;jP˫UO=b=?=ն2JS%%(Kdh7[_5UHdwtsRDw s҄o;/۷fS?3H"Gˏ -LTR,qǩőbi$@kuG_h:WmmBj36 NMeH*oՖL,4 k6u3 /[V-_E2|P䓒xιp礞- /V3%ܐ?3~\?گ@4"'\S,.v:@k@uӵIu1md`n)#i8C-TА*ҳ%8(ū $V 4Z*K!ӡp=v csdNM19Tno[o kRx28T%6lkK7]J"-%qqɸ]{. zնɫ![C7fQLhTزT^߾$;{9X;Z3H_:94ge05 nUnNM'\2PxHwgL2Ӑ疛O4L77~IJġk?lmS%>3ƫ"ٟOܵ%z59ݨ8"FTr4 fj57Kn%RMw,>+r4PnGKҖͱn3K֫%>3k"'d\R]lҝf'v(,c{RS~X;S"f~!eK._˖ǎjx:)G>nlXJcw%t^Ŗzr[ۡVQ Ƙxٴ-D;uL:* ȢCtG\z |AQ7QWQVl䨐9Vc^ɾG{{Г_9={>nLF=̷ΉU?s )lIBgѫK:iv$*G5:]RN ϼV@>:UnTt:'}V;ўj{m@gWJpR@j^|zYzNQ-.Y߲}Ka7\2zNh_]q7-@kq޿5/u7G[{16( 3ζOӶhD/=s4qӳi\t?uSn յS~t݅CGủ5HŦ*M6)ocye,kk_; s^[cZV8Ԩ}Unݾs]UiQĝuzhZ:';v%a[1zUu*Anubk$Q@rѺnp@=X2_1oc7\o_5C:F:Xom>-jۧ1YsP[ڃ>e6x-+Ĺu$qԥJ- n\P]cBοf4d!W.ksm a\6[b P&\l9[%hoVoذu G65_3 3ks[eؒش Swd|O*vV%YLsoA}'PןR1I 7(u5pMㅐ4g {SKӸCuJi4rnwfU6c} YqYHh,HH 42TthW=d[s!d!%} kŦ|R~vq͑3okzh3?Է}ԃ$qc79fxWSڱ܍wO}jzwmkn!fk>]Gfֽqow9gxJ#/[OZpC1y5Wj??5OsݦߡK9%̝~b; }g͵Gns|guYZe{iIKcs՜n??Z\b?; və։?\q`{%at 4sb?O}mVo?'1{5)?g,w4 _9خs,[";\esoeXR1)Րmw{)cziɨkQCKM"|bW]Oа!^zͦ=vnx,Pl٣syuQֹKN<»,kk{UUGkK9TYՁyuC!1~'ұ㇗\ ;mgkN ) wmHI"kXZ)5`(mk+ү =G jn&lxb_zYGϫ<~JN5mv_ԻQ#q&BA.ߖOwooxzzgQCAѼO:dR}gɸd1نrlC()xkJz)V)&hbKW_'ұКXWJJSbb}(V{rHNt覇xJtK'u^7ϙa'w^o- }j\y衇-GNgK%lwə/|[47 MqQ،ڥz+U:3wf%|jmzOG7yDczak}$}(GI/=qt^j_SWr?&+sJֵ,Y?ɥK$y*9vѫ}'X(TLvѹNlBIE=o5soU#KcD5wϳ FPYS zP^o낡»puP;8=gk8w TSCoPӱ]o}eݦu{?z\%aJ̩ 5w/m$7ϛt/-ۿ;T*!rqutc)~(NXbXf_xJ.~}u:6=.&VfK-zb띫Gbݩ/wH?q{!34p5կW^yߊ|M?R/5%JKٹƼfC%K~SOe;6%ђ%vL/{ 9\G(w숮eO_$뎣dsauڮctĖ6UOB=h] oǾğzj؍6Qszޡdtlf̕;{7n %J Ɇ7Skb,%B (߸~Wmsr~ [OS%4ph^T}fQ첥ġ47d;xA^rjO3ߏe`Q/ĸŎ;QR"]xK\S,ޕX7.bSO>>n%>wCخG>;^XpyESkN,W=S8 ׈C)J40^QC0(P^& Y!Eɟ(AP|BJ:G7$bL] $%tCVq;De84{_%ҥD;/=VB,Jй&~6}ǩhlAB YtbHQzj"ۧ>QRI'䆁,`5 BLUWWgy. `o3YKj8R[N9L]6wWs}51OK␹2{a,o|SS,s7X8z9u☾I*LlSP=He r8ԺWWWp=&^bbG*vI=R󧤏CU;dJ~PXHGRFUg0tn'_2?-GY櫥k 7e 7a\}@>SC|ClO-S$Y+[\Ϲ)nq=B4XtNS/50 dz]Ğj.wl%&̚ɇLsTNh;?Ÿ\bw.W .dWDo %IG7\#𓉋[u"JhoN|L5C%B  7p3z*L霚"b˔T3%qOԣL`a$]o6%??RcnK7W_\kx(1ѶrJ h(X s伆uq[kמ؝ĩzi񖮉7sjJPכM~ӕjtb_=x4pȵơ{3z&,K9 gybiwOf.VФڒy4<㨡][ zϖоma[+n@Zh4%p9}ZjHD7dya\;i_Ki(INa;n.ɓa[M]> Z /,DCsHᱞaO*^-eh6 ä\LSV,wKh{p7!sɺ%AԐ޿z)!2'h5k4V9J;nY!MFIͧ֒#w- Yb+h-QӍ> !ml nƒ6|S".U*, {e<SD/M,}Y]7zz($N jVB,'Mopp=0u<ٲXoBrP ^AsP f폼ƴ!:t.&yݜh^TNRQr.$4pSN9}]Cv{,MX$[l:)K7Rbe8v͖{0g߲ynl9sMՒmod]צv:(5͑%1uo"z ӹɻV^i :n;0#l7%?}͖^t-Bc3lT?!eM-HXԖ,֤ŤC #dŦey1VÐGI&]h43"ޣcEJG%jְiюWtMl!Z̉-y%4<||7uG w\q>>G{oVZb%(gs+NCB-;0y]pr?3W{ǾH{(KLŮh.Ml!6DE7 A6AALBs$zBDj}oqDԠ%ߕfuA׻ P{o5 ^Q C⇐|enWG<5BS(9=0SI'&Os5ey͜9s}e>W쮪?6YO&bWs)٦^z_-w3O6i,z Wg(8$Yj?=nܾ.1TJ40T9=K }xJhIWĎmJ(lKE=Շ\O7%xfH%-htͨd_݌4ɶd[CRs7Ϥ䝎&3`Wߗ{N׶J%RT /ѾrgM{m wп^sݵm ;pJVwi΂v?~<HИyԐ-wf&z11RŞd@s_^\-C, 1n0m\:ɜM4h1؞hu{HkG7Le&O?j9' 5&\eҸ)$nn@0A #Wh({2b @L}+W4|sIxD @S5%?ڲѸ9w{t?BcD B ( ~ %hn-YI7ц}Owb @L:o.ɐgH$J|X& 7q1O &hH![# ةTGp86ı#u%ƚ5k-Ŧh4?'CblJ4p@;d'FϴNHIҶkK%RUielT$ۚ;w(d;we%̝71crҸqի=SkI?d2\1)0=ܾ?manstCA}]opkدXPZؓ9 8.BΖU7XJoׯ=G=weYܔnڴo/*wk>4v61VC.6U*%P\З}f[_nw3/Μiuy=ǰ]L%r7yra:+6 o wʔK IJ+Cl06lgr~@#.\hc΀ 1 iΘWf[vle,"u޸yFie֖;FwfTmfD #1obSվfNzpi}{w?/l?f衟yMUTTӧQ820Ȯز–Î-+myƱLIQ`ҢJ=l0koЖ@!zgB[9}a7zڲ5"&1xbL4@!߽P#lI͟x>޾=]J]=iZ1I.n.[lŦ[W{H& 5Vٹ>GeK5qGPˋQl׶uWz2y\ crg.G[ᢥ7UѺu֬Yc~vn0f$;Ak@LBk?;v3 w/V%⋱!Vɳ<5}m8ҐIM >뭷25(tَ5 g.6UW17/c֕6zPJKKmH7%[t-O=T[fk-Ow}^1~MڶD@U7v%E3AúfNvg[W| `Y<K# Gy 3k,s oz}"FLB!k>G䳕Gj[3~PsĐ`ΕT7 \` >s{fއ^EH^a%l3yfp`~7~[;b QKŤ]\P,[ ߞ.rYdݵԩ N oEtoMh25(4A5xPw7+Nv[cMҳcIömKuH,bS2jQrk_jmt}%3e8Yڔ[d{U;or֕xzQgwy&ز>ؼvH+ټ}ϙh|G=/70I(-y~1aiSOYz,z]x&=̌;27C(;]ld:ud;v2Ȉ5(A5n |Um c;um[ؤn[,0Z_rطl]g[ĦTOqKC駝f:uL=6_˭G17}})Xbmj/_[UDq@kߚ~s> kl+eMf͞m{fx1T j|7-6[m{C/3c?kGʧxڳ 1 QcRhwۦd!Hn<ٰu}ܭk9`@?3oOӶmؾ y@رs2+׬7ev*IA[C lVSvy_۞&jNiOo=ADAk/>.Ԫm< vιa4GkK:^L*6EE%^M؄Q]D#զr6S9'bS*YI`[E^rԨQCq[oMTnL{3U7W]{rCbsƱ6g[sǏS膫#G>Pf5h0w 5 &5ktO_enD53ܔnI.qG \%$k)&fA5/kyWZ Y>Ʀd4ٹ_]P+9'54Z6gps@r3Mfٺf}fS9wCͭGY;ө}ӯ{{s̈氡:dh ZSTМJJ@:ܐf@v]ԛII@@p}n D$ p2@ 7'AD k"n@H@^ D$ AD 7 $ .[C5@p2@ n5@p#F 7 $ REcK5@p2@ nj D$ {i"n@H d5@p2@ 7ۧAD n뎨"n@H wim5@pһ_Q8bLV"&+lLdVTجJ 5YW3deu_ɜv`@##ȞezP;&twf CMZٲ [2l‹htݴnGAan[F%aXͻl ?"amݖX@Vm[ E? 1ek-{cOc* {*͒ۍ=m_}}&zVOt ͪA0ofD W<>i{XC&ʹlR 72NSinUmxłOm8ugۼ%nȢ_pSWPļ:b~UѵS_'+]{\۳ڕZ 7 CO_k\{)mRpDCUvebZy6pShٱkyuZ+y fD̢yӯoޟpp8zʧ__ƞ Swk\i~f#_i׿-Yimx ̷VM{F|7[n|~*b* ܛ+Zri$4d$O^[o S/3T>;׽oQ'&Ego_gVokans֘1U:Tk6'i'8 ݧG_l'FN! В"ymFjHZ&ܤMev00x _g.1 ?jLĬ$emΌm4sM4SCKcJ@K諒(?憒Ѕ?ymdYʄnqD?g E-]_ZF|Ozؘ+?)ԛpyӮ{+KcSvB;14y|D͝]TJ &;GѩT_?J.ʁ؇fJQٲ-)mVM*J]WmifSfu \Գ펿7nE>WTW_m_A~}TuL:oy`ؓ@ҜmF2ֳMɶo~L{3|%:2ՄswCqzܣ=9fe$,4T'+w?d-bkh u Y, 7g1Mxɴm6GaF&:+oOex-lsՈEP'-Y׬ 7 QddL -O7۞nCw6zu2=ڙ>ڛ>=:}[)CQӵ#(l[*kmÖ=ͻ̪ ;̒sqf{s<͡#Si[Ͻge4a Dǘꈘ=&l^Dӌ)z']?"Z<o𥷵/Qv\:: sH X>@updV&(. P}6s<>i/rp]/4 7 $ p2@ 7 $ p2@ 7 $ p2@ 7 $ p2@ 7 $ p2@ 7 $ p2@ 7 $ p2@ 7 $ p2@ 7 $ p2@ 7 $ p2@ @( gFz!P4t E%Bm.꫷@PoD$5Ȅ腣M6TMn@@p3j4)͉LǮ]:ϟxߧ٭ߣel)nVb^lRa"T14 ]PhJ]U6Wo,*nk:toK:6=ZFuoN|ڷz#ǫ{v1?z]+-F6m4۳ͫ7ti-lv4: ͯ&[^wkq{oM8-KEuX5m'~1Ev-?!n-m(v[x m%xG 79Ͻqzw1ML)*2O?U]| 9ֹ` 2VЩ]Rɵ]oiPz$zNn,z{]b% \Jco7XMqty˽ҢsR6%^FW'\ ]-v ~g/,nr$d80AH9J;P ݮ bF #dsХolh$M4z,A 'D(!%ģq+zKy?GvH>)l zt˗2z(~ߕE @NTjζ;vW!WoTo)n;'y7~y_+j9ޢ!<엚UJ xKK$ $F W99$2C Ҧ}%~.;Wt oWE[~t o[z)k> 7J==vns.m?o< \Z_oŜm ќnozc:PʿOzhIg l~iymF5DexQ}Usn[j'24wkx\;s,qdֽy{Sm{^K%i}{N|?Wz3lWĿSzܜ:/}}i_x=9ܿ;p޼uۨ]vy+g3\췑A .u!]r#Top SXh_5,<=Wg~ {[tAz͑[4 {[jEs9.t:g-:[RCȡ(^Gu!Ջ4D"=gyzSxgec{&i<:LLMx_߃WS}/2w[D-gL|/kGoJP<,As?N6_-.y[%&Ә=V"h$z9^-Iyӿ>ߒϬ+oFswl>F\-uеG~soQ mC1Fgyd@cpd !ttǯ|[v]]Tޢ;JSM.:>-Gir.>W;EOzjq޵x"`_uaxzz$.QTRHQ9Qۧ~-5?}(ᑔw.ꥣ^@= ^K@[M︪U_dH"yJH{%$qsqyǫ<cᗉ~s9uMdI}s9^x?[U~wjqC߀uw?I]og;v9Ic=z.y}_b{;?k=o&p qS%-t.z%$ӿ% e2]tî).u%.tGdDj(w;zd.ȡ;0k <] 0]TjFo]}fQ-P]|xou3ՑDuDu z^z%?NR?s.w CzIQ~ &amoT}5CJJH|԰.SIշkzbP$uթ}n%R˴w]Rt?wvk{B{TLoT\b_{K_ƻ&u%~g2ECM1z{=O&s_y/@ZHE-jC8hZw{.fXxqpj L4/n:]ǣ|ΓbO^}(٢[-^]HIi0W/5%4Ps+PRbAEǴTp CZJ7ꗙrC}Nyxkl}5n8NWەy>{ynDSy_M^.?t\{mC%ˆ\-J0dJYR4KSP*տ6L +ߣ4[@pdwF]\5_;]CFz|1SC  r6nqw&HhuT8=^FPKuC[x[O5|[l">TVz8iJ2Dw\ seJ,N8W;syܼп%ma$]P(iur[lj?^_&5t]R,~DKMwnkHgLk~i쵞Kںo52[HR(1~Y.E48s %x]]\j`l~t FĥְJ4oQPVp!"x5$$?oɆo %ƸiS|69 s*$-?έ`jl{%7պMz/^poKйa/^Fq708 K߽OC%)e$ss=4?搘lnHcܼnIW>A 5"h:Bw/Żp0 j(qsK7P1GlomMj#$μ̩-J)#0|n^7$I4. S'"LxK!Iwu^z-ɒUzK%t͕ߊƩ{k {̖~iyk*c4^S!ܒw$\-pԅМ Tc-5>&œ^u55}uboqZ[tn_-Dg~DwC8j Eօ)59ua&环9} pzV+)ꊪsa<9_GTPu3wCh[W[q ꭕ48\禛T-.R*PuzooQ]mv 4Zt3ۓ_jnH]cG:?oyAߓ7ֵ~OoKJ/uuK|N{Oc?Ou;5oqѿUo-sn==ZFxߔk2V*Mw-X$uk(]GOB@.Ѧ%w.Xu粛ڽ^kBwfڋKoѾV까箹%܅;&容#O !jh"oy=_{ H]y5wz>fou}VqW bR}Iu,hsu3BQ]*6WU7SIu35[޺JFiUxK:QtuIqeqCD&[4\>>>k0Q-=j}2/kР5?N@nl xy{}=\i]x4W~ewAȼ{uIө~NsߑK4sMާI~{[4Z_DƔ:[$>oc$/2[QB\2+4 bKf7:[ 7\cl4cK@an@H dn@H dn@H dnr"5KTn)nɶmdU{ TUڒz#nr$b(H֬S(dP޸oN(H*wْz#nr" Y ̾j-"y;'+j[@z&mku@# '6OTgf DMɶYn,*/- 9Uv#[VʝX_5z=GF;ac*3;tߣeh6 #mJE2ȿwg %L.}MqێGМmFR=۔l! b'&<ߔ[(\F @Pod$ܸq)*c'{it(dO=؉_h÷@PoLӿ{OIENDB`fastrpc-1.0.2/Docs/images/Term_definitions.png000066400000000000000000001552361512345705400213430ustar00rootroot00000000000000PNG  IHDR/k5sRGBgAMA a pHYsod3IDATx^ 0!f1cQQD@E(YTY3愂#b ("(A{Zkt{gP]uԩSN֙_B!ƳPB!#]!B ]!B ]!B ]!B ]!B ]!B ]!B ]!B ]!B ]!B ]!B ]!B ]!B ]!B ]!B ]j`ҤIns^x9sfhqmn#B!X)yDZXm ~훻R= n=pw?rW[ԩ֭^xܑx8 7j(B!}%{?~{ɓ'[cǎn7ckfmw! knnUWu2d;YgU`۝r)NB!L /%\mYl?v}wwq19s渧~ڝ|ܧ~ZhYf7n8sX_~nUVqGq9r;c+bp sr-\sMraÆwyuQvW[]zg}wK.qz{Zlir駟^O?u]-":|g>H9:ݮ];נAwwۢaVpz=zk۶횟=CV7|Zj^xw[hÔ)S잛oRooWtӦMs7x;~?1b]ØYc5.B!̓gyƝs9nWwr9>^zE=wy9!>]ӹsgsq_|E;tM7*wBINlpƌ^|ܢ8Oӧ[w]t޽9جYF_|qwGcǺ^z+L4hk֬С-6h#[P@no ]ve{1:k+ӖSV;oB!:8V޳gOl:ԍ5*w3' d%cDP{8 ׺ukt($(D>4i_~y??!oc?X/vHҥͳhd'}d!I!O=laβ=s+㨳DY|3~a"gPG_|1s]&BA;x"~19RnӰaC4xfϞ_{#z[[lEƉl_wuAǞ.jeB,)_,J=_~4n~r-u J&2Nzrc? ~fI#B}?n/)9j@ ym"ouM6]$ȓ'jOGIѡ^ !bڝw4'Z/_Or(7|:c}W[^8߰V[޾sW^y}+28|<ؾf„ K}zۋ܋7 IiӦ-bqq_~eۡ~?=_J]we/Rq?}B! y'vv2|uу*! ߶ri8>c3N;/󕏼I;i5|M;h䱓L}oη/Mu 2`\^syvʮ[oe_Eׯ)AB!ݔO‚B! !B!2w!B!2fB! !B !B !B !B !B !B !B !B !B !B !B !B !B !B !B !B !B?~nw!B!D ]!BQQڌB!AλB!AλB!AλB!AλB!AλB!AλB!AλB!AλB!AλB!AλB!AλB!AλB!AλB!AλB!AλB!!3{߾}?ܹsrRe Q Çww9sf7n;餓O?;R^&Nh4$ّjg2D :QFenBlRV?pgq;uRz܍7O;RuEl14hP~DWXzes֓{g<ܑDH)vGC:ˮ #?klXXyS!D6)=z2d2eJhҥܢ.;R>l!Dv9ꨣܙgի;R$;";Si޼{ݺ뮛; S!D6)Nwu쳏[eUlK89<ж$=IC2?+&lzkׯ_s]NMf"2\s}|t&Z6[o0׳ϻc9M)_<̙J.2.\ѯC?ow)M]Ao.Rs/1bw}Fn~}ᇹ3w5kV쿰>,G7\{rV_~={x:t_mլ~~il,7rwN#{7xõn <߷zq?e{R{am:\BxyɓSٙrh;2\oo@j% 4rH ?nhaرmZ\߆ӫzSd7Tm8=-ԧ?ܕX?r mbn1L]dq8~~Gvgך6PSߟ˧k=C) ߰Łܹ[xݪj[n[l1s0tj{gDst fI-nv=O*g.V|n;7nl oRD#u\sMw+bpXho$Yr h}G\~QhFf+xa,X -9,6Eb\|<#KTN>lڂn;v\}խ6̢iStlZqիzC<li ǝ>qzbǸ_ |So8kG,h'`\qh^ydƂ yQX80Ʊ#<{챶c!ļ,;N2nk2:Si{0>a:ujH|`YfäńO](mXlLDpDmFaR!r7Fs3Pj.0ę?e"l['|؆={vngE8ީ'tHnwy²8UHºAƭhz(V؝"7y>pM%rljcg AJ$Q)RD)%jđ༑bFYbiO|jcwm#K{: gTJ'q.IzZ]e1B4>\FI;ΫI0M4Bd8 H0!zcHh8,/"M6LyPncV$e|QbakCI"TO8,NS%>eoLWJnA6Bir/h تGf>5 % o %O:%#GN3Gj.Jh;h-OC78pٹDI"ed B i &].RIR%IOQh:〜rr̩m&? q\noW].iƽ0!K;1&^?íMjIN +1(x-A 8;8C#b;5DJ+Ytg`y>۬ǐm j ^# d"DR1e߭LLLbŽ7)>"\nt f󴇶=C>tgT᫯1uųx/_*2!]pd0'~~8IcPw㸓NJWn A)#ؓgqxѝd#&%;8Dx% ! kűk:xFCvDۙd2Q{&+?9i?//; E}89Qs٥q xq]v |E <&I^~%2^D& "NND):H-Ify/v2נŶ(A3N,B*z6~#&ՀcȒrɒzϧ8PSQbRphs狗 ;c-(b3 6 o~ag:l!O^xDF\MJZ ;Z7W\qnp 2WvzW$=iusmhD8 c]GO?t /&v9 ㎳~X1ֺwn潏0&uc0D7#jpU.Bd !B!9B!Bdy6#B!( EޅB!rޅB!rޅB!rޅB!rޅB!rޅB!rޅB!rޅB!rޅB!rޅB!rޅB!rޅB!rޅB!rޅB!rޅB!rޅB!rޅB!uƏ?7B!Sg.B!(mF!B ]!B ]!B ]!B ]!B ]!B ]!B ]!B ]!B ]!B ]!B ]!B ]!B ]!B ]!B ]!BP#~ɝtInܸq#B̙3y;R}PeQfM`РAo߾LƏ9j}*R˘5jq Gy3g~wk8fR~mw٩S'wwW,tpzkwUWiӦ5-B8< >}1cƸoэ9҄3%ļbw0aB&ܦMרQ#WnܙGm!駟vW_};Sѣ݀?>$9/=nv]vsW,8s;[}]z +w_|VQogr8+pK'rʜs9+,! AnM6qmeHt{=dEʜ{キ{7\֭L2Ōev=# RΞqnpX?oQ?&B[)RO?Va/;w!:&?pzE4w}~gwWZ]_~2/rٳ8q{}<'0;.j%@?E)ԧ<wuYہg]DF~)*Sw}guYț!ч>}裏Ga&IC ! u@F_IQGFN8w=X6+"':G<[<`7ߘLi3<Ŷ[x}OU՗(ٮmР|{ԩ4iu~ǂc6S^~}*wyRmF6p^A]w5wE<L 0X#D +:vh#LҀ$ի}6|g7 C2dg*I)gnf6pLԏB˖-ݰal2~G1X]tE<&}ǝynԩV}ᇶ]3_I]we?i#es߳>ke0ag6IkH*rc䉔ۣD {mE۶mݹkЇ|X0 6t&Msl _&8O wauÙILV7|ɿPyB:7tS+f$B_}L7]LDprink2_v`[la6u FvWdk$mp cX𨣎2޽ g}f/oeSEafF:8?:.&m}NNiUї${-ױ8_vjr1bet=cAxm`yX:tg-eqts",Rz?ƋÐ4mtC&g1GhHҷL|I^hP&|qrJ3_yQZk;,Y ;BgK[$Hes~[veX`C"o5k؂r%t|Ilx0)0`䙠YS3c e]rgm2.:wl}N?)m:EDsҽr-mP4/Be+[򁃄˴;\4 "rlV]v+CZj)˴ 5\ڂLY8f-Z09֟y\?(z1$#'dBp, ()0n%Ay /oiز&8v)O;4L= 91R3rřYDq(8 ݡhzsW&%Xœ7k~+RwWfZ/8cٳ3S|UH?1FӦMsW,8yJMqA݂: [o:bp]d(L(QOlx[Iva!" W_v&hu5$"a~)fQ΄A NXO"uy&SO3:|0^r%,L@!Dkv,E6}F`&erIA?(T4pTUi Rȹe:#c!֗rS)IUu"blקhۼ]blC4&5C×E bX(ygd ̪ B[0~Vy(h!Bئ#7 "6$]۩"%Vv!I4:q'm}xt3D!%"3؞&?/<9 l% _Bhs=#.)PE]ixTp~I HZ6rW8Q|ߟ ::K;8C09zȐλ%M[9,SaIgz8D$r38[$IƋYPEp :&J?b^A~gaxL-·m!\M]ˮ8m~aNwPl%/)#i!>MqTxG=y,19D9C/ /dN A In'2daćY QG)/ub+0,\GtyLc{#{mN\`ב#/ur:è/Ŷq,F䃜&]B$KUI%<pbeRH"nC|qY஘1^Lڶ_]H &h4O!$;[ "b+ż;=gI1akʡ"yiڅ%D5I`a(U!tR ,wY"QmJ!Ăl"9B tI!-M+f[U!dKq(mF!BȻB!AλB!AλB!AλB!AλB!AλB!AλB!AλB!AλB!AλB!AλB!AλB!AλB!AλB!AλB!AλB!AλB!~B!B`/߅B!5!B !B !B !B !B !B !B !B !B !B !B !B !B !B !B !Bg~ɝtInܸq#3gOo;"jÇww9sfH:ГC9B_&NhND  QF-y u(Iv9iO}yMM˼&ۏ?>s7w!NYw j?R7P}[oz;;^sUWiӦ5~xvMNwmg]r68Vɳ>x_ RH*~p_~y8Yc~d.,k+ J;R<2E{nF7}!N"￿s 'Ζ/=ns^z_rW8w5X5 /lO?jwꩧѣGت}Yb%-f!娣rgyW^ȂIݽ]w!DM'[.]u]]t!lc /Tl(dMLb{iN9EuqM4q{9>֭m[?"n<; 4p+;믿&L_]m=Њm?&Q~>?#wGXcEw(rOݻwTF)kvfXqY>C=F!]#ܾk9TA?B;Z^t 8!sY;mȧ3ŵ_s=V'p;v+5n믦<Y9ҎC\FưǏ9 =6/߸/8ww&>]g}: _kǐ/~2W_}sñRHȌ>{7'mFAlR38b N{E!4CԖ/p΀9 ] o1}/W\߳gϊTB!^g܋-#9p BeȐ!7:|o]Agh%}$GS32g/#ƈO;&Mr}q9lS3( ;o ߿ (o5k=eg"=Qٳg88kV?08 gqSOه|AL# ԩS^v 08;wc!}0P8qOtk<nO,N/B[@R_$u튶QԖ(9##{mx{s=RR;̶m5'O.(RY>}|u_c5<2cƢ#<ŘQ[l1kpo?8ԕ+Y| )Oċ.6uG esމp̤ǯ6Yf3[n[hlzW6cDZha +N;lҀf"`+rBg֡ݪU*9 4?.NGmmf lvv G"c*A{キɩqnvk=qRac<ƋO>"ܷڄ$e<Y&NHBLd'}LYEС=guppfI!8,:cR.zՃkL'qm8Ro;nq}-Mq$Tp>J8gP^R[5z2ΰu뭷]}A`qpR=+d#B]ӦMAG\ aG gk9ΜLk8 A&on,t+4c9gcĂA&mO<&&W 8VD 8Rb&pʟAa(6+k" I88l1#4|}c=V1yB1cM+R?@#w?`T`T5u@LY&R_7v`jqL7^Y}z~"BCK.[jrG9LJ9 Jwi ,p9?q"9D_C9EqÎ΄$Fʝ6b?ԥ B}XGdG'=7[գBDG S:qiOZc$ m=8ޮK$}`y Ț~ e8B?/o]#ig%եP[8%i9Dyg*)՞6Qx&:K/=F:[ϋP_gv‰{lGaؙY}}>B$7T)g ,yoR+0CD-;aۑ#i}}C0/ #"+MAIҵ;̜Pu>?̏cB#%3Y(da̲^L7%1䏎1qX>묳*&yoY^hIY @4'&J:/(fA9z?ٖ|[DT׸ x3g׹,PGlR(lT2ByO&tVDЉ2X"$_<%i!:E=/1WQXq؝vi6S,,X@vC{lQo6wXZ>"/b>EBm[gA= t.(4~) "$l͆/ y ՄPgwr](,n8v[[E=פQ"n PdXeq:z1AR6e3VD. S@ש9Z4Q6QBƓ:}r8B|!}|8B!k:_?I8[)v=i$?_-^ Qj[0gQO(ιm!,u^QB3ױS@ y?qE*bUL#ƈjw =ɋl[qDSǁbBƠ`tp|Ɖ4pTf@~f[._aR 6s?ff jzg !Ȃ:)/̈́1 8Oaɖb~L9Ҏ/-B?ۉ=I٤^t"uYǶy7Y=]޾Cy6a+9y1R/ȋ< GTb+4.F ?E~D= Crxy&}G۹/߸~"[oJ_3^igɗP>vIkXأICoozK"qre}7IV_I eovLizD79Խmg!HWǵ%_jKHmIqIX(1_ ɣ":KZa'xiGԝ: c2(96=$nL1bڝw,ry%E&[ /l _ԋ#jʘgBQK@0%E1v=Τ%.ImIj+?*1_TFQN{dEi駛7~^`v{עKqw=DSRƈ:s˱/%1baΗ-;M,qBdj !\eU!턨"q{!Bλ UsRWHSc{\6 ҊHТI!jJB!"#(.B!DF.B!DF.B!DF.B!DF.B!DF.B!DF.B!DF.B!DF;ֻ_~SNnV8tPxᚷ~; 4~XB!Btj>sLwWcǺѣGۿW6lX*ڷooNqܘ1c욫x!B!j#eqމvn}ulٳ8qb?nkm&vȑ#sg+3b_O<ѭ AvO׮]͹R^=f=t믿rgB!=y'}޽{S޶m[wɓ'pw;vq~˝>mne.]sBJB! &%{DŸy׭[7k^آr氷j"[iӦ",֭;M4ׯ;/W^?x!B!j%;3fpSNuJ3YfRg7nH3gNy7l˪ѣa,B/B!DmrPoŁO4?ؓ/T|L*^zy#B!BJv6l6m&L;ܬYܔ)S\sGӲeK7j(<îO>VvH?~x~ !B5JvOܹ98˳g϶xr۴i*=oy+7@SOwٞʙ4i}C /ƒc3 P+B!D(KV[m{ou^*{_~iԨ;3RK-exn͝tIn7] 9D?#סC׮];7dwe-ZB!";ԙmB!FSm/ !B!ʋw!B!2w!B!2w!B!2w!B!2w!B!2w!B!2w!B!2w!B!2w!B!2w!B!2w!B!2w!B!2w!B!2w!B!2w!B!2w!B!2w!B!2w!B!2w!B!2B.B!ԙ_r !B!j0JB!"#yB!"#yB!"#yB!"#yB!"#yB!"#yB!"#yB!"#yB!"#yB!"#yB!"#yB!"#yB!"#yB!"#yB!"#yB!"#y( rw9sf_?ws}2g駟~-w$0G5_1V[m57|˼qƹC9~fUwj* 1qDON2],;ʈ~J5Ld8G[޽{{\uUnڴiv vx]өS'ww<=P@6&'x'M6ĝqn̘1+{xn#KqQb_ܑ 1?_{mxxsg-Qyʩ;}FY[g}=6JcPqτs&vکE}|zm _Vprtج?|0x`{u|ݬY|ںkyMtp ?/tO>[lܥ^~]s5V /.23Oڝznn=Ł a~6r;S[h!mboڷoo~m^xo]Q=t]wunE%Xr-nm͛77'zu7`ڴi5j֭;U5:ʝy普^z#5g/9pn6+V5h8ɀ~/O7l0nY/k}A|Ν;C:3آO>\q#G &m~0OC}W׏g*5=}yy;itr>hk{]QdU/WȿgϞeCep-ѷ|s(4^PBhmyP]h=dA]((+,:m6~-v~:xЩ·$,DRyߚ㒔;ν[7}e1'~B>Nʳ) ,}ؒ7xõnݺX7Q&|`2Ax饗\ƍn>]Æ mݪU+sU؆Blv֟?vwqGs0 WA;&M2oldk 2w7f͚G}Ԣ(:EYJ fϞm?yǩ_krGaG1 1iif*/՝AtVlDyw;v4ǑEwa"My"vC?;&Gy& E]dq}~BWE]۶mlL&BiV2y8>`xԩSmIv[3`lxBh/oFvs)ĵ=  ($ &YٲeKvtMVV^@8s՟ɜ ?J! K i'JC⩧;8=^{J[x`׈p V& (_qr{P~ܳsL+b"}ϥ%ba];eD&OlC1:yQ.}yLlwхD nCϽk±26&2WE./vy4:_B}ڵ$}HӦMݲ.[w8tcs 7Bv $q>N cӊ+h [#8@Gp,.pOlRÍw%"BV,WYekc8!{AR6睕'FGPYf3[n9SlfԁUh-r-gOJZ|:r#jDG8@aCU\t2L((6Νw܁h'|b1e]L{v} g2%JS( 13tف!SV(װ}Z V[me:c/ +0Jg 8@'qk[s5-ڱKJN:1)KDDg&3:PcԸɊ2pȨ۪jϡ({DD;XPP2a28Q9p?9G)$d'bQ{5ְ>#W>Dl89"OL^'0D}LXg!Iî=b-Nct*")2n?ՁC!>ZʠN^;*Cx>H 9\PHjc9 {-~zMFU!WA n5~߂lqbx&8B2IC1tgC}mqal3AK '8;I% |W¸6"Q=}I!'RwFt*Z|ygCdGPܯڝxP#H(1+pGh4 .xW4QmE|Ec%]U>D)X]2<K&8 . EMDeD` Faƌl!C/Od  6G>F1}QŘ`YR>:3p1 c=f,ea+3)DQv\8 ^I}# Ao~Frdq?q[(LJL$LJ!FK.d S0&7ۮ0=D2);g&=}^˭Kȟ)}ٌ0u&CC+Dx>HCUdUؘ6 -BE[3J oI9& Oqځ$ $ q:NG[0^c)z IRHd! oѣXXU'O?vD[b][՞6 -A GC$7:": upΈGruBjC:0bıX" ^I# C-8]^m'|b1;'"/I ŁEQjF 4^QxPRM<,z uD[ddŘ~;8:OTM-8yЃP=XPg }ԕcRӴr 'O^Po|;ͷY#&-D7 Ș;{7c^ƞ 0ŬT` ?t^A輘 l^b`haSy:9R~ # ƙry񅯇"gGqQ4fOM B{BiebiY| .Fp^d>, KSl_p"KDb“ 2A-Ա]%k{9B]v5P}. yB'u_qyQR}D_g?V0^Q9qT?&Iɀsx)I;mO?a;!^$ѥ2H*oL;q.  N(F>PLla#n&"0P> .:9;zdB?`~٤ߒd\7|ydF0 ~G>;V _.;MgD[د$w -36oA>p*fGߢ3Oբ>N>耮1)޾Rgn9BQ V888q"}oi"Ҥ|` E=.B,x !(9B!D5 %H B!ByB!"#yB!"#yB!"#yB!"#yB!"#yB!"#yB!"#yB!"#W}ĉ̜9ӝwyn#K/MB +̙~[ܐ_7n;餓O?;"ȑ#ݾvi'5jTNƫStO?u[lZY#OBKYw jV9?o dz>x_1鶴'e g/_Ubnowzr 4ȝ:, 28Jwy9?[eU9:Cɂ~p_~x`{3?x7~x| oO9!\{Lp. Gy?!w5'+$>1ܙn)[oh/}9k,z>s??v1h'o HG'$ܳaڴi̮,rԁ]drW[u}|r Ic<]9'<~cyi#hs8CцQG E<ﮰy!;`כ*4g|ME{m/|Ϟ=+RSgw>`ĈG>X}N;HC弯 nwqs= .+W/V]uՊk1tM]F;}Q3V\7 =n 7cb\T&)2km6d~۬lS&ec|wsW8OZ]gmޤI\ue'-"v.4mٸ;lg"2d h±CL~88DL{I:?م]w̤OmSOه|qMXN&[S&MX_wA )n8uT;g`}݇^FȔzWȌ"@Sy Yz~„ ۀ{1[`n)` G /~ĵ+%m$3l0wM7Yz͘yMSO=}Dᠥy^(hTC^y啊fJY/_]tEV.zO92ocHHرk/EdEg"EWq.?!:@܃]py:oi۶;sɓm!PGhUW]e6,J}.v D9li4ʹ.v&Db 3b_}Vyx]n܊+henvۙqLd^$V[v 6t_|M % 3=ԏ E"5<۴KPi[̭V&(͚5s3f̰ 9lLg#6md3&wFm`^|m1vG-ܲ`-(=({>vMUJ!9vȕ:h^)=5|Pe] d͢h喳88ƍu8A,YlP/&PSogչsgk3dtG,CJHP$9zxcD<C|Wl [keq^{Ճ"_^6`)eXR}Eg!'c@,xo^ah3;:A=5\ڵEB?L1oF!I*c_$yưP:cưJ`0& f>< Q( #LT`dϨOL:lz㈦m_ʯjú{pVߺ%\&>OQ)`cgiYLI'lQ^p"^zM&> MF)$'߇jx! ^hN8*􋿟^S3MT _Q]c5lNP5So(.{6rӝRR" xumVI|hmӲSK"óatG:$=hpXoRGr*R%%,P|1,D3˂<묳*R a# 6 >uW;G tmY% g1nu)Ln=2Ѿ8=ƈVḓ;"c"~QDtlwHU1$jL+7&@^e%G73Y !]EL)QBȀEMoi Rys@|@AY;L[Bq݈#٤_(胧E)FG9V8J/.XCC.'ȷ1.z 7(fC`gw.dn!;Co1_g0=CD*x'bCnyw1ʡ8xFj;!/Iknz10IҞ8=lw; ;TGZN&OΨ'^ "GXhdp@IwJ6Dep/PgvГ&bDd\-O$v!P~,xʸaF߅$r[(":"o"bi&RQ"9}% ^Fa#B& 2 $ C9g<~A$aD&}Ƽ31O11=l?r1&J/G";L;`|)>l;MADy 9u21so3VQSrhIwg!S|[2[4vm74'A{Ao3w/jֲQY(-uDy6,R/==x*@K}p=nV$% c_Iݑo`ؠ|3 /3 ^fFj7":(EP/kC%~D¡\q&Cl#6dn!ͷ_$D~H8q"n 5u8 xN>Dv(,]rB_f'&V !O Ax MbR.ar_7)P9B M-~i?ė43?dr%rqC!ByB!"#yB!"#yB!"#yB!"#yB!"#yB!"#yB!"#yB!"#yB!"#yB!"#yB!"#yB!"#yB!"#yB!"#yB!"#yB!"#?~B!BL%B!!B!2w!B!2w!B!2w!B!2w!B!2w!B!2w!B!2w!B!2w!B!2w!B!2w!B!2w!B!2w!B!2w!B!2w!B!2w!B!2w!B!2Zʏ?>s7w O?N:ɍ7.wD |H_9!/6A'!̙>Sodb1eVSceg2~xw1ǸV[ >7{nF7}ܑMUT@zhp&DՙWXωI:.*s?9;6`wǻQFUrذdlGvAw_{sGj?j~tQ_{ ct7ΝPoUp ?/tO>[lܥ^~]s5V /.23JOڝznnƁ>JmB;vkW_}eevBb 7t2da̙<$-JsѥKwu׹E]4wS9 !?&y"(/?=c̘1fo6+Vpvm7w ?s&c fP/®YXb%-fܑς8gdXPi5jխ[7wFpvvLPL^-[t#FkB-BEV{,Zd/ݑGiN.|G#h[T,*huD1l5-RPBr&gz6c."C}&_n!rC8"[o Yf9)ꫯ} >#Q(vokݺuE@_ӷp'N&!^x+ȑ#sw$]wv#~ʡvsŸ~ ;ף³ΊAuK-7@5WN;>nx8[nZॗ^r7v~ 5Zr=\%wߵ AɓrMeǚ׵'x矹Ӈ~:Jr,OIzN`OU7N ]Qvaĉ3<+qvy~$:)|~ :tco yARYz>}s恵WqL9'􄹗`8/r={ԇQ=mT>i$|/:G18|M׿387|k֬{G8q$0{lZk;(>[lEK@9_Ev4"\` D۶mkQ& lڸJ+Y?0L8ԓSڵf`;wcY!*' mc1ED [lxy]_}F҃cMh'Ї,J/"+Id*c/ϢgyXg}I$W6I&qBl3yGT ,Ա#nɊUq{W6$:q:Onk_F.0}ٶBBۄmÎakɗ6#/3/%-~iW4 B%8B098{͜M:+`}Љr^3 }VWk|af(ڶh]<0H.$=gуL;69:Ph@vy-uС sC>tvj B*ر_πIu!{;&d,= qױcG[\(i;`Wp{s%>V;1A}Q~S?ڃoNMOfk+esY!|JieIB -dѕW^bEn3eav. |Ќ- CM%8x ? O

rZve.beEg F$]%n!Cd%871 ;$vQ'[}391iIC=Ld6c Wԓ ^έ5ca%i􁿑5eEBd;?VG&%\ĄI{i 4S_5~^ #B&^:ڎሓm(YPdFm"38W,qBx.:@:F]Acv@Y 17Sªp l:@Ìh]<󍣋\qwXczh>@HIvy 1`0>#^ʠ,_&snGN,@X`бF΀\-`oqyVY! ogԉhygE'Lk5@P F&S裰@ǢlqB1QB .CTO~VĚ6m(( rHd *$3 30l/G=X,hmqa}L6{)~bTeC_8 D~wx,$I&qbÄӣG|gMarc$SA1_gB ,J/)"zzWXdk?QFBgOKx/i  ʥ-i>:_ B2OF 4 Sg6Q64V%V88&r?gBƐFoP`[ ]e2[DD1*i(]N%0aIbu그 niBp a@?FTNv-b¶W ONUH1/ĵG71ΤPuY6a`~EGP& b(L,ؗzLl'P>m4eʡ/1i˶Im!|YD;DCg!d!u<%:ꝒZvQk=sƁÄ %b /RʿQ;Ɩ aN? #bC$PZ>DS REMG-W ǃpQ‚u,禁"!kc=, |@{ʉ-Z!t|(-Nq E=a{XLXpח:FI$]~ 0Vق&%@D(=zs\\NJȱ(quL֟=&dub޳ 33_*$ȏ袏퉓mN07x W$)^Dq.NҾXpycaې#2pO8f`<'Ŋ6紥D¾{oQt `[t; zx 4QN{V,ƅߴ)jw8&j&姞zʶZh3[*ČR`PGAI+dyAi8[ 6u-GPΜz1 E~k./>\"@oVEd)znr| +pX2yzR>OzgF}aRfADHp0 C9 %9x`3^ΐ7Ԡ+:NQ&8DD8#@˞7F^F;8JL0q$yqIE y<;|Y|/`x6}T=(]xq}>l %}:ɒt;נSm@n&PN{ )f;syzAڝwEryK (JKho)/&yfQ/8lYryсcOG^e@V/Hvi 9tD(;hN2|߰wBs@H!zK'o|rY lf$9! h׮M1&@p2$:JT̓3gM*^+d{0Jt#cjreI l26(?nD! 38 I2)8.t.r9c͞'T$ωcE& Ęcy>͋LL|/o>w1IHӏQKOH1@N*/,И-Az""N@')Q:9bRvOi~C.9I2Ƒ8vȥc{vAL mi`f1qAiWhp(i6oaC\nkwr!=υ(=W8J@ 9~D%2#8Qgnuqq4`N ͋?BNzSv`K!'!B$伋Z y~kڴiHeBirG_'7nLRq M'?~~˺wwsIe3f 8\[J+duʗ+/BډwQkxW1Ɖ~w-"w2[gu,ǚ<1εh¢椷TB*/BK/dN7#Gsα\zݻO, 8ó>oCcƌ|i3q/W,z-˃B!DEλ5zh>}ܩV]u(-0W-vբO}e8^m/ww5\ӝyvs|W\Xc wc=8NzΝl׫WN 9Cݹk/tBQ{?iFozi^P`!x .p￿!Ȼ>p_|,u矷(>)?B!y"DxW^qgqFtB}6#B!DFP]!B ]!B ]!B ]!B ]!B ]!B ]!B ]!B ]!B ]!B ]!B ]!B ]!B ]!B ]!B ]!B ]!BPgss !B!j0uB!BfB!rޅB!rޅB!rޅB!rޅB!rޅB!rޅB!rޅB!rޅB!rޅB!rޅB!rޅB!rޅB!rޅB!rޅB!rޅB!r3O?N:$7nܑܸ̙3}~Ç;͜93wd@EĉS*CrkJbРAo߾#*ʩjYY!|LJzwm\c J7Qu~G矻sT'B9&R睁jϧDDŽ賶zk׻wowyOM6ͮ۽k:u;z~ M$Qs)T޳>x_Qb#J] V7%t[r܍7O;R{lߢ(p ?/tO>[lܥ^~]s5V /.2sl駟vW_};Sѣ݀lEO:,[nqlM &Gu;3]zrGUAc)t]wunEv}'i38` {^xᅊm"ߛl;ݔ)Ss=)w˹N:I&n2GC5ݺu-ǻ~=#Og6h v0aBFvۣ |=\~G#(1c [Kw peD\O??ۇ~hJF&) R[oޔ3k,X޽{2H!]3s矷YE/+ߏ1ᆭsN#=Egː83,6xE*m|+ٳgJۍqW_}R;Cz{x ׺u늱%~d x6unP6v1 ?n}@_,1tP;)+U#flIsh zM?~T.:M=8}Dvs2gϢ W^yG'=?N ȑ#Nb 80NUB?oM!:NO9܁^^ )f,yxF>C-i,w6s=VǨ}8p`]t|yҁBc(/*$w 8Ky"ioJbvӧejw'MdBolM_|gEY bN75k}Q|,"vO0{l~ gXX 8xꩧ>)mEPV(QSڽ0q;wlB^y;s6lhrOXyzCmڴ.a9<= KD?5<Ɩ-[aÆn1g[ͳq0`L1ڗ\r0 Ϯ[ Ȝgw^g{.rY]{U1fk΃el>01{wۜi8v7jȂ'<>?׏}~~{N+ r>9uf}@Oڼzd=OFNq6"k&`ntۨ$ƒy1Tc2v[m,l瓞C'ؙ 7Ў ?v98,@}D3fC԰1,.Bgԁ8[Qf*RH4U~$I ,h2xd }A ӷ,R6׺k"[fḛmnr͛7w+u믮E6v. t@"Iͯ;[jU%%[|h}fu,4PZۯ:A*3x(Sƍ;`z'cΤc 5Xv>e].y7C&_5R5>ZuU]ǎMvxSd/JLpq$xV׮]M' cs=Ϥ #<Ҏq#Jɞatvmܓ\`𸆶` I:Bd5\N'W\qE{$Nol}FqBb2v)rjBA!JBG =/&ysLdH*:/,!.GCR^{mgIϏ敖FxWʏ?n饗65{dH(^SMFa^]ܸMCuIJF?vW+sh#}ʗ~A۱ 2$Za~3 Uav~7fKج4V?e<7x#ySwL@bBUEsJN݉'hcr v1 xV1Q:$\(Й<amֈ6m4wEyA)X3x`hԑ%ZcULP{g̘a J+ a7(#ŀbucR/oHhF6k8\ }eA98_r%RK-;o9>1OXVc zRNp1<08Iyddz}=ޏ$鯗;70eQeG),&y[f2*R-R8#,)bȤr;|uNcHj7zߚ~r,q]\('M88I?g#$|6$RZ[߀*l? S,s1$"GBx~b{9o7fXbWd4O3PC;7ҷR6lŠ/>6' +йG*ԨS$l9V^Б Q ,GYmfa[l Q+vV^"R֫wLRIҵ;vBYm7@XP:.M̓fK2- j=v.ߞx'BE,]-0!zE- |tۋØ Ա(ֹrbmDV)W3/Q:SL~&p+E8n#7Y$ a5S~A=6%Bx/g!,nٹ榏5Nå]-Nq)($EF2WH5璞ߞB}4:s'3GblDZi{M*V]9,bp:lÁϷKH!@spQLUlVH 扤y*̫R;2@P VJl[*DQÁbBB1Qf* &_Ǡl 8k Lrxt/­ zqiQl1cȩ+m`h* i^70Yx'ċN>dN6ŖW8'tv0^y_'N ?DߡwLPj%~C05B+(DrDžHj7si -},8 j0?IpNyk1]&6QnHCRQQŵq?pI).^8X`y]ϧ $٬8C/̨0{챦(("ve{;4Ƚg$d砃&4\< '}ԛ\@Ҏhư$ƈksK5 FϽ`):@lBLps @Dew4wK{i駟n@k0" ƐE ߚ~&@7L&oP4 #=DXh/mz:iR9}܈(EaggM|h)}G#ΖD6 zq&)[yfrQL"02S?u؈{~~,s@=qDgӓbl?6v'iHCRQ'Qŵ9#s&^TfK~6o7| t-yjDCT|͊{9+$iHg%8ԙ^B!Hq~xB8=.B!(rޅB!JB!"#(.B!DF.B!DF.B!DF.B!DF.B!DF.B!DF.B!DF.B!DF.jӦMszsGJcnn̙#qƹN:O#bРAo߾j.!b?5қ? ̙>SodyU CuÇP49 V[{Νs9nM6gƏoΫT[o*sD?p7txݢ.j<ԁ 6nԨQx<=6qr-Xb w=Tn|1M3СCM\өS'[M>k|U^dUoq2j#Qʸx܍7X5B_}{^R *LtI~jd}6;]{r]v9gлwo_ 2{3_~{' /l+*+j/kڴtMsG-z`twm7w1c<=3o7gN:nmu&LkjIkĈ6z>s?9}k|ХKwu٢>+4[6l;"jY%Q(_~ٳ8qb?pR쉒sȑ#sg Sn]׼ysw 'ٽvGU/b-YdsHZliG&MnݺٖW/b 9&:& rK[EW駟ngc;t`ѿˎE2e97G,.}{gg'|(*c\?#wGXc1:BkذaM6UV~6v3[&$-O?(=md a!F)ӟc-/Q /+~";}|饗|}_ fW} >p]t3N]E12ӷYf/K/OP8AD(<0dJ+;RuVXa뻏?8wĹ5\Сif>wy9DĉQfF1L"0Fs /l`L.&cꫯvSNID8tW^yew]wW_=w8|(}Q;W\R*_|"'xaﺣ>ZvNLİ }uQG3#zڄ?q2^r%VdƢ n͂ئ~U-#v3yp] aKYl;ꉾ]x(lp :T7,,XR7?3m>X1 odSOG4_<(E @oy%Ir6R~M4o܇~.rsiǮ^z%;~w4/oe}6x.,|QPy6ʥiO?əZƍK]/6FGtwQ7]Lv"y 44#Tgf܉'n38pFLg,Q.2Q3 :5_cJdɀ0{E%}7c"aR~tj]GÆ cQ񅓌HG8)&n|Qw8}\ۻ\{e]dbh;0.'ըQ#[\Nv_^spqmY85ȊgdEY{[E=Zha6׍{`dJpq rCϘC~n u!2It7J磜z.n'2 BTUVYŮG3dISdqS8G6{碔q:ا^<9{gW^1]Njo;HvZh!HA2KtDZ7b1|YS+Dg'Q.]LvqO;4 b@.|~ga胓XT$[^n0 f,wvFW,Ϙ1 ڃR0E@4duqgq@oWX|X'C^]C]i뮻kaM&b9Aoܣp s ᷌QcdBSvZΤc%Nʅv9gLvŻ,É:b2BV1}e:kxeA|0  cGVk [<*<&V>4zapbG9rHS;*+d%tK-TyC!}(jmbYHpp,3>ัCHbOi2^w>SOO2q iDt1,yї SX3!yg1;fÂGj{a5N a9c1a-O>bp|H R_mQAcݹsg3,e._?>u" '˻WlC<:Ϛ OQZr"I<^_,Mu g&oJ|0WHenV(qD/]U ,H!KN|U)IۗI GĝhN{uK1TDIbA@)3dm'&pk+D Rfc"A'+&A´R!6&>Qe":.eK:`<$E;{J|1'/@ˣ!_$U+t?2D(5[L~yp<_V"Ŵ9HDqkg{0fXP`1dq~%1C=#/4)iܳM9o:F;80Dx3-!Pe"& oE@#JtmAVɿKn,}&xS!8o{衇l1G^L.8Aa[㮏BF΅|7ԖbApr׹p\@)O'tGЏ8YkeyY\K;@0  ׅd2_t:itc.Kt!J(kb]6,m;HC,د}",fSX[S (K >y[|/4VJʚ2d>+"1 L|_eϋ =zT a2q%Iba71k^`CHdI-u~&ATo`̐wNdu>/^x;&:E? =ȓ*/"c$'f2+w |?pK 7L>pR dLy߼xu&ٲ@ls-Q8twq ]ɝ"r}ӤC7Q[Ȋ^LF爔r1:.J<.`[+Vu=BdD[q(9NUη4B=yű)WB_]YHQQm/ 1ar;q&[M/b^B]]Y Sw[Y솽 -:u|M飄[[ombr;t?쮼J+ׯB_6AzYi;v{'x˫Zq?rSu]gmw)ѧP a/Mp '`NJt6(|wvk[՗w=l5rv9eUe%9!oh#[kzD`(,EfE\=OȘR>7g!=BC}J}ˆ#*=ߓmqWqi1 /n|k3Yq]gnf6>JC[l f>jp믿."3<I>c1uol]~ 0vuWK/'cX.I)*'& 3&|0\{QF&7&&'|ο{u{ɶm۶sϵ] 0K 6t&MslQ,_}!щ,_+ ;cE=1gq@+>Gu19lN2_HnjrA8(Q<6pCd{G__YEIzNډKݻvjLTpq~#:ȂdL=qr:wXOgsmT:cME7BsK,auM7EY$q֗\ yg򪫮E4m+o:t09c>;B˻UW]v?~AKlBprqc??U9oРA?$i\!o^.!(ɮ(ygb!ڰK[ oEH>N{-:|L΋cDo5k؂r%t|IlDd$Nr&3fwDveYFm ]gc|v.mYnE!:t/^n-t- -k޼[y啭MIDVeԝy.qۄV[v ufe'Gp2tͭ3~g9mѢqv~QޮIYp?rB&ڴic>e#7\BQb|n7|~hժɔQ6z0֭[לu]ל:m'"9vIWr-gd;.ev'/s ggydȡ{&;TOچRrYol.B\;g>Z_t粓M? _tEQv!}^a/|7rOK!@xzCJ裫-n{xV_'47-qcX;ԧ2x]SwO?=nuֱ(,e*fbapAGcݎ{"L~Rx3!`̪(&4~щb;-''mt߇Ϟ=Sg>!t/`=O'-B`dReRcy>q? geq/x1E}8F67k̜?8+R?1# I鏴O^ȍ-}lM$TUc'ݡ;<Bȳ ϶5 u$|*.'_UUs7^H%y<g9#ZzFI|ɸ9+☲KI|g,EIj[lަ`p<ܓW jkM47n{#u  Ic#IVI7-qc;}^>-UQ]S6(`4˖ ^{rٮĹ?Uْ .Dɫ<묳* ۦskCķ-@ k-|vaut4sW_}e[,6e{8 [ NNZ/҄z) 4`VCuB*St%dJ9AN>dGyd"/Y^68O񆜸zcXE_YWСoBzi^_ܪB);$i,}>[r#YL;k"F,)+8On Rky™g{iӦ4]08h 21x`/Qf(Nd>uD3%uq&$QB/h Hϋ+7=M? ;|M@8f\ص`'ó PݰOBEJ~ʄۚmM;D9H a"J}AoX8[Lw9SU9a ¦E)mC?s'Ii3,.|q†SI@/FnR-tvčRHRˏ#$.dU>9|*$9pr0t6RP2%`f_4OFqZqVƘax c’40׏02y=fm(Dx&S>/il3E}Xd,$QK" LL DhN[YlK|+ n߿X#Q|wv:GּD9NjL%#Or"2ֱ A.dzyH mԩW^& OO`Gk>Dya"^WV'Ȏ%!7/ BWFdK98_I$S0nB@I`|1x>`qgx~ܜs}b8C;(=vѡ|xw¦NO*O }7CN8At:i#Kˢkk( B)s$iW6틳xJvQ"lkZk QtB aF\doLޠ&/DxQ(FɁ ^"Gr{c\w`2`ڽ{w{IR&(Lz9oD<  0fxcԒ(^r?z%I^@h屐$D(۴q)gNZ>ǀSty2]dqEۈc>rl5_xֿlo7$ڧI[t1ݾ}{tG,m=7gVtqYZDsדj?CyQ1 Ǚ4W wD>Na!D-j(R<]@A4QH*q]Qgn9KNή\Fr'D:ֱC!W}(lExē9xB!*rޅ(l"8ۡjRέh!B,(mF!BȻB!AλB!AλB!AλB!AλB!AλB!AλB!AλB!Aλ?w?kHu.#G}Nnܸq 4wu׹M6dĉ3/@fU~ɝtItS!rEs7x>}zȂ!ڱ9s;*9Sv;y*;ŶX >SSO>:wz'g}=)^pݡjN{L^m[޽{.w?l&\F||wFop!ļCλt".hHٳ]ݺuoׯoKXnWtwuQ3Ϝ/~}'tk;_|aX]{n,&#nΜ9vη矷vR~>o/WgϞi"9< ~Ww5X)zs}Yf }(~IN/gEKD{8N{8 }X6>NB|tv j4|a;a뮻^zɜ~7L&|=XJ Lj,C~wk +` 6)N{E]dNǟx ;v{= m۶ɓ'̹wO)6;v4y Rppt.Ii~h)Qp42YK_tgl}_>3An8~nEQ/ !8|8ᴋs ^Ho_|兠[nq;w'>,\x&>J_||-nbVg ݾ}{?qH`l 6̞ };N`˚[X?Ff,Jh$"9a'XS]vh pDa1 սT{H.L Q>c@ɍFѣGϮC 8iuqt :ꪫZ¨}"+`"cʢſv#]JZhJ*rE|kM0Yt\y3,JcA1QC&v>!g,^$Hm|.-ZKsՇ&!%Tk֬Y߰Ҹqoi#ud dKEu]K-TX-D;uPLDQwv&TR筱âŢv#]<01-|6wIv,LłEeNH9 \BkB2g4,Pn:TpqPY|yrig;vNB#zl /-R)nnA0'|a \'h &~"M6&X}xߋtLž0X,8z~}K.nDʼnlȗʧ.N /eQcBntUL㣳G䁧I)싥T)DUe7,q`ouʩ/r Ҽ -7`W%bubR*/ƒ6l͊JB^ 7#NR/pYg FZ/Hp>_Jy|C=dN}W^Bg˵Lԏ|h9FD_~Y,l|"QOPɂgn"DpC~WM6≶/ Rt6h#k3mEL^NP#磷g`HG 6rޅ|S/B2;B%\b˗|O7K"UTU (R#LķHײ'^8)J%˺8,N1u~'>JHh-y)3itQt:ċ`L. 믿s@nYm_ffN*̌c+T933339Q:i4*v{~=ցH׳gpGF=@DDzoH7JK9?G("""հ.""""RLEDDDDJfDDDDDJw`.""""RLEDDDDJɻHI0y) &"""""%]DDDD$w`.""""RLEDDDDJɻHI0y) &"""""%]DDDD$wУ_~+HGQ[DDDDD0.) &"""""%]DDDD$w`.""""RLEDDDDJɻHI0y) &"""""%]DDDD$w`.""""RLEDDDDJɻHI0yBy3)Rs_K/\Ni7|SR^oW Lg_34~wЈ$ﵔa P1Sv|fy;Ān1na_Kk7uW˦nږ$jM6߉[o5\ve?l|ᨣ OLNm9{gx+Go z<+2q?ΥYj\~xL5dO>d8O?T9t%;Fڙ͠PKT_+Deᮺ(xc؆r-s1!:^aalL:/30CeKN>.ls?xeo>c~g ^x@~[O>7 ~+[npI'GE1@%Tmp /pw /-"VzvoTK#-2~/#T2tӅ=#<1ǥ^+T&8_T_#8"Cט>`gyfe]bBD% zyGN?O^^guVMwnrZ+^c9Uxkc'*|I7dC$K676>쐶r;r~E;NNGꪫ:Cw1V1? o:ۛ?H@}eP<3 ).V_+K½Xc:w{cyn?eQ’K.jx.oˇ* & ^cxL槟~Z3Jdgɧz*^;_T,)w,E ̢6Z񢞾}a7 x衇^U#γF1d.=;6ޝw}HVYsE⿐wqw} 5~: UX'3 0>kUn?~>\;v.1)fms=W?K&{=zD{,ʝ K?p?۷o ȃc'pؾ4 k -X5\3{.hh;, |8jeY0vadM60묳FY9昕-c1 @ˇv*r%S!;DOO=E(ȯw>}yol6Y ,'c|&w\oEgg\SlkT<>GG:蠁su%:-yG8QG56hQGP$5T?CGa:FM$d:cPC Y7T&|hzVZiW_pr8;t&e5g=:l[bW,L T'mP%ek-H lAL\IԨX{p c +s?H S"vM5NZ -m"wo6#F)?|y'ʔ#gCڷj@iR%q}* -[.w>}}7u]7Y*_}Y|֟R1{챣nPb0[+˂ O,:t=Dҧ\{\;/SpmD;etZA2y)a *)^s5N SX\z8""QEE_p2&t Fн$ ̃D$9I  y,G}􁪝1E^ |.&pTgʖi|=9lY+񠝴Ȟ~Qu$\/={V|v[q}PE.<7ξ^bTݗY-z;_~"HMP#nkQ1 R~cz{2CT9m-B-lĆQO5LYy ̓U߻!W$v&ruȣzRؼ+*+^?N}$٥%l)/}-lټ}ܳY>_ZoDGB:2(`Pr-cYJ ܧ^Eh]c\;/o%Ntc8$L #NGg}vg? }aFJ_h5I ֳ<2C'lb.L*V3$6l[`PczY0)MRt$ـHC, 6ߓ0U}衇6ih*LS cdzPnxf6*l y(B3zҊNSVVVNQbV%++$Xd;{cr O,ٶViKNpeG(-#Qc+Fn;uf1˞{p:PqRnAS=.Apj q%k%1* 2~}Q݁!UdӲ /x1U4NҺx9>NPyJ@WS/21r~ĄDYzP'QipF0s>c$εBf-/6@[vuBU-9Pa[G8_ hF|97 T(x>6NR 6f$`I67 q.dd=Aެƹ z5&ĀpF8yVh\x6EL˻ܟh80T/@)y@7&ҍ4=S-Yw#x! FW-C"~ cauUދT5:>ji3zҬNUSDVBb.2ߐ#bkpJ^VkoiȠjOl;'z~_`K"ws1q$ܧFȋ^@QL޼$ $E7ىVUDJ8Qkl"TEDD:Ui w`]DDDD$w`.""""RLEDDDDJɻHI0y) &"""""%]DDDD$w`.""""RLEDDDDJɻHI0y)!랤ZIENDB`fastrpc-1.0.2/Docs/images/adspmsgd.png000066400000000000000000001501651512345705400176370ustar00rootroot00000000000000PNG  IHDRvpsRGBgAMA a pHYsod IDATx^fW}ߋ޿E[^C:ۜ[J %wnoj#B]u` rd3'Q| `j]1Ŏ"c010NfCHQ;g{=~Zz魯^~6.xp`l<8] v.xp`l<8] v.xp`l<8] v.xp`l<8] v3t䶫׾uсks쉯vZc_th Jy+3ĭ3+>QRqM?uie8y*A@[@8yG#&ݠR]+'J֡IO.ݟ8kxp'Ouxױ_ULgA(ZAt7'%4@q^}>p0C|Yy<[qs+'JaЃ[l8kxpP;'N.C|KGy%uQL8>_'1~g j':/%D5N<奤.xpDI]:$SkN4Ro;z Nt^:vz#%_}A5}{VZEByԷ7twܬJ"ʯ/-'kTiE+2X%ƙjӡ YH:j+f4tvPr:Vk-غƒ\m PR?~~w^G{ډ&U'1D&oi&cRkhS'NJ~ێޓoTsһѸ 1+qbm8{5";2#_d_JͼPs03EwkUS]mFqP7m BK fX8xpP;)GF myee+v>1Fws˩Qu;*)II:y3Hn;=%\~j1)2je6PʎwƼdg@٢/eإW 4@Zӫ/;-mZ܇FSh gu!>F: P\uhD01tu*Do1[lNh샯YH"Ũ!cLy0Wzpd'4b`$f)RsՓX΅Ͷe3<ؖ.)@=iІyUb5cQ~ϩX <8hF35o>rױm !jc~hػZr6LO5t.G4Ag?p#ӟ.ab% [͌s{puHkBݨr<̬6xYA(2m$Ѽ SuPC|9:})Y?Il}䥭[B]JyףK Ī{,x03c*9.vT+lnA>̼uJ l{M:,6h{.u׏4XgCJgx'F2o k>KFo sh[A Ɉ e\3qS R5D6xjc.8M+Y(OWш Wn[ep<ȗGݸ 1I4ك+D;=R YalQ_jfSƃƈ'R5D̖iqc1V  T<8W8yc'o3*-Jr>}2[eS*+۫|gu4ɷ ~UDj J.E M= +lVߎLtmK`xp9qT4,Bm2]ănxfZLsbt>*I]-gOƃ+nU^po[ )&m|Θ*o>rױ̘cxE\4cDxpE֭S?~4~5y36-q(-29S-9zpp֢|gu4 O/Ѓ뢦RXU̶7\E*hQ6&o]ɘVE&g42V~}~ $uQCxW_vZŎ㙥.jS8nѕK>*2\LJúx=R5D6d0bn{}6f?{=#+-29?aXИbxE Vci)qK[S&%4a J5wiE:O!biИ8%8r軟c3 ft䶇rYt.IߛVn[dr9O:t}y7nOq߮2~MoQw⣑'Y(hEI}{p"}kL=,m/O!b uKaG.)gO<%3ʩmcqVj-J::}TۣăsP0vyl]1&WSY2ch`=z˷ݐ@tсko;zΣn:r[‡o>2ތ 5^wMUw }-{:)q\u+Z:vU+j}~I<8r{`;,X"2_iD̀ <8qױ%ێXao;zՋ\s):t<8E:v[`t6wy`/.xp`l<8] v.xp`l<8] v.xp`l<8] v.xp`l<8] v.xp`l<8] v.xp`l<8] {}ggBffݶZx?kF!4t_ֆ<R!Pn[-<:"\v,y!T{VkA-/yOBZ5/q`X,!TېGXB%`FBhjnCZ`Gկ|{\ z:|.8Tts =.j&[xӦBڰ3 q x7M:C yj!T[݃5VŮx[Ϫw; ?ʻy/O>k=7t69j}Piת^}•zсkw!܆<z_-Ã{/ elov×To==7SyU,3NhB\m#xpP ܒ_ӡ~⣬,_c⳴Z w_5dI`/y񖤟]9bei P6Cb~oqe+JVeRe3ƒT.TnnyJRm^I<D'I:LfrکzIةfņ㚗B\m#xpP ܒ_I 0yNOpn.}=I(E9ThaF,ɺÆ*y DټKꌒ xīʷ`ruX$Z[y](wIQV±_xUV"-N5dEQϤj򦅒G'jmfF0 J1ު3HR#I;bVPҡul?'W2B\m#xpP ܒ=d&W"">*y"cI}+AI^a$pɣ =GS@+,OWL+ >RI#Nf&I(lvU"}ٸ*IŠpi]oq~b~;`+BhjnCZ`Gկ|i=ڃGVϯ${\ *a*Ͻ$(ЯГbC1lxo3I? *buߞȴ+%Y$vf2+TT2$xmF܉OJ Un͕7-8(kz-0EUW%>c"&Ū%Slĩ j0ɚ_<:e L+yBhjnCZ`Gկ=8{˞*bꞔ{m&I?? * [Wa>JOYqH$ +Rub=}*ɦE+[I ;6]BEte RBS޴Gŕ-TE'tx483#NEfP$u v;"=j?(J<8ڹېGXB%FOPn}IQ_'%fzI?;*bu£{kvdfZ91ɐPIλRȴHxRJNAW1^ Kyb<;>b gIO-2AE{~~2C yj!T[7i6>?"OR =)!0L?x[С#U(JBeylV&P%,oIjNWMi%k3~qI)CM(yb*Tՠѡcb K'u簦gIRyW}DV!܆<z_-3zpBGЫn-,o?I1V+͞=)PaoW5zr I[6E"7dw'Jym g գuɐPai%lފZV&r=[D=\QA`f&V~1aI6̤јQWg&&-֬Ck:v>L+yBhjnCZ`Gկ|Wɳ=NKR| a|WU.IΙ)V[$='y"8X1W'Nݎ"$:v"ub|qZ⡤qYzIyWXC,!ǁ'9 ~FmUYf [-,,3ST+*ڌ٠UXpC^7@ xp!s5!A-#WsK~[zleXy9/&+7ŠQ|)ŲFU%]u$I<8oHzhVS5jծle <8ڹېGXB%g`gpѹ!܆<z_- =.s{|-}qUB\m#xpP ܒ_}, #f p7;%xp!s5!A-#WsK`įu3cN!܆<z_-xp3B;Ws=B~5B\m#xpP ܒ0#xp!s5!A-#WsK=.굯wQ8| k!܆<z_-syp=,<8ڹېGXB%.N\tlw>D1E7Y8hS=< V4ڐ(!v6<8{PjnɏUn0&L=tRF#y=ȗ*)Ւ0+;uuTw'cw+g>NNbw!܆<z_-EJa3nՊ&NīRغ㭠;JBfh?Ű)IٳxMpߦTδx+$zR.bC yj!T[y\aܓjΔPx-βY:=)!OU ,ɬKeUk(v>di%A>:ѡ%IBX,xp!s5!A-#WsK~mܠx tYD9ܨ:|.)ƛUdƖC7,ɪ] oHъʻTV)1IWcXm⣛ݖT=K&IhY.bC yj!T[:ߴX <8ڹېGXB%.b(!v6<8{Pjnǃ\ỸIC yj!T[/A03o .B\m#xpP ܒpr'~'@C yj!T[`K>}5\lϿpK!܆<z_-xp%yp} B\m#xpP ܒK\pgמ/xp!s5!A-#WsK>l7?*ܯGK//xp!s5!A-#WsK>g|~g̃SK/W{OC yd7}GCޛ~el=C5Kۿ?tBNg;z_-v63Wx_Tܘ; `߲*{rPjnCS{_zӯ 5=NuvXB%N;7w;;؏,ʞ!TېGȃ3tfӼܒo7`3/,3$I,ʞ!TېGƒw^:a+ڗzӯ;SaGկ|Kwq;ӷ]j[wp.[r%Tٓ#*Ws=o|^[t78{Pjnɷ[two5ă;}(]b 7U܆<]niĆcGկ|9wS9}~O_tQgI<8qϽ9WpSeO\m#[^?ŀ[tƿW+`MXB%nT;>?W/r7 eSdpSeO\m#μg=[Тt.5aGկ|3wOstQSdUnB yd[o>ǶDjJeGկ|-w}?~bp^sŃ;U"M*{rPjnCيw?SKz_-v[k_{ڌ6N>c*3pSeO\m#[>vK>_aGկ|'wcnڿ7G79;/Ǻc}nB yd+܁'X]vj(!T[̍,%Tٓ#*Ws}G8KWBwMz_-vCnB yd~ƀLg{Pjnɷrw07xp4pSeO\m#{pC'lqB (!T[ ,%Tٓ#*Ws_L~%=BkU}u7ުWҝw2f.jք;g1IA-vCnB ymKxpmU} #u ` 7U܆<]eޣ*3ߤC7,l8܇OCMRv\4уmf EZ)Z+VpUnae%nB ynꮉ2X~ug߃Cw<&dܥ[T:Ry'-`,+T$31\c} w&&Y+H>yNJA-XM=9Br5!oxw<񧾯wb>)~~O:rϩR$xE&`GUOfS!U猶~)OXb;s 5eVd/ %KM(V2IQUsK1@9xp4pSeO\m#xp9άc5thN%G燙ăSX?P?-lwIxؐk {_u¯:hQ궗L(*Oom,{/+(|ū?1IR2;@|E䝯G-XM=9Br5!<苙,$)năsN2 >VbBUA /Iуx,莍5{=m,^5d4%޹['܍{rZŭd}E%+vJ+3Ǘ7ʷ^lŤ 3nth(k66+wJ%#?&Ťufϥ6JR$r$gpYӱ4y SaCN"eWM%7Ũ6<xagIR42I+=8u밟1&ʘ}Gi{2RNKyRڷ,C6VLOϙ[AoBFc$:0ܭ['܍yKXMu=yjn).,HQ,Ŝ+WQ̬ڼ Iz魛,gR6"cSQ>ӧznp&[AY*na\${gg:@՜\kIԅax̰ېGrN[LRgChߨ*kmMUVytHmlbRg;$7F^Cñx[8Ed궏׊xX$9q)ظv wcc 7q+2&[S;&JF"o{ fm3f-7*AyXoQd2'eKZ*m,we33 JVPMXαȦ.{ɜW`rB'HeM{~MW{ېGxnꮉ2f_DZl{&h3=$UR+hCxɶDxc ,IQ(>Iw%ېy%ӧHXMu=Ye -2cLq_Il[JY8L^7*c1E*gi]JEcx-(NL"mO2eʺ|c=tY[I+c|=FZT[v4yURWA &3vl &ZIhbYϐ4ǒ4(yՙ6u܆<WY7!ԮyLʼn/-%X-}p4pS}OnOIdTƋE( `fk܁~LI{i;ĹH#K)ÏT2"M†I+VOzR[%BIy<IN%y8g*èإdffblbq'}`+Qq$XIjˆfa%ld{S=uېGrgn)CE*lm5%32Ie yR[ꮉ2f_B5H jfReQFvjnɟp7(nkSsK1@9xp4pS}O<'JԓC{O(2e3+i+veLVLTv,)3q~8Lb2d] HY6MS`iNDH`,0; ){evFRʤH#3 -TLIfzd1ݶz 5CWV쭅-:9DzIN`"9UؓTBɺr 6 ǰOށL+Q֊NŽru $2 u)g-5!-&ʘ}Gܒ?n Pg`,:IR,ldeSqO]6<8EuD!4['܍`i,ᦺxk4G^λ?kUߴBidƘ~OېGw} $ WYk}#['܍>ۓۻKc/㠭_t2h?h:xBs_f€K>6!,ڃ{û#G_O>S߷Cgߓ`]e!ܒ?n P,%Tٓ#*Ws_dO}_>=?TX9}Ͻ6+$53˒,x/w ~hEI<)KZ*uDhG}O'yձѵ3/'񭫹%\p,%Tٓ#*WsB'ya拹՗9bʦgϾINE*1kvY7jݳHJ5Q=Z3/_ܔ~Ti5OK'GU6ރ[ n6%X~ kN:`+U&`G T߃{ǾiH'_zGO^zVp'%NAw07O*{rPjnCK=/ k󏬪3$D.W(-PBHG=' %ϥ6wsXM=$AhېG>{LZ\ȚSkT:ɤT%ꮉ2X~Ǔo|0SӺF &4lwsKc 7U{&ijnCڡk {@} Ǔtԟ$٪_iU[Rjnɷ5\,u ` 7U{&ijnCC[TwMqbGԓ8콤G~oxKg&|4#զ[Jjnɷy`3pSeOg;I6<8EuvKgjQ Rۯ{>\ 7gox Iܒo';<8XKJ,hK;ILchjnCiÃ;?zgO$}Y7FI;O}ÛKXw ^U]p?%+Dۯ$O;L|;XMVdD^y^Dyx*OM'}%*:#u ` 7U[o͚D7)зƌ':+):2EGzVER9.??Ӈ76jKXC-RɈXt/ҟImnp+I(է2TxPI=x?)jR&Tʪˠ:m<5JC,%[+6ZKzč%j™v-mL16܆pש$d(#"p> ꕇjnɷ ,%TmKMt?(rt"Idߏ1EG;`oq)Y_& ?vU?wnT~+)TaDA%FMZiFn2;Izϔ&nNRIy&W=^Cy&̹܆(IQFǤD1gR*LRg ʺ'%J"/ҟ^o+d []jPeKRsH\bI:f7TN{O=5OR!jI&ВϹf6*ܱQ2 zn`5n%&3 LJճz"T0EOQLq 3+ClJѐ^)b"&VE_߭_{n`ϼ_?ۃPhJFdeiHIfaѡ;IW$c=L? p<RFǒ$%WQrESIReŮi%c:'^+IjvMV%s yyN8^X^5*Y)ȧ8c~EzzI*bIzam]gC QB?w]t'(q&;I܃[;Ize=Tc>&y|l*R =>&%9RTfb?lֽ~~Fi%OIClkR I yϢeY $)zpU)k1OMzMʬAy~y$1,Նqm86Zb-c_$3 =I}|;#ܼ悋`,j+]m1BR||7ŧwe"ILVWFޜVa?qǡ+W W,hJ kξ^OOĆﳘܣaRCqB\W6,$qn$gr${8(R7Ilra)LRrؽk%و2$Q+g$o=)od([?ېG oƹ =8wsʼ*o49ԖZLۨ}3B2 )S3 >g-6?,IU֥$oT? $3`=T1YdN.wХ<(u xu;9^^Ī( [WB%;1dM[cWؽ~[pDqBϰ%I&uUkRdΥ6=c٨\'s$< =8ɪRCYKj_3c'=1G,cҨ-^Q{ImKkI5q> naGE}Ow`Iz C|;/ܜ>}Fn(nBTe|W;c`0 z0ŕL{[7<֙,Øl,y֠#FT)iQy4:,g2~'yp{O+mW2QjQ )oI Y,[Iѐ}J%\R?$MzCRc?|+"VԨ%\ي+_)v'me]xjnC݃33Sש=~2$3jQvDhuQxpv`Oۓ_wщY;IT\i6ѫz֧gQsHSUT({=]mH'myk˫&p;ƃC>L~.=ɗ^I35۩nlOnXΖg+[`h^1xp kUx]e#ѓ8_{ \'%%){WWaMU䕈$AhPqCxpseă쉥}&ʰ_ !܇}O'ճ%||Vv<8XTZ8ؓ#|C"xps^',t_[k EJ~B_w}?I͢Gᕇ{{C-۝-NsKcM=yU;IJdxp*~k EJ~B}q3>L;OxmiS'=$Ҥ߽㡶 8k.XjsaO^N:=y ꮉ2)B ?7<sG?u͖wxOS&g`3&T3$$Aȅwɯ>֑/|=8y&Ch]=' O=UCxͤyhр,ܜ>}F7 8=y;I#oٿ:`\ƃ(ikwcu.mVS?zz$w` Kcݛ~ߊ{w wu}7^ss:|7;/-A5QBoҞ,/xyw ZKoi'Ox3>W  ,uo/^vфؓW.-\xp]■(Ym٧pßxRny\;{>#?>6R7~B,m${huY1ڢ Ǟ $hƒ;K\?}Uꮉ2BK{C=MuY1ڜ Ǟ!$h2렻ö^]e/RۅBUT=MuY19$hQ yw{m=ض|#ꮉ2)BK~[OSv\p,Mn -I ߐ\ͮonwMaHoBU>Mw=߫G+0lȆ7&Wٓ/Am] ysƝ+hҕ]e/RۅBU)YOS.Wܜ>}F7+~k_|H?Ew2F>|^*ِ:XJ讉2XB'OSxp(>8XT+_8ؓW^׾gtu7;Юߐ7}EAK(!T4\7՚j\v y+o_@QUyϺ {P[i ,o.ɫՠeIfyfr.FJ+nR8Aʣ1rK Bc&؊Qф=B~e|{ƒEKcޛj {j5]wMm7N6,dd^PGFNfVlM#42يw? -SLhK] Ű#W~׭7 ,o.ɫ՘@ gE)!7\oJ\ށhIvh ?DhF7䕳N|ޗlB Դ#WsKݖyKXM=y%zbAԄU^yOСkW6܆<-NW*%u `G(mЌk@|3wK'V=8bK<8J<8AC{ph{jnC٢Rh9suW#TDz#ި%nܜ>}Fnɫ1{7u[tkP6Ϥ13XmG*gݧChF5!lуB=~ܯ=B%{,K5;nɫN/YEZ$7~1NZܛ3ڒېG lhCN#TDzR&߽HiBGRsKݢ*{rPjnCٺ'Ww^+ܝ並#T_I{pLϠ SV 0c #SsKݥ*{rPjnC }{pzNgv?aH`GDc_aiG͆sbdjnɷ{uw07xp4pSeO\m#{3/:eK׾"=={_z;zP&{p.jے"ă뫹%XM=9Br5!{ct=;Jֶ]v9Igwhw"h\A9N<8*|ws .*{rPjnCٍؽ/zܗL {J4,low)K, qU|[،%Tٓ#*Ws =B%Ivh̞'7.+A-uss;XK'GU6<{PjnɷŨ;nB ynf!T[m1nB ynf!T[m1nB ynf!T[m1nB ynf!T[m1nB ynf!T[m15\,u ` 7U܆<7xpzІz/굯+VOI|jnɷŨ;XM=9Br5!,#@-uss;XK'GU6<{6%`n>8XK'GU6<{V,6E#w㯻_teyd V5WLsl1nB ynf^{^~[2H)FZ+vN,* ÃU 6*|[*{rPjnCp) i#pQsK>l\p,<8ڹېGXm|<8C yj=܆jnǃr;Xxp!s5!A-#Wo^yw|I"V+{cyp5fQV[`}p4BhjnCZ`G(/g>ʫCM{/^w ff~,3꫹% , <8ڹېGX+~Ԭ4O&y1V2X2ţD-xpU`i!܆<zP^}.|根fr\%R*\^-xpU`i!܆<{C7'@ᛏt9)̖";Uh}~/wQ3³`}w*6f2>^*%\=8\^-xpU`i!܆lӧHC y N2)1_frJaO^%yN'ZػaKŰ @ͻdV±_xUV"qWn3Iz_-xpU>8Xxp!s5!?fqQɔda3*dY8IXR߽RW=m$뼙h6^C+,OWL+ >RI#Nf&ivXB% , <8ڹېG,jw\-1+Llh?@BOJ Ű$$ ~~+UL+ QI{PjnǃK!v6} ՗Ȧ@42U7~zT /fZII|MELRw0+ܒ[B\m#=Hb$$IQL#WsK>l<8Xxp!s5!dol[ohV012@BOJ=6th~~c#ʴ'AbI{Pjnǃ .B;Ws>ydL)wh?caٔGIzth]9-"G%gvaH+[-I{PjnǃmsDěC!v6*}W#T%%/rA&+ "c"^{}X?yJW̝w$D?=ƤyWVK]VL`9;eVvVocSџD%#Rg'ΪԠKmATlIJ)H& c]i ym6$rPv5~a̳ېGvBbZ̾#jnǃr;>eIIDxx. 5hEnB s_gVmJcTiQnK$ NEJFdvOS=&NLj1Y*na\${gg7=8Iĩ9ԵagNz̰ېGJ{ b!fWsK>c6\< 4kiĮ6V~{wW(`-upȃUYypVa,k]R?RɈ剳IdzT+&,XKdSDdΫ NztM[gkƒ_r5!a ٙ}Gܒ\q\z9\< 4k̸Q@cR~3_92< shXJ$J`9=ҺSaZ*QKGSuۓL.mX]֖udy,F=O]?M^UP?Ĺ<ĹɺgVZ|+.`o 65m3^jis6Ubu܆<7}Zܶ}Gܒ0#xpdIdTƋQR6=[8_r7&]}0y'%~z5+Wrzu)2(&?RɈ4 n'X=Km)7 %Y-f$'YN;Y9,)bseIZIS8v@DY IOkI՜,ld!({j^m#xpP !4[_8.u0cy"h1CMcyo$#ELMXf|2"[Y"UGJj"|Dd#HUEY=롟"6-I6OV&I{U(N`omN2Ij2aŐi%teb'Mˮ6<8{]-xpP< {7%OɡLfLaRX)XS4YԜ+}(E&NbZ5dIC^K%#RscM6FEz^booŊx|X|>i {2DY|2]VUbSXIʠpR喿i[몹 yja!fWsK>sŁ_rxp&(y,w='Rc->f6#ZNfb4+V=8L_P6.|$-*9J:m`$((Ϥ[kE#"U>žYؓdڡQ~If ͞[X$6J]b*x˩^*4)SشɆWz➚Ws=Bͮ|<8kNxk4G^λ?i>yFiDy1W yja}|<8(K לݥ7qVޏo9gF[z{Τ_]^m#;n㺎5]qC7tu~7*4.j&01m.zڗjnǃr>(=G'Usoʹdmܖm#UxpLfG8|`V7@<8|<8(n%xpJ|$ dsܦg!PmjnǃrVfo|?O?iT>7:#4ېGֳJWAɝ\c1}G1`2G񳨖&x#[sjK;KlQzGS= кjE-lűlM]Yb1JLvz_-xpPJЌڗɗ^yѓz~YnD܆<Ҁ'ͤtvQxMLl@LY<|̄esMxQu-09zp1K 놅cq İ70v@l%b5 } xX$+8/ܒE <,ʞ|aٯK1O=rM܆6WsȾ}I#eSfQx0i8M< w&2$xm ({Pjnɷ-ow[nLW}2>͈ϥ ܆<Ұ-!EƏRZA7s䎕ƒI7%Ƥo(LLjc\|=9o}/TېG\z_-\q\z9\%Tٓ^ă'NԠ/?\[r?$Ϙʨ yn5\z_-`3pSeOj_&wwGM6܆<7̫wa ܒo; /b 7U{eh_uW$/v]5!A-#WsK퀻,|JpSeO $[zKgu7 5!A-#WsKm,xp+YM=~>J :%yEm#xpP ܒo JpSeO%\GOJ 4ېGXB%6@<,:+Nk[Rd_Tku7KgW#>\YR̬ڼEփu[{ҘHod9cq瑼cSQ%S=&N]2Ո\惨V[zԟRlsnQv6YWErIŠS`ӱqېGf_Bhv5/q2,:<1ke~~&*7_V~9@lMC\jPd2~|˿PO݃^qZ*:"$rU%'kTI%taijnCZ}GܒE=c 7ѬLcƓ{ TcJ|1Cn,G~ )b Y^K%#cR>Q݃GTmXMjE>]٦"MIQC7yRVXiTZf)(3^2(lra)JKTlټޮ fybgZXp,IRVTشK!XLu܆Qh?,S9dM3fo'/)Fi%9R-I*lڥ9ېG຃IMfH L!|<8(n%xpȠPuHy<ޫ:2E#1O!Ez%ȤÖ#Yooq;6T2"vo1,һ}߳ ރ{˿xjQG}w'EylmŜIx*3IQ6(^j?L+Qg&/%ysMT2([?ېGr\u߀3̾#jn_"JpS}O>f@DST)SH*^)b KM|ļ.o{B?3OPO^-[hJFdeiHIfaO~)L}?|݋h^aOXD*Jx*3I x?lֽ~~Z2DLjӡ*4-ViQeKgQsHEQC|-ᛏvױ-`RfWf~)I[Mi6߃5iPsòG6-ƻdFyRf tS Fꇅo*^aOUUga٬K[,O {~ȴ ֨OBLp3zB%@<,:|̀g$2>+CIJewc3+ ?Q=n7{ % "6(~؅W=SJ7Z1mdB\W6kOz 5CϘISV0QF=)MN?,SIJΝ7s$QX &5H>~)¦]G-Em#O7:C76 ypCHCzp$kZ}5{<>|3DIrڜն̾#jnɷ=qw2,:\n$`)c$,\pD.:RҢ}cg~7w VJƕvZsoI?Nrz!LV~&I.?8$[VDQwKobVIy|>4Ra.Ugʪn66']Fkyp*Y“핱ƒ$? `~3.Ӂ?6EQxp!T|wYK=u7z|~='̃s]$3/_z9u0'dO jenT&U=Û yBU63ڄIUYx-.1'%ĜI)?$ zpct u,)֯C<8*WsK팻,|JpSg{r{jpF}!ɳ+|7]pԟi]$Z:І?19{p4E*^˃7I X`$cb8ɯJ gZ / !ܒo; JpS{r]Y/%6/$)YWnn?a.$y.&D՜W[tKpw yj鳞{R?R͙ Y6+"T'%Dʺj5&,aCV"9cjZaʣ~v[BO-9d 7}'דNC4/sl{:e7/d_tUDaͥ=xsHܠx tY9_=87tF4YIl/oHVJNX؊$]cVWN$NBɷ.%} rG35;Ȃ%Tٓףo?&G~ॳѱQ5pWγdChjnCٱW fHu#XB%߶@<,ʞ*=SwTdm?y9Ɇ y\z_-K\q\z9\%Tٓצ6ܠ*WhQjnC;;`#WsKm،%TٓW'q7>p{TހC yd XB%@_8.u0nԓ8u/DN'fOJ 7Vm#z_-]}p+YM=y:yO~=jm.|=i׼K1-T܆<z_-cd 7U{Il}l>7Mz(ɆN܆<z_-od 7Uo>8qsg%?)Gm#xpP ܒo[ JpSeOފц=~.V/rS<M"~զ6<8{Pjnɷ twn%K'oKK^u/ѻݷK=Us=B~5/q2,ʞE}3wLSO<'Q'_z'x'f}STېGXB% {nɛS/'~t[?k[W=~?tw ~CI ?&܆<z_-xpP/!v6<8{Pjnǃr>!܆<z_-xpPJBhjnCٱwk_Er UaՓςU(]u.j&l_auó`J6-z_-xpPJBhjnCƒ&=9|8͎wz_-xpPJBhjnCqաfت *ܒ!v6䑪=\ԇZ71c[OϐRo_ jK8fIcxb1)]-[1bYϠF=F-I{XB%ʹ/r< xp!s5!E07<, gdab{UC9ePM70bW?,~P {> f]ސ fybEe V6 %I;!T[f.j=u-O&g5zݟG~H^m#O7Unp)zm6(flHCzp$kZ}5{<>|3$(Fjŭ*W]z_-xpP/P^kv?C<8@5!4}pGr[%<)!LJY֥؟An0blt$xk" o+9ܒ}p+C;B66']Ff9C3TU4'%D+c%I Xl=`~3.ӁۄiXI{PjnǃrVvA.ʒ)nݰym =8c1RRLRr"4ېG:)Te3_IDkyp%<)!LJE l,)'aЃ̯] ^ZH$u{=B~5@9xp+C;Ԙwݍ>-xs 3M?OZ̏JR=rЃޙ+TXy [fTsH;MīR,wthF[QOJW$%Mp_(Iδx+r(IܒPc1lNg鯡|lIW6K?fQsHyjI]tH5gJ(g٬D˺j%q,j Þ߇,2$(G":u$i'#WsK><8CM}ypj*_ٛw^YA{m[m#UxpzG,e=]t3ܨo[h&v'!EF ,ɖcV)1IWcXm⣛ݖT=K&iaGկ|<8(2j|[uI&ި yd\%W@#WsK>jgv *w-H y f4ygau&6gж܆<׽w!T[_8.u0ڡ&xplA'w5̌ƒCVsy߹;!T[n%xp!s5!,у_&aU=B~5@9xp+C yXB%[ B\m#xpP ܒ!v6<8{PjnǃrVB;Ws=B~5@9Wx%^!v6<8{Pjnǃ<8ڹېGXB%yRwC!܆<z_-xpP<8ڹېGXB%[ B\m#xpP ܒ!v6<8{PjnǃrVB;Ws=B~5@9xp+C yj!T[+K/ǃˀB;Ws=B~5B\m#xpP ܒ!v6<8{PjnǃrVB;Ws=B~5@9xp+C yj!T[sŁ_rxpBhjnCZ`Gկ|<8C yj!T[_8.u0B\m#xpP ܒ}p+C yj!T[Yu=D7Ɲ]Cʜ_)u/giሐܒMSխ17jH|1)[CMRpl8^h;:T6<8{mWҺd[uAv?*o~VHnW&H=L -Iܒ\q\z9\<84M7*8O_X)=׬|'.)4ͽ vBϽU)*QsBn}ִ۳xdҘ~If-feUaT|Op_xp҄m Z[fMӆW?WI Җ>h 5{/lC yj>Iq]䶞An}'}(,m~)ɩXbVT< '}!u J:qT|<8(K iCT7~[V?{Tu8MSUq?G"ܵ&W[98ØMIj_\M#Zafu/4Zՠ/*rDT6<8rhmSLdL}6gq1U=SsK><84MqpR,yqI;$)sMX'=RZ(I%~!yʐ&lQ^m#xpP 5q]u06KxvF=b7\dIZk +$^O$ԫN'Rj2RIy\챚[pԳkí̺\rMvWe.]KG{bʼsrf^SF^rgsճjnǃr8K.. 7R !*}#І J.m~;vbmI<=d!FIɟ~j}r ҵԓwTTl]@R6mnY=7f)2J#'IP~Usճ5 7dÖJ= ; /|JS\>Hxtl^le yj>&۫$uP|jۮoHouͫ 2ɺY-1ǫR1g '֤rzF*_IS̓m@ْ7\)yԥi%4W=;QsK> ǥCӴՔ|bpsVۧX:ԕJ6Îե$,\ℹB5!A-Թǻn386q-cʌd+ӷ,OfPɼ699c)3I=3q?svIjT4%V)[+Wb kO#rNs5$u1'aGZW 7 V2a4Ym#xpP uѕ[fZRNkLilnl8խq2$lߤˏ"ι2$XlwdC3(%Y$)o &gWjnǃrVi5JQD`%mKUj{ v &RI=Ij^vWo7?j}8ZKm#xpP Y0fB\鿬{[[|*ys4h m~g??fl?ﶬu2j]g*2o2<$C_hTȺW<睾A%q@2'% jzv|<8(n%xphݸ+ԓ\X:Ԍ4y8#Ӧ䅃<#IE yj>._'YRr[1ch'RB'NRjW*Yզ򉦙JJo_Nإ^*֓41&͆*'rzv|<8(n%xphun0jFGO=f\,7R+[aa`򰓤 ?x7܆<PzW LIjTbvװ>AjLI R2QMz;Jkje=~]CRly&lAZ/%YZMg3YI.\콚[_8.u06^T@Fg~V%N؟Bl+x˯?<Ժ/$'']{$m6<8:JNN\1mMi}U2ƒs%՚ G=&6_8W={|<8([ Ũdw _{FUi+Ձu퇝ꏕL>hPm#xpP U%oelV-)\&4VfLka{$ĬtFI=\49}4W={|<8(n%xph&o6@I_>Db c]Ͷ3KJ2g jnCZg 5NƘb^MJv=Y2cZ/%&f3J$ƾO*\lO-xpPJ4ͲqM>PiJvڒ%a150<6<8z{7~{ {P?|4VecLyfʌiNPk?yIt5z v0 Js3[\8'q&Uƿm2oz:A[=ܒ\q\z9\<84MgoI g}Ֆ;PT nL&|W܆<Pzi% dū(4u8ÛQhaIA㵯x$E5u b~jRO~;cgWjnǃ<84Mg ֐lu@*Za*ف1a5!A-԰' O_*_6V*!uekíL^zpq\ZhWfڜԯD'k#SH<Ž4s8ٕ[_8.u0M6'}Xպ2xMa&&'|3jnCZaOndy}eD`tv$.Qd[6æ<8 $I?fNNbHn;z%n廔L`sճ+5@9|J4evkiix:IZEw%Y7A~5I0cO$;blh5!A-԰\xz;frM: {~]k| L-uS|Yi[B%;ݮ&$4-/ͩlmɟFDIcSdRU `%Us&^4W=;QsK><84MWm~N[ r)>)(~Kd>IT~;'ae܆<zߴ>/j"a\ެ-vMK_aSY*tߢT7my5ٔ__Geu)إ UUϞ%ʹ/r< xph}N^)iwnkR,N&{#nּi˪ >6<8{PjnǃH_ 6Qw1Sؓ3מ?4 zO`Ps=B~5/q`-FAhiž!TېGXB% k6 B]L܆<z_-Kx\X Qj_n xa/eI"M'N%+gv>]L܆<z_-Kx\X Qn/'N?/)F?=fWw1Sؓ#*Ws=B~5/q`-FG?Gd6ܮL+IeeeYhK.Tbs[u>=9Br5!A-#WsKmJdě3eVIR%$% ]L܆<z_-Kx\X Q_'z| m9M,TU)I] ]L܆<z_-Kx\X Q҉pnT%ݎ,ռ-,~zeB-6{ 6.IHm.} {rPjnCZ`Gկ%<.(ɜ)W$$YKy'Ų͚2A2I]Rm: ^u>=9Br5!A-#WsKm&)B yj!T[n 4YŴOaO\m#xpP ܒEp.} {rPjnCZ_$_mn 4YŴO.yEz܆<G%YYuHBmOIV=S=5-mGBha)]!Tx`l<8] v.xp`l<8] v.xp`l<8] v.xp`l<8] v.xp`l<8] v.xp`l<8] v.xp`l<8] v.xp`l<8] v.xp`l<8] v.xp`l<8'5HKB]Rߒ"Rup%eSXlo:rۆaJgg3tu"w`?w<ȗô eNMϾmw+_mGIj8up`}-︹K+`wʜRێ >g(^}'wX7mi.yR\{LlS #EJԡ"n c, \}SR969N̼t5+,lfp‰w/`81HhiE&_5&w+R1sH}_tA㦤Ơ&@|rs cjP1[qsƟRRqJQbgT<&uQ=tF47-1Jc!EY^`?Gď@N{( E st)-u;,,Iǩ*2IAc[K%9cVy)[7zxʢyN܆6#uQDdݵdޓfEa%Ycz6ɼ`~(u8~V_m|r~5FtcǙAu5YR7J<]*WJ. #h ,<8 Z3t6) ,- *a_QwO-i~쉯z))'72 Mo?ѩT[@tgVzB0=*gM~0. #hLr'b;xp{Atݨ4G,-/;q(Mj'w8TIW{m}0!Z6Þ]l\|yp%+_?AʈA`?‰$w.`E͉&[Z"~T|{j;qǒ'h<.!vL+"zp̲AÃĎI]̐! 7^\6C'K'Ho;zO/qxUXծ3ś濼֓i>Qo+]{Ʌ!05Ojg6Ml6NS/n^b6H4B)W#Mxrl1H]'.v=y~=ve>葯=Gu+1ǂYeWNρzaSu'|c`%.]^ /.uQSs:(uxL$[tatz/.<QyE߁}clEM cLPg̉5J2d6_A ^Ѹת$_/fn15hI~\~1;@+lhx=u$]l-)yBKR4; &g'Hlyѐ==eZ1ӣNкs'v|-H]T1y/.uQ)KǤl7+"]]Yj/{$:.ORJ3yWKR5g/ ?IrR_3T.0ie;ʲϦZ#u=#%g!1 8_iHr xpE!|+1C?(>?+&_LJɤ'e:@'ؽ@̑ xg[b+Mpcc.j}ԍ>. #7SWw.mIJfY ؜ugFM z^cE#ӻ4XEO%>vs/ێ]6x3xB㯿goWَUo5 Q㉳09)Ŭ&G#>8 >(FCZyDQlbyhFHf >䙟cаTVEg[u'XZWFQzokDdI^yb[NSv5䩙$ASSs$ڒ_$#Rj .j*@Mc칈x6_FS)MvJb9?0/oh ؍4WMx+3\~K]yLć&'>4NpF2a'1ΥISXj,'6EÆW5Q&AreF\n;D<.t~'I]9!1w) =Z_KmA8sřwg-՟Xw3xJc-L~etMzZ/敧5gIؓ8ߔؓUIx%<8- yk@lg`\٢-8&=sh&0&t81t,O{^ i/Q=2fpˉ uQP>3xYZx@̜ų9/Bs&CQ]Jܓ.j%7]-bgxwyƬ2Tr *5G8Ѧ~xy?W$Y$s&)a``ħS|.&88'ytOгJcs#JU1WǞ|E.Ūa|z2V[Vr`4x*c.j֝/+uQkgS3;B S}+ӓ?u$uQt aoZ_Kmmޙ>)y1ft,x1N4Ŭ{x㢓`xLw`byEП=)`E+NJt2cg+ Os t/.uQSټ3}S//c̖X׽&E:$b7bRS$yE,<8m*@|?+:c=wr123g]8cϴ&PWurtUFgL-9qc`b.jp&\i^V!̯CdWcRDLpgC2W}gYWx|xfh7%zY:&#q\ 2OΠx|œG+RUf,#uBN17FfJ)[OOs_r{EM3WO5'ftl;uW `$nIp2R5B$ʥ)h<8YI^?{>4Ij Gᰋ:g{54۞a|&UGV-&֜BRSRU,.j/BaowRI k]F=IΑ@t/.uQS)LV¹29/.V~abER;B*Y2g.j `fF]B}Z؎:6>ICgܵT1]lmZd Mo%4]nN)2K]& P-xp3gxXGYH!zRQ 9kN>'Vwd >FOױ!UgY꿖'ιQt Z.8ck 9+5c\3'')! ɔF+'?-j".{E#oE29gj ^\ꢦ2)f_*S3wmZtv#xfݮ cz;z3KIE?^ֽIT "=Hte0)yŠw:r[Wo֍4+)\*iM P…7nJ?C 0G%gwvؽ9p8SIl<[*VGVn&|ĸrkZ딚96axt:fVk%rNh5,kICʺ՝ '.탽+\ڮ\&XC!fv5yjພYtO%ʒ3,?9օʜ̜ _sm4r㴏y<[u֡-{~WBbkK2GMs&n@WK&g|z쯶GU۔nfw潤zD{xbz6ɴS!dr*l_pPu?Eש_OJ"o,IK{zSfoG}FN΁'ʙ2!VuyESמ=aM6ury]A~_'xf]Qhu "Ӻo{@?+J=8w?|v.2anXr[ Oߏ?՛_38m7k>]Q\zpp.=88KΥ҃s\zpp.=88KΥ҃s\zpp.=88KΥ҃s\zpp.=88KΥ҃s\zpp.=88_\uIENDB`fastrpc-1.0.2/Docs/images/adspmsgd_msg_format.png000066400000000000000000000110211512345705400220400ustar00rootroot00000000000000PNG  IHDReogsRGBgAMA a pHYsodIDATx^u8aTǖT[EFI@ ˲?A|O CcP"J_@ɾC|~'{|\yϓ{y|z#|}*w"2А%K{,[:^wv7wJ{j1[/_~]lyoZMm5_MOwgzQ[Ou?okm e\kfGk@}<] [rUtKL-kE]6b{^XOz33{-r^ ӕw eI3[8RLZ ?-z{Q3_\dE-rLo|;G?n\XX]>(!kzq&VK*TT/eGMhӰ^,%O_ԕϮՕ` S_].o*׋R^֋;Ώ"z3[VWe;RyyuiDq{oqpܢ {QV0i}YU[7_totGr7߲+$ rR^?no[V<ċ;mwÿxr?^[l'?RZ/ym:E>tEk}__ӝbQ?4<[I>RfG'|movo֋(}>P/EP"J_@ (a%E.Бk\ 6ȵAn"h\ 6ȵA./k\ 6ȵq\5B rmk\ڸtx}$a\ܾ\ܾ:_LǾB;!Wȍ#\r=rc!6ȵA rm\:/k\ 6ȵq\5B rmk\ڸt. JEP"J_@ (a%/:F`>}Fb??-;ʽ>恼Tn-r|F^KCnԼRb>$k8\s=rmk%ԍ?j;}WrmF s88w#renZCOjs&{ISV?w$pmYDSZ:>7r۽:q|jy5_{.}e͛ΣB4Wrڧ>|JXK/6W]q#si&?uչsד}~>Hs>-i˝k|ezS.&\1y>D}s%RMSF犓Y/ټh iߓsغ벿(U(M@UuuV^ΟG?jo+uva:|}~9ć>Sׯk'X u+'^d֣d-wկ_-Nyս3>W#t,H:~^q=g>;پ[7fU>zHuuɕrW?ܩ&Wu]uS g=ݕU}|wҐqe(n^7ώ+&-w=M-onGXP "Mtj5{zӆ]'w7z,Q͓J_xFPמg!6mת~~i,w1f\$5%!\뛖c_7E>2H?>ν&GzW ^Brqr~nhc㍴7䈴j\zz:x)uNV\4*ڑ~]:`׷w5@V?<Q"F4F}zƑa0B:+sO u#; ƕso3[\{ZH/9 6ȵA rmkKnb$ (a%/EP_|dȵA rmk\ Ab~A rmk\ F\5B rmk\ڸt.!6ȵA rm\:w_>nww0zEGn_zEGn_s/c_G+UȍK.1rcrkErk\ 6.5B rmk\ڸt.!6ȵA rm\:%E`"J_@ (a%/EPs?ϟOynPJ3r_|pWcßMY610^mW#W'7^r֫W޳ըzuu_Ƽ&hX?_nf#WsMI?Yk^k헛]Ņ#mR~~]^;2{][aT*玫W[GU;^IoUwD*W[UrGի+tTmq1Qd8͖p%/7wmhw)^3ծJdmʅO`)s׫؍W_*W*ޱju4WW:^iQoZ3FOZXEi)1^\Os7U"W7֫LYji{2נ^e;^̮PzOUZglHm^KA4luoL$3n7\5Ev[0k7{դRѮ{tܐq=\>zECU2נ^Wq&wxjzkz?zBW)qX/ϣX-Vҽ d\/΂V3| cZ'C7Y U"W#WZԿ^%s団վZ֫W\zuPzOG}Ǜ}ۑ<С Nc^=i1!+`6Ֆco: t{|]i\yx"blPf^WjvW+K=Tm7h症z_̛}TSm\aL{e,-xV.NU\իԑ-U&wٓs;^y`WWW뫗P.c`#N:_')SK?? Qm!W^%\'zo^W|m~,L+ׯ, CU9w\*y`jѨz'׫RwDՎ!j+wPsW/OsP"J_@ (a%/EP"J_@ (ay$z\IENDB`fastrpc-1.0.2/Docs/images/apps_mem_map.png000066400000000000000000000572171512345705400204770ustar00rootroot00000000000000PNG  IHDR3ksRGBgAMA a pHYsod^$IDATx^y|MgKH"$I,!VU,C*SҩHS2?RhGe R C0ՎZ4RbTkj)E,5"G'w͑y||?}B!怮O!>!bBYB!fO!>!bBYB!fO!>!bBYB!fO!>!bBYbWرc:u|||ի׽{ 6(mEE 6|\/׭[7""GQz8lٲgϞx*U<}ݹsO<^w߾}-[ lРgggc6nջt~eL1h}Wq??Gy_?{´bχY啙):GOƊV<~ݺuYjUŊ{TTI}!{$AAAb ::>TU?,Fرf͚J=sѡtB OHSXXςO?^׻woG8:/6l֬Ymڴ͛;ާqƨg̘8q"Nވ .:E3gj D'#G3F"'` jժܵkԩS(Zi !FC'}1"rʕʕ+{1Q7jHGvܹs 尰}>s:t(n߾-"Qy۶m"ңGINNjVVN4ItnٲRLK1>!Fq?w߅ۉ?hҤhUܹs"&L K.EՑ>?~x~S\PP "_D䫯EdĉΘ1CTy=Μ9}J1-!hN4h(_R%Qdddx 55UG=z4!!A\ﯞڳRMDžG-{Si !FC'ٷoE>gggUʕ+Qu ''O/bjD+fžgϞ-W"!t}Bʞ?PuΝ;EC۷ъH N8H]v+f͢C~~~bb%K)y)D\Q"!t}Bʞe˖ 3kР .\)"QQQ^^^#F;wy8;/믿^hj_'|*Uuӧ !~EH'DB=/_U3_z```nn.G]E-QO)AtKy˖-!!!"Rzuk>!B'ױcG8?8t}B>!C'|wcJoB R>֩SGQz8&MCm^u7! !@'B]B1 t}B!, !@'B]B1 t}B!, !@'B]B1 t}B!,+"%JA, ڙe9́򞉇dHYb*Y &qS"ajgኩg)tǽLJZ+b`=N0*-jqyIx;HYb*Y &qS"ajgኩg)tǽLJZ+b`=N0*-jqyIx;HYb*Y &qS"ajgኩg)tǽLJZ+b`=N0*-ƕKׯܳgOKŕشikTRz?=zToիף>^XX4ܹSHCZyLSiTJx(` TZ$L+T:_vm?3np#"""AW`*U _1_wu٩SG~xx2]~}i֬`޼y[ Jx(` TZ$L++ ׿p©SD6׿0jѢEJRqe)CBJ'O ;vTXQFgΜp޽{cdϋG}xHH͛7N[ ?-,,W*z:7nPJesHxp咴8.[Ris˗H•(є$PU$OQQQZ7hڵkRw WJCq('N׷nݺENJ[Qу>+̛7f͚x^xA=`…Z|cccW^48&[>#F=ܹs]6p8^PP0a„6ٳJ[i,.\$C'کJJ3>>{4hP˖-UviCЮ];CBBv`]XX؋/ؿ |`woWyf/Y)W†냶mۢU|$dqHMMz`MI;>ÕP;'$ _jR/*9s&"6LU%?ODڷo/txGՏlق֗_~YT@^xΝ;"ҢE DpW?&}Q:u*  'Q-Ŝ3(%ipJr})OgU3OJ UJǕ}Ew}2v Lҽ{iӦ|"zX~AA6~;qw3(%⡸w](d>sL↎sSs.]Gmws7n84k߻wǕ=ہ@|rJ^T4qDDp[U"##o x{{_~RY:0RW.ILвeD3ψaҥ$/ +(OS9s&v;ܸq#))I|o EsZTt}}o9K fPJ%ᮊ֮o;_A+WQJǕڵCBS֭[O[Tmu\y-p"Pv  qFӰ0#""DYe֬Y|rvP9tPzzc=glC'xGI~(UtSlKP]ߑ_vMQJǕ0{9oqnٲh`јd(+wK-Г'Ob(ڵkԺ~Ŋ->kٳe~1c`N:UmJիWeԱcNJ2]t躾[_FRp}7 GEEURw'Q"}v;ŋ1V=@D|]DpEK.^> *׿U=֦M?Bk)C[V"`͚5}*]t躾 HкFR3f̨TR' > =###ŏ;-ó}W_}7V< ㏋"RNjժam֠m۶v޽;&D+ӟoV¡\ҤID7o>x=zxyyծ][dCÏQs4&~W۝o,pzt944A___s"퍧޽{# 6Djժ{;Aڶm+0m;/ʸ>S?6(n؄ڟF;ӨQ#tnӦŋRΡoܸ1j(4h7$׷7ovwv<^tIMк>= ~Rׂ{ݺuqT~PgϞjՂWjժ#wC' 6Tԕv; 9 WLy'P (2@ث}{t}bBa ׿z0)oذ![xyyծ]+_reHJ 1 pk׮ʕ~?Wb ]( bVZJ-m_rcǎC Qxs'P (2q5jT@@%KDU<77A[nUxs'P (,Ysϝ;.JoD % rn'N+b]( b,_}Rxyy)b]( b,ay1./х Aaɂ&=./х Aaɂ&W-??7rL. % \k@wk>)0APXrh1Df( b,hψg۶mJ@y%HA ’u->cǎCU%D~( b,`d@d<'N={vxx!C1\FP (,Y(6˫nݺ7oV \) Aa6 g}rar.1 K&{}r`r.1 KM.o}%P (,YnrkW]( b,Xlr W`r.1 K78\ A ’MR'Kt0APXP&s{0L.х AaɂMWJ͝Badܜ0D % y'P (,Y&7';х Aa79aމ.1 K Nt0APXMnNw A ’nrs¼]( b,pBadܜ0D % đC=Ѯ];Gnz/^*I&XjAz/_sAAApӧ#r1c `ZZZQMJJ*hmڴ hܸ 488xڵE+W޽[Tΰ[k8>UV1^4hБ#G0h={={6 SRRڶm{ADbccUtRGн{woHH¬ߦ##zx_|1;;[4iuÇ+ % đ ߿:u;D._ ={,pqx֯_Ȁ511=m4_z\pҥ/#ar,0ƍk֬)>Y6mڴr5?~>}ZbŒ\_w8.ތcO?Իw]!gg}M#&Tv}T=^QFxŸܹS\dgP.C)RPXMnNl]?, IgѣG#Y^v q>,**Jt&Lׯ06."W^EY1+W7o^<.ÇOHH_Aϰ0x0ʰI&wκ\ uҥ$:N+V˻}7D#^۴8}Ϝ9Su}۷o8qb֭1۰aD3lR<!e % 椤&k.ZHuTUu& }2x".-))O>"f͚ׯ!CϜ9#*κ׀QDg֮ߣGp~G*x?;pŅM#*֮?rH ?/Aŋ1CPq0R"LdܜST/,,Ujժ/[L< N< ߲kliii$#F~"++:v("Zua8+x/"/\_wѣGۇ*ŴiX A6]t[nթSG/+++((ի \t ߿e> K͉uUWTG'﨨.]>j֬C90,,l…v LZf ixi 222DD5ڵRJϟ?UPaܹ7oޜ?>fa{n4ܾ}_jU%]}p'bTvv6.駟VrKkꩧ4vԩ;vub ]% "Z"u 6\^BBׯ_6lƪTR^lPXMnNy|4+#GW*1f.dx,p5֖DSy#޽{q(߰ar {Ba79y׵| 0?"K,yw Igx*,p$J'b>}b,pbs'DE"),pg}b O ’nrs".aAPXMnNԼK~R0 (,Y&7'ڼ[@O ’nrsbw W|0 (,Y&7'y"'Aa79ͻjJf% 椤) 3dܜ;_)1 K Nt0APX`&?uf.((P JB?&W^bb˗E?CҮ];6^"2ydA})%B4P (,Y0h-ZضmR\„ Ν;}tVVaÆnBpʕ+رCtپk]qx]AwP (,Y0hߴiR\ƌJ(//VZsAY~N/W4!vZnGrEޔR"DA ’2h??1c ۷ooӦM@@ ,(Z{LLL```˖-l"ƒUtRT;ֹs砠 < L>x/p}0bĈ^z \޼y 4Mcǎ鈫g:裏"… <\Fhh(.#-- ׃jRRc}^s]=8py__ݻwIމAadM~uɓL>>>0-k׿xbHHHJJJvvʕ+aYYY(Ν{8+L=??_wB O'22rܸq~zxgFFFkGYf(߿:u;D._\jճg">^O(O<jbb"wڴi(KҥKiwBa) ܸqc͚5ܹk3AӦM8^K) Aaɂ_s|e19rD:](>z8p c>I;:fSJh0APX&/LӪUרQC飌)*5kV\\,mРAJ"~jj*ݺu+?]ȑO_5t}ѢEZw2P7&___uP_.C :t(03gD)0R"DA ’Һj*x t]?---::Z#F9SNJhҝ-[&ZpIRߺuN:_jժZjnn8Láqcoٸqcr{vG.p}A$W7رcGq̦@ad&W-Fŋ#a8N<=/_n8ҥ5keff222Њ@x!>PC׬Y399pkp'bly-rO|bsTTT.]PV]Vre\݉Ѵg^]ֽNt03A`6D % 66"???!!3f L/h]=n_~=M6!;ӧGK,A;wƢRP92>>^8Jt0APXɭ-(m~޽{kԨa%+%Nt0A*,Hډ1V)YaxL4х Q V,X=.I`.1WEib`3~Dž5 L4х ᪰(M3~Dž5 L4х ᪰(MuJa6V kh A UaQpm$0D ¢4-V)㷱z\XD]( b Ҵ^ǍqaMMt0A*,Jңdlqd8h A Uay4O:SPPRI KlD]( b ˓I'&BapUXYXXTO?L4х ᪰tyܹk֯_ȑ UVSرcܹ>۶m lٲ-[pႿ1cBCCOPMJJ*رc;wFqtpp.֭ pDt]mڴ hܸ \5lZ}N<&BapUX҄{{{0ٳWF'N_v3fΆ+ϝ;̙3~j虘xʕiӦK/榧|%􉌌7nc*x|FFQ5ׯ'OK[ŋCBBRRR+Wgee^2̠JFG&P \4a8pe~*U]&̙6}"RXX8{윜ǏGի(>|;wT\ȑ#ݨAw0aB~*k |xig87мyseLQt/^T`T2682xL4х ᪰t)\i 4qq5j> ![<塌yD/;55rUufw([2eJLLLVKu>}(cf͚{`T2682xL4х ᪰t)\_n'@ZZZf&MԩS'Ǐ?t]^lYdd'O"X:_jU<>6::Z#F׽x3(Ǒ`.1W+M G911̙37o[ԩSa9998s¼wnnn͚51jӦMaaa .,/^844Ǒɓ'c˭]/+tҚ5k233u/^WfPJ%c#ÉD]( b KW߸q~.[v1cM_~=M6"ܹ366H\????!!1qD\/k]=nWlذ~닷3(Ǒ`.1WeWp&M(3Ȧч{$0D ²+M l7 L4х ᪰Js޽cǎU*oy=Ȧч{$0D ¢4K‘ч kh A UaQ%Å5 L4х ᪰(͒pdelš&BapUXfI826paMMt0A*,J$Y}&&P \Y>\XD]( b , GVF.I`.1WEi#+c$0D ‚4II(kT2682xL4х Aa't}D]( bVyB'L4х Aa't}D]( bVyB'L4х Aa't}D]( bVyB'L4х Aa't}D]( bVyB'L4х Aa't}D]( bVyB''NTJhU N<ŋ?C'fwbVyB//Zhm6"++V@!::>AqHJwbVyBw¼,b ",R"L{@%`„ sqD^ÇQIrG4o޼x]% #NT~ײVxa1{쁹@*U]`Μ98_|YUםx+n߾-Zňe}9sE3Ϟ=;''GT-ϋ`+KtJ2*Ollly CSSSq.Y\[nc[PƐE𘤤$9`֬Yqqq(;mq_K쾖)SĴjժ5jנA 8r=ug@>?8+t}/A)!EP*HWJ)VybccsaW0-[)ɓxLZZ8bĈxTGԝV oժU0Qs’.Yf˗/ug8z}PKԎ1e}I&uID:T~\QxDxƏR"L{h*77f͚9990 tҥKk֬  G;mnx/ &Opw gΜټysݺuNCӧX H\ݻqx#!!!oFg=jQEZb*t~.kGP)RPX前=vv  OIIAĮǠu֘jذ ?5j"K,AzZ]\7xjDDĉnj'y5n߆֮]A՞{}N81x`<9ZjqF1J}eZ\AAׯoڴx-]"2X"#)S(7 aR1r"U=Ə(RPX前=o?ʢ!e Uŷ~J2e޽cǎU*y"H]%QPzRPX前=oF)V_!e UN!( B K nrqPXMnNws 'Ba79aM]dܜ0&C|B K nr}1Z(%B K nr % y79( b,p@֖( b,pZ>0APXMnNw@71X# HR"fy'8( c@*|`T,pB7H%,>?# ܽy'͆H}0~*F{ Nt 5F?# ܽy'͆6?# ܽy'͆E*3~*F{ Nt TdT,pB7>>>Ȧ.J22O-q wVPPC=Ѯ];G.\TyyyJݬ4i W^bb˗" x```۶m {={& A)B;Aav_r;v(l___]q-Zl۶ ?a„sΝ>}:++ U 6uhѣ?_~9vX?~<]vuGshwY(y'8( n;uo(9s +_~M6F_XXhug̘TBjR TX.ܬY3QO:U޽{ǎStS B;Aav?o޼ (;#.\ݺu0??1c z؄U֩SR'ZUtR}YFzu ou9((ӧOU0/萖&%%>382jmڴ4nx vZDp+W|}}w-*3uQkEq{b`ĈV/fgg&-aA7Ů;,yj[]n7yw\|^~Yׯ_O<֘σ5>>ĉׯ]8߳gϜ}իW9n8fYfdd1*11;m4_z\8r%쎺xbHHHJJ F\2000++ o{x7nYx7mT\ x *txJ^8kv}T=OEܹS\KdgPׂqdSK0t ?xk6zhD`upk׮!ׇ={UTA1 $*ljvĉ˨(&LׯR)F:~8W^EYnǕ+W>r vG7o^<.ÇOHHWaaax@:iҤCwطo_(X̙3UxiܽVZU檮j*8: ?^jiii3_ _lx8Fߤ0DM6l@y޼y(3f <}7noだvbǨQ,Y(ܹ366}SRRD]FzGFmݺ5&&`oW ﯺ38#cUܠjذaxRJz^9]oRw(CS*ȑ#㕊@Xx7';х_̽w5jlذA t}ws¼]/ÀهhB7oNww}"'t}ל0D>=^s¼]D@X{ Nt]c5';хOt}ל0D>=^s¼]D@X{ Nt]c5';q'2wY(y'P (,Y&7';х Aa79aމ.1 K Nt0APXMnNw A ’nrs¼]( b,pBadܜ0D % y'P (,Y&7''NTJh % qN(..<v4hn055rnݺ!nBׯET 夤${0k,̬@% ;>yq}p5a0H7O˖-&Mԩ:tH7lٲH%T7xPt˗/a-ҝJi].#Fv R]O ’MZ>y ۽{ CBBn߾}ҥ *̝;͛Gvp܀)Sbn077f͚ M6a 꾐nO;UI> \5k233]O ’M|D.;x`8+rѪU78F+Vl֬s=Gp8L7mT=npΝx OIIADh?<S`֭111ܰaC7DAPXB9'Aaɂɭ-&BI'Aaɂ亖DBI'Aa6yIN5jR"Dw=1 KB@5RPXMγ ar.1 K&f%P (,YP79o*\ A ’&6~xL.х Aaɂ&0~%J<&Badzk_ %P (,Y+uq0D % %mr?]( b,0~D<܉.1 K Nt0APX &_xqxx~1f̘Aɓ'E6Q*I&H^zx_/_VڊP6l⁁m۶MNN.((Mʰ۳gh +%B4P (,Y(MޢEm۶)}JE֪SSSWX!ʶ)wjA&L8wӧڵkװa[n=zο嗑cǎMXc صkWy;wVNt0APX&/,,S*~6mR*%cc-pLAk]vq(wΘ1CJjժ5g*UN7kLSNew^$رcJdxs'P (,YpdvZ8ҹs砠 TO^^^ժU[t#G|}}@гgٳgkg@P^zYws!!!Cuʕ=?sC V}…>}w/Zn/,, ^.vHII m۶=x𠍠vAPݾ}{6m7n`G#F`ePW/fgg&-a^2]( b,8 8{l~~~ddq`BׯsgddlRGKr}uv `ϟ߽{wšVzևb f8}̙3+V({-Bɓ'%0;J7hmܸ&xk?S޽v Z.ŋLǎ,GQUx_5uō?~Ν"߿gPoD % >8peVTT &Rˠo߾-QVQ]gw< Сp^ V ;/,fϞ=8^^Zwn[[v-*VXwmnuAӛ7o.` J֮Nx8qb֭qÆ q>ʕ+lM!( b,8Ʌ5Trjj*8t \G_zUt9ۆ'&&5J1)SbbbZjտ5juGyk}ٰyׯ__TqӦMctŃ iiif#FW*p[nթSG|񑕕>$K.ߏ#GkG\) Aaɂ#\k5kLNNɁ-\q xR Ν{c+/OOO?<^J*jO>-zC9\;yďgQAo ݻqh }nP\ -88xʔ)X5k[ӂ;qD̖~տ+((?S_Svѽ{֭[>6~!( b,8ɵv"FBdɒ%(pXbf͞{9W\Fjժ=z0a+ҩS'#""`cƌb v|xqjjƍ%-.֭[cbbP~\/wGÆ “JzM>0~D!( b,p{6w ZGUBadܳTGYt D A ’nra((=@adܳV_!( b,`7l( 1 K=bg}R1 K=&K>A ’nrkom( b,p{6w勸( Aa7gsZ>@D) Aa7gs,0D % 䞍BadܳA~-0D % 䞍Badܜ0D % yw'O&&&*υ Aa79aޝ%55uŊJs0APXMnNwgڵ7J Yuۡ\0APXMnNd{JJJxx_۶m<ȑ#G|}}E+ٳٳQضm[LLL```˖-l"ZuǎܹsPPPO./TR… }eΝ;vZD/^333oަMƍ/X3:O)!dܜH7oڴ駟~ݻ7N~vv6wܹgΜyUƍCCCC322t_H7ϟh"t{{{0ٳŋCBB+WăHVV\*xC Aa7968㜽bŊ۷ou]ڴi۷BDrrrtpܨ(&Lׯ ?etc=8޼yw>|xBBC9?$ K͉y裏>,ӈX~=`0A){SSS}||p.W֭/~:^QN%A[NJJRf|PXMnNѣGۇµkpp 8>-[O4SN"Ə!e"##PaB ._]>^ۡ5ɆT3oPXMnN;2,,l.\HNN }K*T0wܛ7oΟ?ׇdddL2%00Ct5klnڴ /\Pt?}<ݩJr} e׬Y)kGP)RPXMnN;\vpVRV6n(5jTXYf=\0ߴiS;w <<<%%"XOU냭[ĠsÆ k;#)S(,Y&7'̻ɹk?@HBa79aM]נ?ʢ!e % y79wGAAHBa79aM]Ə*=)S(,Y&7'{Æ %D)S(,Y&7'̻)wKx'Aa79aM]%^ % y79w}^O’nrs¼VE\)[(,Y&7'̻ɹh- )S(,Y&7'̻ɹkV( b,pZ>0APXMnNwX[>0APXMnNwk  Ң$I"ΠQ(x(nJHZ+b`=N0*-jqyIx;HYb*Y &qS"ajgኩg)tǽLJZ+b`=N0*-jqyIx;HYb*Y &qS"ajgኩg)tǽLJZ+b`=N0*-jqyIx;HYb*Y &qS"aj\~ax^^={4T\YM6aJ*իWѣGN^z=裾qqq酅JsQΝ;4ԪUgT:L @EԸrIsk֯_>S+K!\?""*tСzVR/P׿q}׮]:u*((}뇇+קOf͚!͛'̠ @EԸrIbp .:uJm -Z /WB>$1yd//\ٱcGŊ5jtW^ݻ7fHNN?|GܼyS 9+#|s Tv1W.IߺuK);w\|Y8I,/\Y\?MIII Ռ QUA4%%>o~]v)upD<N=qD||<}}}֭]=ʼyj֬ .\تU+t?3rw$A'O|ꩧ*TݤIt3 0 44OaJಕqe)lŋ E/ zBQeƌӧOeߧO4}Jy\y-p"}ӻwAl˫ZjO`= ڵC9$$dǎv_х  D]`<\R֭|ͧ~=O>dӦMGݩS'DoCp: ꫯ9PoDRY:0RW.$׷5kwъDcIc=; :jժ'vg[oKpU7oRqe)l>h۶-ZG2K,AԫW֔#Jy0\)Ž@qBUV)3g">hQ _D}HG}TXx˖-h}E.0ܹ#"-Z@7}_aթS*X`"xRY:0RW.$׷bOL\_d^x{Q;\ϯAt`Zdz\Y ۮ߷o_~w(cW$ݻw6m'`wCWW 0R"{'@۱j~?DŽ*n8Y<5w}DvlݺUdoEƯ\ǕwJN+aWPaȐ!7n; [ j]?""BUf͚>˗/GnCa=cf:4zw$t뗎\_E7_Akה `dz\Y ǑCw!oo-[& FI,X2]{'=y$ƪ?]AWXV={P~3f TСZ՟[ۦ]zhQVIMM;v(KMHP]؝o, ~TTT*UpwU-B۷oGO\\j^xcDGmEZTt"O>P¯kQѣhmڴS/pQ-oR8[o*n% ֬YK۷KMp}Z۝o,EI?cƌJ*km>=|I322R8O\@b8!bBYB!fO!>!bBYB!fo !q(>X0hEIENDB`fastrpc-1.0.2/Docs/images/apps_mem_unmap.png000066400000000000000000000531161512345705400210340ustar00rootroot00000000000000PNG  IHDRRbbKGD IDATx{@?װ eZZ&$9iGQZi鱤c'Lɀ+`I44X`A`ky_}gfaY@? ? ? ? ? ? ? ? ? ??=zh//'|ҥKg?1 0B&m߾Ou4**mܹ_~q0 #5ͫ*JnjC]p}]+^~}ʕ?ӝ7IXX0F/trrb&((S_DL8'## ,PDdaa- ¢E̙3Lbaadff_gϞ= q㬬a;vO?͵׿uԨQ\$"{aM"Jo֪!"HdooOD֧Of6m׋~#v^#1c>>|' v$~'x?s ˲G.[r% ,˞>}ܜK<:<s=Ymmm?>iZcB略ۛ+̙Õٳ[+))+?ɲlss=CD<4ە1_חۏ?ȲX_.I<S \/ұcNJt8w\333";_.w}\Q*?u͛Ddiis֭gr3[rc||;t/}Z%`P vAsѭ[^|EHDD555&y~A|^^^;{SUU5f??^{˅,7H$%+Wlܸeٶ 9:: {.w[~Ŋn$F<$~ӧsI777ڵkDt??SN*O2ﶲZd WqNwWݝ+ٴiرc҈(&&fP'L@D)))vvv`fÆ 1@Yt)7sN[[[WWWTLDf;j#egg_( ƨ^ ZV[1Dqƴ4gggXө;v9sR1cƮ]rrr5:;;~>]pAKٴiGo?O8w 8 8 H H H H H2,aCn#؎  L}T۱O@vEB@$~A$~A$~A$~A$~A$~A$~A$~vn$~BBBy c*oذҥKݻ=gNOOqFZv׮]gvvv677=zO?}ܹdF$DDD틃iܩcj*Ԑ__ eڴiaaaDޮT*KKK 7lg͞=[W-66v߾}&Lx'nݺu̙>_|ŴiӺ6HDk~~~^^^VV… ri~jb0`=ïFO^|?۷O.Wyyy?K/tԩ$S(/bLL[ qĉO<񄇇SO=UYY{'`FR=󮮮}y睻fV52 2 ?Y"XYY~w+VJcƌ6mڙ3gתYlٸqbD"Orks?GDDܹsoՍ^{mGβN-ƚ]~=z#GfXG"hŻv}/D`ODz{6mڬY@pG 瞓J.]裏;::뮻֯_?yԨQK,1²e>e˖Qaa/|ʕ-[!]>!!aV\`%77+VxǮ^;TS޸q^vZFFFXXرcf̘ѿ6W_uppOW^}wO42tvvv;v`~饗lmmiA,,j*ed2C(&&{=qį:qDwww"***zѯSO u֭$m۶=%%%>>all,EGG*444X[[{yyY˲D?+$]7|=|E"Qyyaccs}ӦmWꖕJ%_ ݳF|2͛7ٵk˲jzԩDt}}ᇿV5v"w؅eYM?s~̙3?'\HtaaaW^5X,Uxw'3::Z]ֵDw޽{k<44mS}|#Kޜ &XZZVUUwlO DTWWGDF:zs=w^x! @"DEEر۷o={'bccRE#Z֭[?:::M8Qʕ+VHKKKNNd=#<8YAZMDJ6> Cm_ __ _Ddii=tppضm{_?~JII~u+oFϟcȂJp?55uƍaaa;vΝ{g:U3fCD۷jժ+##СC}0<|Ч[:]cBBByNէ7~躻ƎǗ#wbH6YYY͝;wܹDظ{K.)Μ9S.sfffaaawuאF#۷}B0]d\>}sT={ٳۿ>lǎ=عs9"xGCZ#Guwweooʕ+6m,XN atT*o߾믻ּpË/ф @DbX.Xlŋ&''/644s˘C{ェp'''FtpFӵ&w.͛C#+0W\ѕ/YYYDN8koݝkQk~%&&=SWW7yd}uKӮ;: >th;;͛7H$|rAAAjj*#Dt]vD"O&ѣG-]t̙?۳{챂>"jmm}Gx[nj^o w%K曐eϜ9k׮iӦ z |k׮UWWoݺ/ hz| ._<})Sa VT*KJJ]o>۷oW(>gWWWx  Ϸ˝R%ɘ1cfΜyqe׮];fTT*˗ ;wZ赂JZbmpp[obd܍/^ԕYJKKu%ܕ999Rl2OOOsss>m;َ෷/Xc\a_eY;;@~? kd`999M2w޹~z7nذaChh3}Wf; xg{y f}^΍7)S }7Xn|I0c?Oslِg Y_۶m KOO1>>~~~ .LHHHIIt07o*DFF[`_,˾&L :|0ŝ;w.::zFfPdiiyw:thܸqW ϝ;7w\"裏899[w^a6JqqC1c\zevWWג"RΙ,˪T*ooÇY={,,{UarssYmll4i͛U*%''k4?Gղ,{ess󚚚NqpV4Bzm¢eSNYXX]xZZZF"""֮]kp"777ɓ'&K38hu]\\u222ݹ+W:::eeemmm=믿Q׍DPt*{'"333lD"ILLZ`7camm]UUU\\,ccchرGaT*Uqq1egg?...Ŭxz?.Hz!"L]0Wwuumjjڽ{R2eʁ{Au{bܸq'={6&&>22캊JJKK an %%%3Ԓ%K.\ꫯfff>쳺򚚚///a{{{pp0D""3f W(4MMMD"5"Ht9;;ulllffYrrr|^V4OAB}}Swa\= `˖-iiio?+XwP{8o>cƌ˗/;::QbbEn֬Y{1% =$~^pY֭[ =zO}wڵhѢ633`VrX}x,VTTս+\e֬YDD--- Ύ>$~n駟V*Ddccsь __߉'666Μ9mmme2ٴi.\hg}<`<} `ewwm۶-Ys ѣ}ݧ~ڴiSTTTGG՟x e,XM'$$DDDҌ^%&&rϞ=[":uޞ\\\JKK'Lfooܹb< M`rb0ڿ #iݼ={#~Z^^޵Zav9{lOOԜ9sx{{'''w1kd2TZ?&ׯׅiӦ>6HsrrXUTDh333rooÇ,Ը ךNFF1c\zevWWג"R\O?e{/))kuuuD~zeϞ=KDiii,^za*qVSSCnn.˲&Mڼy|>>>Ze˗/:x_n|0X!33"333ĿD"ILL6Xkƍkll={'3 >>>g^FGGQbbC 6`"  H"𰶶!*..űD4v#GI\\J~q/;;Guqq`zQRR2o޼8;;QMMMCCWlNwww%K,\W_|gںu7\]]nz6kccCD"ƌD"FC=%HtK$eܘX[[fffΚ5+''7lH&nw&J+++Z3VsΈ°ѣG]'Yfƿu-BVKDׯ_߽{wLLL:SN]hQ||X,ST#k'"GfddN8q̙ ?{lDr){{Nu~iRi?###>>^D$lݺȻ ׵lmme2ٴi.\h }˗/?3} `DC񬻿~m6l8}i0_porq=RRR$ dvZLks0A.\/ݽ2xďψ!of0aXYYLH&G.# A7E0HMr? $~Ӆߤ!<~WP`K ` CGÀ\./..;  \waC,kA_`#~A$~Aac555|G1(z뭕+Wv*ܸqmRRR ˲Zv|GjJϟ7o^;v45$~` lٲɩ̙33f̐dAAADT[[0Ν;gϞ陚3goodPLVΝ;}v"ڬAu%an޼Տ\n֞={̙3yG}Řs=^^^Ǐ_n]ra?p֬Yqqq--->}~att x㍥Kleٗ_~{„ AAA&"Q7ɓ'N?aGQTDh333rooÇY={,,{UarssYmll4i͛YD=˲5L}]xZZZk׮JMMeY㮻赩6{{>e .ⲲWQJJ ˲>5k:s,k墢"777.'OFEEiZQhnnvrrcYT,WWWa4M=50L0D`ffVTTdffƝH$\ Q@@EFFuUUUqqX,%c9rD5zXkѢED$&O\YYkSb [&MGEEu"1زkSSݻJ)S80FQQuXXRtuuh EII QQ|#3444xyyqܲ D""3f W(4MMMD"5%HjkkYz談lmm333]͞O;::r̺#0vׯV ?"1r@@@AA-[<==|܆0RԕC10y7t à7ܤR8S__RT*777 .~7_+O8q"d2S*ɉe2~z6e\.˵Zcbb^Ot C*pwwץ>}M٭[`\.omm%UVpBP{%ׯ޽;&&bqCCC5ܜ;\QQqCIK&L m۶T*n۶m#={>>kyBBgaaÆkatxi  @ݎ|&oܙ~B1 %x0D  d}0HYL?B0%1abYG#| lfO8qԩSM| 9a02cW2a\]]KKK}}}YLիW?c7n6ugFoQ`zN/b4_xc lH+n`Y"O?t@.T?bfǎJW^LX,>p?;omԝ7ѣӧOwww)@ l8lkkZ~{L۷}8 H H0XZZ,\pҥCkjjanY\]]bѣ/_^[[{g?~T*J ,rJ---%ITT>HA"@?.ٳ,j۷o766ٳ{]=jϝ;T*+**###;x_~eQQQ!?Q[[0̞={̙3yG}+ܹsٳ===SSSsrr̙흜̭{?~uʕ+ |ᇳf kii+..ܹs۷oJ;>>Ze˗/fci@\\\rrrK222ݹ+W:::eeemmm=믿Q8w#~fѢED$&O\YY.Xa𰶶ŕD$|||ģk<**~/_>j(SVVV%%%D"ILLVBkb;6>>ȑ#$$$ũT*dgg?...!lqw}O>9{lLL}dd?uJ)_f4~Z5쎎a\; -;=foooMMMCCWu롅גH$% ;ggg"̜5kVNNΛo)Z08=?uϟ?|"g̘qenovvvfڳgO?0yGy{ȲO?x~7_+O8q"d2S*ɉs1ܤR1}j絤R)7-QTnnnܲn/^P(JKKkkkÍoOZΝ;#""0!!{'==}֭D׏^ S /aÆJr O=T h۶m*͛S۶m#={<ÝV 5+[[[sss}ժU} -( Zw^"~ݻcbb:ՙ:uEbq?Z˲qqquuu Wlٲ5k455QKK7GGG `y_cǎ *--&g2/88eٔիW=zCBBVXiń4=z4##wĉ3gS`k6???==]&M6m…U<쳗/_~g݂A}gϖH$N΀O2ܹs9|va0v횧gSS_1 oذ|7wW5R׿k)))|$~kdH@&0lQ`T?&L@ ? ? ?L ?¯`T? ? ? ? ?@g6l;0B>G H0 [+W;  y_eYVu0!б,/{{{O0!((Dt%an޼Չ\n}z]TWW3 e''#GBCCe2jjZ֯\^^>c ^ 9***rsskiiaYɓQQQZŋD,vf''}㓒 v]:~~~}Ȼv+JeY-++{&N(֮]h:U!753aX[ `$_0or0ߴ 뛂C,k8 .xa+++G28 CLN $~#ˑ` "~$H& BoҐ``%pXwP( n! #a@.SDQ\\,b_aa+n|/=a''{##8l̀/�{ĔO.#G`xAS0 ~.r? ,-- >Pv>Ce Wo6X.2S H BO7nMJJ;0,˲)~ ŋJ0Zcn|&[v3 &jal~a>Yfŵɓ'NOD ܹsٞ999sNNNZ>š3d2YPPPzzku}…7xcҥіw` ; R(99Y\zRRRXmoo׬Y䔗DzliiX,#׳,{Y"JKKcYի TUU577;;;gffr]x{{>|׵<000''S0XhP_g l̀/xMBBn|ѢEDdnnU\\\TTdaaNDaaaJՕ`"  H"𰶶***233K$^S_bY-;JRWBDe"DD4fP$i4///=88׵.z`į*ɉ%T*=[QQknnnRR~5E^^^BeH߶mٳV(YYYDTVV]3\ښKDV @~ې&~??+Vmٲ5)))77W*ڈѣG322|}}'N8ś`C/`v횧gSSݝwgpCeHk/3ϟZ0M3@@@@@@@@@@QB)IDAT@@x[o\(x?o<,j.Z:AiX}嗽'Lta"t07oDFF[N<9uT|YgΜ1cL& JOO#WTTL>Sy.ٲeӑ#Gteee2?55UVW.// Xr= o"77eO<j/^HD\!˲k׮mnnvrrcYT,WWWwW윙ɲJ>| vpΝѝ vR(99Y/755988,8iҤ͛7W0f{ ̀/8i\]]vޭT*Lra ,**'0R]YRRI$l{~~>~`v`ff\\\,ccchر|1P(JJJX ((((,, 9rHw5J0 kjjc۶m;wZ]XX8wNrvvUkjj$P"vܫy!Ќ;xr\.kڃTUUD""bYLDRT/`T*#'''U?.ɺg],Jt*Mnݺ5o޼\nZG]v-Z,88Xr3gϞ%ӧOB"r577WZo#uw=.{ BVݻ_{ qEBðinnNLL䮫7o;k֬%K}t'%%577쨻u;w;W*,/,[VVL8Q&]Vt+w~x_n|a!0{O4aeeV! ~"` ? kA<^} Sw;|1;ӯP(>~G> YYY Y Y abYv3 A#r M6 f? ? Px뭷V\wC"??޼ygYVv]2 `cY_0aBPPÇҥK ܼyn:":yԩS=<<g 9sfƌ2,(((== vR___QQ1}N]ff˖-NNNG-d2TZ_|0`bW&hm"77eO<j/^HD\!˲k׮mnnvrrcYT,WWWwW윙ɲJ>| vpΝѝ vR(99Y/755988,8iҤ͛7Wv8\]]vޭT*Lra ,**'0R]YRRI$l{~~>~`v`ff\\\,ccchر|€Q(%%%|G_L ((((,, 9rHw5J0 kjjc۶m;wZ]XX8wNrvvUkjj$P"vl͛&er\MD #++BBBZZZ \"joo_jU~~ 5* Zw^"~ݻcbbp q  ܜ]W͕o޼w֬YK,yꩧ֬Yò~{:ti|>>>ǏOJJjnn6Qw}w#wXT*Y_fY8qL&[vFTZYY_7v31Pa@ɝW(Ca`(_ $~!`( 냉@t`:>$~A7 l( ̀/8,e} ˯a5Sf k+b}wMS_?@DPi dW.~AA$~A$~A$~{|B, ]s6a Hˀq$1SkR&* k.DHd%bt  =?tf .מw^}v{]0!( A` ?CP~0LRbb"q펎 @fiiiHpVVVss8qR&===#u:]AAAhh>haaamm=o޼ߩC$kttteeL=0$Rfff?#0%00PTV,++RաbXBBBqqU{{{j_~yQ___ccW_}URRRXXv);aP!/^t!T:À{nŊw7Ң***x ":|qqqpps,,,[wꐈxokjjbbb<==Νnݺޘ:;;e2\.?tnspptoڵ_7ovqq 駟#%%塇J...+W/rT|JMDUUU nHv9gkkk\~Ř{HHH033y˭Ϝ935ii$H^z饂4ҥKD_(22p޽cJ>ݿF,`mmmHHSRR[ssCΝ;0{l"~~~EEE}6olnnqFCRRRW^BDeeeZkk~hk֬/~W_}566VP~&===""MٹtҞT\~ARw=SD_oc=裏xRq޽{n:k֬^xR)۶my~ǎ ,kjjϟADϟOMM8N?rݺut(FcMfGYlم Ė\"6(..N 겵;w666˖-B2d/"%''-+W$h_&*a399Y"֊W^W(sbuh&s&jݒo>":{x?{9{ Ox&M&Ǐ']v^꓂.]JD ⣏>|N3Áy'?&֧o LPVVV׮]3̘{'ݸqͿ뤤ԅ V9 ܶEp{~x}q%{xƹ+0Cﰉ&<<<<:~ljj""oooH*;v,%%Hp\]]ۅiEfɧɇ1߿ڵk*yxxxӦM*jxxxt0?LEl~Lq\kkrBDkj\RSSh"Lv׀j͍u~%>>֭[7|}}Kq Ӯɧɇцsrr222>"H$433"h4DX `ll귶VT%%%6m tѣG"""JKKj/Dۛ388sNP(7nXUU|]]]AAA``kݥof{{R~ÇlbxkI,FO.YdCʄ:N^pãX"ѣ!!!٧Nzgd2]~F20i^N8!vggի]\\삂***x뭷ܴZ(W^qwwJ .Oٙckk;k֬ŋ#755-v"JEɓbVMII򲰰puu&L8iυyEabL {Lbe,Y}===YYYfffVVV>>>6lx<$pxԩ6aX6Cc8#!cFNbS[sckz ][[ۙ(So;ɓS3`I4UwwcWw"2f$$=1 Q!cFNbS.` ?CP~0!( A` ?CPSY^{p8}E`~ !8~0!( A` ?C4sIENDB`fastrpc-1.0.2/Docs/schemas/000077500000000000000000000000001512345705400154755ustar00rootroot00000000000000fastrpc-1.0.2/Docs/schemas/fastrpc-config-schema.yaml000066400000000000000000000001061512345705400225210ustar00rootroot00000000000000machines: map(key=str(), value=map(DSP_LIBRARY_PATH=regex('^/.+/'))) fastrpc-1.0.2/LICENSE.txt000066400000000000000000000030351512345705400150060ustar00rootroot00000000000000""" 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 """ fastrpc-1.0.2/Makefile.am000066400000000000000000000000601512345705400152120ustar00rootroot00000000000000SUBDIRS = inc src test ACLOCAL_AMFLAGS = -I m4 fastrpc-1.0.2/README.md000066400000000000000000000223461512345705400144500ustar00rootroot00000000000000# 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. ![FastRPC Architecture](Docs/images/FastRPC_architecture.png) **Stub and skel** are generated by the IDL compiler. Other modules are part of the software stack on the device. **Definition of the terms in the diagram:** ![Term Definitions](Docs/images/Term_definitions.png) ### FastRPC Workflow The FastRPC framework consists of the following components. ![FastRPC Workflow](Docs/images/FastRPC_workflow.png) **Workflow:** 1. The CPU process calls the stub version of the function. The stub code converts the function call to an RPC message. 2. The stub code internally invokes the FastRPC framework on the CPU to queue the converted message. 3. The FastRPC framework on the CPU sends the queued message to the FastRPC DSP framework on the DSP. 4. The FastRPC DSP framework on the DSP dispatches the call to the relevant skeleton code. 5. The skeleton code un-marshals the parameters and calls the method implementation. 6. 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. 7. The skeleton code calls the FastRPC DSP framework to queue the return message to be transmitted to the CPU. 8. The FastRPC DSP framework on the DSP sends the return message back to the FastRPC framework on the CPU. 9. The FastRPC framework identifies the waiting stub code and dispatches the return value. 10. 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. Please download and install the Hexagon SDK from the following location: [Hexagon SDK](https://developer.qualcomm.com/software/hexagon-dsp-sdk) ## Build & Installation ### Steps to Generate Native Binaries on Device ```bash git clone https://github.com/quic/fastrpc cd fastrpc ./gitcompile sudo make install ``` ### Steps to Generate ARM Binaries Using Linaro Toolchain on Ubuntu Build Machine 1. **Install Linaro tools and add the tools bin location to the path:** ```bash wget -c https://releases.linaro.org/components/toolchain/binaries/latest-7/aarch64-linux-gnu/gcc-linaro-7.5.0-2019.12-i686_aarch64-linux-gnu.tar.xz tar xf gcc-linaro-7.5.0-2019.12-i686_aarch64-linux-gnu.tar.xz export PATH="$PATH:/toolchain/bin" ``` 2. **Create softlink files for the compiler, linker, and other tools. Create environment variables as below for the auto tools:** ```bash export CC=aarch64-linux-gnu-gcc export CXX=aarch64-linux-gnu-g++ export AS=aarch64-linux-gnu-as export LD=aarch64-linux-gnu-ld export RANLIB=aarch64-linux-gnu-ranlib export STRIP=aarch64-linux-gnu-strip ``` 3. **Sync and compile using the below command:** ```bash git clone https://github.com/quic/fastrpc cd fastrpc ./gitcompile --host=aarch64-linux-gnu ``` ### Steps to Generate Android Binaries on Ubuntu Build Machine 1. **Download Android NDK from [here](https://developer.android.com/ndk/downloads/index.html), and set up the `ANDROID_NDK_HOME` environment variable as mentioned. Add the tools bin location to the path:** ```bash export ANDROID_NDK_HOME="/usr/home/android_ndk" export PATH="$PATH:$ANDROID_NDK_HOME/toolchain/bin" ``` 2. **Create softlink files for the compiler, linker, and other tools. Create environment variables as below for the auto tools:** ```bash export CC=aarch64-linux-android34-clang export CXX=aarch64-linux-android34-clang++ export AS=llvm-as export LD=ld export RANLIB=llvm-ranlib export STRIP=llvm-strip ``` 3. **Sync and compile using the below command:** ```bash git clone https://github.com/quic/fastrpc cd fastrpc ./gitcompile --host=aarch64-linux-android ``` ## Testing For detailed instructions on testing FastRPC, please refer to the [README.md](test/README.md) in the `test` directory. ## Logging Control and Verbosity Both VERIFY and FARF are logging mechanisms used in fastRPC. While VERIFY is a legacy module, FARF is commonly utilized on both DSP (Digital Signal Processor) and HLOS (High-Level Operating System). ### Verify Logging Macros - `VERIFY_IPRINTF(format, ...)`: This macro is enabled by `VERIFY_PRINT_INFO` and is used for debug logs. - `VERIFY_EPRINTF(format, ...)`: Enabled by `VERIFY_PRINT_ERROR`, this macro is used for error logs. - `VERIFY_WPRINTF(format, ...)`: This macro is enabled by `VERIFY_PRINT_WARN` and is used for warnings. - `VERIFY_EPRINTF_ALWAYS(format, ...)`: This macro does not require any enabling macros and is used for logs that should always be printed. **Example:** ```c #include "verify.h" #define VERIFY_PRINT_ERROR VERIFY_EPRINTF("Error: Operation failed with result %d\n", result); ``` ### Farf Logging The FARF API is a macro used to print debug logs. It allows developers to selectively enable or disable certain types of messages based on their priority level. The priority levels include LOW, MEDIUM, HIGH, ERROR, FATAL, and ALWAYS. **Key Points:** - **Usage:** FARF is used similarly to the `printf` function, where the first parameter is the level of the message, and the rest are the message contents. - **Levels:** The FARF levels allow users to control the verbosity of the logs. For example, setting a FARF level to 1 enables the corresponding FARF macros to be compiled in. - **Runtime FARF:** Runtime FARF messages are prefixed with "RUNTIME_" and can be enabled or disabled at runtime. These messages are always compiled in but can be controlled during execution. - **Implementation:** To use FARF, the header file `HAP_farf.h` needs to be included in the build. This inclusion is typically sufficient to enable FARF. **Example Code:** ```c #define FARF_LOW 1 #include "HAP_farf.h" FARF(LOW, "LOW message"); FARF(HIGH, "HIGH message"); // This message will not be compiled in ``` ### Log Files - **adsprpcd.farf:** This file is used to configure the FARF logging levels. You can specify which levels of logs should be enabled. - **adsprpcd.debugconfig:** This file can be used to configure additional debug settings. ### Logging from DSP Logs from the DSP can be obtained using the logging mechanisms described above. When userspace and kernel logs indicate that an error is received from the DSP, you can use the FARF and VERIFY macros to capture and analyze the logs for troubleshooting. ## Bug Reporting Guidelines When reporting bugs, please provide the following details to facilitate debugging: - **Platform/SoC Name:** Specify the name of the platform or System on Chip (SoC) being used. - **User Space Library Version/HLOS Build Details:** Include the version of the user space library and details of the High-Level Operating System (HLOS) build. - **Kernel Version:** Provide the version of the kernel. - **stdout & stderr for User Space:** Share the standard output and standard error logs for the user space. - **dmesg Logs:** Include the dmesg logs. - **User Library Logs:** Can be captured from /var/log/syslog - **QXDM/mini-dm Logs:** Provide QXDM or mini-dm logs. Note that the Hexagon SDK includes mini-dm for collecting logs from the DSP. - **Tests Run & Parameters:** Detail the tests that were run along with their parameters, including any environment variables explicitly set for FastRPC. - **Custom Test Code:** If a custom test was conducted, please share a code snippet or the complete code to reproduce the issue. - **Performance Logs:** For performance-related issues, provide performance logs enabled by setting specific environment variables. The following environment variables can be used: - `export FASTRPC_PERF_KERNEL=1` - `export FASTRPC_PERF_ADSP=1` - `export FASTRPC_PERF_FREQ=1` - **ftrace Logs:** Include ftrace logs for performance issues. ## Resources - Hexagon SDK documentation: [Hexagon SDK](https://developer.qualcomm.com/software/hexagon-dsp-sdk) - Linaro documentation: [Testing FastRPC](https://git.codelinaro.org/linaro/qcomlt/fastrpc/-/wikis/Testing-FastRPC) ## Contributions Thanks for your interest in contributing to FastRPC! Please read our [Contributions Page](CONTRIBUTING.md) for more information on contributing features or bug fixes. We look forward to your participation! ## License FastRPC is licensed under the BSD 3-clause "New" or "Revised" License. Check out the [LICENSE](LICENSE.txt) for more details.fastrpc-1.0.2/autogen.sh000066400000000000000000000003221512345705400151550ustar00rootroot00000000000000#!/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; } fastrpc-1.0.2/ci/000077500000000000000000000000001512345705400135555ustar00rootroot00000000000000fastrpc-1.0.2/ci/MACHINES.json000066400000000000000000000007461512345705400156460ustar00rootroot00000000000000{ "qcs6490-rb3gen2": { "deviceTree": "qcs6490-rb3gen2", "linuxFirmware": "qcs6490", "lavaDeviceName": "qcs6490", "hexDSPBinary": "qcm6490" }, "qcs9100-ride-r3": { "deviceTree": "qcs9100-ride-r3", "linuxFirmware": "sa8775p", "lavaDeviceName": "qcs9100-ride", "hexDSPBinary": "sa8775p" }, "qcs8300-ride": { "deviceTree": "qcs8300-ride", "linuxFirmware": "qcs8300", "lavaDeviceName": "qcs8300-ride", "hexDSPBinary": "qcs8300" } }fastrpc-1.0.2/configure.ac000066400000000000000000000032521512345705400154520ustar00rootroot00000000000000# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.63]) AC_INIT([fastrpc], [0.0.1]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) AC_CANONICAL_HOST AM_INIT_AUTOMAKE(1.10 foreign subdir-objects) LT_INIT(disable-static) AS_CASE([$host], [*-linux-android], [ compile_for_android=yes ], [ compile_for_android=no ] ) AM_CONDITIONAL([ANDROID_CC], [test "$compile_for_android" = yes]) # Add shared object versioning m4_define([LT_MAJOR], [1]) m4_define([LT_MINOR], [0]) m4_define([LT_PATCH], [0]) AC_SUBST([LT_VERSION], LT_MAJOR.LT_MINOR) AC_SUBST([LT_VERSION_NUMBER], LT_MAJOR:LT_MINOR:LT_PATCH) # 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. # Enable pkg-config PKG_PROG_PKG_CONFIG # Check for libyaml only if not Android AS_IF([test "$compile_for_android" = no], [ PKG_CHECK_MODULES([YAML], [yaml-0.1], [], [AC_MSG_ERROR([libyaml (yaml-0.1) is required but not found.])]) AC_SUBST(YAML_CFLAGS) AC_SUBST(YAML_LIBS) ]) # Configure config base path option (--with-config-base-dir) AC_ARG_WITH([config-base-dir], [AS_HELP_STRING([--with-config-base-dir=PATH], [Base directory for config files (default: /usr/share/qcom)])], [config_base_dir="$withval"], [config_base_dir="/usr/share/qcom/"]) AC_MSG_NOTICE([Config base path: $config_base_dir]) AC_SUBST([CONFIG_BASE_DIR], ["$config_base_dir"]) AC_CONFIG_FILES([ Makefile inc/Makefile src/Makefile test/Makefile ]) AC_OUTPUT fastrpc-1.0.2/gitcompile000077500000000000000000000003021512345705400152370ustar00rootroot00000000000000#!/bin/bash autoreconf -is export CFLAGS='-O2 -Wall -pipe -g' echo "CFLAGS=$CFLAGS" echo "./configure $@" ./configure $@ || exit 1 unset CFLAGS if [ -z "$GITCOMPILE_NO_MAKE" ]; then make fi fastrpc-1.0.2/inc/000077500000000000000000000000001512345705400137335ustar00rootroot00000000000000fastrpc-1.0.2/inc/AEEBufBound.h000066400000000000000000000230331512345705400161240ustar00rootroot00000000000000// 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 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 ======================================================================= */ #endif /* #ifndef AEEBUFBOUND_H */ fastrpc-1.0.2/inc/AEEQList.h000066400000000000000000000343341512345705400154620ustar00rootroot00000000000000// 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_ fastrpc-1.0.2/inc/AEEStdDef.h000066400000000000000000000174771512345705400156100ustar00rootroot00000000000000// 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 #include /* ----------------------------------------------------------------------- ** Standard Types ** ----------------------------------------------------------------------- */ /** @defgroup stdret standard return values * @{ */ //! @cond Doxygen_Suppress #ifndef _AEEUID_DEFINED typedef uint32_t AEEUID; #define _AEEUID_DEFINED #endif #ifndef _AEEIID_DEFINED typedef uint32_t AEEIID; #define _AEEIID_DEFINED #endif #ifndef _AEECLSID_DEFINED typedef uint32_t AEECLSID; #define _AEECLSID_DEFINED #endif #ifndef _AEEPRIVID_DEFINED typedef uint32_t AEEPRIVID; #define _AEEPRIVID_DEFINED #endif #ifndef _AECHAR_DEFINED typedef uint16_t 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 * @{ */ //! @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_t _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_t 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_t 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_t AEECLSID ======================================================================= AEEPRIVID Description: This is a privilege ID type, used to express a privilege. It is a special case of AEEUID. Definition: typedef uint32_t AEEPRIVID ======================================================================= AECHAR Description: This is a 16-bit character type. Definition: typedef uint16_t 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_t _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 */ fastrpc-1.0.2/inc/AEEStdErr.h000066400000000000000000000523341512345705400156310ustar00rootroot00000000000000// 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) /// (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) 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 #ifdef __cplusplus extern "C" { #endif /* #ifdef __cplusplus */ //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); #ifdef __cplusplus } #endif /* #ifdef __cplusplus */ /* ======================================================================= 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) 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_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_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_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 unsigned char 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_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_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 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 =======================================================================*/ #endif // AEESTD_H fastrpc-1.0.2/inc/HAP_debug.h000066400000000000000000000054061512345705400156670ustar00rootroot00000000000000// 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. */ bool HAP_log_data_packet(unsigned short log_code_type, unsigned int dataLen, unsigned char* 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 fastrpc-1.0.2/inc/HAP_farf.h000066400000000000000000000170141512345705400155150ustar00rootroot00000000000000// 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 fastrpc-1.0.2/inc/HAP_farf_internal.h000066400000000000000000000003651512345705400174120ustar00rootroot00000000000000// 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__*/ fastrpc-1.0.2/inc/HAP_pls.h000066400000000000000000000076401512345705400154010ustar00rootroot00000000000000// 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 fastrpc-1.0.2/inc/Makefile.am000066400000000000000000000030771512345705400157760ustar00rootroot00000000000000# Export fastrpc headers fastrpc_includedir = $(includedir)/fastrpc fastrpc_include_HEADERS = $(top_srcdir)/inc/AEEStdErr.h fastrpc_include_HEADERS += $(top_srcdir)/inc/AEEStdDef.h fastrpc_include_HEADERS += $(top_srcdir)/inc/remote.h fastrpc_include_HEADERS += $(top_srcdir)/inc/rpcmem.h fastrpc_include_HEADERS += $(top_srcdir)/inc/HAP_farf.h fastrpc_include_HEADERS += $(top_srcdir)/inc/HAP_debug.h noinst_HEADERS = \ AEEBufBound.h \ AEEQList.h \ AEEstd.h \ HAP_farf_internal.h \ HAP_pls.h \ adsp_current_process.h \ adsp_current_process1.h \ adsp_default_listener.h \ adsp_default_listener1.h \ adsp_listener.h \ adsp_listener1.h \ adsp_perf.h \ adsp_perf1.h \ adsp_pls.h \ adspmsgd_adsp.h \ adspmsgd_adsp1.h \ adspmsgd_apps.h \ adspmsgd_internal.h \ apps_mem.h \ apps_mem_internal.h \ apps_remotectl.h \ apps_std.h \ apps_std_internal.h \ dspqueue.h \ dspqueue_rpc.h \ dspqueue_shared.h \ dspsignal.h \ fastrpc_apps_user.h \ fastrpc_async.h \ fastrpc_cap.h \ fastrpc_common.h \ fastrpc_config.h \ fastrpc_config_parser.h \ fastrpc_context.h \ fastrpc_hash_table.h \ fastrpc_internal.h \ fastrpc_ioctl.h \ fastrpc_latency.h \ fastrpc_log.h \ fastrpc_mem.h \ fastrpc_notif.h \ fastrpc_perf.h \ fastrpc_pm.h \ fastrpc_procbuf.h \ fastrpc_process_attributes.h \ fastrpc_trace.h \ listener_android.h \ listener_buf.h \ log_config.h \ mod_table.h \ mutex.h \ platform_libs.h \ pls.h \ remote64.h \ remotectl.h \ remotectl1.h \ rpcmem_internal.h \ sbuf.h \ sbuf_parser.h \ shared.h \ std_dtoa.h \ uthash.h \ verify.h \ version.h fastrpc-1.0.2/inc/adsp_current_process.h000066400000000000000000000042741512345705400203420ustar00rootroot00000000000000// 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 fastrpc-1.0.2/inc/adsp_current_process1.h000066400000000000000000000103341512345705400204150ustar00rootroot00000000000000// 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 fastrpc-1.0.2/inc/adsp_default_listener.h000066400000000000000000000016541512345705400204520ustar00rootroot00000000000000// 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 fastrpc-1.0.2/inc/adsp_default_listener1.h000066400000000000000000000155211512345705400205310ustar00rootroot00000000000000// 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 fastrpc-1.0.2/inc/adsp_listener.h000066400000000000000000000045601512345705400167450ustar00rootroot00000000000000// 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_t* data; int dataLen; }; typedef uint32_t adsp_listener_remote_handle; typedef uint32_t 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_t* 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_t* prevbufs, int prevbufsLen, adsp_listener_invoke_ctx* ctx, adsp_listener_remote_handle* handle, uint32_t* sc, uint8_t* 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_t* bufs, int bufsLen, int* bufsLenReq) __QAIC_HEADER_ATTRIBUTE; #ifdef __cplusplus } #endif #endif //_ADSP_LISTENER_H fastrpc-1.0.2/inc/adsp_listener1.h000066400000000000000000000205231512345705400170230ustar00rootroot00000000000000// 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_t* data; int dataLen; }; typedef uint32_t adsp_listener1_remote_handle; typedef uint32_t 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_t* 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_t* prevbufs, int prevbufsLen, adsp_listener1_invoke_ctx* ctx, adsp_listener1_remote_handle* handle, uint32_t* sc, uint8_t* 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_t* 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 fastrpc-1.0.2/inc/adsp_perf.h000066400000000000000000000046421512345705400160550ustar00rootroot00000000000000// 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_t* 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 fastrpc-1.0.2/inc/adsp_perf1.h000066400000000000000000000204451512345705400161350ustar00rootroot00000000000000// 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_t* 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 fastrpc-1.0.2/inc/adsp_pls.h000066400000000000000000000043541512345705400157170ustar00rootroot00000000000000// 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 fastrpc-1.0.2/inc/adspmsgd_adsp.h000066400000000000000000000022161512345705400167160ustar00rootroot00000000000000// 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_t ion_flags, uint32_t filter, uint32_t 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 fastrpc-1.0.2/inc/adspmsgd_adsp1.h000066400000000000000000000057511512345705400170060ustar00rootroot00000000000000// 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_t ion_flags, uint32_t filter, uint64_t buf_size, uint64_t* buff_addr) __QAIC_HEADER_ATTRIBUTE; __QAIC_HEADER_EXPORT int __QAIC_HEADER(adspmsgd_adsp1_wait)(remote_handle64 _h, uint64_t* 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 fastrpc-1.0.2/inc/adspmsgd_apps.h000066400000000000000000000025611512345705400167350ustar00rootroot00000000000000// 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 fastrpc-1.0.2/inc/adspmsgd_internal.h000066400000000000000000000026611512345705400176070ustar00rootroot00000000000000// 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__ */fastrpc-1.0.2/inc/apps_mem.h000066400000000000000000000035621512345705400157130ustar00rootroot00000000000000// 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_t ion_flags, uint32_t rflags, uint32_t vin, int32_t len, uint32_t* vapps, uint32_t* vadsp) __QAIC_HEADER_ATTRIBUTE; __QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_mem_request_unmap)(uint32_t vadsp, int32_t len) __QAIC_HEADER_ATTRIBUTE; __QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_mem_request_map64)(int heapid, uint32_t ion_flags, uint32_t rflags, uint64_t vin, int64_t len, uint64_t* vapps, uint64_t* vadsp) __QAIC_HEADER_ATTRIBUTE; __QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_mem_request_unmap64)(uint64_t vadsp, int64_t len) __QAIC_HEADER_ATTRIBUTE; __QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_mem_share_map)(int fd, int size, uint64_t* vapps, uint64_t* vadsp) __QAIC_HEADER_ATTRIBUTE; __QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_mem_share_unmap)(uint64_t 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 fastrpc-1.0.2/inc/apps_mem_internal.h000066400000000000000000000010541512345705400176010ustar00rootroot00000000000000// 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__*/ fastrpc-1.0.2/inc/apps_remotectl.h000066400000000000000000000025461512345705400171340ustar00rootroot00000000000000// 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 fastrpc-1.0.2/inc/apps_std.h000066400000000000000000000221101512345705400157150ustar00rootroot00000000000000// 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_t 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_t tsz; uint64_t dev; uint64_t ino; uint32_t mode; uint32_t nlink; uint64_t rdev; uint64_t size; int64_t atime; int64_t atimensec; int64_t mtime; int64_t mtimensec; int64_t ctime; int64_t 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, unsigned char* buf, int bufLen, int* bytesRead, int* bEOF) __QAIC_HEADER_ATTRIBUTE; __QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fwrite)(apps_std_FILE sin, const unsigned char* 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, unsigned char* 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 unsigned char* 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_t* 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, unsigned char* 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_t* numPaths, uint16_t* maxPathLen) __QAIC_HEADER_ATTRIBUTE; __QAIC_HEADER_EXPORT int __QAIC_HEADER(apps_std_fileExists)(const char* path, bool* 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 fastrpc-1.0.2/inc/apps_std_internal.h000066400000000000000000000022621512345705400176170ustar00rootroot00000000000000// 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" #define MAX_NON_PRELOAD_LIBS_LEN 2048 #define FILE_EXT ".so" #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 for acdb path #ifndef ADSP_AVS_CFG_PATH #define ADSP_AVS_CFG_PATH ";/etc/acdbdata/;" #endif int fopen_from_dirlist(const char *dirList, const char *delim, const char *mode, const char *name, apps_std_FILE *psout); #endif /*__APPS_STD_INTERNAL_H__*/ fastrpc-1.0.2/inc/dspqueue.h000066400000000000000000000600701512345705400157420ustar00rootroot00000000000000// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause /** @file Asynchronous DSP Packet Queue API. */ #ifndef DSPQUEUE_H #define DSPQUEUE_H #include #include #include /** @defgroup dspqueue_consts Asynchronous DSP Packet Queue API Constants * @{ */ /** Infinite timeout */ #define DSPQUEUE_TIMEOUT_NONE 0xffffffff /** * Packet flags. The flags are used as a bitfield in packet read/write operations. */ enum dspqueue_packet_flags { DSPQUEUE_PACKET_FLAG_MESSAGE = 0x0001, /**< Packet contains a message */ DSPQUEUE_PACKET_FLAG_BUFFERS = 0x0002, /**< Packet contains buffer references */ DSPQUEUE_PACKET_FLAG_WAKEUP = 0x0004, /**< Early wakeup packet */ DSPQUEUE_PACKET_FLAG_DRIVER_READY = 0x0008, /**< Packet is ready for driver consumption. Currently unused. */ DSPQUEUE_PACKET_FLAG_USER_READY = 0x0010, /**< Packet is ready for userspace library consumption */ DSPQUEUE_PACKET_FLAG_RESERVED_ZERO = 0xffe0 }; /** * Buffer flags. The flags are used in dspqueue_buffer.flags as a bitfield. */ enum dspqueue_buffer_flags { /* 1 and 2 reserved */ DSPQUEUE_BUFFER_FLAG_REF = 0x00000004, /**< Add a reference to a previously mapped buffer */ DSPQUEUE_BUFFER_FLAG_DEREF = 0x00000008, /**< Remove a reference from a previously mapped buffer */ DSPQUEUE_BUFFER_FLAG_FLUSH_SENDER = 0x00000010, /**< Flush buffer from sender caches */ DSPQUEUE_BUFFER_FLAG_INVALIDATE_SENDER = 0x00000020, /**< Invalidate buffer from sender caches */ DSPQUEUE_BUFFER_FLAG_FLUSH_RECIPIENT = 0x00000040, /**< Flush buffer from recipient caches */ DSPQUEUE_BUFFER_FLAG_INVALIDATE_RECIPIENT = 0x00000080, /**< Invalidate buffer from recipient caches */ DSPQUEUE_BUFFER_FLAG_RESERVED_ZERO = 0xffffff00 }; /** * Statistics readable with dspqueue_get_stat() */ enum dspqueue_stat { DSPQUEUE_STAT_READ_QUEUE_PACKETS = 1, /**< Numbers of packets in the read queue */ DSPQUEUE_STAT_READ_QUEUE_BYTES, /**< Number of bytes in the read queue */ DSPQUEUE_STAT_WRITE_QUEUE_PACKETS, /**< Number of packets in the write queue */ DSPQUEUE_STAT_WRITE_QUEUE_BYTES, /**< Number of bytes in the write queue */ DSPQUEUE_STAT_EARLY_WAKEUP_WAIT_TIME, /**< Total accumulated early wakeup wait time in microseconds */ DSPQUEUE_STAT_EARLY_WAKEUP_MISSES, /**< Number accumulated of packets missed in the early wakeup loop */ DSPQUEUE_STAT_SIGNALING_PERF /**< Signaling performance; 0 or undefined indicates the first implementation, DSPQUEUE_SIGNALING_PERF_REDUCED_SIGNALING or higher a version if reduced signaling for polling clients. */ }; /* Request IDs to be used with "dspqueue_request" */ typedef enum { /* * Create a multi-domain dspqueue i.e. a queue which has one or more * DSP endpoints. Any packet written to the queue will be delivered * to each endpoint and a signal will be sent to all waiting threads * on each endpoint. */ DSPQUEUE_CREATE, } dspqueue_request_req_id; /** Signaling performance level: Reduced signaling for polling clients. */ #define DSPQUEUE_SIGNALING_PERF_REDUCED_SIGNALING 100 /** Signaling performance level: Optimized signaling for all clients. */ #define DSPQUEUE_SIGNALING_PERF_OPTIMIZED_SIGNALING 1000 /** @} */ /** @defgroup dspqueue_types Asynchronous DSP Packet Queue API Data Types * @{ */ struct dspqueue; typedef struct dspqueue* dspqueue_t; /**< Queue handle */ /** * Buffer reference in a packet. * The buffer must already be mapped to the DSP using the same file descriptor. * The subsection of the buffer as specified by #offset and #size must fit * entirely within the mapped buffer. * Note that buffer references are tracked based on the buffer file descriptor, * and taking/releasing a reference to a buffer applies to the entire buffer as * mapped to the DSP, not just the subsection specified. */ struct dspqueue_buffer { uint32_t fd; /**< Buffer file descriptor */ uint32_t size; /**< Buffer size in bytes. The client can set this field to zero when writing packets; in this case the framework will set the field to the size of the buffer as mapped. */ uint32_t offset; /**< Offset within the buffer in bytes as allocated and mapped. The virtual address #ptr includes the offset */ uint32_t flags; /**< Buffer flags, see enum #dspqueue_buffer_flags */ union { void *ptr; /**< Buffer virtual address; NULL if not mapped in the local context */ uint64_t address; }; }; /** * Callback function type for all queue callbacks * * @param queue Queue handle from dspqueue_create() / dspqueue_import() * @param error Error code * @param context Client-provided context pointer */ typedef void (*dspqueue_callback_t)(dspqueue_t queue, AEEResult error, void *context); /* Struct to be used with DSPQUEUE_CREATE request */ typedef struct dspqueue_create_req { /* [in]: Fastrpc multi-domain context */ uint64_t ctx; /* [in]: Queue creation flags (unused for now) */ uint64_t flags; /* * [in]: Total request queue memory size in bytes; * use 0 for system default */ uint32_t req_queue_size; /* * [in]: Total response queue memory size in bytes; * use 0 for system default. * For each domain, one response queue of this size will be created * and mapped i.e. if there are N domains provided, there will be N * response queues created. */ uint32_t resp_queue_size; /* [in] Queue priority (unused for now) */ uint32_t priority; /* * [in]: Callback function called when there are new packets to read. * When there are response packets from multi-domains on the queue, * this callback can be called concurrently from multiple threads. * Client is expected to consume each available response packet. */ dspqueue_callback_t packet_callback; /* * [in]: Callback function called on unrecoverable errors. * NULL to disable. */ dspqueue_callback_t error_callback; /* [in]: Context pointer for callback functions */ void *callback_context; /* [out]: Queue handle */ dspqueue_t queue; /* * [out]: Queue ID array. Needs to be allocated by caller. * Array will be populated with queue IDs of each domain. * Size of array should be same as number of domains on which * multi-domain context was created. */ uint64_t *ids; /* [in] Size of queue IDs array (must be same as number of domains) */ uint32_t num_ids; } dspqueue_create_req; /* Request payload */ typedef struct dspqueue_request_payload { /* Request id */ dspqueue_request_req_id id; /* Request payload */ union { dspqueue_create_req create; }; } dspqueue_request_payload; /** @} */ #ifdef __cplusplus extern "C" { #endif /** @defgroup dspqueue_funcs Asynchronous DSP Packet Queue API Functions * @{ */ /** * Create a new queue to communicate with the DSP. Queues can only be * created on the host CPU. * * This function cannot be used to create multi-domain queue. * Refer 'dspqueue_request' for that. * * @param [in] domain DSP to communicate with (CDSP_DOMAIN_ID in remote.h for cDSP) * @param [in] flags Queue creation flags * @param [in] req_queue_size Total request queue memory size in bytes; use 0 for system default * @param [in] resp_queue_size Total response queue memory size in bytes; use 0 for system default * @param [in] packet_callback Callback function called when there are new packets to read. * The call will be done in a different thread's context. * NULL to disable the callback. Clients cannot use blocking read * calls if a packet callback has been set. * @param [in] error_callback Callback function called on unrecoverable errors. NULL to disable. * @param [in] callback_context Context pointer for callback functions * @param [out] queue Queue handle * * @return 0 on success, error code on failure. * - AEE_ENOMEMORY: Not enough memory available * - AEE_EUNSUPPORTED: Message queue not supported on the given DSP * - AEE_EBADPARM: Bad parameters, e.g. Invalid domain (use CDSP_DOMAIN_ID for cDSP) * - AEE_ERPC: Internal RPC error, e.g. Queue list corrupt */ 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); /** * Close a queue and free all memory associated with it. The * function can be called on the host CPU with queue handles from * dspqueue_create() or on the DSP with handles from * dspqueue_import(). * * This function can be called on both single-domain and multi-domain * queues. * * @param [in] queue Queue handle from dsp_queue_create() from dsp_queue_import(). * * @return 0 on success, error code on failure. * - AEE_ERPC: Internal RPC error, e.g. The queue is open on the DSP when attempting to close it on the host CPU */ AEEResult dspqueue_close(dspqueue_t queue); /** * Export a queue to the DSP. The CPU-side client calls this function, * passes the ID to the DSP, which can then call dspqueue_import() to * access the queue. * * This function is not required to be called on multi-domain queues. * * @param [in] queue Queue handle from dspqueue_create() * @param [out] queue_id Queue ID * * @return 0 on success, error code on failure. */ AEEResult dspqueue_export(dspqueue_t queue, uint64_t *queue_id); /** * Import a queue on the DSP based on an ID passed in from the host * CPU. The DSP client can use the returned queue handle to access the * queue and communicate with its host CPU counterpart. * * @param [in] queue_id Queue ID from dspqueue_export(). * @param [in] packet_callback Callback function called when there are new packets to read. * The call will be done in a different thread's context. * NULL to disable the callback. * @param [in] error_callback Callback function called on unrecoverable errors. NULL to disable. * @param [in] callback_context Context pointer fo callback functions * @param [out] queue Queue handle * * @return 0 on success, error code on failure. * - AEE_EITEMBUSY: The queue has already been imported * - AEE_EQURTTHREADCREATE: Unable to create callback thread; the system may have * reached its thread limit. * - AEE_EBADSTATE: Bad internal state */ AEEResult dspqueue_import(uint64_t queue_id, dspqueue_callback_t packet_callback, dspqueue_callback_t error_callback, void *callback_context, dspqueue_t *queue); /** * Make dspqueue related requests - like creation of multi-domain queue * * @param [in] req : Request payload * * @return 0 on success, error code on failure. * - AEE_ENOMEMORY : Not enough memory available * - AEE_EUNSUPPORTED : Not supported on given domains * - AEE_EBADPARM : Bad parameters, e.g. invalid context * - AEE_ERPC : Internal RPC error */ int dspqueue_request(dspqueue_request_payload *req); /** * Write a packet to a queue. This variant of the function will not * block, and will instead return AEE_EWOULDBLOCK if the queue does not have * enough space for the packet. * * With this function the client can pass separate pointers to the * buffer references and message to include in the packet and the * library copies the contents directly to the queue. * * When this is called on a multi-domain queue, the packet will be shared * with all remote domains the queue was created on. * If any of the domains is unable to receive the packet, it means the * queue is in a bad-state and is no longer usable. Client is expected to * close the queue and reopen a new one. * * @param [in] queue Queue handle from dspqueue_create() or dspqueue_import() * @param [in] flags Packet flags. See enum #dspqueue_packet_flags * @param [in] num_buffers Number of buffer references to insert to the packet; * zero if there are no buffer references * @param [in] buffers Pointer to buffer references * @param [in] message_length Message length in bytes; * zero if the packet contains no message * @param [in] message Pointer to packet message * * @return 0 on success, error code on failure. * - AEE_EWOULDBLOCK: The queue is full * - AEE_EBADPARM: Bad parameters, e.g. buffers is NULL when num_buffers > 0 * - AEE_ENOSUCHMAP: Attempt to refer to an unmapped buffer. Buffers must be mapped to the DSP * with fastrpc_mmap() before they can be used in queue packets. * - AEE_EBADSTATE: Queue is in bad-state and can no longer be used */ 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); /** * Write a packet to a queue. If the queue is full this function will * block until space becomes available or the request times out. * * With this function the client can pass separate pointers to the * buffer references and message to include in the packet and the * library copies the contents directly to the queue. * * When this is called on a multi-domain queue, the packet will be shared * with all remote domains the queue was created on. This call will block * (for specified timeout or indefinitely) until the packet is shared with * all domains. * If any of the domains is unable to receive the packet, it means the * queue is in a bad-state and is no longer usable. Client is expected to * close the queue and reopen a new one. * * @param [in] queue Queue handle from dspqueue_create() or dspqueue_import() * @param [in] flags Packet flags. See enum #dspqueue_packet_flags * @param [in] num_buffers Number of buffer references to insert to the packet; * zero if there are no buffer references * @param [in] buffers Pointer to buffer references * @param [in] message_length Message length in bytes; * zero if the packet contains no message * @param [in] message Pointer to packet message * @param [in] timeout_us Timeout in microseconds; use DSPQUEUE_TIMEOUT_NONE to * block indefinitely until a space is available or * zero for non-blocking behavior. * * @return 0 on success, error code on failure. * - AEE_EBADPARM: Bad parameters, e.g. buffers is NULL when num_buffers > 0 * - AEE_ENOSUCHMAP: Attempt to refer to an unmapped buffer. Buffers must be mapped to the DSP * with fastrpc_mmap() before they can be used in queue packets. * - AEE_EEXPIRED: Request timed out * - AEE_EINTERRUPTED: The request was canceled * - AEE_EBADSTATE: Queue is in bad-state and can no longer be used */ 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); /** * Read a packet from a queue. This variant of the function will not * block, and will instead return AEE_EWOULDBLOCK if the queue does not have * enough space for the packet. * * This function will read packet contents directly into * client-provided buffers. The buffers must be large enough to fit * contents from the packet or the call will fail. * * When this is called on a multi-domain queue, it will return the * response packet from the first domain where it finds one. If multiple * domains have posted a response to the multi-domain queue, the client is * expected to call this function as many times to consume the response * packet from all domains. * * @param [in] queue Queue handle from dspqueue_create() or dspqueue_import() * @param [out] flags Packet flags. See enum #dspqueue_packet_flags * @param [in] max_buffers The maximum number of buffer references that can fit in the "buffers" parameter * @param [out] num_buffers The number of buffer references in the packet * @param [out] buffers Buffer reference data from the packet * @param [in] max_message_length Maximum message length that can fit in the "message" parameter * @param [out] message_length Message length in bytes * @param [out] message Packet message * * @return 0 on success, error code on failure. * - AEE_ENOSUCHMAP: The packet refers to an unmapped buffer. Buffers must be mapped to the DSP * with fastrpc_mmap() before they can be used in queue packets. * - AEE_EWOULDBLOCK: The queue is empty; try again later * - AEE_EBADITEM: The queue contains a corrupted packet. Internal error. */ 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); /** * Read a packet from a queue. If the queue is empty this function * will block until a packet is available or the request times out. * The queue must not have a packet callback set. * * This function will read packet contents directly into * client-provided buffers. The buffers must be large enough to fit * contents from the packet or the call will fail. * * This function is currently not supported on multi-domain queues. * * @param [in] queue Queue handle from dspqueue_create() or dspqueue_import() * @param [out] flags Packet flags. See enum #dspqueue_packet_flags * @param [in] max_buffers The maximum number of buffer references that can fit in the "buffers" parameter * @param [out] num_buffers The number of buffer references in the packet * @param [out] buffers Buffer reference data from the packet * @param [in] max_message_length Maximum message length that can fit in the "message" parameter * @param [out] message_length Message length in bytes * @param [out] message Packet message * @param [in] timeout_us Timeout in microseconds; use DSPQUEUE_TIMEOUT_NONE to * block indefinitely until a packet is available or * zero for non-blocking behavior. * * @return 0 on success, error code on failure. * - AEE_ENOSUCHMAP: The packet refers to an unmapped buffer. Buffers must be mapped to the DSP * with fastrpc_mmap() before they can be used in queue packets. * - AEE_EBADITEM: The queue contains a corrupted packet. Internal error. * - AEE_EEXPIRED: Request timed out * - AEE_EINTERRUPTED: The request was canceled */ 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); /** * Retrieve information for the next packet if available, without reading * it from the queue and advancing the read pointer. This function * will not block, but will instead return an error if the queue is * empty. * * When this is called on a multi-domain queue, it will return the * response packet info from the first domain where it finds one. If * multiple domains have posted a response to the multi-domain queue, the * client is expected to consume a peeked packet first before attempting * to peek the next available packet from any of the domains. * * @param [in] queue Queue handle from dspqueue_create() or dspqueue_import(). * @param [out] flags Packet flags. See enum #dspqueue_packet_flags * @param [out] num_buffers Number of buffer references in packet * @param [out] message_length Packet message length in bytes * * @return 0 on success, error code on failure. * - AEE_EWOULDBLOCK: The queue is empty; try again later * - AEE_EBADITEM: The queue contains a corrupted packet. Internal error. */ AEEResult dspqueue_peek_noblock(dspqueue_t queue, uint32_t *flags, uint32_t *num_buffers, uint32_t *message_length); /** * Retrieve information for the next packet, without reading it from the * queue and advancing the read pointer. If the queue is empty this * function will block until a packet is available or the request * times out. * * This function is currently not supported on multi-domain queues. * * @param [in] queue Queue handle from dspqueue_create() or dspqueue_import(). * @param [out] flags Packet flags. See enum #dspqueue_packet_flags * @param [out] num_buffers Number of buffer references in packet * @param [out] message_length Packet message length in bytes * @param [out] timeout_us Timeout in microseconds; use DSPQUEUE_TIMEOUT_NONE to * block indefinitely until a packet is available or * zero for non-blocking behavior. * * @return 0 on success, error code on failure. * - AEE_EEXPIRED: Request timed out * - AEE_EINTERRUPTED: The request was canceled * - AEE_EBADITEM: The queue contains a corrupted packet. Internal error. */ AEEResult dspqueue_peek(dspqueue_t queue, uint32_t *flags, uint32_t *num_buffers, uint32_t *message_length, uint32_t timeout_us); /** * Write an early wakeup packet to the queue. Early wakeup packets are used * to bring the recipient out of a low-power state in anticipation of a real * message packet being availble shortly, and are typically used from the DSP * to signal that an operation is almost complete. * * This function will return immediately if the queue is full. There is no * blocking variant of this function; if the queue is full the other endpoint * should already be processing data and an early wakeup would not be useful. * * When this function is called on a multi-domain queue, early wakeup * is done on all the domains that the queue was created on. * * @param [in] queue Queue handle from dspqueue_create() or dspqueue_import() * @param [in] wakeup_delay Wakeup time in microseconds; this indicates how soon * the real message packet should be available. Zero if not known. * The recipient can use this information to determine how to * wait for the packet. * @param [in] packet_flags Flags for the upcoming packet if known. * The recipient can use this information to determine how to * wait for the packet. See enum #dspqueue_packet_flags * * @return 0 on success, error code on failure. * - AEE_EWOULDBLOCK: The queue is full */ AEEResult dspqueue_write_early_wakeup_noblock(dspqueue_t queue, uint32_t wakeup_delay, uint32_t packet_flags); /** * Retrieve statistics from a queue. Statistics are relative to the queue * as viewed from the current endpoint (e.g. "read queue" refers to the * queue as being read by the current endpoint). * * Reading an accumulating statistic (such as early wakeup wait time) * will reset it to zero. * * Note that statistics values are only valid at the time when they're * read. By the time this function returns the values may have * changed due to actions from another thread or the other queue * endpoint. * * This function is currently not supported on multi-domain queues. * * @param [in] queue Queue handle from dspqueue_create() or dspqueue_import() * @param [in] stat Statistic to read, see enum dspqueue_stat * @param [out] value Statistic value. Reading a statistic will reset it to zero * * @return 0 on success, error code on failure. * - AEE_EBADPARM: Invalid statistic */ AEEResult dspqueue_get_stat(dspqueue_t queue, enum dspqueue_stat stat, uint64_t *value); /** @} */ #ifdef __cplusplus } #endif #endif //DSPQUEUE_H fastrpc-1.0.2/inc/dspqueue_rpc.h000066400000000000000000000065631512345705400166150ustar00rootroot00000000000000// 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_t process_state_fd) __QAIC_HEADER_ATTRIBUTE; __QAIC_HEADER_EXPORT AEEResult __QAIC_HEADER(dspqueue_rpc_create_queue)(remote_handle64 _h, uint32_t id, int32_t queue_fd, uint32_t count, uint64_t* queue_id) __QAIC_HEADER_ATTRIBUTE; __QAIC_HEADER_EXPORT AEEResult __QAIC_HEADER(dspqueue_rpc_destroy_queue)(remote_handle64 _h, uint64_t queue_id) __QAIC_HEADER_ATTRIBUTE; __QAIC_HEADER_EXPORT AEEResult __QAIC_HEADER(dspqueue_rpc_is_imported)(remote_handle64 _h, uint64_t queue_id, int32_t* imported) __QAIC_HEADER_ATTRIBUTE; __QAIC_HEADER_EXPORT AEEResult __QAIC_HEADER(dspqueue_rpc_wait_signal)(remote_handle64 _h, int32_t* 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 fastrpc-1.0.2/inc/dspqueue_shared.h000066400000000000000000000125171512345705400172730ustar00rootroot00000000000000// 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 #include #include "dspqueue.h" /* 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]; }; /* Info specific to multi-domain queues */ struct dspqueue_multidomain { /* Flag to indicate if queue is multidomain */ bool is_mdq; /* Multi-domain context id associated with queue */ uint64_t ctx; /* Number of domains on which queue was created */ unsigned int num_domain_ids; /* Effective domain ids on which queue was created */ unsigned int *effec_domain_ids; /* Array of queue handles - one for each domain */ dspqueue_t *queues; /* Array of queue ids - one for each domain */ uint64_t *dsp_ids; }; /* 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 fastrpc-1.0.2/inc/dspsignal.h000066400000000000000000000164651512345705400161040ustar00rootroot00000000000000// 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 /* Verify if the handle is configured for staticPD. */ #define IS_STATICPD_HANDLE(h) ((h > 0xff) && (h <= 0x200)) /* * Enum defined for static PD handles. * The range for constant handles is <0,255>, * and the range for staticPD handles is <256,512> */ typedef enum { OISPD_HANDLE = 256, AUDIOPD_HANDLE = 257, SENSORPD_HANDLE = 258, ATTACHGUESTOS_HANDLE = 259, ROOTPD_HANDLE = 260, SECUREPD_HANDLE = 261 } static_pd_handle; /* * 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_t 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_t 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 fastrpc-1.0.2/inc/fastrpc_async.h000066400000000000000000000043301512345705400167430ustar00rootroot00000000000000// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause #ifndef FASTRPC_ASYNC_H #define FASTRPC_ASYNC_H #include "remote64.h" #include "fastrpc_internal.h" #define POS_TO_MASK(pos) ((1UL << pos) - 1) #define FASTRPC_ASYNC_JOB_POS 4 // Position in jobid where job starts // Store jobs in Queue. Index of queue calculated based on hash value of job. Always needs to be 2^value #define FASTRPC_ASYNC_QUEUE_LIST_LEN 16 // Position where hash ends in jobid #define FASTRPC_ASYNC_HASH_IDX_POS (FASTRPC_ASYNC_JOB_POS + (FASTRPC_ASYNC_QUEUE_LIST_LEN >> 2)) // Position in jobid where timespec starts #define FASTRPC_ASYNC_TIME_SPEC_POS 48 #define SECONDS_PER_HOUR (3600) #define FASTRPC_ASYNC_DOMAIN_MASK (POS_TO_MASK(FASTRPC_ASYNC_JOB_POS)) #define FASTRPC_ASYNC_JOB_CNT_MASK (POS_TO_MASK(FASTRPC_ASYNC_TIME_SPEC_POS) & ~FASTRPC_ASYNC_DOMAIN_MASK) #define FASTRPC_ASYNC_HASH_MASK (POS_TO_MASK(FASTRPC_ASYNC_HASH_IDX_POS) & ~FASTRPC_ASYNC_DOMAIN_MASK) // Async job structure struct fastrpc_async_job { uint32_t isasyncjob; // set if async job /* * Fastrpc async job ID bit-map: * * bits 0-3 : domain ID * bits 4-47 : job counter * bits 48-63 : timespec */ fastrpc_async_jobid jobid; uint32_t reserved; // reserved }; /* * Internal function to save async job information before submitting to DSP * @ domain: domain to which Async job is submitted * @ asyncjob: Async job structure * @ desc: Async desc passed by user * returns 0 on success * */ int fastrpc_save_async_job(int domain, struct fastrpc_async_job *asyncjob, fastrpc_async_descriptor_t *desc); /* * Internal function to remove async job, if async invocation to DSP fails * @ jobid: domain to which Async job is submitted * @ asyncjob: Async job id * @ dsp_invoke_done: DSP invocation is successful * returns 0 on success * */ int fastrpc_remove_async_job(fastrpc_async_jobid jobid, bool dsp_invoke_done); /* * API to initialize async module data strcutures and globals */ int fastrpc_async_domain_init(int domain); /* * API to de-initialize async module data strcutures and globals */ void fastrpc_async_domain_deinit(int domain); #endif // FASTRPC_ASYNC_H fastrpc-1.0.2/inc/fastrpc_cap.h000066400000000000000000000024331512345705400163730ustar00rootroot00000000000000// 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__*/ fastrpc-1.0.2/inc/fastrpc_common.h000066400000000000000000000214301512345705400171160ustar00rootroot00000000000000// 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 #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 8 #endif /*NUM_DOMAINS*/ /* Number of sessions allowed per process */ #ifndef NUM_SESSIONS #define NUM_SESSIONS 4 #define DOMAIN_ID_MASK 7 #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; \ } /** * @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 */ /* * 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 */ }; /* Utility function to get pd type of a DSP domain * @domain: DSP domain ID * @return -1 if device not opened and pd type if opened */ int fastrpc_get_pd_type(int domain); /** * @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 */ void fastrpc_session_close(int domain, 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); /* 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. */ int open_device_node(int domain_id); #endif //FASTRPC_COMMON_H fastrpc-1.0.2/inc/fastrpc_config.h000066400000000000000000000135411512345705400170770ustar00rootroot00000000000000// 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 bool - true/false **/ bool 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 bool - true/false **/ bool 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 bool - true/false **/ bool 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 bool - true/false **/ bool 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 bool - true/false **/ bool 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 bool - true/false **/ bool 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 bool - true/false **/ bool 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 bool - true/false **/ bool 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 bool - true/false **/ bool 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(); /* * fastrpc_config_is_setdmabufname_enabled() - Check if DMA allocated buffer * name attribute debug support has been requested. * Returns: True or False, status of debug support */ bool fastrpc_config_is_setdmabufname_enabled(void); #endif /*__FASTRPC_CONFIG_H__*/ fastrpc-1.0.2/inc/fastrpc_config_parser.h000066400000000000000000000010221512345705400204420ustar00rootroot00000000000000// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. // SPDX-License-Identifier: BSD-3-Clause-Clear #ifndef FASTRPC_YAML_PARSER_H #define FASTRPC_YAML_PARSER_H // DEFAULT_DSP_SEARCH_PATHS intentionally left empty - these paths should be provided through configuration files #ifndef DEFAULT_DSP_SEARCH_PATHS #define DEFAULT_DSP_SEARCH_PATHS "" #endif #define DSP_LIB_KEY "DSP_LIBRARY_PATH" extern char DSP_LIBS_LOCATION[PATH_MAX]; void configure_dsp_paths(); #endif /*FASTRPC_YAML_PARSER_H*/ fastrpc-1.0.2/inc/fastrpc_context.h000066400000000000000000000043511512345705400173150ustar00rootroot00000000000000// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause #ifndef FASTRPC_CONTEXT_H #define FASTRPC_CONTEXT_H #include #include #include "remote.h" #include "uthash.h" typedef struct fastrpc_context { /* Hash table handle */ UT_hash_handle hh; /* Array of effective domain ids on which context is created */ unsigned int *effec_domain_ids; /* Array of domains on which context is created */ unsigned int *domains; /* Array of device fds opened for each session */ int *devs; /* Number of effective domain ids on which context is created */ unsigned int num_domain_ids; /* Kernel-generated context id - key for hash-table */ uint64_t ctxid; /* Mutex for context */ pthread_mutex_t mut; } fastrpc_context; typedef struct fastrpc_context_table { /* Hash-table */ fastrpc_context *table; /* Mutex for hash-table */ pthread_mutex_t mut; /* Flag to indicate context table init is done */ bool init; } fastrpc_context_table; /** * Initialize the fastrpc-context table * * Function expected to be called during libxdsprpc load. * * Returns 0 on success */ int fastrpc_context_table_init(void); /** * Deinitialize the fastrpc-context table * * Function expected to be called during libxdsprpc unload. * * Returns 0 on success */ int fastrpc_context_table_deinit(void); /** * Create session(s) on one or more remote domains and return a * multi-domain context. * * @param[in] create : Context-create request struct * * Returns 0 on success */ int fastrpc_create_context(fastrpc_context_create *create); /** * Destroy fastrpc multi-domain context * * This function cleans up the sessions that are part of the * multi-domain context and frees the resources associated with * the context. * * @param[in] uctx : Multi-domain context * * Returns 0 on success */ int fastrpc_destroy_context(uint64_t uctx); /** * Get info about a multi-domain context like number of domains & list of * effective domain ids on which it was created * * @param[in] req : Request payload * * Returns 0 on success */ int fastrpc_context_get_domains(uint64_t uctx, unsigned int **effec_domain_ids, unsigned int *num_domain_ids); #endif // FASTRPC_CONTEXT_Hfastrpc-1.0.2/inc/fastrpc_hash_table.h000066400000000000000000000033561512345705400177270ustar00rootroot00000000000000// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause #ifndef FASTRPC_HASH_TABLE_H #define FASTRPC_HASH_TABLE_H #include "uthash.h" /* Add members to a struct to hash it using effective domain id */ #define ADD_DOMAIN_HASH() \ int domain; \ UT_hash_handle hh; /* Declare hash-table struct and variable with given name */ #define DECLARE_HASH_TABLE(name, type) \ typedef struct { \ type *tbl; \ pthread_mutex_t mut; \ } name##_table; \ static name##_table info; /* Initialize hash-table and associated members */ #define HASH_TABLE_INIT(type) \ do {\ pthread_mutex_init(&info.mut, 0); \ } while(0) /* Delete & all entries in hash-table */ #define HASH_TABLE_CLEANUP(type) \ do { \ type *me = NULL, *tmp = NULL; \ \ pthread_mutex_lock(&info.mut); \ HASH_ITER(hh, info.tbl, me, tmp) { \ HASH_DEL(info.tbl, me); \ free(me); \ } \ pthread_mutex_unlock(&info.mut); \ pthread_mutex_destroy(&info.mut); \ } while(0) /* Declare a function to get hash-node of given type */ #define GET_HASH_NODE(type, domain, me) \ do {\ pthread_mutex_lock(&info.mut); \ HASH_FIND_INT(info.tbl, &domain, me); \ pthread_mutex_unlock(&info.mut); \ } while(0) /* Allocate new node of given type, set key and add to table */ #define ALLOC_AND_ADD_NEW_NODE_TO_TABLE(type, domain, me) \ do { \ pthread_mutex_lock(&info.mut); \ HASH_FIND_INT(info.tbl, &domain, me); \ if (!me) { \ me = (type *)calloc(1, sizeof(type)); \ if (!me) { \ pthread_mutex_unlock(&info.mut); \ nErr = AEE_ENOMEMORY; \ goto bail; \ } \ me->domain = domain; \ HASH_ADD_INT(info.tbl, domain, me); \ } \ pthread_mutex_unlock(&info.mut); \ } while(0) #endif // FASTRPC_HASH_TABLE_H fastrpc-1.0.2/inc/fastrpc_internal.h000066400000000000000000000452721512345705400174540ustar00rootroot00000000000000// 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(CDSP1_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 MCID_MULTICAST + 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_t Q6_R_cl0_R(uint32_t 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)) /* From effective domain ID, get actual domain ID */ #define GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(effec_dom_id) (effec_dom_id & DOMAIN_ID_MASK) /* Check if given domain ID is in valid range */ #define IS_VALID_DOMAIN_ID(domain) ((domain >= 0) && (domain < NUM_DOMAINS)) /* Check if given effective domain ID is in valid range */ #define IS_VALID_EFFECTIVE_DOMAIN_ID(domain) ((domain >= 0) && (domain < NUM_DOMAINS_EXTEND)) /* Check if given effective domain ID is in extended range */ #define IS_EXTENDED_DOMAIN_ID(domain) ((domain >= NUM_DOMAINS) && (domain < NUM_DOMAINS_EXTEND)) /* Loop thru list of all domain ids */ #define FOR_EACH_DOMAIN_ID(i) for(i = 0; i < NUM_DOMAINS; i++) /* Loop thru list of all effective domain ids */ #define FOR_EACH_EFFECTIVE_DOMAIN_ID(i) for(i = 0; i < NUM_DOMAINS_EXTEND; i++) /** * @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 // 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, }; /** * @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 * kmem_support - Stores whether kernel can allocate memory for signed process * dev - file descriptor returned by open() * 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 kmem_support; int dev; int setmode; uint32_t mode; uint32_t info; 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 refs; // Number of multi-domain handles + contexts on session 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. **/ const char* get_dsp_search_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; case ENOENT: /* No such file or directory */ nErr = AEE_ENOSUCH; case EBUSY: /* Device or resource busy */ nErr = AEE_EITEMBUSY; default: nErr = AEE_ERPC; break; } return nErr; } /** * @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, const char *name); /** * @brief functions to wrap ioctl syscalls for downstream and upstream kernel **/ int ioctl_init(int dev, uint32_t flags, int attr, unsigned char* shell, int shelllen, int shellfd, char* initmem, int initmemlen, int initmemfd, int tessiglen); int ioctl_invoke(int dev, int req, remote_handle handle, uint32_t sc, void* pra, int* fds, unsigned int* attrs, void *job, unsigned int* crc, uint64_t* perf_kernel, uint64_t* perf_dsp); int ioctl_invoke2_response(int dev, fastrpc_async_jobid *jobid, remote_handle *handle, uint32_t *sc, int* result, uint64_t *perf_kernel, uint64_t *perf_dsp); int ioctl_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); /* * Manage multi-domain context in kernel (register / remove) * * @param[in] dev : device for ioctl call * @param[in] req : type of context manage request * @param[in] user_ctx : context generated in user * @param[in] domain_ids : list of domains in context * @param[in] num_domain_ids : number of domains * @param[in/out] ctx : kernel-generated context id. Output ptr * for setup req and input value for * remove request. * * returns 0 on success */ int ioctl_mdctx_manage(int dev, int req, void *user_ctx, unsigned int *domain_ids, unsigned int num_domain_ids, uint64_t *ctx); const char* get_secure_domain_name(int domain_id); int is_async_fastrpc_supported(void); #include "fastrpc_ioctl.h" #endif // FASTRPC_INTERNAL_H fastrpc-1.0.2/inc/fastrpc_ioctl.h000066400000000000000000000173041512345705400167450ustar00rootroot00000000000000// 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 CDSP1RPC_DEVICE "/dev/fastrpc-cdsp1" #define GDSP0RPC_DEVICE "/dev/fastrpc-gdsp0" #define GDSP1RPC_DEVICE "/dev/fastrpc-gdsp1" #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 CDSP1RPC_SECURE_DEVICE "/dev/fastrpc-cdsp1-secure" #define GDSP0RPC_SECURE_DEVICE "/dev/fastrpc-gdsp0-secure" #define GDSP1RPC_SECURE_DEVICE "/dev/fastrpc-gdsp1-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) 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]; }; /** * @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; }; 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; }; }; /* Types of context manage requests */ enum fastrpc_mdctx_manage_req { /* Setup multidomain context in kernel */ FASTRPC_MDCTX_SETUP, /* Delete multidomain context in kernel */ FASTRPC_MDCTX_REMOVE, }; /* Payload for FASTRPC_MDCTX_SETUP type */ struct fastrpc_ioctl_mdctx_setup { /* ctx id in userspace */ __u64 user_ctx; /* User-addr to list of domains on which context is being created */ __u64 domain_ids; /* Number of domain ids */ __u32 num_domains; /* User-addr where unique context generated by kernel is copied to */ __u64 ctx; __u32 reserved[9]; }; /* Payload for FASTRPC_MDCTX_REMOVE type */ struct fastrpc_ioctl_mdctx_remove { /* kernel-generated context id */ __u64 ctx; __u32 reserved[8]; }; /* Payload for FASTRPC_INVOKE_MDCTX_MANAGE type */ struct fastrpc_ioctl_mdctx_manage { /* * Type of ctx manage request. * One of "enum fastrpc_mdctx_manage_req" */ __u32 req; /* To keep struct 64-bit aligned */ __u32 padding; union { struct fastrpc_ioctl_mdctx_setup setup; struct fastrpc_ioctl_mdctx_remove remove; }; }; #endif // FASTRPC_INTERNAL_H fastrpc-1.0.2/inc/fastrpc_latency.h000066400000000000000000000036121512345705400172670ustar00rootroot00000000000000// 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__*/ fastrpc-1.0.2/inc/fastrpc_log.h000066400000000000000000000006231512345705400164100ustar00rootroot00000000000000// 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__*/ fastrpc-1.0.2/inc/fastrpc_mem.h000066400000000000000000000053311512345705400164060ustar00rootroot00000000000000// 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); /* * Register or deregister a buffer with fastrpc framework, managing its reference count * and associated metadata. * * @param buf Pointer to the buffer to be registered or deregistered * @param size Size of the buffer in bytes * @param fd File descriptor associated with the buffer; use -1 to deregister * This function internally calls `remote_register_buf_common` with default attributes. * - If `fd` is not -1, the buffer is registered and its reference count is incremented. * - If `fd` is -1, the buffer is deregistered and its reference count is decremented. * If the reference count reaches zero, the buffer is unmapped and its metadata is freed. * * @return void */ void remote_register_buf(void *buf, int size, int fd); #endif //FASTRPC_MEM_H fastrpc-1.0.2/inc/fastrpc_notif.h000066400000000000000000000030471512345705400167510ustar00rootroot00000000000000// 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 fastrpc-1.0.2/inc/fastrpc_perf.h000066400000000000000000000020761512345705400165670ustar00rootroot00000000000000// 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 fastrpc-1.0.2/inc/fastrpc_pm.h000066400000000000000000000013351512345705400162440ustar00rootroot00000000000000// 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 fastrpc-1.0.2/inc/fastrpc_procbuf.h000066400000000000000000000005331512345705400172670ustar00rootroot00000000000000// 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__*/ fastrpc-1.0.2/inc/fastrpc_process_attributes.h000066400000000000000000000023471512345705400215600ustar00rootroot00000000000000// 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 fastrpc-1.0.2/inc/fastrpc_trace.h000066400000000000000000000032701512345705400167260ustar00rootroot00000000000000// 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 { \ FARF(RUNTIME_RPC_CRITICAL,fmt,##__VA_ARGS__);\ } #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 { \ FARF(RUNTIME_RPC_CRITICAL,"%s end", __func__);\ } #endif //API to get Systrace variable int is_systrace_enabled(void); #endif // FASTRPC_TRACE_H fastrpc-1.0.2/inc/listener_android.h000066400000000000000000000023621512345705400174340ustar00rootroot00000000000000// 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 fastrpc-1.0.2/inc/listener_buf.h000066400000000000000000000052611512345705400165710ustar00rootroot00000000000000// 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_t*)&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_t*)&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_t*)&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_t*)&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_t*)&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_t*)&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 fastrpc-1.0.2/inc/log_config.h000066400000000000000000000011021512345705400162040ustar00rootroot00000000000000// 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__*/ fastrpc-1.0.2/inc/mod_table.h000066400000000000000000000065471512345705400160460ustar00rootroot00000000000000// 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_t 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_t 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_t 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_t 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_t 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_t 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_t 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_t sc, remote_arg* pra)); #ifdef __cplusplus } #endif #endif // MOD_TABLE_H fastrpc-1.0.2/inc/mutex.h000066400000000000000000000046661512345705400152620ustar00rootroot00000000000000// 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_t #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 fastrpc-1.0.2/inc/platform_libs.h000066400000000000000000000065401512345705400167460ustar00rootroot00000000000000// 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; atomic_uint 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 fastrpc-1.0.2/inc/pls.h000066400000000000000000000127601512345705400147100ustar00rootroot00000000000000// 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 "verify.h" #include "HAP_farf.h" struct PLS; struct plskey { uintptr_t type; uintptr_t key; }; struct PLS { uintptr_t next; struct plskey key; void (*dtor)(void* data); uint64_t data[1]; }; struct pls_table { atomic_uintptr_t lst; atomic_uint uRefs; uint32_t primThread; }; unsigned int atomic_CompareOrAdd(atomic_uint* puDest, unsigned int uCompare, unsigned int nAdd) { unsigned int previous; unsigned int current; unsigned int result; do { current = atomic_load(puDest); previous = current; result = current; if(current != uCompare) { atomic_compare_exchange_strong(puDest, &previous, current + nAdd); if(previous == current) { result = current + nAdd; } } } while(previous != current); return result; } /** * 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; } while (1) { unsigned int current; current = atomic_load(&me->uRefs); if (current == 0) return -1; if (atomic_compare_exchange_strong(&me->uRefs, ¤t, current + 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 && 1 == atomic_fetch_sub(&me->uRefs, 1)) { struct PLS* lst, *next; lst = (struct PLS*)atomic_exchange(&me->lst, 0); while(lst) { next = (struct PLS*)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; uintptr_t 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 = atomic_load(&me->lst); prev = pls->next; atomic_compare_exchange_strong(&me->lst, &prev, (uintptr_t)pls); } 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; uintptr_t 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 = atomic_load(&me->lst); if(0 == pls_lookup(me, type, key, ppo)) { if(pls->dtor) { pls->dtor((void*)pls->data); } free(pls); return 0; } prev = pls->next; atomic_compare_exchange_strong(&me->lst, &prev, (uintptr_t)pls); } 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 = (struct PLS*)atomic_load(&me->lst); me->uRefs != 0 && lst != 0; lst = (struct PLS *)lst->next) { if(lst->key.type == type && lst->key.key == key) { if(ppo) { *ppo = lst->data; } return 0; } } return -1; } #endif //PLS_H fastrpc-1.0.2/inc/pthread_rw_mutex.h000066400000000000000000000021161512345705400174650ustar00rootroot00000000000000// 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 fastrpc-1.0.2/inc/remote.h000066400000000000000000002002211512345705400153740ustar00rootroot00000000000000// 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 #define CDSP1_DOMAIN_ID 4 #define GDSP0_DOMAIN_ID 5 #define GDSP1_DOMAIN_ID 6 /** Supported Domain Names */ #define ADSP_DOMAIN_NAME "adsp" #define MDSP_DOMAIN_NAME "mdsp" #define SDSP_DOMAIN_NAME "sdsp" #define CDSP_DOMAIN_NAME "cdsp" #define CDSP1_DOMAIN_NAME "cdsp1" #define GDSP0_DOMAIN_NAME "gdsp0" #define GDSP1_DOMAIN_NAME "gdsp1" /** 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" #define CDSP1_DOMAIN "&_dom=cdsp1" #define GDSP0_DOMAIN "&_dom=gdsp0" #define GDSP1_DOMAIN "&_dom=gdsp1" /** 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, CDSP_DOMAIN_ID, or GDSP_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 */ MCID_MULTICAST, /** Multicast widget programming */ /** 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, CDSP_DOMAIN_ID, or GDSP_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; /* struct to be used with FASTRPC_CONTEXT_CREATE request ID */ typedef struct fastrpc_context_create { /* * [in]: List of effective domain IDs on which session needs to be * created. Needs to be allocated and populated by user. * * A new effective domain id CANNOT be added to an existing context. */ uint32_t *effec_domain_ids; /* * [in]: Number of domain ids. * Size of effective domain ID array. */ uint32_t num_domain_ids; /* [in]: Type of create request (unused) */ uint64_t flags; /* [out]: Multi-domain context handle */ uint64_t ctx; } fastrpc_context_create; /* struct to be used with FASTRPC_CONTEXT_DESTROY request ID */ typedef struct fastrpc_context_destroy { /* [in]: Fastrpc multi-domain context */ uint64_t ctx; /* [in]: Type of destroy request (unused) */ uint64_t flags; } fastrpc_context_destroy; /** * 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 */ FASTRPC_MAX_THREAD_PARAM, /** Set max thread value for unsigned PD */ FASTRPC_CONTEXT_CREATE, /** Create or attaches to remote session(s) on one or more domains */ FASTRPC_CONTEXT_DESTROY, /** Destroy or detach from remote sessions */ }; /** * 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 /** * Opens a remote handle to a DSP module for FastRPC communication * * NOTE: This function should not be called directly from applications. It is automatically * called by the stub functions generated by the QAIC compiler from IDL files. Applications * should use the generated stub functions instead. * * This function creates a handle to communicate with a module running on the DSP. The handle * can be used to invoke remote functions defined in the module's IDL interface. * * @param name [in] URI of the module to open, found in the auto-generated header file. * Format: "uri:module[;option1=value1][;option2=value2]..." * * Available URI options: * - _domain=: Specify target DSP domain * Values: adsp, cdsp, sdsp * - _modver=: Module version requirement * - _session=: Session ID for multi-session support * - _sgver=: Interface version requirement * - _trace=: Enable tracing (1-3) * * Example URIs: * "uri:libexample.so;_domain=adsp" * "uri:libfoo.so;_domain=cdsp;_session=1;_trace=2" * * @param ph [out] Pointer to store the opened remote handle. This handle should be used in * subsequent remote_handle_invoke() calls and must be closed using * remote_handle_close() when no longer needed. * * @return 0 on success, otherwise error code: * - AEE_EINVALIDFORMAT: Invalid URI format * - AEE_EUNSUPPORTED: Domain or module not supported * - AEE_ENOSUCH: Module not found * - AEE_EBADPARM: Invalid parameters (NULL pointers) * - AEE_ENOMEMORY: Not enough memory * - AEE_ECONNREFUSED: Connection to DSP failed * - AEE_EVERSION: Version mismatch when _modver or _sgver specified * * @note The opened handle is only valid for the current process and cannot be * shared across processes. Each process needs to open its own handle. * * @note For unsigned modules, DSPRPC_CONTROL_UNSIGNED_MODULE must be called via * remote_session_control() before opening the handle. * * @note This API is not thread-safe. The caller must ensure thread-safety when * opening/closing handles from multiple threads. */ __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 a remote function on the DSP through a FastRPC handle * * NOTE: This function should not be called directly from applications. It is automatically * called by the stub functions generated by the QAIC compiler from IDL files. Applications * should use the generated stub functions instead. * * This function invokes a remote function defined in the module's IDL interface using * the handle opened via remote_handle_open(). * * @param h [in] Remote handle obtained from remote_handle_open() * * @param dwScalars [in] Scalar value encoding the number and types of arguments: * - REMOTE_SCALARS_INBUFS(sc): Number of input buffers * - REMOTE_SCALARS_OUTBUFS(sc): Number of output buffers * - REMOTE_SCALARS_INHANDLES(sc): Number of input handles * - REMOTE_SCALARS_OUTHANDLES(sc): Number of output handles * * @param pra [in] Array of remote_arg structures containing the arguments in order: * 1. Input buffers * 2. Output buffers * 3. Input handles * 4. Output handles * Each remote_arg contains: * - buf.pv: Pointer to buffer data * - buf.nLen: Length of buffer in bytes * * @return 0 on success, otherwise error code: * - AEE_EBADPARM: Invalid parameters (NULL pointers) * - AEE_EINVALIDHANDLE: Invalid remote handle * - AEE_EUNSUPPORTED: Operation not supported * - AEE_ENOMEMORY: Not enough memory * - AEE_ECONNREFUSED: Connection to DSP failed * - AEE_ETIMEOUT: RPC call timed out * * @note This API is thread-safe and can be called concurrently from multiple threads * using the same handle. * * @note For output buffers, the caller must ensure sufficient buffer size is allocated * before making the RPC call. */ __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; /** * Closes a remote handle previously opened with remote_handle_open() * * This function closes the remote handle and frees any associated resources. The handle * becomes invalid after this call and should not be used again. * * @param h [in] Remote handle to close, obtained from remote_handle_open() * * @return 0 on success, otherwise error code: * - AEE_EINVALIDHANDLE: Invalid remote handle * - AEE_EBUSY: Handle is still in use by pending operations * - AEE_EFAILED: Internal error occurred during cleanup * * @note This API is thread-safe but should not be called while other threads are * using the same handle for RPC operations. * * @note All open handles should be closed when no longer needed to avoid resource leaks. * Handles are not automatically closed when the process exits. */ __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; /** * Sets control parameters for remote handle operations * * This function allows configuring various control parameters for remote handle operations * like latency requirements, wake lock control, domain info etc. * * @param req [in] Request ID specifying the control parameter to set, defined in enum handle_control_req_id: * - DSPRPC_CONTROL_LATENCY: Configure latency requirements * - DSPRPC_CONTROL_WAKELOCK: Enable/disable wake lock control * - DSPRPC_GET_DOMAIN: Get domain ID for a handle * See handle_control_req_id enum for full list * * @param data [in] Pointer to request-specific data structure containing parameters: * - For DSPRPC_CONTROL_LATENCY: struct remote_rpc_control_latency * - For DSPRPC_CONTROL_WAKELOCK: struct remote_rpc_control_wakelock * - For DSPRPC_GET_DOMAIN: struct remote_rpc_get_domain * Structure must match the request ID * * @param datalen [in] Size of the data structure in bytes * * @return 0 on success, otherwise error code: * - AEE_EBADPARM: Invalid parameters (NULL data pointer, invalid datalen) * - AEE_EUNSUPPORTED: Request ID not supported * - AEE_EFAILED: Internal error occurred * - Request-specific error codes * * @note This API is thread-safe and can be called concurrently from multiple threads */ __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; /** * Sets control parameters for remote sessions * * This function allows configuring various control parameters for remote sessions * like process lifecycle, thread parameters, session management etc. * * @param req [in] Request ID specifying the control parameter to set, defined in enum session_control_req_id: * - FASTRPC_THREAD_PARAMS: Set thread priority and stack size * - FASTRPC_REMOTE_PROCESS_KILL: Kill remote process * - FASTRPC_SESSION_CLOSE: Close all open handles for a domain * - FASTRPC_RESERVE_NEW_SESSION: Reserve a new FastRPC session * See session_control_req_id enum for full list * * @param data [in] Pointer to request-specific data structure containing parameters: * - For FASTRPC_THREAD_PARAMS: struct remote_rpc_thread_params * - For FASTRPC_REMOTE_PROCESS_KILL: struct remote_rpc_process_kill * - For FASTRPC_RESERVE_NEW_SESSION: struct remote_rpc_control_session * Structure must match the request ID * * @param datalen [in] Size of the data structure in bytes * * @return 0 on success, otherwise error code: * - AEE_EBADPARM: Invalid parameters (NULL data pointer, invalid datalen) * - AEE_ENOSUCH: Process/session not found * - AEE_EINVALIDDOMAIN: Invalid domain ID specified * - Other error codes returned from FastRPC framework * * @note This API is thread-safe and can be called concurrently from multiple threads */ __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; /** * Invokes a remote handle asynchronously * * This function allows asynchronous invocation of remote methods, providing non-blocking * execution and callback mechanisms. * * @param h [in] Remote handle obtained from remote_handle_open() * * @param desc [in] Async descriptor containing: * - type: Type of async job (FASTRPC_ASYNC_NO_SYNC, FASTRPC_ASYNC_CALLBACK) * - context: User context passed to callback * - cb: Callback function and arguments (for FASTRPC_ASYNC_CALLBACK type) * See fastrpc_async_descriptor_t for details * * @param dwScalars [in] Method invocation parameters encoded as scalar value: * - Number of input/output buffers * - Number of input/output handles * Use REMOTE_SCALARS_* macros to decode * * @param pra [in] Array of remote_arg structures containing: * 1. Input buffers * 2. Output buffers * 3. Input handles * 4. Output handles * Output buffers must be allocated via rpcmem_alloc() or * registered as ION buffers using register_buf() * * @return 0 on success, otherwise error code: * - AEE_EBADPARM: Invalid parameters * - AEE_EUNSUPPORTED: Async operations not supported * - AEE_ENOSUCH: Invalid handle * - Other error codes from FastRPC framework * * @note The async job status can be queried using fastrpc_async_get_status() * @note Resources must be released using fastrpc_release_async_job() after completion */ __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; /** * Gets the status and result of an asynchronous FastRPC job * * This function allows checking the completion status of an asynchronous FastRPC job * and retrieving its result. It can be configured to wait for job completion with * different timeout behaviors. * * @param jobid [in] Job ID returned by remote_handle_invoke_async() when submitting * the asynchronous job * * @param timeout_us [in] Timeout value in microseconds: * - 0: Returns immediately with current status/result * - Positive value: Waits up to specified microseconds for completion * - Negative value: Waits indefinitely until job completes * * @param result [out] Pointer to store the job result: * - 0 if job completed successfully * - Error code if job failed * Only valid when function returns 0 (job completed) * * @return 0 on success (job completed), otherwise error code: * - AEE_EBUSY: Job is still pending and not completed within timeout * - AEE_EBADPARM: Invalid job ID provided * - AEE_EFAILED: Internal FastRPC framework error * * @note After job completion, resources must be released using fastrpc_release_async_job() * @note This function is thread-safe and can be called concurrently from multiple threads */ __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); /** * Releases resources associated with an asynchronous FastRPC job * * This function must be called after an asynchronous job completes to free associated * resources and cleanup internal state. It should only be called after receiving job * completion status either through: * - Callback notification (for FASTRPC_ASYNC_CALLBACK jobs) * - Polling via fastrpc_async_get_status() (for FASTRPC_ASYNC_POLL jobs) * * @param jobid [in] Job ID returned by remote_handle_invoke_async() when submitting * the asynchronous job * * @return 0 on success, otherwise error code: * - AEE_EBUSY: Job is still pending and has not completed yet * - AEE_EBADPARM: Invalid job ID provided * - AEE_EFAILED: Internal FastRPC framework error * * @note This function is thread-safe and can be called concurrently from multiple threads * @note Calling this function before job completion will return AEE_EBUSY * @note Resources must be released exactly once per async job to avoid memory leaks */ __QAIC_REMOTE_EXPORT __QAIC_RETURN int __QAIC_REMOTE(fastrpc_release_async_job)(__QAIC_IN fastrpc_async_jobid jobid); /** * DEPRECATED: Use fastrpc_mmap() instead. * * Maps memory to the remote domain. This function is limited to 32-bit addresses and * provides basic mapping functionality without cache configuration control. * * @param fd [in] File descriptor associated with the memory to be mapped. Must be a valid * DMA buffer file descriptor. * @param flags [in] Mapping flags. Currently only REMOTE_MAP_MEM_STATIC is supported. * @param vaddrin [in] Input virtual address on CPU side. Must be the address returned by * mmap() when mapping the DMA fd. * @param size [in] Size of buffer in bytes to map. Must be page aligned (4KB). * @param vaddrout [out] Pointer to store the mapped address on remote domain. * * @return 0 on success, error code on failure: * AEE_EBADPARM - Invalid parameters * AEE_EFAILED - Internal mapping failure * * @note This API is deprecated and will be removed in a future release. * Use fastrpc_mmap() instead which provides 64-bit address support and * better cache configuration control. */ __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; /** * DEPRECATED: Use fastrpc_munmap() instead. * * Unmaps memory previously mapped using remote_mmap() from the remote domain. * This function is limited to 32-bit addresses. * * @param vaddrout [in] Remote virtual address returned by remote_mmap() * @param size [in] Size of buffer to unmap in bytes. Must match the size used in remote_mmap(). * Partial unmapping is not supported. * * @return 0 on success, error code on failure: * AEE_EBADPARM - Invalid parameters * AEE_EFAILED - Internal unmapping failure * AEE_EBUSY - Memory is still in use and cannot be unmapped * * @note This API is deprecated and will be removed in a future release. * Use fastrpc_munmap() instead which provides 64-bit address support. */ __QAIC_REMOTE_EXPORT __QAIC_RETURN int __QAIC_REMOTE(remote_munmap)(__QAIC_IN uint32_t vaddrout, __QAIC_IN int size) __QAIC_REMOTE_ATTRIBUTE; /** * DEPRECATED: Use fastrpc_mmap() instead. * * Maps memory to a specific remote domain process. This function provides more control * over domain selection compared to remote_mmap(). * * @param domain [in] DSP domain ID to map memory to. Use -1 for default domain based on * linked library (lib(a/m/s/c)dsprpc.so). * Valid domains: ADSP_DOMAIN_ID, MDSP_DOMAIN_ID, SDSP_DOMAIN_ID, CDSP_DOMAIN_ID, GDSP_DOMAIN_ID * @param fd [in] File descriptor of DMA memory to map * @param flags [in] Mapping flags from enum remote_mem_map_flags * @param virtAddr [in] Virtual address of buffer on CPU side * @param size [in] Size of buffer in bytes to map * @param remoteVirtAddr [out] Pointer to store the mapped address on remote domain * * @return 0 on success, error code on failure: * AEE_EBADPARM - Invalid parameters * AEE_EFAILED - Internal mapping failure * * @note This API is deprecated and will be removed in a future release. * Use fastrpc_mmap() instead which provides better cache configuration control. */ __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; /** * DEPRECATED: Use fastrpc_munmap() instead. * * Unmaps memory previously mapped using remote_mem_map() from a specific remote domain process. * * @param domain [in] DSP domain ID to unmap memory from. Use -1 for default domain. * Must match domain used in remote_mem_map(). * @param remoteVirtAddr [in] Remote virtual address returned by remote_mem_map() * @param size [in] Size of buffer in bytes to unmap. Must match size used in remote_mem_map(). * * @return 0 on success, error code on failure: * AEE_EBADPARM - Invalid parameters * AEE_EFAILED - Internal unmapping failure * AEE_EBUSY - Memory is still in use and cannot be unmapped * * @note This API is deprecated and will be removed in a future release. * Use fastrpc_munmap() instead which provides better integration with the FastRPC framework. */ __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; /** * DEPRECATED: Use fastrpc_mmap() instead. * * Maps memory to the remote domain with 64-bit address support. This is the 64-bit * version of remote_mmap(). * * @param fd [in] File descriptor associated with the memory to be mapped * @param flags [in] Mapping flags. Currently only REMOTE_MAP_MEM_STATIC is supported. * @param vaddrin [in] Input virtual address on CPU side (64-bit) * @param size [in] Size of buffer in bytes to map * @param vaddrout [out] Pointer to store the mapped address on remote domain (64-bit) * * @return 0 on success, error code on failure: * AEE_EBADPARM - Invalid parameters * AEE_EFAILED - Internal mapping failure * * @note This API is deprecated and will be removed in a future release. * Use fastrpc_mmap() instead which provides better cache configuration control. */ __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; /** * DEPRECATED: Use fastrpc_munmap() instead. * * Unmaps memory previously mapped using remote_mmap64() from the remote domain. * This is the 64-bit version of remote_munmap(). * * @param vaddrout [in] Remote virtual address returned by remote_mmap64() * @param size [in] Size of buffer to unmap in bytes. Must match size used in remote_mmap64(). * * @return 0 on success, error code on failure: * AEE_EBADPARM - Invalid parameters * AEE_EFAILED - Internal unmapping failure * AEE_EBUSY - Memory is still in use and cannot be unmapped * * @note This API is deprecated and will be removed in a future release. * Use fastrpc_munmap() instead which provides better integration with the FastRPC framework. */ __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 a DMA buffer with file descriptor. New fastrpc session * will be opened if not already opened for the domain. This API maps the buffer with RW- permission * and CACHE WRITEBACK configuration. Driver will clean cache when buffer is passed in a FastRPC call. * * @param domain [in] DSP domain ID of a fastrpc session. Use -1 for default domain based on linked library. * Valid domains are ADSP_DOMAIN_ID, MDSP_DOMAIN_ID, SDSP_DOMAIN_ID, CDSP_DOMAIN_ID, or GDSP_DOMAIN_ID. * @param fd [in] DMA memory file descriptor obtained from dma_alloc_fd() or similar DMA allocation APIs. * @param addr [in] Virtual address of the buffer on CPU side. Must be the same address returned by mmap() * when mapping the DMA fd. * @param offset [in] Offset from the beginning of the buffer. Must be page aligned (4KB). * @param length [in] Size of buffer in bytes to map. Must be page aligned (4KB). * @param flags [in] Controls mapping functionality on DSP. See enum fastrpc_map_flags for valid flags: * FASTRPC_MAP_CACHE_WRITEBACK - Map with writeback cache configuration (default) * FASTRPC_MAP_CACHE_WRITETHROUGH - Map with writethrough cache configuration * FASTRPC_MAP_CACHE_UNCACHED - Map as uncached memory * FASTRPC_MAP_CACHE_NONCACHED - Map as non-cached memory * * @return 0 on success, error code on failure: * AEE_EALREADY - Buffer already mapped. Multiple mappings for same buffer not supported. * AEE_EBADPARM - Invalid parameters (null pointers, unaligned sizes, etc) * AEE_EFAILED - Failed to map buffer (internal driver error) * AEE_ENOMEMORY - Out of memory in driver * AEE_EUNSUPPORTED - API not supported on target DSP * * @note This API must be called before using the buffer in any FastRPC calls. * The mapping persists until explicitly unmapped via fastrpc_munmap() or * the fastrpc session is closed. */ __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 created by fastrpc_mmap() for a DMA buffer on the remote process. * The mapping must be removed before closing the DMA file descriptor. * * @param domain [in] DSP domain ID of a fastrpc session. Use -1 for default domain based on linked library. * Valid domains are ADSP_DOMAIN_ID, MDSP_DOMAIN_ID, SDSP_DOMAIN_ID, CDSP_DOMAIN_ID, or GDSP_DOMAIN_ID. * @param fd [in] DMA memory file descriptor that was used to create the mapping. * @param addr [in] Virtual address of the buffer on CPU side. Must match the address used in fastrpc_mmap(). * @param length [in] Size of buffer in bytes to unmap. Must match the length used in fastrpc_mmap(). * * @return 0 on success, error code on failure: * AEE_EBADPARM - Invalid parameters (null pointers, unaligned sizes, etc) * AEE_EINVALIDFD - No mapping found for the specified file descriptor * AEE_EFAILED - Failed to unmap buffer (internal driver error) * AEE_EUNSUPPORTED - API not supported on target DSP * * @note This API must be called to cleanup mappings before closing DMA file descriptors. * Failing to unmap can lead to resource leaks in the driver. */ __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 to enable zero-copy sharing with DSP via SMMU. * * These functions are thread-safe and can be called from multiple threads concurrently. * However, registering/deregistering the same buffer from different threads simultaneously * is not supported and will lead to undefined behavior. * * @note These APIs are limited to buffers < 2GB in size. For larger buffers, use * remote_register_buf_attr2 which supports 64-bit sizes. * * @note Some versions of libcdsprpc.so lack these functions, so users should set * these symbols as weak: * #pragma weak remote_register_buf * #pragma weak remote_register_buf_attr * * @param buf [in] Virtual address of the buffer to register. Must be a valid mapped address. * @param size [in] Size of the buffer in bytes. Must be > 0 and < 2GB. * @param fd [in] File descriptor for the buffer. Use -1 to deregister a previously registered buffer. * @param attr [in] (remote_register_buf_attr only) Buffer attributes: * 0 - Non-coherent mapping (cached) * 1 - Coherent mapping (uncached) * * @return void. Check errno for error details: * EINVAL - Invalid parameters (null buf, size=0, etc) * ENOMEM - Out of memory in driver * EBADF - Invalid file descriptor * EBUSY - Buffer already registered * ENOSYS - API not supported on this platform */ __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 to enable zero-copy sharing with DSP via SMMU. * This version supports 64-bit buffer sizes, unlike remote_register_buf/remote_register_buf_attr. * * This function is thread-safe and can be called from multiple threads concurrently. * However, registering/deregistering the same buffer from different threads simultaneously * is not supported and will lead to undefined behavior. * * 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 [in] Virtual address of the buffer to register. Must be a valid mapped address. * @param size [in] Size of the buffer in bytes. Must be > 0. * @param fd [in] File descriptor for the buffer. Use -1 to deregister a previously registered buffer. * @param attr [in] Buffer attributes: * 0 - Non-coherent mapping (cached) * 1 - Coherent mapping (uncached) * 2 - No mapping, buffer used as identifier only * * @return void. Check errno for error details: * EINVAL - Invalid parameters (null buf, size=0, etc) * ENOMEM - Out of memory in driver * EBADF - Invalid file descriptor * EBUSY - Buffer already registered * ENOSYS - API not supported on this platform */ __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 to enable zero-copy sharing of ION memory with DSP via SMMU. * This API is only valid on Android systems with ION-allocated memory. * * This function is thread-safe and can be called from multiple threads concurrently. * However, registering/deregistering the same buffer from different threads simultaneously * is not supported and will lead to undefined behavior. * * Some versions of libadsprpc.so lack this function, so users should set these symbols as weak: * #pragma weak remote_register_dma_handle * #pragma weak remote_register_dma_handle_attr * * @param fd [in] File descriptor for the ION buffer. Use -1 to deregister a previously registered buffer. * @param len [in] Size of the buffer in bytes. Must be > 0. * @param attr [in] (remote_register_dma_handle_attr only) Buffer attributes: * 0 - Non-coherent mapping (cached) * 1 - Coherent mapping (uncached) * 2 - No mapping, buffer used as identifier only * * @return 0 on success, -1 on failure. Check errno for error details: * EINVAL - Invalid parameters (fd < -1, len = 0, etc) * ENOMEM - Out of memory in driver * EBADF - Invalid file descriptor * EBUSY - Buffer already registered * ENOSYS - API not supported on this platform */ __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 with FastRPC to enable zero-copy sharing of memory with DSP. * This API is useful when users have a file descriptor but no virtual address mapping. * * The function creates a PROT_NONE mapping that cannot be accessed directly, but serves * as an identifier for the buffer in FastRPC calls. The mapping is used internally by * the RPC layer to share the buffer with DSP. * * This API has a 2GB size limitation. For larger buffers, use remote_register_fd2(). * * This function is thread-safe and can be called from multiple threads concurrently. * However, registering/deregistering the same buffer from different threads simultaneously * is not supported and will lead to undefined behavior. * * Some versions of libadsprpc.so lack this function, so users should set this symbol as weak: * #pragma weak remote_register_fd * * @param fd [in] File descriptor for the buffer. Must be a valid file descriptor. * @param size [in] Size of the buffer in bytes. Must be > 0 and < 2GB. * * @return On success, returns a virtual address that can be used in FastRPC calls. * On failure, returns (void*)-1. Check errno for error details: * EINVAL - Invalid parameters (fd < 0, size = 0 or size >= 2GB) * ENOMEM - Out of memory in driver * EBADF - Invalid file descriptor * EBUSY - Buffer already registered * ENOSYS - API not supported on this platform * * To deregister the buffer, call remote_register_buf(addr, size, -1) with the returned address. */ __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 with FastRPC to enable zero-copy sharing of memory with DSP. * This API is useful when users have a file descriptor but no virtual address mapping. * Unlike remote_register_fd(), this function supports buffers larger than 2GB. * * The function creates a PROT_NONE mapping that cannot be accessed directly, but serves * as an identifier for the buffer in FastRPC calls. The mapping is used internally by * the RPC layer to share the buffer with DSP. * * This function is thread-safe and can be called from multiple threads concurrently. * However, registering/deregistering the same buffer from different threads simultaneously * is not supported and will lead to undefined behavior. * * Some versions of libadsprpc.so lack this function, so users should set this symbol as weak: * #pragma weak remote_register_fd2 * * @param fd [in] File descriptor for the buffer. Must be a valid file descriptor. * @param size [in] Size of the buffer in bytes. Must be > 0. * * @return On success, returns a virtual address that can be used in FastRPC calls. * On failure, returns (void*)-1. Check errno for error details: * EINVAL - Invalid parameters (fd < 0, size = 0) * ENOMEM - Out of memory in driver * EBADF - Invalid file descriptor * EBUSY - Buffer already registered * ENOSYS - API not supported on this platform * * To deregister the buffer, call remote_register_buf(addr, size, -1) with the returned address. */ __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 fastrpc-1.0.2/inc/remote64.h000066400000000000000000000004531512345705400155530ustar00rootroot00000000000000// 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 fastrpc-1.0.2/inc/remotectl.h000066400000000000000000000031551512345705400161060ustar00rootroot00000000000000// 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_t phyAddr, uint32_t nSize) __QAIC_HEADER_ATTRIBUTE; __QAIC_HEADER_EXPORT int __QAIC_HEADER(remotectl_set_param)(int reqID, const uint32_t* params, int paramsLen) __QAIC_HEADER_ATTRIBUTE; #ifdef __cplusplus } #endif #endif //_REMOTECTL_H fastrpc-1.0.2/inc/remotectl1.h000066400000000000000000000170071512345705400161700ustar00rootroot00000000000000// 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_t phyAddr, uint32_t nSize) __QAIC_HEADER_ATTRIBUTE; __QAIC_HEADER_EXPORT int __QAIC_HEADER(remotectl1_set_param)(remote_handle64 _h, int reqID, const uint32_t* 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 fastrpc-1.0.2/inc/rpcmem.h000066400000000000000000000136241512345705400153750ustar00rootroot00000000000000// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause #ifndef RPCMEM_H #define RPCMEM_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_t 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_t 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 fastrpc-1.0.2/inc/rpcmem_internal.h000066400000000000000000000025001512345705400172600ustar00rootroot00000000000000// 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" /* * rpcmem_set_dmabuf_name() - API to set name for DMA allocated buffer. * Name string updates as follows. * Heap : dsp___ * Non-heap : apps___ * * @name : Pointer to string, "dsp" for heap buffers, "apps" for * non-heap buffers * @fd : File descriptor of buffer * @heapid : Heap ID used for memory allocation * @buf : Pointer to buffer start address * @rpcflags: Memory flags describing attributes of allocation * Return : 0 on success, valid non-zero error code on failure */ int rpcmem_set_dmabuf_name(const char *name, int fd, int heapid, void *buf, uint32_t rpc_flags); /* * returns an file descriptor associated with the address */ 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_t flags, size_t size); /* * frees the allocated memory from dma */ void rpcmem_free_internal(void *po); #endif /*__RPCMEM_INTERNAL_H__*/ fastrpc-1.0.2/inc/sbuf.h000066400000000000000000000106641512345705400150520ustar00rootroot00000000000000// 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) { memmove((void*)buf->bufCur, (void*)src, STD_MIN(buf->bufEnd - buf->bufCur, 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) { memmove((void*)dst, (void*)buf->bufCur, readLen); } } sbuf_advance(buf, dstLen); } #endif fastrpc-1.0.2/inc/sbuf_parser.h000066400000000000000000000132071512345705400164220ustar00rootroot00000000000000// 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 fastrpc-1.0.2/inc/shared.h000066400000000000000000000025771512345705400153650ustar00rootroot00000000000000// 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 fastrpc-1.0.2/inc/std_dtoa.h000066400000000000000000000101221512345705400157010ustar00rootroot00000000000000// 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_t)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_t)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 ) // // 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 fastrpc-1.0.2/inc/uthash.h000066400000000000000000001632641512345705400154140ustar00rootroot00000000000000/* 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 (unsigned char 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 */ fastrpc-1.0.2/inc/verify.h000066400000000000000000000107541512345705400154170ustar00rootroot00000000000000// 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 fastrpc-1.0.2/inc/version.h000066400000000000000000000047551512345705400156040ustar00rootroot00000000000000// 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 fastrpc-1.0.2/public_headers/000077500000000000000000000000001512345705400161335ustar00rootroot00000000000000fastrpc-1.0.2/public_headers/config.yml000066400000000000000000000003331512345705400201220ustar00rootroot00000000000000project: https://github.com/qualcomm/fastrpc branches: development: modes: blocking: headers: - inc/remote.h - inc/remote64.h - inc/dspqueue.h - inc/rpcmem.h fastrpc-1.0.2/src/000077500000000000000000000000001512345705400137515ustar00rootroot00000000000000fastrpc-1.0.2/src/BufBound.c000066400000000000000000000106661512345705400156320ustar00rootroot00000000000000// 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_t uOffset = (uint32_t)((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, 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); } fastrpc-1.0.2/src/Makefile.am000066400000000000000000000121311512345705400160030ustar00rootroot00000000000000lib_LTLIBRARIES = LIBDSPRPC_CFLAGS = -fno-short-enums -U_DEBUG -DARM_ARCH_7A -DLE_ENABLE -DENABLE_UPSTREAM_DRIVER_INTERFACE -DUSE_SYSLOG -DCONFIG_BASE_DIR='"$(CONFIG_BASE_DIR)"' -DMACHINE_NAME_PATH='"/sys/firmware/devicetree/base/model"' -I$(top_srcdir)/inc if ANDROID_CC LIBDSPRPC_CFLAGS += -DDEFAULT_DSP_SEARCH_PATHS='";/vendor/lib/rfsa/adsp;/vendor/dsp;"' else LIBDSPRPC_CFLAGS += -DPARSE_YAML @YAML_CFLAGS@ -DDEFAULT_DSP_SEARCH_PATHS='";/usr/lib/rfsa/adsp;/usr/lib/dsp;"' endif 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.c \ dspqueue/dspqueue_rpc_stub.c \ listener_android.c \ apps_std_imp.c \ apps_mem_imp.c \ apps_mem_skel.c \ rpcmem_linux.c \ adspmsgd.c \ adspmsgd_printf.c \ std_path.c \ std_dtoa.c \ BufBound.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 \ fastrpc_context.c if ANDROID_CC # Do nothing (or Android-specific sources) else LIBDSPRPC_SOURCES += fastrpc_config_parser.c endif LIBDEFAULT_LISTENER_SOURCES = \ adsp_default_listener.c \ adsp_default_listener_stub.c \ adsp_default_listener1_stub.c if ANDROID_CC USE_LOG = -llog else # Add YAML libs to link flags for non-Android builds libadsprpc_la_LIBADD = @YAML_LIBS@ libcdsprpc_la_LIBADD = @YAML_LIBS@ libsdsprpc_la_LIBADD = @YAML_LIBS@ libgdsprpc_la_LIBADD = @YAML_LIBS@ endif ADSP_CFLAGS = $(LIBDSPRPC_CFLAGS) -DDEFAULT_DOMAIN_ID=0 lib_LTLIBRARIES += libadsprpc.la libadsprpc_la_SOURCES = $(LIBDSPRPC_SOURCES) libadsprpc_la_LDFLAGS = -ldl -lm $(USE_LOG) -version-number @LT_VERSION_NUMBER@ libadsprpc_la_CFLAGS = $(ADSP_CFLAGS) lib_LTLIBRARIES += libadsp_default_listener.la libadsp_default_listener_la_SOURCES = $(LIBDEFAULT_LISTENER_SOURCES) libadsp_default_listener_la_DEPENDENCIES = libadsprpc.la libadsp_default_listener_la_LDFLAGS = libadsprpc.la -shared -module $(USE_LOG) -version-number @LT_VERSION_NUMBER@ libadsp_default_listener_la_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 $(USE_LOG) -version-number @LT_VERSION_NUMBER@ libcdsprpc_la_CFLAGS = $(CDSP_CFLAGS) lib_LTLIBRARIES += libcdsp_default_listener.la libcdsp_default_listener_la_SOURCES = $(LIBDEFAULT_LISTENER_SOURCES) libcdsp_default_listener_la_DEPENDENCIES = libcdsprpc.la libcdsp_default_listener_la_LDFLAGS = libcdsprpc.la -shared -module $(USE_LOG) -version-number @LT_VERSION_NUMBER@ libcdsp_default_listener_la_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 $(USE_LOG) -version-number @LT_VERSION_NUMBER@ libsdsprpc_la_CFLAGS = $(SDSP_CFLAGS) lib_LTLIBRARIES += libsdsp_default_listener.la libsdsp_default_listener_la_SOURCES = $(LIBDEFAULT_LISTENER_SOURCES) libsdsp_default_listener_la_DEPENDENCIES = libsdsprpc.la libsdsp_default_listener_la_LDFLAGS = libsdsprpc.la -shared -module $(USE_LOG) -version-number @LT_VERSION_NUMBER@ libsdsp_default_listener_la_CFLAGS = $(SDSP_CFLAGS) -DUSE_SYSLOG GDSP_CFLAGS = $(LIBDSPRPC_CFLAGS) -DDEFAULT_DOMAIN_ID=5 libgdsprpc_la_SOURCES = $(LIBDSPRPC_SOURCES) libgdsprpc_la_LDFLAGS = -ldl -lm $(USE_LOG) -version-number @LT_VERSION_NUMBER@ libgdsprpc_la_CFLAGS = $(GDSP_CFLAGS) libgdsp_default_listener_la_SOURCES = $(LIBDEFAULT_LISTENER_SOURCES) libgdsp_default_listener_la_DEPENDENCIES = libcdsprpc.la libgdsp_default_listener_la_LDFLAGS = libcdsprpc.la -shared -module $(USE_LOG) -version-number @LT_VERSION_NUMBER@ libgdsp_default_listener_la_CFLAGS = $(GDSP_CFLAGS) -DUSE_SYSLOG bin_PROGRAMS = adsprpcd cdsprpcd sdsprpcd gdsprpcd adsprpcddir = $(libdir) adsprpcd_SOURCES = dsprpcd.c adsprpcd_DEPENDENCIES = libadsp_default_listener.la adsprpcd_CFLAGS = -I$(top_srcdir)/inc -DDEFAULT_DOMAIN_ID=0 -DUSE_SYSLOG -DUSE_ADSP adsprpcd_LDADD = -ldl $(USE_LOG) cdsprpcddir = $(libdir) cdsprpcd_SOURCES = dsprpcd.c cdsprpcd_DEPENDENCIES = libcdsp_default_listener.la cdsprpcd_CFLAGS = -I$(top_srcdir)/inc -DDEFAULT_DOMAIN_ID=3 -DUSE_SYSLOG -DUSE_CDSP cdsprpcd_LDADD = -ldl $(USE_LOG) sdsprpcddir = $(libdir) sdsprpcd_SOURCES = dsprpcd.c sdsprpcd_DEPENDENCIES = libsdsp_default_listener.la sdsprpcd_CFLAGS = -I$(top_srcdir)/inc -DDEFAULT_DOMAIN_ID=2 -DUSE_SYSLOG -DUSE_SDSP sdsprpcd_LDADD = -ldl $(USE_LOG) gdsprpcddir = $(libdir) gdsprpcd_SOURCES = dsprpcd.c gdsprpcd_DEPENDENCIES = libcdsp_default_listener.la gdsprpcd_CFLAGS = -I$(top_srcdir)/inc -DDEFAULT_DOMAIN_ID=5 -DUSE_SYSLOG -DUSE_GDSP gdsprpcd_LDADD = -ldl $(USE_LOG)fastrpc-1.0.2/src/adsp_current_process1_stub.c000066400000000000000000000657061512345705400215000ustar00rootroot00000000000000// 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; }; //unsigned char 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 fastrpc-1.0.2/src/adsp_current_process_stub.c000066400000000000000000000723551512345705400214150ustar00rootroot00000000000000// 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; }; //unsigned char 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 fastrpc-1.0.2/src/adsp_def_symbols.lst000066400000000000000000000004451512345705400200150ustar00rootroot00000000000000// 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: *; }; fastrpc-1.0.2/src/adsp_default_listener.c000066400000000000000000000342571512345705400204700ustar00rootroot00000000000000// 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 #include #include #define MAX_DOMAIN_URI_SIZE 12 #define ROOTPD_NAME "rootpd" #define ATTACH_GUESTOS "attachguestos" #define CREATE_STATICPD "createstaticpd:" #define POLL_TIMEOUT 10 * 1000 #define EVENT_SIZE ( sizeof (struct inotify_event) ) #define EVENT_BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) ) #define ADSP_SECURE_DEVICE_NAME "fastrpc-adsp-secure" #define SDSP_SECURE_DEVICE_NAME "fastrpc-sdsp-secure" #define MDSP_SECURE_DEVICE_NAME "fastrpc-mdsp-secure" #define CDSP_SECURE_DEVICE_NAME "fastrpc-cdsp-secure" #define CDSP1_SECURE_DEVICE_NAME "fastrpc-cdsp1-secure" #define GDSP0_SECURE_DEVICE_NAME "fastrpc-gdsp0-secure" #define GDSP1_SECURE_DEVICE_NAME "fastrpc-gdsp1-secure" #define ADSP_DEVICE_NAME "fastrpc-adsp" #define SDSP_DEVICE_NAME "fastrpc-sdsp" #define MDSP_DEVICE_NAME "fastrpc-mdsp" #define CDSP_DEVICE_NAME "fastrpc-cdsp" #define CDSP1_DEVICE_NAME "fastrpc-cdsp1" #define GDSP0_DEVICE_NAME "fastrpc-gdsp0" #define GDSP1_DEVICE_NAME "fastrpc-gdsp1" // Array of supported domain names and its corresponding ID's. static domain_t supported_domains[] = {{ADSP_DOMAIN_ID, ADSP_DOMAIN}, {MDSP_DOMAIN_ID, MDSP_DOMAIN}, {SDSP_DOMAIN_ID, SDSP_DOMAIN}, {CDSP_DOMAIN_ID, CDSP_DOMAIN}, {CDSP1_DOMAIN_ID, CDSP1_DOMAIN}, {GDSP0_DOMAIN_ID, GDSP0_DOMAIN}, {GDSP1_DOMAIN_ID, GDSP1_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; } static const char *get_secure_device_name(int domain_id) { const char *name; int domain = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain_id); switch (domain) { case ADSP_DOMAIN_ID: name = ADSP_SECURE_DEVICE_NAME; break; case SDSP_DOMAIN_ID: name = SDSP_SECURE_DEVICE_NAME; break; case MDSP_DOMAIN_ID: name = MDSP_SECURE_DEVICE_NAME; break; case CDSP_DOMAIN_ID: name = CDSP_SECURE_DEVICE_NAME; break; case CDSP1_DOMAIN_ID: name = CDSP1_SECURE_DEVICE_NAME; break; case GDSP0_DOMAIN_ID: name = GDSP0_SECURE_DEVICE_NAME; break; case GDSP1_DOMAIN_ID: name = GDSP1_SECURE_DEVICE_NAME; break; default: name = DEFAULT_DEVICE; break; } return name; } static const char *get_default_device_name(int domain_id) { const char *name; int domain = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain_id); switch (domain) { case ADSP_DOMAIN_ID: name = ADSP_DEVICE_NAME; break; case SDSP_DOMAIN_ID: name = SDSP_DEVICE_NAME; break; case MDSP_DOMAIN_ID: name = MDSP_DEVICE_NAME; break; case CDSP_DOMAIN_ID: name = CDSP_DEVICE_NAME; break; case CDSP1_DOMAIN_ID: name = CDSP1_DEVICE_NAME; break; case GDSP0_DOMAIN_ID: name = GDSP0_DEVICE_NAME; break; case GDSP1_DOMAIN_ID: name = GDSP1_DEVICE_NAME; break; default: name = DEFAULT_DEVICE; break; } return name; } /** * fastrpc_dev_exists() - Check if device exists * @dev_name: Device name * * Return: * True: Device node exists * False: Device node does not exist */ static bool fastrpc_dev_exists(const char* dev_name) { struct stat buffer; char *path = NULL; uint64_t len; len = snprintf(0, 0, "/dev/%s", dev_name) + 1; if(NULL == (path = (char *)malloc(len * sizeof(char)))) return false; snprintf(path, (int)len, "/dev/%s", dev_name); return (stat(path, &buffer) == 0); } /** * fastrpc_wait_for_device() - Wait for fastrpc device nodes * @domain: Domain ID * * Return: * 0 - Success * Non-zero - Failure */ static int fastrpc_wait_for_device(int domain) { int inotify_fd = -1, watch_fd = -1, err = 0; const char *sec_dev_name = NULL, *def_dev_name = NULL; struct pollfd pfd[1]; sec_dev_name = get_secure_device_name(domain); def_dev_name = get_default_device_name(domain); if (fastrpc_dev_exists(sec_dev_name) || fastrpc_dev_exists(def_dev_name)) return 0; inotify_fd = inotify_init(); if (inotify_fd < 0) { VERIFY_EPRINTF("Error: inotify_init failed, invalid fd errno = %s\n", strerror(errno)); return AEE_EINVALIDFD; } watch_fd = inotify_add_watch(inotify_fd, "/dev/", IN_CREATE); if (watch_fd < 0) { close(inotify_fd); VERIFY_EPRINTF("Error: inotify_add_watch failed, invalid fd errno = %s\n", strerror(errno)); return AEE_EINVALIDFD; } if (fastrpc_dev_exists(sec_dev_name) || fastrpc_dev_exists(def_dev_name)) goto bail; memset(pfd, 0 , sizeof(pfd)); pfd[0].fd = inotify_fd; pfd[0].events = POLLIN; while (1) { int ret = 0; char buffer[EVENT_BUF_LEN]; struct inotify_event *event; ret = poll(pfd, 1, POLL_TIMEOUT); if(ret < 0){ VERIFY_EPRINTF("Error: %s: polling for event failed errno(%s)\n", __func__, strerror(errno)); err = AEE_EPOLL; break; } if(ret == 0){ VERIFY_EPRINTF("Error: %s: Poll timeout\n", __func__); err = AEE_EPOLL; break; } /* read on inotify fd never reads partial events. */ ssize_t len = read(inotify_fd, buffer, sizeof(buffer)); if (len < 0) { VERIFY_EPRINTF("Error: %s: read failed, errno = %s\n", __func__, strerror(errno)); err = AEE_EEVENTREAD; break; } /* Loop over all events in the buffer. */ for (char *ptr = buffer; ptr < buffer + len; ptr += sizeof(struct inotify_event) + event->len) { event = (struct inotify_event *) ptr; /* Check if the event corresponds to the creation of the device node. */ if (event->wd == watch_fd && (event->mask & IN_CREATE) && ((strcmp(sec_dev_name, event->name) == 0) || (strcmp(def_dev_name, event->name) == 0))) { /* Device node created, process proceed to open and use it. */ VERIFY_IPRINTF("Device node %s created!\n", event->name); goto bail; /* Exit the loop after device creation is detected. */ } } } bail: inotify_rm_watch(inotify_fd, watch_fd); close(inotify_fd); return err; } 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); VERIFYC(AEE_SUCCESS == (nErr = fastrpc_wait_for_device(domain_id)), AEE_ECONNREFUSED); // 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 (!strncmp(argv[1], ROOTPD_NAME, strlen(argv[1]))) { strlcpy(name, ITRANSPORT_PREFIX ATTACH_GUESTOS, strlen(ITRANSPORT_PREFIX ATTACH_GUESTOS) + 1); } else { strlcpy(name, ITRANSPORT_PREFIX CREATE_STATICPD, strlen(ITRANSPORT_PREFIX CREATE_STATICPD) + 1); strlcat(name, argv[1], strlen(ITRANSPORT_PREFIX CREATE_STATICPD) + strlen(argv[1]) + 1); } // Concatenate domain to the URI 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) { VERIFYC(AEE_SUCCESS == (nErr = fastrpc_wait_for_device(domain_id)), AEE_ECONNREFUSED); 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 strlcpy(name, ITRANSPORT_PREFIX CREATE_STATICPD, strlen(ITRANSPORT_PREFIX CREATE_STATICPD) + 1); 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); strlcpy(name, ITRANSPORT_PREFIX ATTACH_GUESTOS, strlen(ITRANSPORT_PREFIX ATTACH_GUESTOS) + 1); } VERIFYC(AEE_SUCCESS == (nErr = fastrpc_wait_for_device(DEFAULT_DOMAIN_ID)), AEE_ECONNREFUSED); // 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; } fastrpc-1.0.2/src/adsp_default_listener1_stub.c000066400000000000000000000235301512345705400215760ustar00rootroot00000000000000// 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; }; //unsigned char 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 fastrpc-1.0.2/src/adsp_default_listener_stub.c000066400000000000000000000371151512345705400215210ustar00rootroot00000000000000// 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; }; //unsigned char 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 fastrpc-1.0.2/src/adsp_listener1_stub.c000066400000000000000000000763451512345705400201060ustar00rootroot00000000000000// 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; }; //unsigned char 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_t* 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_t* prevbufs, int prevbufsLen, adsp_listener1_invoke_ctx* ctx, adsp_listener1_remote_handle* handle, uint32_t* sc, uint8_t* 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_t* 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 fastrpc-1.0.2/src/adsp_listener_stub.c000066400000000000000000001074251512345705400200170ustar00rootroot00000000000000// 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; }; //unsigned char 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_t* 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_t* prevbufs, int prevbufsLen, adsp_listener_invoke_ctx* ctx, adsp_listener_remote_handle* handle, uint32_t* sc, uint8_t* 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_t* 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 fastrpc-1.0.2/src/adsp_perf1_stub.c000066400000000000000000000324401512345705400172010ustar00rootroot00000000000000// 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; }; //unsigned char 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_t* 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 fastrpc-1.0.2/src/adsp_perf_stub.c000066400000000000000000000452401512345705400171220ustar00rootroot00000000000000// 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; }; //unsigned char 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_t* 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 fastrpc-1.0.2/src/adspmsgd.c000066400000000000000000000134661512345705400157310ustar00rootroot00000000000000// 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; uint64_t 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; uint64_t 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); } } } fastrpc-1.0.2/src/adspmsgd_adsp1_stub.c000066400000000000000000000375631512345705400200620ustar00rootroot00000000000000// 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; }; //unsigned char 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_t ion_flags, uint32_t filter, uint64_t buf_size, uint64_t* 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_t* 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 fastrpc-1.0.2/src/adspmsgd_adsp_stub.c000066400000000000000000000426511512345705400177730ustar00rootroot00000000000000// 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; }; //unsigned char 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_t ion_flags, uint32_t filter, uint32_t 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 fastrpc-1.0.2/src/adspmsgd_apps_skel.c000066400000000000000000000327571512345705400177760ustar00rootroot00000000000000// 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; }; //unsigned char 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 fastrpc-1.0.2/src/adspmsgd_printf.c000066400000000000000000000030641512345705400173040ustar00rootroot00000000000000// 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); } fastrpc-1.0.2/src/adsprpc_blacklist.txt000066400000000000000000000001421512345705400201730ustar00rootroot00000000000000src:*/adspmsgd_apps_skel.c src:*/apps_mem_skel.c src:*/apps_remotectl_skel.c src:*/apps_std_skel.cfastrpc-1.0.2/src/apps_mem_imp.c000066400000000000000000000300711512345705400165640ustar00rootroot00000000000000// 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 #include "fastrpc_hash_table.h" #define ADSP_MMAP_HEAP_ADDR 4 #define ADSP_MMAP_REMOTE_HEAP_ADDR 8 #define ADSP_MMAP_ADD_PAGES 0x1000 #define ADSP_MMAP_ADD_PAGES_LLC 0x3000 #define FASTRPC_ALLOC_HLOS_FD \ 0x10000 /* Flag to allocate HLOS FD to be shared with DSP */ typedef struct { QList mem_list; pthread_mutex_t mem_mut; int init; ADD_DOMAIN_HASH(); } apps_mem_info; DECLARE_HASH_TABLE(apps_mem, apps_mem_info); struct mem_info { QNode qn; uint64_t vapps; uint64_t vadsp; int32_t size; int32_t mapped; uint32_t rflags; }; /* Delete and free all nodes in hash-table */ void apps_mem_table_deinit(void) { HASH_TABLE_CLEANUP(apps_mem_info); } /* Initialize hash-table */ int apps_mem_table_init(void) { HASH_TABLE_INIT(apps_mem_info); return 0; } /* 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) { int nErr = AEE_SUCCESS; apps_mem_info *me = NULL; GET_HASH_NODE(apps_mem_info, domain, me); if (!me) { ALLOC_AND_ADD_NEW_NODE_TO_TABLE(apps_mem_info, domain, me); } QList_Ctor(&me->mem_list); pthread_mutex_init(&me->mem_mut, 0); me->init = 1; bail: return nErr; } void apps_mem_deinit(int domain) { QNode *pn; apps_mem_info *me = NULL; GET_HASH_NODE(apps_mem_info, domain, me); if (!me) { FARF(ALWAYS, "Warning: %s: unable to find hash-node for domain %d", __func__, domain); return; } if (me->init) { while ((pn = QList_PopZ(&me->mem_list)) != 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(&me->mem_mut); me->init = 0; } } __QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_mem_request_map64)(int heapid, uint32_t lflags, uint32_t rflags, uint64_t vin, int64_t len, uint64_t *vapps, uint64_t *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(); apps_mem_info *me = NULL; GET_HASH_NODE(apps_mem_info, domain, me); VERIFYC(me, AEE_ERESOURCENOTFOUND); VERIFY(AEE_SUCCESS == (nErr = get_unsigned_pd_attribute(domain, &unsigned_module))); FASTRPC_ATRACE_BEGIN_L("%s called with rflag 0x%x, lflags 0x%x, len 0x%llx, " "heapid %d and unsigned PD %d", __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); rpcmem_set_dmabuf_name("dsp", fd, heapid, buf, lflags); /* Using FASTRPC_MAP_FD_DELAYED as only HLOS mapping is reqd at this point */ VERIFY(AEE_SUCCESS == (nErr = fastrpc_mmap(domain, fd, buf, 0, len, 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_t)fd; } else { /* Memory for unsignedPD's user-heap will be allocated in userspace for * security reasons. Memory for signedPD's user-heap will be allocated in * kernel. */ if (((rflags != ADSP_MMAP_ADD_PAGES) && (rflags != ADSP_MMAP_ADD_PAGES_LLC)) || (((rflags == ADSP_MMAP_ADD_PAGES) || (rflags == ADSP_MMAP_ADD_PAGES_LLC)) && (unsigned_module && ualloc_support))) { VERIFYC(NULL != (buf = rpcmem_alloc_internal(heapid, lflags, len)), AEE_ENORPCMEMORY); fd = rpcmem_to_fd_internal(buf); VERIFYC(fd > 0, AEE_EBADPARM); rpcmem_set_dmabuf_name("dsp", fd, heapid, buf, lflags); } 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(&me->mem_mut); QList_AppendNode(&me->mem_list, &minfo->qn); pthread_mutex_unlock(&me->mem_mut); 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_t lflags, uint32_t rflags, uint32_t vin, int32_t len, uint32_t *vapps, uint32_t *vadsp) __QAIC_IMPL_ATTRIBUTE { uint64_t vin1, vapps1, vadsp1; int64_t len1; int nErr = AEE_SUCCESS; vin1 = (uint64_t)vin; len1 = (int64_t)len; nErr = apps_mem_request_map64(heapid, lflags, rflags, vin1, len1, &vapps1, &vadsp1); *vapps = (uint32_t)vapps1; *vadsp = (uint32_t)vadsp1; return nErr; } __QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_mem_request_unmap64)(uint64_t vadsp, int64_t len) __QAIC_IMPL_ATTRIBUTE { int nErr = AEE_SUCCESS, fd = -1; struct mem_info *minfo, *mfree = 0; QNode *pn, *pnn; int domain = get_current_domain(); apps_mem_info *me = NULL; FASTRPC_ATRACE_BEGIN_L("%s called with vadsp 0x%llx, len 0x%llx", __func__, vadsp, len); GET_HASH_NODE(apps_mem_info, domain, me); VERIFYC(me, AEE_ERESOURCENOTFOUND); pthread_mutex_lock(&me->mem_mut); QLIST_NEXTSAFE_FOR_ALL(&me->mem_list, pn, pnn) { minfo = STD_RECOVER_REC(struct mem_info, qn, pn); if (minfo->vadsp == vadsp) { mfree = minfo; break; } } pthread_mutex_unlock(&me->mem_mut); /* If apps_mem_request_map64 was called with flag FASTRPC_ALLOC_HLOS_FD, * use fastrpc_munmap else use remote_munmap64 to unmap. */ if(mfree && mfree->rflags == FASTRPC_ALLOC_HLOS_FD) { fd = (int)vadsp; VERIFY(AEE_SUCCESS == (nErr = fastrpc_munmap(domain, fd, 0, len))); } else if (mfree || fastrpc_get_pd_type(domain) == AUDIO_STATICPD){ /* * Map info not available for Audio static PD after daemon reconnect, * So continue to unmap to avoid driver global maps leak. */ VERIFY(AEE_SUCCESS == (nErr = remote_munmap64((uint64_t)vadsp, len))); if (!mfree) goto bail; } VERIFYC(mfree, AEE_ENOSUCHMAP); /* Dequeue done after unmap to prevent leaks in case unmap fails */ pthread_mutex_lock(&me->mem_mut); QNode_Dequeue(&mfree->qn); pthread_mutex_unlock(&me->mem_mut); 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_t vadsp, int32_t len) __QAIC_IMPL_ATTRIBUTE { uint64_t vadsp1 = (uint64_t)vadsp; int64_t len1 = (int64_t)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_t *vapps, uint64_t *vadsp) __QAIC_IMPL_ATTRIBUTE { struct mem_info *minfo = 0; int nErr = AEE_SUCCESS; void *buf = 0; uint64_t pbuf; int domain = get_current_domain(); apps_mem_info *me = NULL; GET_HASH_NODE(apps_mem_info, domain, me); VERIFYC(me, AEE_ERESOURCENOTFOUND); 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(&me->mem_mut); QList_AppendNode(&me->mem_list, &minfo->qn); pthread_mutex_unlock(&me->mem_mut); 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_t vadsp, int size) __QAIC_IMPL_ATTRIBUTE { int64_t len1 = (int64_t)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; } fastrpc-1.0.2/src/apps_mem_skel.c000066400000000000000000000564271512345705400167520ustar00rootroot00000000000000// 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; }; //unsigned char 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_t, 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_t)*_in0, (int)*_in1)); _CATCH(_nErr) {} return _nErr; } static __inline int _skel_method_3(int (*_pfn)(int, int, uint64_t*, uint64_t*), 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_t*)_rout2, (uint64_t*)_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_t, int64_t), 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_t)*_in0, (int64_t)*_in1)); _CATCH(_nErr) {} return _nErr; } static __inline int _skel_method_5(int (*_pfn)(int, uint32_t, uint32_t, uint64_t, int64_t, uint64_t*, uint64_t*), 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_t)*_in1, (uint32_t)*_in2, (uint64_t)*_in3, (int64_t)*_in4, (uint64_t*)_rout5, (uint64_t*)_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_t, int32_t), 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_t)*_in0, (int32_t)*_in1)); _CATCH(_nErr) {} return _nErr; } static __inline int _skel_method_7(int (*_pfn)(int, uint32_t, uint32_t, uint32_t, int32_t, uint32_t*, uint32_t*), 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_t)*_in1, (uint32_t)*_in2, (uint32_t)*_in3, (int32_t)*_in4, (uint32_t*)_rout5, (uint32_t*)_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 fastrpc-1.0.2/src/apps_remotectl_skel.c000066400000000000000000000402611512345705400201570ustar00rootroot00000000000000// 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; }; //unsigned char 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 fastrpc-1.0.2/src/apps_std_imp.c000066400000000000000000001550051512345705400166050ustar00rootroot00000000000000// 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 "AEEstd.h" #include "HAP_farf.h" #include "apps_std.h" #include "apps_std_internal.h" #include "fastrpc_internal.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 #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_t 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; bool 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_ALWAYS(&tdiff, stream = fopen(name, mode);); if (stream) { FASTRPC_ATRACE_END_L("%s done, fopen for %s in mode %s done in %" PRIu64 " us, fd 0x%x error_code 0x%x", __func__, name, mode, tdiff, *psout, nErr); 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; bool 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(RUNTIME_RPC_CRITICAL, "%s: done for %s with fopen:%" PRIu64 "us, read:%" PRIu64 "us, rpc_alloc:%" PRIu64 "us, mmap:%" PRIu64 "us, fd 0x%x error_code 0x%x", __func__, name, fopen_time, read_time, rpc_alloc_time, mmap_time, *fd, nErr); 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; uint64_t tdiff = 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) { PROFILE_ALWAYS(&tdiff, nErr = fclose(sinfo->u.stream); ); VERIFYC(nErr == AEE_SUCCESS, 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_L("%s fd 0x%x in %"PRIu64" us error_code 0x%x ", __func__, sin, tdiff, nErr); 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(); uint64_t tdiff = 0; 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; } PROFILE_ALWAYS(&tdiff, nErr = fclose(freefd->stream); ); VERIFYC(nErr == AEE_SUCCESS, 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_L("%s fd 0x%x in %"PRIu64" us error_code 0x%x", __func__, fd, tdiff, nErr); return nErr; } __QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_fread)(apps_std_FILE sin, unsigned char *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_ALWAYS(&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 in %"PRIu64" us, requested was %d " "bytes, errno is %x\n", nErr, out, tdiff, bufLen, err); return nErr; } *bEOF = feof(sinfo->u.stream); clearerr(sinfo->u.stream); } *bytesRead = out; } else { unsigned int read = STD_MIN(bufLen, sinfo->u.binfo.flen - sinfo->u.binfo.pos); memcpy(buf, sinfo->u.binfo.fbuf + sinfo->u.binfo.pos, read); *bytesRead = read; sinfo->u.binfo.pos += read; *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," "fd 0x%x", __func__, out, tdiff, bufLen, sin); return nErr; } __QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_std_fwrite)(apps_std_FILE sin, const unsigned char *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, unsigned char *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)) { 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 unsigned char *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; } 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 <= INT_MAX - 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_t *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 = strlen(vv) + 1; 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; const char *dsp_search_path = NULL; int nErr = AEE_SUCCESS; int envListLen = 0; int envListPrependLen = 0; int listLen = 0; int envLenGuess = 0; dsp_search_path = get_dsp_search_path(); envLenGuess = STD_MAX(ENV_LEN_GUESS, 1 + 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 (strncmp(envvarname, ADSP_LIBRARY_PATH, strlen(ADSP_LIBRARY_PATH)) == 0 || strncmp(envvarname, DSP_LIBRARY_PATH, strlen(DSP_LIBRARY_PATH)) == 0) { // Calculate total length of env + semicolon + DSP_SEARCH_PATH envListPrependLen = envListLen + 1 + 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 semicolon before DSP_SEARCH_PATH strlcat(envList, ";", envListPrependLen); // Append default DSP_SEARCH_PATH to user defined env strlcat(envList, dsp_search_path, envListPrependLen); envListLen = envListPrependLen; } else if (strncmp(envvarname, ADSP_AVS_PATH, strlen(ADSP_AVS_PATH)) == 0) { envListPrependLen = envListLen + strlen(ADSP_AVS_CFG_PATH); if (envLenGuess < envListPrependLen) { FREEIF(envListBuf); VERIFYC(envListBuf = realloc(envListBuf, sizeof(char) * envListPrependLen), AEE_ENOMEMORY); envList = envListBuf; VERIFY(0 == (nErr = apps_std_getenv(envvarname, envList, envListPrependLen, &listLen))); } strlcat(envList, ADSP_AVS_CFG_PATH, envListPrependLen); envListLen = envListPrependLen; } } else if (strncmp(envvarname, ADSP_LIBRARY_PATH, strlen(ADSP_LIBRARY_PATH)) == 0 || strncmp(envvarname, DSP_LIBRARY_PATH, strlen(DSP_LIBRARY_PATH)) == 0) { envListLen = listLen = 1 + strlcpy(envListBuf, dsp_search_path, envLenGuess); } else if (strncmp(envvarname, ADSP_AVS_PATH, strlen(ADSP_AVS_PATH)) == 0) { envListLen = listLen = 1 + strlcpy(envListBuf, ADSP_AVS_CFG_PATH, envLenGuess); } /* * Allocate mem. to copy envvarname. */ if ('\0' != *envList) { srcStr = envList; } else { envListLen = strlen(EMTPY_STR) + 1; } VERIFYC(dirListBuf = (char *)malloc(sizeof(char) * envListLen), AEE_ENOMEMORY); dirList = dirListBuf; VERIFYC(srcStr != NULL, AEE_EBADPARM); 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; } int fopen_from_dirlist(const char *dirList, const char *delim, const char *mode, const char *name, apps_std_FILE *psout) { int nErr = AEE_SUCCESS; char *absName = NULL, *dirName = NULL, *pos = NULL; uint16_t absNameLen = 0; int domain = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(get_current_domain()); VERIFYC(NULL != dirList, AEE_EBADPARM); while (dirList) { pos = strstr(dirList, delim); dirName = dirList; if (pos) { *pos = '\0'; dirList = pos + strlen(delim); } else { dirList = 0; } // Append domain to path absNameLen = strlen(dirName) + strlen(name) + 2 + strlen(SUBSYSTEM_NAME[domain]) + 1; VERIFYC(NULL != (absName = (char *)malloc(sizeof(char) * absNameLen)), AEE_ENOMEMORY); if ('\0' != *dirName) { strlcpy(absName, dirName, absNameLen); strlcat(absName, "/", absNameLen); strlcat(absName, SUBSYSTEM_NAME[domain], absNameLen); strlcat(absName, "/", absNameLen); strlcat(absName, name, absNameLen); } else { strlcpy(absName, name, absNameLen); } nErr = apps_std_fopen(absName, mode, psout); if (AEE_SUCCESS == nErr) { // Success FARF(ALWAYS, "Successfully opened file %s", absName); FREEIF(absName); return nErr; } FREEIF(absName); // fallback: If not found in domain path /vendor/dsp/adsp try in /vendor/dsp absNameLen = strlen(dirName) + strlen(name) + 2; VERIFYC(NULL != (absName = (char *)malloc(sizeof(char) * absNameLen)), AEE_ENOMEMORY); if ('\0' != *dirName) { strlcpy(absName, dirName, absNameLen); strlcat(absName, "/", absNameLen); strlcat(absName, name, absNameLen); } else { strlcpy(absName, name, absNameLen); } nErr = apps_std_fopen(absName, mode, psout); if (AEE_SUCCESS == nErr) { // Success if (name != NULL && (strncmp(name, OEM_CONFIG_FILE_NAME, strlen(OEM_CONFIG_FILE_NAME)) != 0) && (strncmp(name, TESTSIG_FILE_NAME, strlen(TESTSIG_FILE_NAME)) != 0)) FARF(ALWAYS, "Successfully opened file %s", name); FREEIF(absName); return nErr; } } bail: FREEIF(absName); 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 *dirListBuf = NULL; char *dirList = NULL; const char *envVar = NULL; 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); 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 (strncmp(envvarname, ADSP_LIBRARY_PATH, 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); nErr = fopen_from_dirlist(dirList, delim, mode, name, psout); bail: FREEIF(dirListBuf); if (nErr != AEE_SUCCESS) { if (ERRNO != ENOENT || (name != NULL && strncmp(name, OEM_CONFIG_FILE_NAME, strlen(OEM_CONFIG_FILE_NAME)) != 0 && strncmp(name, RPC_VERSION_FILE_NAME, strlen(RPC_VERSION_FILE_NAME)) != 0 && strncmp(name, TESTSIG_FILE_NAME, 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_t absNameLen = 0; int domain = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(get_current_domain()); 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 (strncmp(envvarname, ADSP_LIBRARY_PATH, 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 + strlen(delim); } else { dirList = 0; } // Append domain to path absNameLen = strlen(dirName) + strlen(name) + 2 + strlen("adsp") + 1; VERIFYC(NULL != (absName = (char *)malloc(sizeof(char) * absNameLen)), AEE_ENOMEMORY); if ('\0' != *dirName) { strlcpy(absName, dirName, absNameLen); strlcat(absName, "/", absNameLen); strlcat(absName, SUBSYSTEM_NAME[domain], absNameLen); strlcat(absName, "/", absNameLen); strlcat(absName, name, absNameLen); } else { 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 = strlen(dirName) + strlen(name) + 2; VERIFYC(NULL != (absName = (char *)malloc(sizeof(char) * absNameLen)), AEE_ENOMEMORY); if ('\0' != *dirName) { strlcpy(absName, dirName, absNameLen); strlcat(absName, "/", absNameLen); strlcat(absName, name, absNameLen); } else { 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 && strncmp(name, OEM_CONFIG_FILE_NAME, strlen(OEM_CONFIG_FILE_NAME)) != 0 && strncmp(name, RPC_VERSION_FILE_NAME, strlen(RPC_VERSION_FILE_NAME)) != 0 && strncmp(name, TESTSIG_FILE_NAME, 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_t *numPaths, uint16_t *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_DOMAIN_FROM_EFFEC_DOMAIN_ID(get_current_domain()); FARF(RUNTIME_RPC_LOW, "Entering %s", __func__); VERIFYC(NULL != numPaths, AEE_EBADPARM); VERIFYC(NULL != delim, AEE_EBADPARM); VERIFYC(NULL != maxPathLen, AEE_EBADPARM); if (strncmp(envvarname, ADSP_LIBRARY_PATH, 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 = strlen(path) + 1 + strlen("adsp") + 1; VERIFYC(pathDomain = (char *)malloc(sizeof(char) * (pathDomainLen)), AEE_ENOMEMORY); strlcpy(pathDomain, path, pathDomainLen); strlcat(pathDomain, "/", pathDomainLen); 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, strlen(pathDomain) + 1); if (paths && i < pathsLen && paths[i].data && paths[i].dataLen >= (int)strlen(path)) { strlcpy(paths[i].data, pathDomain, paths[i].dataLen); } i++; } if ((stat(path, &st) == 0) && (S_ISDIR(st.st_mode))) { *maxPathLen = STD_MAX(*maxPathLen, strlen(path) + 1); if (paths && i < pathsLen && paths[i].data && paths[i].dataLen >= (int)strlen(path)) { 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, unsigned char *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, bool *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_t)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; 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; uint64_t tdiff = 0; if (NULL == name) { return EINVAL; } FASTRPC_ATRACE_BEGIN(); errno = 0; PROFILE_ALWAYS(&tdiff, 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)); } FASTRPC_ATRACE_END_L("%s done for %s mode %d in %"PRIu64" us error_code 0x%x", __func__, name, mode, tdiff, nErr); 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; uint64_t tdiff = 0; 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); PROFILE_ALWAYS(&tdiff, nErr = fstat(fd, &st);; ); VERIFYC(nErr == AEE_SUCCESS, 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_t)st.st_atim.tv_sec; ist->atimensec = (int64_t)st.st_atim.tv_nsec; ist->mtime = (int64_t)st.st_mtim.tv_sec; ist->mtimensec = (int64_t)st.st_mtim.tv_nsec; ist->ctime = (int64_t)st.st_ctim.tv_nsec; ist->ctimensec = (int64_t)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_L("%s done for %s in %"PRIu64" us \ fd 0x%x error_code 0x%x", __func__, name, tdiff, ps, nErr); 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; } fastrpc-1.0.2/src/apps_std_skel.c000066400000000000000000001753671512345705400167730ustar00rootroot00000000000000// 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; }; //unsigned char 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*, bool*), 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, (bool*)_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_t*, uint16_t*), 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_t*)_rout3, (uint16_t*)_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, unsigned 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((apps_std_FILE)*_in0, (unsigned char*)*_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_t*), 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_t*)_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 unsigned char*, 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 unsigned char*)*_in1, (int)*_in1Len)); _CATCH(_nErr) {} return _nErr; } static __inline int _skel_method_23(int (*_pfn)(apps_std_FILE, const unsigned char*, 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 unsigned char*)*_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, unsigned char*, 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, (unsigned char*)*_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 fastrpc-1.0.2/src/dspqueue/000077500000000000000000000000001512345705400156045ustar00rootroot00000000000000fastrpc-1.0.2/src/dspqueue/.dirstamp000066400000000000000000000000001512345705400174160ustar00rootroot00000000000000fastrpc-1.0.2/src/dspqueue/dspqueue_cpu.c000066400000000000000000002544521512345705400204660ustar00rootroot00000000000000// 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 "fastrpc_context.h" #include "remote.h" #include "verify.h" #include #include #include #include #include #include #include #include #include struct dspqueue { unsigned id; int domain; struct dspqueue_multidomain mdq; struct dspqueue_header *header; void *user_queue; int user_queue_fd; uint32_t user_queue_size; remote_handle64 dsp_handle; uint64_t 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) #ifdef __ARM_ARCH #define barrier_full() __asm__ __volatile__("dmb sy" : : : "memory") #define barrier_store() __asm__ __volatile__("dmb st" : : : "memory"); #else #define barrier_full() /* FIXME */ #define barrier_store() /* FIXME */ #endif #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(IS_VALID_EFFECTIVE_DOMAIN_ID(domain)); 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 = (dom == CDSP1_DOMAIN_ID) ? strlen(CDSP1_DOMAIN_NAME) + 1 : 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) { strlcpy(dspqueue_skel.domain_name, CDSP_DOMAIN_NAME, dspqueue_skel.domain_name_len); } else if (dom == ADSP_DOMAIN_ID) { strlcpy(dspqueue_skel.domain_name, ADSP_DOMAIN_NAME, dspqueue_skel.domain_name_len); } else if (dom == CDSP1_DOMAIN_ID) { strlcpy(dspqueue_skel.domain_name, CDSP1_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); 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); /* In case of failure due to SSR, return corresponding error to client */ if (nErr != AEE_ECONNRESET) 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); /* In case of failure due to SSR, return corresponding error to client */ if (nErr != AEE_ECONNRESET) 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_internal( 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(IS_VALID_EFFECTIVE_DOMAIN_ID(domain)); 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) { domain = get_current_domain(); if (!IS_VALID_EFFECTIVE_DOMAIN_ID(domain)) { return AEE_ERPC; } } else if (!IS_VALID_EFFECTIVE_DOMAIN_ID(domain)) { 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_internal( 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 = UINT32_MAX; 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; } /* * Clean-up multi-domain queue * This function calls 'dspqueue_close' on each individual queue. */ static int dspqueue_multidomain_close(struct dspqueue *q, bool queue_mut) { int nErr = AEE_SUCCESS, err = AEE_SUCCESS; struct dspqueue_multidomain *mdq = NULL; dspqueue_t queue = NULL; VERIFYC(q, AEE_EBADPARM); mdq = &q->mdq; VERIFYC(mdq->is_mdq, AEE_EINVALIDITEM); if (queue_mut) { pthread_mutex_lock(&q->mutex); } // Close individual queues for (unsigned int ii = 0; ii < mdq->num_domain_ids; ii++) { queue = mdq->queues[ii]; if (!queue) continue; err = dspqueue_close(queue); if (err) { // Return the first failure's error code to client nErr = nErr ? nErr : err; } } if (mdq->effec_domain_ids) { free(mdq->effec_domain_ids); } if (mdq->queues) { free(mdq->queues); } if (mdq->dsp_ids) { free(mdq->dsp_ids); } if (queue_mut) { pthread_mutex_unlock(&q->mutex); pthread_mutex_destroy(&q->mutex); } FARF(ALWAYS, "%s: closed queue %p (ctx 0x%"PRIx64"), num domains %u", __func__, q, mdq->ctx, mdq->num_domain_ids); free(q); bail: if (nErr) { FARF(ALWAYS, "Error 0x%x: %s: failed for queue %p", nErr, __func__, q); } 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); if (q->mdq.is_mdq) { // Recursively call 'dspqueue_close' on each individual queue return dspqueue_multidomain_close(q, true); } VERIFYC(IS_VALID_EFFECTIVE_DOMAIN_ID(q->domain), 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 * Not required in case of SSR (i.e AEE_ECONNRESET) * as signals are cancelled by the SSR handle. */ if (dq->dsp_error != AEE_ECONNRESET) { 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); /* * In case of SSR (i.e., AEE_ECONNRESET), there is no need to call * dspsignal_destroy as the process close during SSR cleans up * signals. */ if (q->have_driver_signaling) { if (dq->dsp_error != AEE_ECONNRESET) { 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; if (q->mdq.is_mdq) { FARF(ALWAYS, "Warning: %s not supported for multi-domain queue, already exported during create", __func__); return AEE_EUNSUPPORTED; } *queue_id = q->dsp_id; return AEE_SUCCESS; } static int dspqueue_multidomain_create(dspqueue_create_req *create) { int nErr = AEE_SUCCESS; bool queue_mut = false; unsigned int *effec_domain_ids = NULL; unsigned int num_domain_ids = 0, size = 0; struct dspqueue *q = NULL; struct dspqueue_multidomain *mdq = NULL; VERIFY(AEE_SUCCESS == (nErr = fastrpc_context_get_domains(create->ctx, &effec_domain_ids, &num_domain_ids))); // Validate output parameter pointers VERIFYC(create->ids && !create->priority && !create->flags, AEE_EBADPARM); VERIFYC(create->num_ids >= num_domain_ids, AEE_EBADPARM); create->queue = NULL; size = create->num_ids * sizeof(*(create->ids)); memset(create->ids, 0, size); errno = 0; VERIFYC(AEE_SUCCESS == (nErr = pthread_once(&queues_once, init_process_queues_once)), AEE_ENOTINITIALIZED); // Alloc & init queue struct VERIFYC(NULL != (q = calloc(1, sizeof(*q))), AEE_ENOMEMORY); mdq = &q->mdq; mdq->is_mdq = true; mdq->ctx = create->ctx; VERIFYC(AEE_SUCCESS == (nErr = pthread_mutex_init(&q->mutex, NULL)), AEE_ENOTINITIALIZED); queue_mut = true; // Alloc & init multi-domain queue specific info mdq->num_domain_ids = num_domain_ids; size = num_domain_ids * sizeof(*(mdq->effec_domain_ids)); VERIFYC(NULL != (mdq->effec_domain_ids = calloc(1, size)), AEE_ENOMEMORY); memcpy(mdq->effec_domain_ids, effec_domain_ids, size); VERIFYC(NULL != (mdq->queues = calloc(num_domain_ids, sizeof(*(mdq->queues)))), AEE_ENOMEMORY); size = num_domain_ids * sizeof(*(mdq->dsp_ids)); VERIFYC(NULL != (mdq->dsp_ids = calloc(1, size)), AEE_ENOMEMORY); // Create queue on each individual domain for (unsigned int ii = 0; ii < num_domain_ids; ii++) { VERIFY(AEE_SUCCESS == (nErr = dspqueue_create(effec_domain_ids[ii], create->flags, create->req_queue_size, create->resp_queue_size, create->packet_callback, create->error_callback, create->callback_context, &mdq->queues[ii]))); // Export queue and get queue id for that domain VERIFY(AEE_SUCCESS == (nErr = dspqueue_export(mdq->queues[ii], &mdq->dsp_ids[ii]))); } // Return queue handle and list of queue ids to user create->queue = q; memcpy(create->ids, mdq->dsp_ids, size); FARF(ALWAYS, "%s: created queue %p for ctx 0x%"PRIx64", sizes: req %u, rsp %u, num domains %u", __func__, q, create->ctx, create->req_queue_size, create->resp_queue_size, num_domain_ids); bail: if (nErr) { FARF(ERROR, "Error 0x%x: %s failed for ctx 0x%"PRIx64", queue sizes: req %u, rsp %u, num ids %u", nErr, __func__, create->ctx, create->req_queue_size, create->resp_queue_size, create->num_ids); dspqueue_multidomain_close(q, queue_mut); } return nErr; } int dspqueue_request(dspqueue_request_payload *req) { int nErr = AEE_SUCCESS, req_id = -1; VERIFYC(req, AEE_EBADPARM); req_id = req->id; switch(req_id) { case DSPQUEUE_CREATE: { VERIFY(AEE_SUCCESS == (nErr = dspqueue_multidomain_create(&req->create))); break; } default: nErr = AEE_EUNSUPPORTED; break; } bail: if (nErr) FARF(ALWAYS, "Error 0x%x: %s failed", nErr, __func__); return nErr; } 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; } /* Write packet to multi-domain queue */ static int dspqueue_multidomain_write(struct dspqueue *q, uint32_t flags, uint32_t num_buffers, struct dspqueue_buffer *buffers, uint32_t message_length, const uint8_t *message, uint32_t timeout_us, bool block) { int nErr = AEE_SUCCESS; struct dspqueue_multidomain *mdq = NULL; bool locked = false; VERIFYC(q, AEE_EBADPARM); mdq = &q->mdq; VERIFYC(mdq->is_mdq, AEE_EINVALIDITEM); // Only one multi-domain write request at a time. pthread_mutex_lock(&q->mutex); locked = true; // Write packet to individual queues for (unsigned int ii = 0; ii < mdq->num_domain_ids; ii++) { if (block) { /* * Multi-domain blocking write operation will serially block * on each individual queue. */ VERIFY(AEE_SUCCESS == (nErr = dspqueue_write(mdq->queues[ii], flags, num_buffers, buffers, message_length, message, timeout_us))); } else { VERIFY(AEE_SUCCESS == (nErr = dspqueue_write_noblock( mdq->queues[ii], flags, num_buffers, buffers, message_length, message))); } } bail: if (locked) pthread_mutex_unlock(&q->mutex); if (nErr) { /* * If multi-domain write operation failed on some but not all * queues, then the MDQ is now in an irrecoverable bad-state as * the packet was partially written to some domains but not all * and it cannot be "erased". Client is expected to close queue. */ nErr = AEE_EBADSTATE; FARF(ERROR, "Error 0x%x: %s (block %d): failed for queue %p, flags 0x%x, num bufs %u, msg len %u, timeout %u", nErr, __func__, block, q, flags, num_buffers, message_length, timeout_us); } 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 = NULL; volatile uint8_t *qp = NULL; struct dspqueue_packet_queue_state *read_state = NULL; struct dspqueue_packet_queue_state *write_state = NULL; struct dspqueue_domain_queues *dq = NULL; unsigned len, alen; uint32_t r, w; uint32_t qleft = 0, qsize = 0; int locked = 0; uint64_t phdr; int wrap = 0; uint32_t i; uint32_t buf_refs = 0; if (q->mdq.is_mdq) { // Recursively call 'dspqueue_write_noblock' on individual queues return dspqueue_multidomain_write(q, flags, num_buffers, buffers, message_length, message, 0, false); } pq = &q->header->req_queue; qp = (volatile uint8_t*) (((uintptr_t)q->header) + pq->queue_offset); read_state = (struct dspqueue_packet_queue_state*) (((uintptr_t)q->header) + pq->read_state_offset); write_state = (struct dspqueue_packet_queue_state*) (((uintptr_t)q->header) + pq->write_state_offset); dq = queues->domain_queues[q->domain]; qsize = pq->queue_length; // 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 barrier_full(); 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 = NULL; struct dspqueue_packet_queue_state *write_state = NULL; _Atomic uint32_t *wait_count = NULL; int waiting = 0; struct timespec *timeout_ts = NULL; // no timeout by default struct timespec ts; errno = 0; if (q->mdq.is_mdq) { // Recursively call 'dspqueue_write' on individual queues. return dspqueue_multidomain_write(q, flags, num_buffers, buffers, message_length, message, timeout_us, true); } pq = &q->header->req_queue; write_state = (struct dspqueue_packet_queue_state*)(((uintptr_t)q->header) + pq->write_state_offset); wait_count = (_Atomic uint32_t*) &write_state->wait_count; 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; struct dspqueue *q = queue; const uint8_t *msg = wakeup_delay ? (const uint8_t *)&wakeup_delay : NULL; uint32_t msg_len = wakeup_delay ? sizeof(wakeup_delay) : 0; if (q->mdq.is_mdq) { // Recursively call 'dspqueue_write_noblock' on individual queues return dspqueue_multidomain_write(q, flags, 0, NULL, msg_len, msg, 0, false); } return dspqueue_write_noblock(queue, flags, 0, NULL, msg_len, msg); } 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; } /* * Read / peek packet from multi-domain queue * * Individual queue of each domain will be read / peeked in a serial * manner. Packet / packet info will be returned from the first queue * where a valid packet is found. * * If multiple domains have written responses to their queues, then client * is expected to call dspqueue_read on the multi-domain queue as many * times to consume all the packets. * * In case of peeking, client is expected to read the packet already * peeked before peeking the next packet. * * If all the individual queues are empty, then no packet is read. */ static int dspqueue_multidomain_read(struct dspqueue *q, 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, bool read, bool block) { int nErr = AEE_SUCCESS; struct dspqueue_multidomain *mdq = NULL; bool locked = false; dspqueue_t cq = NULL; VERIFYC(q, AEE_EBADPARM); mdq = &q->mdq; VERIFYC(mdq->is_mdq, AEE_EINVALIDITEM); if (block && mdq->num_domain_ids > 1) { /* * Blocked read cannot be supported on multi-domain queues because * the read operation is done in a serial manner on the individual * queues of each domain and the first queue with a valid packet * is returned to client. * Say if the first domain's queue does not have any response * packets to consume but the second domain's queue does, then * the read call will just block indefinitely on the first queue * without ever checking the subsequence queues. */ nErr = AEE_EUNSUPPORTED; FARF(ALWAYS, "Error 0x%x: %s: not supported for multi-domain queue %p", nErr, __func__, q); return nErr; } // Only one multi-domain read request at a time. pthread_mutex_lock(&q->mutex); locked = true; // Read packet from individual queues for (unsigned int ii = 0; ii < mdq->num_domain_ids; ii++) { cq = mdq->queues[ii]; if (read) { if (block) { nErr = dspqueue_read(cq, flags, max_buffers, num_buffers, buffers, max_message_length, message_length, message, timeout_us); } else { nErr = dspqueue_read_noblock(cq, flags, max_buffers, num_buffers, buffers, max_message_length, message_length, message); } } else { if (block) { nErr = dspqueue_peek(cq, flags, num_buffers, message_length, timeout_us); } else { nErr = dspqueue_peek_noblock(cq, flags, num_buffers, message_length); } } if (!nErr) { // Packet found in an individual queue break; } else if (nErr == AEE_EWOULDBLOCK) { // If queue is empty, proceed to next queue continue; } else { // If any queue is in bad state, bail out with error goto bail; } } bail: if (locked) pthread_mutex_unlock(&q->mutex); if (nErr && nErr != AEE_EWOULDBLOCK) { FARF(ALWAYS, "Error 0x%x: %s (read %d, block %d): failed for queue %p, max bufs %u, max msg len %u", nErr, __func__, read, block, q, max_buffers, max_message_length); } 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 = NULL; volatile const uint8_t *qp = NULL; uint32_t r, qleft; int locked = 0; if (q->mdq.is_mdq) { // Recursively call 'dspqueue_peek_noblock' on individual queues return dspqueue_multidomain_read(q, flags, 0, num_buffers, NULL, 0, message_length, NULL, 0, false, false); } pq = &q->header->resp_queue; qp = (volatile const uint8_t*) (((uintptr_t)q->header) + pq->queue_offset); 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 = NULL; struct dspqueue_packet_queue_state *read_state = NULL; _Atomic uint32_t *wait_count = NULL; int waiting = 0; struct timespec *timeout_ts = NULL; // no timeout by default struct timespec ts; if (q->mdq.is_mdq) { // Recursively call 'dspqueue_read_noblock' on individual queues return dspqueue_multidomain_read(q, flags, 0, num_buffers, NULL, 0, message_length, NULL, timeout_us, false, true); } pq = &q->header->resp_queue; read_state =(struct dspqueue_packet_queue_state *) (((uintptr_t)q->header) + pq->read_state_offset); wait_count = (_Atomic uint32_t *) &read_state->wait_count; 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 = NULL; struct dspqueue_packet_queue_header *pq = NULL; volatile const uint8_t *qp = NULL; struct dspqueue_packet_queue_state *read_state = NULL; struct dspqueue_packet_queue_state *write_state = NULL; uint32_t r, qleft; uint32_t f, num_b, msg_l, qsize = 0; uint32_t len; int locked = 0; unsigned i; uint32_t buf_refs = 0; uint64_t header; errno = 0; if (q->mdq.is_mdq) { // Recursively call 'dspqueue_read_noblock' on individual queues return dspqueue_multidomain_read(q, flags, max_buffers, num_buffers, buffers, max_message_length, message_length, message, 0, true, false); } dq = queues->domain_queues[q->domain]; pq = &q->header->resp_queue; qp = (volatile const uint8_t *) (((uintptr_t)q->header) + pq->queue_offset); read_state = (struct dspqueue_packet_queue_state *) (((uintptr_t)q->header) + pq->read_state_offset); write_state = (struct dspqueue_packet_queue_state *) (((uintptr_t)q->header) + pq->write_state_offset); qsize = pq->queue_length; 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 = NULL; struct dspqueue_packet_queue_state *read_state = NULL; _Atomic uint32_t *wait_count = NULL; int waiting = 0; struct timespec *timeout_ts = NULL; // no timeout by default struct timespec ts; if (q->mdq.is_mdq) { // Recursively call 'dspqueue_read_noblock' on individual queues return dspqueue_multidomain_read(q, flags, max_buffers, num_buffers, buffers, max_message_length, message_length, message, timeout_us, true, true); } pq = &q->header->resp_queue; read_state = (struct dspqueue_packet_queue_state *) (((uintptr_t)q->header) + pq->read_state_offset); wait_count = (_Atomic uint32_t *) &read_state->wait_count; 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; } /* Get stats of multi-domain queue */ static int dspqueue_multidomain_get_stat(struct dspqueue *q, enum dspqueue_stat stat, uint64_t *value) { int nErr = AEE_SUCCESS; struct dspqueue_multidomain *mdq = NULL; bool locked = false; VERIFYC(q, AEE_EBADPARM); mdq = &q->mdq; VERIFYC(mdq->is_mdq, AEE_EINVALIDITEM); if (mdq->num_domain_ids > 1) { /* Stats requests are not supported for multi-domain queues */ nErr = AEE_EUNSUPPORTED; goto bail; } // Only one multi-domain stats request at a time. pthread_mutex_lock(&q->mutex); locked = true; /* * Always return stats from first queue only as this api is currently * supported for single-domain queues only. */ VERIFY(AEE_SUCCESS == (nErr = dspqueue_get_stat(mdq->queues[0], stat, value))); bail: if (locked) pthread_mutex_unlock(&q->mutex); if (nErr) { FARF(ALWAYS, "Error 0x%x: %s: failed for queue %p, stat %d", nErr, __func__, q, stat); } return nErr; } AEEResult dspqueue_get_stat(dspqueue_t queue, enum dspqueue_stat stat, uint64_t *value) { AEEResult nErr = 0; struct dspqueue *q = queue; if (q->mdq.is_mdq) return dspqueue_multidomain_get_stat(q, stat, value); 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(IS_VALID_EFFECTIVE_DOMAIN_ID(effec_domain_id)); // 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; } fastrpc-1.0.2/src/dspqueue/dspqueue_rpc_stub.c000066400000000000000000000446601512345705400215160ustar00rootroot00000000000000// 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; }; //unsigned char 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_t 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_t id, int32_t queue_fd, uint32_t count, uint64_t* 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_t 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_t queue_id, int32_t* 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_t* 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 fastrpc-1.0.2/src/dsprpcd.c000066400000000000000000000074331512345705400155630ustar00rootroot00000000000000// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. // 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 "fastrpc_common.h" #include #include #include #include #ifndef ADSP_LISTENER_VERSIONED #define ADSP_LISTENER_VERSIONED "libadsp_default_listener.so.1" #define ADSP_LISTENER_UNVERSIONED "libadsp_default_listener.so" #endif #ifndef CDSP_LISTENER_VERSIONED #define CDSP_LISTENER_VERSIONED "libcdsp_default_listener.so.1" #define CDSP_LISTENER_UNVERSIONED "libcdsp_default_listener.so" #endif #ifndef SDSP_LISTENER_VERSIONED #define SDSP_LISTENER_VERSIONED "libsdsp_default_listener.so.1" #define SDSP_LISTENER_UNVERSIONED "libsdsp_default_listener.so" #endif #ifndef GDSP_LISTENER_VERSIONED #define GDSP_LISTENER_VERSIONED "libcdsp_default_listener.so.1" #define GDSP_LISTENER_UNVERSIONED "libcdsp_default_listener.so" #endif typedef int (*dsp_default_listener_start_t)(int argc, char *argv[]); // Result struct for dlopen. struct dlopen_result { void *handle; const char *loaded_lib_name; }; /** * Attempts to load a shared library using dlopen. * If the versioned name fails, falls back to the unversioned name. * Returns both the handle and the name of the library successfully loaded. */ static struct dlopen_result try_dlopen(const char *versioned, const char *unversioned) { struct dlopen_result result = { NULL, NULL }; result.handle = dlopen(versioned, RTLD_NOW); if (result.handle) { result.loaded_lib_name = versioned; return result; } if (unversioned) { VERIFY_IPRINTF("dlopen failed for %s: %s; attempting fallback %s", versioned, dlerror(), unversioned); result.handle = dlopen(unversioned, RTLD_NOW); if (result.handle) { result.loaded_lib_name = unversioned; return result; } } return result; } int main(int argc, char *argv[]) { int nErr = 0; struct dlopen_result dlres = { NULL, NULL }; const char* lib_versioned; const char* lib_unversioned; const char* dsp_name; dsp_default_listener_start_t listener_start; #ifdef USE_ADSP lib_versioned = ADSP_LISTENER_VERSIONED; lib_unversioned = ADSP_LISTENER_UNVERSIONED; dsp_name = "ADSP"; #elif defined(USE_SDSP) lib_versioned = SDSP_LISTENER_VERSIONED; lib_unversioned = SDSP_LISTENER_UNVERSIONED; dsp_name = "SDSP"; #elif defined(USE_CDSP) lib_versioned = CDSP_LISTENER_VERSIONED; lib_unversioned = CDSP_LISTENER_UNVERSIONED; dsp_name = "CDSP"; #elif defined(USE_GDSP) lib_versioned = GDSP_LISTENER_VERSIONED; lib_unversioned = GDSP_LISTENER_UNVERSIONED; dsp_name = "GDSP"; #else goto bail; #endif VERIFY_EPRINTF("%s daemon starting", dsp_name); while (1) { dlres = try_dlopen(lib_versioned, lib_unversioned); if (NULL != dlres.handle) { if (NULL != (listener_start = (dsp_default_listener_start_t)dlsym( dlres.handle, "adsp_default_listener_start"))) { VERIFY_IPRINTF("adsp_default_listener_start called"); nErr = listener_start(argc, argv); } if (0 != dlclose(dlres.handle)) { VERIFY_EPRINTF("dlclose failed for %s", dlres.loaded_lib_name); } } else { VERIFY_EPRINTF("%s daemon error %s", dsp_name, dlerror()); } if (nErr == AEE_ECONNREFUSED) { VERIFY_EPRINTF("fastRPC device is not accessible, daemon exiting..."); break; } VERIFY_EPRINTF("%s daemon will restart after 100ms...", dsp_name); usleep(100000); } bail: VERIFY_EPRINTF("daemon exiting %x", nErr); return nErr; } fastrpc-1.0.2/src/dspsignal.c000066400000000000000000000167151512345705400161130ustar00rootroot00000000000000// 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(IS_VALID_EFFECTIVE_DOMAIN_ID(domain)); // 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(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), 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; VERIFYC(id < DSPSIGNAL_NUM_SIGNALS, AEE_EBADPARM); domain = get_domain(domain); VERIFYC(flags == 0, AEE_EBADPARM); VERIFYC(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), AEE_EBADPARM); VERIFY((nErr = init_domain_signals(domain)) == 0); VERIFYC((ds = (struct dspsignal_domain_signals *)signals->domain_signals[domain]) != NULL, AEE_EBADSTATE); errno = 0; nErr = ioctl_signal_create(ds->dev, id, flags); if (nErr) { if (errno == ENOTTY) { FARF(HIGH, "dspsignal support not present in the FastRPC driver"); nErr = AEE_EUNSUPPORTED; } else { nErr = convert_kernel_to_user_error(nErr, errno); } 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; VERIFYC(id < DSPSIGNAL_NUM_SIGNALS, AEE_EBADPARM); domain = get_domain(domain); VERIFYC(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), AEE_EBADPARM); VERIFYC((ds = (struct dspsignal_domain_signals *)signals->domain_signals[domain]) != NULL, AEE_EBADSTATE); errno = 0; nErr = ioctl_signal_destroy(ds->dev, id); if (nErr) { nErr = convert_kernel_to_user_error(nErr, errno); 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; VERIFYC(id < DSPSIGNAL_NUM_SIGNALS, AEE_EBADPARM); domain = get_domain(domain); VERIFYC(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), AEE_EBADPARM); VERIFYC((ds = (struct dspsignal_domain_signals *)signals->domain_signals[domain]) != NULL, AEE_EBADSTATE); FARF(MEDIUM, "%s: Send signal %u", __func__, id); errno = 0; nErr = ioctl_signal_signal(ds->dev, id); if (nErr) { nErr = convert_kernel_to_user_error(nErr, errno); 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; VERIFYC(id < DSPSIGNAL_NUM_SIGNALS, AEE_EBADPARM); domain = get_domain(domain); VERIFYC(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), AEE_EBADPARM); VERIFYC((ds = (struct dspsignal_domain_signals *)signals->domain_signals[domain]) != NULL, AEE_EBADSTATE); fastrpc_qos_activity(domain); FARF(MEDIUM, "%s: Wait signal %u timeout %u", __func__, id, timeout_usec); errno = 0; nErr = ioctl_signal_wait(ds->dev, id, timeout_usec); if (nErr) { if (errno == ETIMEDOUT) { FARF(MEDIUM, "%s: Signal %u timed out", __func__, id); return AEE_EEXPIRED; } else if (errno == EINTR) { FARF(MEDIUM, "%s: Signal %u canceled", __func__, id); return AEE_EINTERRUPTED; } else { nErr = convert_kernel_to_user_error(nErr, errno); 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; VERIFYC(id < DSPSIGNAL_NUM_SIGNALS, AEE_EBADPARM); domain = get_domain(domain); VERIFYC(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), AEE_EBADPARM); VERIFYC((ds = (struct dspsignal_domain_signals *)signals->domain_signals[domain]) != NULL, AEE_EBADSTATE); FARF(MEDIUM, "%s: Cancel wait signal %u", __func__, id); errno = 0; nErr = ioctl_signal_cancel_wait(ds->dev, id); if (nErr) { nErr = convert_kernel_to_user_error(nErr, errno); 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; } fastrpc-1.0.2/src/fastrpc_apps_user.c000066400000000000000000004443051512345705400176520ustar00rootroot00000000000000// 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 #define _GNU_SOURCE #ifndef VERIFY_PRINT_WARN #define VERIFY_PRINT_WARN #endif // VERIFY_PRINT_WARN #ifndef VERIFY_PRINT_ERROR_ALWAYS #define VERIFY_PRINT_ERROR_ALWAYS #endif // VERIFY_PRINT_ERROR_ALWAYS #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 "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" #include "fastrpc_context.h" #include "fastrpc_process_attributes.h" #include "fastrpc_trace.h" #include "fastrpc_config_parser.h" #define VENDOR_DSP_LOCATION "/vendor/dsp/" #define VENDOR_DOM_LOCATION "/vendor/dsp/xdsp/" char DSP_LIBS_LOCATION[PATH_MAX] = DEFAULT_DSP_SEARCH_PATHS; #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", "libcdsprpc.so", "libcdsprpc.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) { int ii = 0; FOR_EACH_DOMAIN_ID(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", "cdsp1", "gdsp0", "gdsp1", "reserved"}; /* 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; char *name; }; // 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; pid_t tid; } 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}; static int domain_init(int domain, int *dev); static void domain_deinit(int domain); static int close_device_node(int domain_id, int dev); extern int apps_mem_table_init(void); extern void apps_mem_table_deinit(void); static uint32_t crc_table[256]; static atomic_bool timer_expired = false; void set_thread_context(int domain) { if (tlsKey != INVALID_KEY) { pthread_setspecific(tlsKey, (void *)&hlist[domain]); } } int get_device_fd(int domain) { if (hlist && (hlist[domain].dev != -1)) { return hlist[domain].dev; } else { return -1; } } int fastrpc_session_open(int domain, int *dev) { int device = -1; if (IS_SESSION_OPEN_ALREADY(domain)) { *dev = hlist[domain].dev; return 0; } device = open_device_node(domain); if (device >= 0) { *dev = device; return 0; } return AEE_ECONNREFUSED; } void fastrpc_session_close(int domain, int dev) { if (!hlist) return; if ((hlist[domain].dev == INVALID_DEVICE) && (dev != INVALID_DEVICE)) { close(dev); } else if ((hlist[domain].dev != INVALID_DEVICE) && (dev == INVALID_DEVICE)) { close(hlist[domain].dev); hlist[domain].dev = INVALID_DEVICE; } return; } 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 (!IS_VALID_EFFECTIVE_DOMAIN_ID(domain)) 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; } 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) { strncpy(value, env, PROPERTY_VALUE_MAX - 1); value[PROPERTY_VALUE_MAX - 1] = '\0'; return strlen(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 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) { strncpy(value, defValue, PROPERTY_VALUE_MAX - 1); value[PROPERTY_VALUE_MAX - 1] = '\0'; return strlen(defValue); } 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, _const_remotectl1_handle, NULL, 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_EACH_EFFECTIVE_DOMAIN_ID(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(IS_VALID_EFFECTIVE_DOMAIN_ID(dom), 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 < 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 (!strncmp(domain_name, SUBSYSTEM_NAME[ADSP_DOMAIN_ID], strlen(SUBSYSTEM_NAME[ADSP_DOMAIN_ID]))) { domain = ADSP_DOMAIN_ID; } else if (!strncmp(domain_name, SUBSYSTEM_NAME[MDSP_DOMAIN_ID], strlen(SUBSYSTEM_NAME[MDSP_DOMAIN_ID]))) { domain = MDSP_DOMAIN_ID; } else if (!strncmp(domain_name, SUBSYSTEM_NAME[SDSP_DOMAIN_ID], strlen(SUBSYSTEM_NAME[SDSP_DOMAIN_ID]))) { domain = SDSP_DOMAIN_ID; } else if (!strncmp(domain_name, SUBSYSTEM_NAME[CDSP1_DOMAIN_ID], strlen(SUBSYSTEM_NAME[CDSP1_DOMAIN_ID]))) { domain = CDSP1_DOMAIN_ID; } else if (!strncmp(domain_name, SUBSYSTEM_NAME[CDSP_DOMAIN_ID], strlen(SUBSYSTEM_NAME[CDSP_DOMAIN_ID]))) { domain = CDSP_DOMAIN_ID; } else if (!strncmp(domain_name, SUBSYSTEM_NAME[GDSP0_DOMAIN_ID], strlen(SUBSYSTEM_NAME[GDSP0_DOMAIN_ID]))) { domain = GDSP0_DOMAIN_ID; } else if (!strncmp(domain_name, SUBSYSTEM_NAME[GDSP1_DOMAIN_ID], strlen(SUBSYSTEM_NAME[GDSP1_DOMAIN_ID]))) { domain = GDSP1_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 CDSP1_DOMAIN_ID: uri_domain_suffix = CDSP1_DOMAIN; break; case MDSP_DOMAIN_ID: uri_domain_suffix = MDSP_DOMAIN; break; case SDSP_DOMAIN_ID: uri_domain_suffix = SDSP_DOMAIN; break; case GDSP0_DOMAIN_ID: uri_domain_suffix = GDSP0_DOMAIN; break; case GDSP1_DOMAIN_ID: uri_domain_suffix = GDSP1_DOMAIN; break; default: uri_domain_suffix = "invalid domain"; break; } return uri_domain_suffix; } #define IS_CONST_HANDLE(h) (((h) < 0xff) ? 1 : 0) 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; } /** * print_open_handles() - Function to print all open handles. * @domain: domain of handles to be printed. * Return: void. */ static void print_open_handles(int domain) { struct handle_info *hi = NULL; QNode *pn = NULL; FARF(RUNTIME_RPC_HIGH, "List of open handles on domain %d:\n", domain); pthread_mutex_lock(&hlist[domain].mut); QLIST_FOR_ALL(&hlist[domain].ql, pn) { hi = STD_RECOVER_REC(struct handle_info, qn, pn); if (hi->name) FARF(RUNTIME_RPC_HIGH, "%s, handle 0x%"PRIx64"", hi->name, hi->remote); } pthread_mutex_unlock(&hlist[domain].mut); } /** * get_lib_name() - Function to get lib name from uri. * @uri: uri for the lib. * Return: @lib_name or NULL */ static char* get_lib_name(const char *uri) { char *library_name = NULL; const char SO_EXTN[] = ".so"; const char LIB_EXTN[] = "lib"; const char *start = NULL, *end = NULL; unsigned int length = 0; int nErr = AEE_SUCCESS; VERIFY(uri); start = strstr(uri, LIB_EXTN); if (start) { end = strstr(start, SO_EXTN); if (end && end > start) { /* add extension size to print .so also */ length = (unsigned int)(end - start) + strlen(SO_EXTN); /* allocate length + 1 to include \0 */ VERIFYC(NULL != (library_name = (char*)calloc(1, length + 1)), AEE_ENOMEMORY); strlcpy(library_name, start, length + 1); return library_name; } } bail: FARF(RUNTIME_RPC_ERROR, "Warning 0x%x: %s failed for uri %s", nErr, __func__, uri); return NULL; } static int fastrpc_alloc_handle(int domain, QList *me, remote_handle64 remote, remote_handle64 *local, const char *name) { struct handle_info *hinfo = {0}; int nErr = 0; char *libname = NULL; VERIFYC(NULL != (hinfo = calloc(1, sizeof(*hinfo))), AEE_ENOMEMORY); hinfo->local = (remote_handle64)(uintptr_t)hinfo; hinfo->remote = remote; libname = get_lib_name(name); hinfo->name = libname; 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); if(hi->name) free(hi->name); 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, const char *name) { int nErr = AEE_SUCCESS; switch (req) { case DOMAIN_LIST_PREPEND: { VERIFY(AEE_SUCCESS == (nErr = fastrpc_alloc_handle(domain, &hlist[domain].ql, h, local, name))); 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, name))); 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, name))); 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; bool expected = false; atomic_compare_exchange_strong(&timer_expired, &expected, true); if (expected == true) return; FARF(ALWAYS, "%s fastrpc time out of %d ms on thread %d on domain %d sc 0x%x handle 0x%x\n", __func__, frpc_timer->timeout_millis, frpc_timer->tid, 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; struct fastrpc_invoke_args* args = NULL; 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 == 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; frpc_timer.tid = gettid(); 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); 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; } /* * handle_info or so name cannot be obtained from remote handles which * are used for non-domain calls. */ 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; struct handle_info *h = (struct handle_info*)local; if (IS_STATICPD_HANDLE(local)) { nErr = AEE_EINVHANDLE; FARF(ERROR, "Error 0x%x: %s cannot be called for staticPD handle 0x%"PRIx64"\n", nErr, __func__, local); goto bail; } 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 module %s, handle 0x%" PRIx64 ", method %d on domain %d (sc 0x%x) (errno %s)\n", nErr, __func__, h->name, local, REMOTE_SCALARS_METHOD(sc), domain, sc, strerror(errno)); } } } 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); 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 (!strncmp(name, ITRANSPORT_PREFIX "geteventfd", strlen(ITRANSPORT_PREFIX "geteventfd"))) { FARF(RUNTIME_RPC_HIGH, "getting event fd"); return listener_android_geteventfd(domain, (int *)ph); } if (!strncmp(name, ITRANSPORT_PREFIX "attachguestos", strlen(ITRANSPORT_PREFIX "attachguestos"))) { FARF(RUNTIME_RPC_HIGH, "setting attach mode to guestos : %d", domain); *ph = ATTACHGUESTOS_HANDLE; hlist[domain].dsppd = ROOT_PD; return AEE_SUCCESS; } if (!strncmp(name, ITRANSPORT_PREFIX "createstaticpd", 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); strlcpy(pdname_uri, name, name_len + 1); char *pdName = pdname_uri + 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 (strstr(pdName, get_domain_from_id(GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain))) && strstr(pdName, FASTRPC_SESSION_URI)) { strlcpy(pdName, pdName, (strlen(pdName) - strlen(get_domain_from_id(GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain))) - strlen(FASTRPC_SESSION1_URI) + 1)); } else if (strstr(pdName, get_domain_from_id(domain))) { strlcpy( pdName, pdName, (strlen(pdName) - strlen(get_domain_from_id(domain)) + 1)); } VERIFYC(MAX_DSPPD_NAMELEN > strlen(pdName), AEE_EBADPARM); strlcpy(hlist[domain].dsppdname, pdName, strlen(pdName) + 1); if (!strncmp(pdName, "audiopd", strlen("audiopd"))) { *ph = AUDIOPD_HANDLE; hlist[domain].dsppd = AUDIO_STATICPD; } else if (!strncmp(pdName, "securepd", strlen("securepd"))) { FARF(ALWAYS, "%s: attaching to securePD\n", __func__); *ph = SECUREPD_HANDLE; hlist[domain].dsppd = SECURE_STATICPD; } else if (!strncmp(pdName, "sensorspd", strlen("sensorspd"))) { *ph = SENSORPD_HANDLE; hlist[domain].dsppd = SENSORS_STATICPD; } else if (!strncmp(pdName, "rootpd", strlen("rootpd"))) { *ph = ROOTPD_HANDLE; hlist[domain].dsppd = GUEST_OS_SHARED; } else if (!strncmp(pdName, "oispd", strlen("oispd"))) { *ph = OISPD_HANDLE; hlist[domain].dsppd = OIS_STATICPD; } return AEE_SUCCESS; } if (!strncmp(name, ITRANSPORT_PREFIX "attachuserpd", strlen(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, _const_remotectl1_handle, NULL, 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 (!hlist[domain].domainsCount && !hlist[domain].nondomainsCount) { /* Close session if there are no open remote handles */ 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); 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, name); 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); 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 (!strncmp(name, ITRANSPORT_PREFIX "geteventfd", strlen(ITRANSPORT_PREFIX "geteventfd")) || IS_STATICPD_HANDLE(h)) { *ph = h; } else { fastrpc_update_module_list(DOMAIN_LIST_PREPEND, domain, h, &local, name); get_handle_remote(local, &remote); *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].domainsCount); } 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) { nErr = remotectl1_close1(handle, h, dlerrstr, err_str_len, &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, _const_remotectl1_handle, NULL, NULL); // Set remotectlhandle to INVALID_HANDLE, so that all subsequent calls // are non-domain calls hlist[domain].remotectlhandle = INVALID_HANDLE; nErr = remotectl_close(h, dlerrstr, err_str_len, &dlerr); } else if (nErr) goto bail; } 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(RUNTIME_RPC_HIGH, "%s: closed module with handle 0x%x (skel unload time %" PRIu64 " us)", __func__, h, t_close); } if (dlerrstr) { free(dlerrstr); dlerrstr = NULL; } if (domain != -1) print_open_handles(domain); 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); 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, NULL); bail: if (nErr != AEE_SUCCESS) { if (is_process_exiting(domain)) { return 0; } /* * handle_info or so name cannot be obtained from remote handles which * are used for non-domain calls. */ 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; bool start_deinit = false; struct handle_info *hi = (struct handle_info*)handle; if (IS_STATICPD_HANDLE(handle)) return AEE_SUCCESS; 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); /* * Terminate remote session if * 1. there are no open non-domain handles AND * 2. there are no open multi-domain handles, OR * only 1 multi-domain handle is open (for perf reason, * skip closing of it) */ if (hlist[domain].domainsCount <= 1 && !hlist[domain].nondomainsCount) start_deinit = true; /* * If session termination is not initiated and the remote handle is valid, * then close the remote handle on DSP. */ if (!start_deinit && remote) { VERIFY(AEE_SUCCESS == (nErr = remote_handle_close_domain(domain, (remote_handle)remote))); } FARF(ALWAYS, "%s: closed module %s with handle 0x%" PRIx64 " remote handle 0x%" PRIx64 ", num of open handles: %u", __func__, hi->name, handle, remote, hlist[domain].domainsCount - 1); fastrpc_update_module_list(DOMAIN_LIST_DEQUEUE, domain, handle, NULL, NULL); FASTRPC_PUT_REF(domain); bail: if (nErr != AEE_EINVHANDLE && IS_VALID_EFFECTIVE_DOMAIN_ID(domain)) { if (start_deinit) { hlist[domain].disable_exit_logs = 1; domain_deinit(domain); } if (nErr != AEE_SUCCESS) { if (is_process_exiting(domain)) return 0; if (0 == check_rpc_error(nErr)) FARF(ERROR, "Error 0x%x: %s close module %s failed for handle 0x%" PRIx64 " remote handle 0x%" PRIx64 " (errno %s), num of open handles: %u\n", nErr, __func__, hi->name, handle, remote, strerror(errno), hlist[domain].domainsCount); } } 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, _const_remotectl1_handle, NULL, 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 (IS_VALID_EFFECTIVE_DOMAIN_ID(domain) && hlist) { fastrpc_latency_invoke_incr(&hlist[domain].qos); } } static inline int enable_process_state_notif_on_dsp(int domain) { int nErr = AEE_SUCCESS; remote_handle64 notif_handle = 0; 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(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), AEE_EBADPARM); VERIFY(AEE_SUCCESS == (nErr = domain_init(domain, &dev))); VERIFYM(-1 != dev, AEE_ERPC, "open dev failed\n"); if (IS_KERNEL_PERF_ENABLED(hlist[domain].procattrs)) { perf_kernel = (uint64_t *)calloc(PERF_KERNEL_KEY_MAX, sizeof(uint64_t)); VERIFYC(perf_kernel != NULL, AEE_ENOMEMORY); } if (IS_DSP_PERF_ENABLED(hlist[domain].procattrs)) { perf_dsp = (uint64_t *)calloc(PERF_DSP_KEY_MAX, sizeof(uint64_t)); VERIFYC(perf_dsp != NULL, AEE_ENOMEMORY); } nErr = ioctl_invoke2_response(dev, &job, &handle, &sc, &res, perf_kernel, perf_dsp); if (IS_KERNEL_PERF_ENABLED(hlist[domain].procattrs) && (!IS_STATIC_HANDLE(handle))) { VERIFYC(perf_kernel != NULL, AEE_ENOMEMORY); FARF(ALWAYS, "RPCPERF-K H:0x%x SC:0x%x C:%" PRIu64 " F:%" PRIu64 " ns M:%" PRIu64 " ns CP:%" PRIu64 " ns L:%" PRIu64 " ns G:%" PRIu64 " ns P:%" PRIu64 " ns INV:%" PRIu64 " ns INVOKE:%" PRIu64 " ns\n", handle, sc, perf_kernel[0], perf_kernel[1], perf_kernel[2], perf_kernel[3], perf_kernel[4], perf_kernel[5], perf_kernel[6], perf_kernel[7], perf_kernel[8]); } if (IS_DSP_PERF_ENABLED(hlist[domain].procattrs) && (!IS_STATIC_HANDLE(handle))) { VERIFYC(perf_dsp != NULL, AEE_ENOMEMORY); FARF(ALWAYS, "RPCPERF-D H:0x%x SC:0x%x C:%" PRIu64 " M_H:%" PRIu64 " us M:%" PRIu64 " us G:%" PRIu64 " us INVOKE:%" PRIu64 " us P:%" PRIu64 " us CACHE:%" PRIu64 " us UM:%" PRIu64 " us " "UM_H:%" PRIu64 " us R:%" PRIu64 " us E_R:%" PRIu64 " us J_S_T:%" PRIu64 " us\n", handle, sc, perf_dsp[0], perf_dsp[1], perf_dsp[2], perf_dsp[3], perf_dsp[4], perf_dsp[5], perf_dsp[6], perf_dsp[7], perf_dsp[8], perf_dsp[9], perf_dsp[10], perf_dsp[11]); } *jobid = job; *result = res; bail: if (perf_kernel) { free(perf_kernel); perf_kernel = NULL; } if (perf_dsp) { free(perf_dsp); perf_dsp = NULL; } if (nErr) { FARF(ERROR, "Error 0x%x: %s failed to get async response data for domain %d errno " "%s", nErr, __func__, domain, strerror(errno)); } return nErr; } /* fastrpc_set_qos_latency: Send user QoS latency requirement to DSP. DSP will use required features to meet the requirement. 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 || nErr == AEE_EUNSUPPORTED) { VERIFY_WPRINTF( "Warning: %s: kernel does not support wakelock management (%s)", __func__, strerror(errno)); fastrpc_wake_lock_enable[domain] = 0; fastrpc_wake_lock_deinit(); 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(IS_VALID_EFFECTIVE_DOMAIN_ID(cap->domain), 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); 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_t domain, int *unsigned_module) { int nErr = AEE_SUCCESS; VERIFYC(hlist, AEE_EBADPARM); VERIFYC(unsigned_module, AEE_EBADPARM); VERIFYC(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), 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(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), 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(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), 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(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), 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, ii = 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 (!IS_VALID_EFFECTIVE_DOMAIN_ID(params->domain)) { 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_EACH_EFFECTIVE_DOMAIN_ID(ii) { VERIFY(AEE_SUCCESS == (nErr = store_domain_thread_params( ii, 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(IS_VALID_EFFECTIVE_DOMAIN_ID(um->domain), AEE_EBADPARM); VERIFY(AEE_SUCCESS == (nErr = set_unsigned_pd_attribute(um->domain, um->enable))); } else { FOR_EACH_EFFECTIVE_DOMAIN_ID(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(IS_VALID_EFFECTIVE_DOMAIN_ID(params->domain), AEE_EBADPARM); VERIFY(AEE_SUCCESS == (nErr = store_domain_thread_params( params->domain, thread_priority, -1))); } else { FOR_EACH_EFFECTIVE_DOMAIN_ID(ii) { VERIFY(AEE_SUCCESS == (nErr = store_domain_thread_params(ii, 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(IS_VALID_EFFECTIVE_DOMAIN_ID(sclose->domain), AEE_EBADPARM); VERIFY(AEE_SUCCESS == (nErr = close_domain_session(sclose->domain))); } else { FOR_EACH_EFFECTIVE_DOMAIN_ID(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_EACH_EFFECTIVE_DOMAIN_ID(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(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), 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(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), 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(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), 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_EACH_EFFECTIVE_DOMAIN_ID(ii) { VERIFYC(is_status_notif_version2_supported(ii), AEE_EUNSUPPORTED); VERIFY(AEE_SUCCESS == (nErr = fastrpc_notif_register(ii, notif))); } } FARF(RUNTIME_RPC_HIGH, "%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 (!IS_VALID_EFFECTIVE_DOMAIN_ID(params->domain)) { 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_EACH_EFFECTIVE_DOMAIN_ID(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(IS_VALID_DOMAIN_ID(domain), 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; 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 (IS_VALID_EFFECTIVE_DOMAIN_ID(ii)); VERIFYC(IS_VALID_EFFECTIVE_DOMAIN_ID(sess->effective_domain_id), 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(IS_VALID_DOMAIN_ID(domain), AEE_EBADPARM); effec_domain_id->effective_domain_id = GET_EFFECTIVE_DOMAIN_ID(domain, effec_domain_id->session_id); VERIFYC(IS_VALID_EFFECTIVE_DOMAIN_ID(effec_domain_id->effective_domain_id), 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(IS_VALID_DOMAIN_ID(domain), 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; } case FASTRPC_CONTEXT_CREATE: VERIFYC(datalen == sizeof(fastrpc_context_create) && data, AEE_EBADPARM); VERIFY(AEE_SUCCESS == (nErr = fastrpc_create_context(data))); break; case FASTRPC_CONTEXT_DESTROY: { fastrpc_context_destroy *dest = (fastrpc_context_destroy *)data; VERIFYC(datalen == sizeof(fastrpc_context_destroy) && dest && !dest->flags, AEE_EBADPARM); VERIFY(AEE_SUCCESS == (nErr = fastrpc_destroy_context(dest->ctx))); 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 (!strncmp(uri, ADSP_DOMAIN_NAME, strlen(ADSP_DOMAIN_NAME))) { domain = ADSP_DOMAIN_ID; } else if (!strncmp(uri, MDSP_DOMAIN_NAME, strlen(MDSP_DOMAIN_NAME))) { domain = MDSP_DOMAIN_ID; } else if (!strncmp(uri, SDSP_DOMAIN_NAME, strlen(SDSP_DOMAIN_NAME))) { domain = SDSP_DOMAIN_ID; } else if (!strncmp(uri, CDSP1_DOMAIN_NAME, strlen(CDSP1_DOMAIN_NAME))) { domain = CDSP1_DOMAIN_ID; } else if (!strncmp(uri, CDSP_DOMAIN_NAME, strlen(CDSP_DOMAIN_NAME))) { domain = CDSP_DOMAIN_ID; } else if (!strncmp(uri, GDSP0_DOMAIN_NAME, strlen(GDSP0_DOMAIN_NAME))) { domain = GDSP0_DOMAIN_ID; } else if (!strncmp(uri, GDSP1_DOMAIN_NAME, strlen(GDSP1_DOMAIN_NAME))) { domain = GDSP1_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 (strstr(uri, ADSP_DOMAIN)) { domain = ADSP_DOMAIN_ID; } else if (strstr(uri, MDSP_DOMAIN)) { domain = MDSP_DOMAIN_ID; } else if (strstr(uri, SDSP_DOMAIN)) { domain = SDSP_DOMAIN_ID; } else if (strstr(uri, CDSP1_DOMAIN)) { domain = CDSP1_DOMAIN_ID; } else if (strstr(uri, CDSP_DOMAIN)) { domain = CDSP_DOMAIN_ID; } else if (strstr(uri, GDSP0_DOMAIN)) { domain = GDSP0_DOMAIN_ID; } else if (strstr(uri, GDSP1_DOMAIN)) { domain = GDSP1_DOMAIN_ID; } else { domain = INVALID_DOMAIN_ID; FARF(ERROR, "Invalid domain name: %s\n", uri); goto bail; } if (NULL != (session_uri = strstr(uri, FASTRPC_SESSION_URI))) { session_uri = session_uri + 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 fastrpc_get_pd_type(int domain) { if (hlist && (hlist[domain].dev != -1)) { return hlist[domain].dsppd; } else { return -1; } } 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 (!IS_VALID_EFFECTIVE_DOMAIN_ID(domain)) { // 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(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), 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_EACH_EFFECTIVE_DOMAIN_ID(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 (GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain)) { case MDSP_DOMAIN_ID: case ADSP_DOMAIN_ID: case CDSP_DOMAIN_ID: case SDSP_DOMAIN_ID: case CDSP1_DOMAIN_ID: case GDSP0_DOMAIN_ID: case GDSP1_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(RUNTIME_RPC_HIGH, "%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].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(RUNTIME_RPC_HIGH, "%s: closed device %d on domain %d (kill time %" PRIu64 " us)", __func__, olddev, domain, t_kill); FARF(ALWAYS, "%s done for domain %d.", __func__, domain); FASTRPC_ATRACE_END(); } 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 = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain_id); 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; case CDSP1_DOMAIN_ID: name = CDSP1RPC_DEVICE; break; case GDSP0_DOMAIN_ID: name = GDSP0RPC_DEVICE; break; case GDSP1_DOMAIN_ID: name = GDSP1RPC_DEVICE; break; default: name = DEFAULT_DEVICE; break; } return name; } int open_device_node(int domain_id) { int dev = -1, nErr = 0; int domain = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain_id); int sess_id = GET_SESSION_ID_FROM_DOMAIN_ID(domain_id); switch (domain) { case ADSP_DOMAIN_ID: case SDSP_DOMAIN_ID: case MDSP_DOMAIN_ID: dev = open(get_secure_domain_name(domain), O_NONBLOCK); if ((dev < 0) && (errno == ENOENT)) { FARF(RUNTIME_RPC_HIGH, "Device node %s open failed for domain %d (errno %s)," "falling back to node %s \n", get_secure_domain_name(domain), domain, strerror(errno), get_domain_name(domain)); dev = open(get_domain_name(domain), O_NONBLOCK); if ((dev < 0) && (errno == ENOENT)) { FARF(RUNTIME_RPC_HIGH, "Device node %s open failed for domain %d (errno %s)," "falling back to node %s \n", get_domain_name(domain), domain, strerror(errno), DEFAULT_DEVICE); dev = open(DEFAULT_DEVICE, O_NONBLOCK); } } else if ((dev < 0) && (errno == EACCES)) { // Open the default device node if unable to open the // secure device node due to permissions FARF(RUNTIME_RPC_HIGH, "Device node %s open failed for domain %d (errno %s)," "falling back to node %s \n", get_secure_domain_name(domain), domain, strerror(errno), DEFAULT_DEVICE); dev = open(DEFAULT_DEVICE, O_NONBLOCK); } break; case CDSP_DOMAIN_ID: case CDSP1_DOMAIN_ID: case GDSP0_DOMAIN_ID: case GDSP1_DOMAIN_ID: 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); } } 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) (Either the remote processor is down, or " "application does not have permission to access the remote " "processor\n", nErr, __func__, domain_id, sess_id, get_secure_domain_name(domain), get_domain_name(domain), errno, strerror(errno)); return dev; } static int close_device_node(int domain_id, int dev) { int nErr = 0; nErr = close(dev); FARF(ALWAYS, "%s: closed dev %d on domain %d", __func__, dev, domain_id); 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_t *ptrlen) { int nErr = 0; uint64_t 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; } 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; char dir_list[PATH_MAX] = {0}; uint16_t shell_absNameLen = 0, absNameLen = 0; int nErr = AEE_SUCCESS; int domain = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain_id); 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 = strlen(shell_name) + strlen(domain_str) + 1; VERIFYC(NULL != (shell_absName = (char *)malloc(sizeof(char) * shell_absNameLen)), AEE_ENOMEMORY); strlcpy(shell_absName, shell_name, shell_absNameLen); strlcat(shell_absName, domain_str, shell_absNameLen); strlcpy(dir_list, DSP_LIBS_LOCATION, sizeof(dir_list)); nErr = fopen_from_dirlist(dir_list, ";", "r", shell_absName, fh); if (nErr) { absNameLen = strlen(VENDOR_DSP_LOCATION) + shell_absNameLen + 1; VERIFYC(NULL != (absName = (char *)realloc(absName, sizeof(char) * absNameLen)), AEE_ENOMEMORY); strlcpy(absName, VENDOR_DSP_LOCATION, absNameLen); strlcat(absName, shell_absName, absNameLen); nErr = apps_std_fopen(absName, "r", fh); if (nErr) { absNameLen = strlen(VENDOR_DOM_LOCATION) + shell_absNameLen + 1; VERIFYC(NULL != (absName = (char *)realloc(absName, sizeof(char) * absNameLen)), AEE_ENOMEMORY); strlcpy(absName, VENDOR_DSP_LOCATION, absNameLen); strlcat(absName, SUBSYSTEM_NAME[domain], absNameLen); strlcat(absName, "/", absNameLen); strlcat(absName, shell_absName, absNameLen); nErr = apps_std_fopen(absName, "r", fh); } } if (!nErr) FARF(RUNTIME_RPC_HIGH, "Successfully opened %s, domain %d", shell_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 " "(errno %s)\n", nErr, __func__, domain, DSP_LIBS_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 = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain); const uint32_t max_concurrency = 25; if (((dom != CDSP_DOMAIN_ID) && (dom != CDSP1_DOMAIN_ID) && (dom != GDSP0_DOMAIN_ID) && (dom != GDSP1_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(RUNTIME_RPC_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, "Info: 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 = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain); int shared_buf_support = 0; char *file = NULL; int flags = 0, filelen = 0, memlen = 0, filefd = -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); VERIFYC(dev >= 0, AEE_ECONNREFUSED); // 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 (IS_EXTENDED_DOMAIN_ID(domain)) 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)(strlen(hlist[domain].dsppdname) + 1)); VERIFYC(file, AEE_ENOMEMORY); strlcpy((char *)file, hlist[domain].dsppdname, strlen(hlist[domain].dsppdname) + 1); filelen = strlen(hlist[domain].dsppdname) + 1; } flags = FASTRPC_INIT_ATTACH; ioErr = ioctl_init(dev, flags, 0, (unsigned char *)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)(strlen(hlist[domain].dsppdname) + 1)); VERIFYC(file, AEE_ENORPCMEMORY); strlcpy((char *)file, hlist[domain].dsppdname, strlen(hlist[domain].dsppdname) + 1); filelen = strlen(hlist[domain].dsppdname) + 1; flags = FASTRPC_INIT_CREATE_STATIC; // 3MB of remote heap for dynamic loading is available only for Audio PD. if (pd_type == AUDIO_STATICPD) { memlen = 3 * 1024 * 1024; } ioErr = ioctl_init(dev, flags, 0, (unsigned char *)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, (unsigned char *)0, 0, -1, 0, 0, 0, 0); VERIFYC((!ioErr || errno == ENOTTY || errno == ENXIO || errno == EINVAL), AEE_ERPC); } else if (pd_type == USERPD) { uint64_t len = 0; int readlen = 0, eof; apps_std_FILE fsig = -1; uint64_t 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, (unsigned char *)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 (!(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, (unsigned char *)(file + len), siglen, &readlen, &eof))); VERIFYC(siglen == (uint64_t)readlen, AEE_EFILE); filelen = len + siglen; } } ioErr = ioctl_init(dev, flags, hlist[domain].procattrs, (unsigned char *)file, filelen, filefd, NULL, memlen, -1, 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].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 (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(RUNTIME_RPC_HIGH, "%s: unloading library %s", __func__, fastrpc_library[DEFAULT_DOMAIN_ID]); FOR_EACH_EFFECTIVE_DOMAIN_ID(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, NULL))); 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, NULL))); 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, NULL))); 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, NULL))); 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, NULL))); 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 = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain); 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 || dom == CDSP1_DOMAIN_ID || dom == GDSP0_DOMAIN_ID || dom == GDSP1_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); } 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))); 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 } } 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_clear_handle_list(NON_DOMAIN_HANDLE_LIST_ID, DEFAULT_DOMAIN_ID); if (hlist) { FOR_EACH_EFFECTIVE_DOMAIN_ID(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_context_table_deinit(); deinit_process_signals(); fastrpc_notif_deinit(); apps_mem_table_deinit(); 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]); } FOR_EACH_EFFECTIVE_DOMAIN_ID(domain) { if (hlist[domain].dev != -1) { if ((handle = get_adsp_current_process1_handle(domain)) != INVALID_HANDLE) { nErr = adsp_current_process1_thread_exit(handle); if (nErr) { FARF(RUNTIME_RPC_HIGH, "%s: nErr:0x%x, dom:%d, h:0x%llx", __func__, nErr, domain, handle); } } else if (domain == DEFAULT_DOMAIN_ID) { nErr = adsp_current_process_thread_exit(); if (nErr) { FARF(RUNTIME_RPC_HIGH, "%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); } const char* get_dsp_search_path() { return DSP_LIBS_LOCATION; } /* * 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))); VERIFY(AEE_SUCCESS == (nErr = pthread_key_create(&tlsKey, exit_thread))); #ifdef PARSE_YAML configure_dsp_paths(); #endif fastrpc_mem_init(); fastrpc_context_table_init(); fastrpc_log_init(); fastrpc_config_init(); pthread_mutex_init(&update_notif_list_mut, 0); VERIFYC(NULL != (hlist = calloc(NUM_DOMAINS_EXTEND, sizeof(*hlist))), AEE_ENOMEMORY); FOR_EACH_EFFECTIVE_DOMAIN_ID(i) { hlist[i].dev = -1; hlist[i].th_params.thread_priority = DEFAULT_UTHREAD_PRIORITY; hlist[i].jobid = 1; hlist[i].info = -1; hlist[i].th_params.stack_size = DEFAULT_UTHREAD_STACK_SIZE; sem_init(&hlist[i].th_params.r_sem, 0, 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 = PL_INIT(apps_std))); GenCrc32Tab(POLY32, crc_table); fastrpc_notif_init(); apps_mem_table_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, ii = 0; 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_EACH_DOMAIN_ID(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", "FASTRPC_CDSP1_REFCNT", "FASTRPC_GDSP0_REFCNT", "FASTRPC_GDSP1_REFCNT"}; char buf[64] = {0}; size_t env_name_len = 0; char *env_name = NULL; int ii = 0; pid_t pid = getpid(); /* Initialize all global array with env variable names along with process id. */ FOR_EACH_DOMAIN_ID(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) { 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); fastrpc-1.0.2/src/fastrpc_async.c000066400000000000000000000375161512345705400167700ustar00rootroot00000000000000// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause #ifndef VERIFY_PRINT_ERROR #define VERIFY_PRINT_ERROR #endif /* VERIFY_PRINT_ERROR */ #define FARF_ERROR 1 #include #include #include #include #include #include #include #include #include #include #include #include #include "AEEQList.h" #include "AEEStdErr.h" #include "AEEstd.h" #include "HAP_farf.h" #include "fastrpc_perf.h" #include "fastrpc_common.h" #include "fastrpc_async.h" #include "platform_libs.h" #include "verify.h" #define GET_DOMAIN_FROM_JOBID(jobid) (jobid & FASTRPC_ASYNC_DOMAIN_MASK) #define GET_HASH_FROM_JOBID(jobid) \ ((jobid & FASTRPC_ASYNC_HASH_MASK) >> FASTRPC_ASYNC_JOB_POS) #define EVENT_COMPLETE 0xff struct fastrpc_async { QList ql[FASTRPC_ASYNC_QUEUE_LIST_LEN]; pthread_mutex_t mut; pthread_t thread; int init_done; int deinit_started; }; struct fastrpc_async_job_node { QNode qn; fastrpc_async_descriptor_t async_desc; bool isjobdone; struct pollfd pfd; int result; }; pthread_mutex_t async_mut = PTHREAD_MUTEX_INITIALIZER; static struct fastrpc_async lasyncinfo[NUM_DOMAINS_EXTEND]; extern void set_thread_context(int domain); static int get_remote_async_response(int domain, fastrpc_async_jobid *jobid, int *result); int fastrpc_search_async_job(fastrpc_async_jobid jobid, struct fastrpc_async_job_node **async_node) { int nErr = AEE_SUCCESS; int domain, hash; struct fastrpc_async *me = NULL; QNode *pn, *pnn; bool jobfound = false; struct fastrpc_async_job_node *lasync_node; domain = GET_DOMAIN_FROM_JOBID(jobid); hash = GET_HASH_FROM_JOBID(jobid); VERIFYC(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), AEE_EBADPARM); me = &lasyncinfo[domain]; VERIFYC(me->init_done == 1, AEE_EBADPARM); pthread_mutex_lock(&me->mut); QLIST_NEXTSAFE_FOR_ALL(&me->ql[hash], pn, pnn) { lasync_node = STD_RECOVER_REC(struct fastrpc_async_job_node, qn, pn); if (lasync_node->async_desc.jobid == jobid) { jobfound = true; break; } } pthread_mutex_unlock(&me->mut); VERIFYC(jobfound, AEE_EBADPARM); *async_node = lasync_node; bail: return nErr; } int fastrpc_async_get_status(fastrpc_async_jobid jobid, int timeout_us, int *result) { int nErr = AEE_SUCCESS; int domain; struct fastrpc_async *me = NULL; struct fastrpc_async_job_node *lasync_node = NULL; eventfd_t event = 0; VERIFYC(result != NULL, AEE_EBADPARM); VERIFY(AEE_SUCCESS == (nErr = fastrpc_search_async_job(jobid, &lasync_node))); domain = GET_DOMAIN_FROM_JOBID(jobid); me = &lasyncinfo[domain]; pthread_mutex_lock(&me->mut); if (lasync_node->isjobdone) { // If job is done, return result *result = lasync_node->result; goto unlock_bail; } else if (timeout_us == 0) { // If timeout 0, then return PENDING nErr = AEE_EBUSY; goto unlock_bail; } // If valid timeout(+ve/-ve), create poll event and wait on poll if (-1 == (lasync_node->pfd.fd = eventfd(0, 0))) { nErr = AEE_EFAILED; FARF(ERROR, "Error 0x%x: %s failed to create poll event for jobid 0x%" PRIx64 " (%s)\n", nErr, __func__, jobid, strerror(errno)); goto unlock_bail; } lasync_node->pfd.events = POLLIN; lasync_node->pfd.revents = 0; pthread_mutex_unlock(&me->mut); while (1) { VERIFYC(0 < poll(&lasync_node->pfd, 1, timeout_us), AEE_EFAILED); VERIFYC(0 == eventfd_read(lasync_node->pfd.fd, &event), AEE_EFAILED); if (event) { break; } } VERIFYC(lasync_node->isjobdone, AEE_EBUSY); *result = lasync_node->result; goto bail; unlock_bail: pthread_mutex_unlock(&me->mut); bail: if (nErr) { FARF(ERROR, "Error 0x%x: %s failed for jobid 0x%" PRIx64 " (%s)\n", nErr, __func__, jobid, strerror(errno)); } return nErr; } int fastrpc_remove_async_job(fastrpc_async_jobid jobid, bool dsp_invoke_done) { int nErr = AEE_SUCCESS; struct fastrpc_async *me = NULL; struct fastrpc_async_job_node *lasync_node = NULL; int domain = -1; VERIFY(AEE_SUCCESS == (nErr = fastrpc_search_async_job(jobid, &lasync_node))); domain = GET_DOMAIN_FROM_JOBID(jobid); me = &lasyncinfo[domain]; pthread_mutex_lock(&me->mut); if (dsp_invoke_done && !lasync_node->isjobdone) { pthread_mutex_unlock(&me->mut); nErr = AEE_EBUSY; goto bail; } QNode_DequeueZ(&lasync_node->qn); pthread_mutex_unlock(&me->mut); if (lasync_node->async_desc.type == FASTRPC_ASYNC_POLL && lasync_node->pfd.fd != -1) { close(lasync_node->pfd.fd); lasync_node->pfd.fd = -1; } free(lasync_node); lasync_node = NULL; bail: if (nErr) { FARF(ERROR, "Error 0x%x: %s failed for domain %d and jobid 0x%" PRIx64 " (%s)\n", nErr, __func__, domain, jobid, strerror(errno)); } return nErr; } int fastrpc_release_async_job(fastrpc_async_jobid jobid) { return fastrpc_remove_async_job(jobid, true); } int fastrpc_save_async_job(int domain, struct fastrpc_async_job *async_job, fastrpc_async_descriptor_t *desc) { int nErr = AEE_SUCCESS; struct fastrpc_async *me = &lasyncinfo[domain]; struct fastrpc_async_job_node *lasync_job = 0; int hash = -1; VERIFYC(me->init_done == 1, AEE_EINVALIDJOB); VERIFYC(NULL != (lasync_job = calloc(1, sizeof(*lasync_job))), AEE_ENOMEMORY); QNode_CtorZ(&lasync_job->qn); lasync_job->async_desc.jobid = async_job->jobid; lasync_job->async_desc.type = desc->type; lasync_job->async_desc.cb.fn = desc->cb.fn; lasync_job->async_desc.cb.context = desc->cb.context; lasync_job->isjobdone = false; lasync_job->result = -1; lasync_job->pfd.fd = -1; hash = GET_HASH_FROM_JOBID(lasync_job->async_desc.jobid); pthread_mutex_lock(&me->mut); QList_AppendNode(&me->ql[hash], &lasync_job->qn); pthread_mutex_unlock(&me->mut); FARF(RUNTIME_RPC_HIGH, "adsprpc: %s : Saving job with jobid 0x%" PRIx64 "", __func__, lasync_job->async_desc.jobid); bail: if (nErr) { FARF(ERROR, "Error 0x%x: %s failed for domain %d (%s)\n", nErr, __func__, domain, strerror(errno)); } return nErr; } void fastrpc_async_respond_all_pending_jobs(int domain) { int i = 0; struct fastrpc_async *me = &lasyncinfo[domain]; struct fastrpc_async_job_node *lasync_node = NULL; QNode *pn; for (i = 0; i < FASTRPC_ASYNC_QUEUE_LIST_LEN; i++) { pthread_mutex_lock(&me->mut); while (!QList_IsEmpty(&me->ql[i])) { pn = QList_GetFirst(&me->ql[i]); lasync_node = STD_RECOVER_REC(struct fastrpc_async_job_node, qn, pn); if (!lasync_node) { continue; } QNode_DequeueZ(&lasync_node->qn); lasync_node->result = -ECONNRESET; pthread_mutex_unlock(&me->mut); if (lasync_node->async_desc.type == FASTRPC_ASYNC_CALLBACK) { FARF(RUNTIME_RPC_HIGH, "adsprpc: %s callback jobid 0x%" PRIx64 " and result 0x%x", __func__, lasync_node->async_desc.jobid, lasync_node->result); lasync_node->async_desc.cb.fn(lasync_node->async_desc.jobid, lasync_node->async_desc.cb.context, lasync_node->result); } else if (lasync_node->async_desc.type == FASTRPC_ASYNC_POLL) { FARF(RUNTIME_RPC_HIGH, "adsprpc: %s poll jobid 0x%" PRIx64 " and result 0x%x", __func__, lasync_node->async_desc.jobid, lasync_node->result); if (lasync_node->pfd.fd != -1) { eventfd_write(lasync_node->pfd.fd, (eventfd_t)EVENT_COMPLETE); } } free(lasync_node); lasync_node = NULL; pthread_mutex_lock(&me->mut); } pthread_mutex_unlock(&me->mut); } } static void *async_fastrpc_thread(void *arg) { int nErr = AEE_SUCCESS; struct fastrpc_async *me = (struct fastrpc_async *)arg; int domain = (int)(me - &lasyncinfo[0]); struct fastrpc_async_job_node *lasync_node = NULL; int result = -1; fastrpc_async_jobid jobid = -1; QNode *pn, *pnn; int hash = -1; bool isjobfound = false; /// TODO: Do we really need this line? set_thread_context(domain); do { nErr = get_remote_async_response(domain, &jobid, &result); VERIFY(nErr == AEE_SUCCESS); FARF(RUNTIME_RPC_HIGH, "adsprpc: %s received async response for jobid 0x%" PRIx64 " and result 0x%x", __func__, jobid, result); isjobfound = false; hash = GET_HASH_FROM_JOBID(jobid); pthread_mutex_lock(&me->mut); QLIST_NEXTSAFE_FOR_ALL(&me->ql[hash], pn, pnn) { lasync_node = STD_RECOVER_REC(struct fastrpc_async_job_node, qn, pn); if (lasync_node->async_desc.jobid == jobid) { lasync_node->isjobdone = true; lasync_node->result = result; isjobfound = true; switch (lasync_node->async_desc.type) { case FASTRPC_ASYNC_NO_SYNC: FARF(RUNTIME_RPC_HIGH, "adsprpc: %s nosync jobid 0x%" PRIx64 " and result 0x%x", __func__, lasync_node->async_desc.jobid, result); QNode_DequeueZ(&lasync_node->qn); pthread_mutex_unlock(&me->mut); free(lasync_node); lasync_node = NULL; break; case FASTRPC_ASYNC_POLL: FARF(RUNTIME_RPC_HIGH, "adsprpc: %s poll jobid 0x%" PRIx64 " and result 0x%x", __func__, lasync_node->async_desc.jobid, result); if (lasync_node->pfd.fd != -1) { eventfd_write(lasync_node->pfd.fd, (eventfd_t)EVENT_COMPLETE); } pthread_mutex_unlock(&me->mut); break; case FASTRPC_ASYNC_CALLBACK: pthread_mutex_unlock(&me->mut); FARF(RUNTIME_RPC_HIGH, "adsprpc: %s callback jobid 0x%" PRIx64 " and result 0x%x", __func__, lasync_node->async_desc.jobid, result); lasync_node->async_desc.cb.fn(lasync_node->async_desc.jobid, lasync_node->async_desc.cb.context, result); break; default: pthread_mutex_unlock(&me->mut); FARF(RUNTIME_RPC_HIGH, "adsprpc: %s Invalid job type for jobid 0x%" PRIx64 "", __func__, lasync_node->async_desc.jobid); break; } break; } } if (!isjobfound) pthread_mutex_unlock(&me->mut); } while (1); bail: if (nErr != AEE_SUCCESS) { VERIFY_EPRINTF("Error 0x%x: %s AsyncFastRPC worker thread exited for " "domain %d (errno %s), async_domain_deinit started %d", nErr, __func__, domain, strerror(errno), me->deinit_started); } dlerror(); return (void *)(uintptr_t)nErr; } void async_thread_exit_handler(int sig) { FARF(ALWAYS, "Async FastRPC worker thread exiting with signal %d\n", sig); pthread_exit(0); } void fastrpc_async_domain_deinit(int domain) { struct fastrpc_async *me = &lasyncinfo[domain]; int err = 0; pthread_mutex_lock(&async_mut); if (!me->init_done) { goto fasync_deinit_done; } FARF(ALWAYS, "%s: Waiting for AsyncRPC worker thread to join for domain %d\n", __func__, domain); if (me->thread) { me->deinit_started = 1; err = fastrpc_exit_async_thread(domain); if (err) { pthread_kill(me->thread, SIGUSR1); } pthread_join(me->thread, 0); me->thread = 0; } FARF(ALWAYS, "fastrpc async thread joined for domain %d", domain); fastrpc_async_respond_all_pending_jobs(domain); pthread_mutex_destroy(&me->mut); me->init_done = 0; fasync_deinit_done: pthread_mutex_unlock(&async_mut); return; } int fastrpc_async_domain_init(int domain) { struct fastrpc_async *me = &lasyncinfo[domain]; int nErr = AEE_EUNKNOWN, i = 0; struct sigaction siga; uint32_t capability = 0; pthread_mutex_lock(&async_mut); if (me->init_done) { nErr = AEE_SUCCESS; goto bail; } VERIFY(AEE_SUCCESS == (nErr = fastrpc_get_cap(domain, ASYNC_FASTRPC_SUPPORT, &capability))); VERIFYC(capability == 1, AEE_EUNSUPPORTED); me->thread = 0; pthread_mutex_init(&me->mut, 0); for (i = 0; i < FASTRPC_ASYNC_QUEUE_LIST_LEN; i++) { QList_Ctor(&me->ql[i]); } VERIFY(AEE_SUCCESS == (nErr = pthread_create(&me->thread, 0, async_fastrpc_thread, (void *)me))); memset(&siga, 0, sizeof(siga)); siga.sa_flags = 0; siga.sa_handler = async_thread_exit_handler; VERIFY(AEE_SUCCESS == (nErr = sigaction(SIGUSR1, &siga, NULL))); me->init_done = 1; me->deinit_started = 0; FARF(ALWAYS, "%s: AsyncRPC worker thread launched for domain %d\n", __func__, domain); bail: pthread_mutex_unlock(&async_mut); if (nErr != AEE_SUCCESS) { VERIFY_EPRINTF("Error 0x%x: %s failed for domain %d (%s)\n", nErr, __func__, domain, strerror(errno)); fastrpc_async_domain_deinit(domain); } return nErr; } /* * Internal function to get async response from kernel. Waits in kernel until * response is received from DSP * @ domain: domain to which Async job is submitted * @ async_data: IOCTL structure that is sent to kernel to get async response * job information returns 0 on success * */ static int get_remote_async_response(int domain, fastrpc_async_jobid *jobid, int *result) { int nErr = AEE_SUCCESS, dev = -1; uint64_t *perf_kernel = NULL, *perf_dsp = NULL; fastrpc_async_jobid job = -1; int res = -1; remote_handle handle = -1; uint32_t sc = 0; VERIFYC(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), AEE_EBADPARM); VERIFY(AEE_SUCCESS == (nErr = fastrpc_session_dev(domain, &dev))); VERIFYM(-1 != dev, AEE_ERPC, "open dev failed\n"); if (is_kernel_perf_enabled()) { perf_kernel = (uint64_t *)calloc(PERF_KERNEL_KEY_MAX, sizeof(uint64_t)); VERIFYC(perf_kernel != NULL, AEE_ENOMEMORY); } if (is_dsp_perf_enabled(domain)) { perf_dsp = (uint64_t *)calloc(PERF_DSP_KEY_MAX, sizeof(uint64_t)); VERIFYC(perf_dsp != NULL, AEE_ENOMEMORY); } nErr = ioctl_invoke2_response(dev, &job, &handle, &sc, &res, perf_kernel, perf_dsp); if (perf_kernel) { FARF(ALWAYS, "RPCPERF-K H:0x%x SC:0x%x C:%" PRIu64 " F:%" PRIu64 " ns M:%" PRIu64 " ns CP:%" PRIu64 " ns L:%" PRIu64 " ns G:%" PRIu64 " ns P:%" PRIu64 " ns INV:%" PRIu64 " ns INVOKE:%" PRIu64 " ns\n", handle, sc, perf_kernel[0], perf_kernel[1], perf_kernel[2], perf_kernel[3], perf_kernel[4], perf_kernel[5], perf_kernel[6], perf_kernel[7], perf_kernel[8]); } if (perf_dsp) { FARF(ALWAYS, "RPCPERF-D H:0x%x SC:0x%x C:%" PRIu64 " M_H:%" PRIu64 " us M:%" PRIu64 " us G:%" PRIu64 " us INVOKE:%" PRIu64 " us P:%" PRIu64 " us CACHE:%" PRIu64 " us UM:%" PRIu64 " us " "UM_H:%" PRIu64 " us R:%" PRIu64 " us E_R:%" PRIu64 " us J_S_T:%" PRIu64 " us\n", handle, sc, perf_dsp[0], perf_dsp[1], perf_dsp[2], perf_dsp[3], perf_dsp[4], perf_dsp[5], perf_dsp[6], perf_dsp[7], perf_dsp[8], perf_dsp[9], perf_dsp[10], perf_dsp[11]); } *jobid = job; *result = res; bail: if (perf_kernel) { free(perf_kernel); perf_kernel = NULL; } if (perf_dsp) { free(perf_dsp); perf_dsp = NULL; } if (nErr) { FARF(ERROR, "Error 0x%x: %s failed to get async response data for domain %d errno " "%s", nErr, __func__, domain, strerror(errno)); } return nErr; } // Make IOCTL call to exit async thread int fastrpc_exit_async_thread(int domain) { int nErr = AEE_SUCCESS, dev; VERIFY(AEE_SUCCESS == (nErr = fastrpc_session_dev(domain, &dev))); nErr = ioctl_control(dev, DSPRPC_ASYNC_WAKE, NULL); bail: if (nErr) FARF(ERROR, "Error 0x%x: %s failed for domain %d (errno: %s), ignore if ioctl not " "supported, try pthread kill ", nErr, __func__, domain, strerror(errno)); return nErr; } fastrpc-1.0.2/src/fastrpc_cap.c000066400000000000000000000151511512345705400164050ustar00rootroot00000000000000// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause #include #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", "cdsp1", "gdsp0", "gdsp1", "reserved"}; 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", "/dev/subsys_gdsp0", "/dev/subsys_gdsp1", "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; char *buffer = NULL; if (domain < ADSP_DOMAIN_ID || domain > GDSP1_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); strlcat(buffer, "/name", BUF_SIZE); int fd = open(buffer, O_RDONLY); if (fd == -1) { break; } FILE *file = fdopen(fd, "r"); if (file != NULL) { memset(buffer, 0, BUF_SIZE); if (fgets(buffer, BUF_SIZE, file) != NULL) { buffer[BUF_SIZE - 1] = '\0'; if (strstr(buffer, search_string) != NULL) { domain_supported = 1; fclose(file); break; } } fclose(file); } close(fd); 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 = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain); VERIFYC(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), 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(dom, 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 = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain); 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; } fastrpc-1.0.2/src/fastrpc_config.c000066400000000000000000000364141512345705400171140ustar00rootroot00000000000000// 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 #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" #define CONFIG_SETDMABUFNAME "setdmabufname" struct fastrpc_config_param { bool pddump; int rpc_timeout; bool perfkernel; bool perfdsp; _cstring1_t *paths; char *farf_log_filename; char *farf_log_filename_userspace; bool log_iregion; bool qtf_tracing; int caller_level; bool uaf_enabled; bool debug_logging; struct err_codes err_codes_to_crash; bool sysmonreservedbit; bool logPackets; int leak_detect; int num_call_stack; bool setdmabufname; }; 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_t len; unsigned char *buf = NULL; int eof; char *path = NULL, *param = NULL, *saveptr = NULL; bool fileExists = false; char *delim = "=", *delim2 = ","; uint64_t logFileNameLen = 0; frpc_config.err_codes_to_crash.num_err_codes = 0; len = snprintf(0, 0, "%s/%s", base, file) + 1; VERIFYC(NULL != (path = calloc(1, sizeof(char) * len)), AEE_ENOMEMORY); 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(unsigned char) * (len + 1))), AEE_ENOMEMORY); // extra 1 unsigned char 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 (strncmp(param, CONFIG_ERR_CODES, 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 (strncmp(param, CONFIG_PDDUMP, 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 (strncmp(param, CONFIG_RPCTIMEOUT, 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 (strncmp(param, CONFIG_PERF_KERNEL, 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 (strncmp(param, CONFIG_PERF_DSP, 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 (strncmp(param, CONFIG_COLLECT_RUNTIME_FARF, strlen(CONFIG_COLLECT_RUNTIME_FARF)) == 0) { param = strtok_r(NULL, delim, &saveptr); if (param != NULL) { logFileNameLen = strlen(param) + 1; VERIFYC(NULL != (frpc_config.farf_log_filename = (char *)malloc(sizeof(char) * logFileNameLen)), AEE_ENOMEMORY); 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 (strncmp(param, CONFIG_COLLECT_RUNTIME_FARF_USERSPACE, strlen(CONFIG_COLLECT_RUNTIME_FARF_USERSPACE)) == 0) { param = strtok_r(NULL, delim, &saveptr); if (param != NULL) { logFileNameLen = strlen(param) + 1; VERIFYC(NULL != (frpc_config.farf_log_filename_userspace = (char *)malloc(sizeof(char) * logFileNameLen)), AEE_ENOMEMORY); 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 (strncmp(param, CONFIG_LOG_IREGION, 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 (strncmp(param, CONFIG_QTF_TRACING, 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 (strncmp(param, CONFIG_CALLER_LEVEL, 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 (strncmp(param, CONFIG_ENABLE_UAF, 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 (strncmp(param, CONFIG_DEBUG_LOGGING, 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 (strncmp(param, CONFIG_DEBUG_SYSMON_LOGGING, 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 (strncmp(param, CONFIG_LOGPACKET, 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 (strncmp(param, CONFIG_LEAK_DETECT, 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 (strncmp(param, CONFIG_CALL_STACK_NUM, 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); } } else if (strncmp(param, CONFIG_SETDMABUFNAME, strlen(CONFIG_SETDMABUFNAME)) == 0) { param = strtok_r (NULL, delim, &saveptr); if (param != NULL && atoi(param)) frpc_config.setdmabufname = true; } 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. bool fastrpc_config_is_pddump_enabled(void) { return frpc_config.pddump; } // Functions to get if profiling mode is enabled. bool fastrpc_config_is_perfkernel_enabled(void) { return frpc_config.perfkernel; } bool 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. bool fastrpc_config_is_log_iregion_enabled(void) { return frpc_config.log_iregion; } // Function to get if debug logging feature is enabled. bool 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. bool fastrpc_config_is_sysmon_reserved_bit_enabled(void) { return frpc_config.sysmonreservedbit; } // Function to get if QTF tracing is enabled. bool 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 bool fastrpc_config_is_uaf_enabled(void) { return frpc_config.uaf_enabled; } // Function to get if Log packet is enabled. bool 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; } bool fastrpc_config_is_setdmabufname_enabled(void) { return frpc_config.setdmabufname; } // 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_t len = 0; uint16_t maxPathLen = 0; uint32_t 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(RUNTIME_RPC_HIGH, "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) { strlcat(data_paths, paths[i].data, sizeof(char) * maxPathLen * numPaths); 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(RUNTIME_RPC_HIGH, "%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; } fastrpc-1.0.2/src/fastrpc_config_parser.c000066400000000000000000000123251512345705400204630ustar00rootroot00000000000000// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. // SPDX-License-Identifier: BSD-3-Clause-Clear #define _GNU_SOURCE #ifndef VERIFY_PRINT_WARN #define VERIFY_PRINT_WARN #endif // VERIFY_PRINT_WARN #ifndef VERIFY_PRINT_ERROR_ALWAYS #define VERIFY_PRINT_ERROR_ALWAYS #endif // VERIFY_PRINT_ERROR_ALWAYS #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define FARF_ERROR 1 #define FARF_HIGH 1 #define FARF_MED 1 #define FARF_LOW 1 #define FARF_CRITICAL 1 // Push log's to all hooks and persistent buffer. #define CONFIG_DIR CONFIG_BASE_DIR "/conf.d/" #include "AEEQList.h" #include "AEEStdErr.h" #include "AEEstd.h" #include "HAP_farf.h" #include "apps_std_internal.h" #include "fastrpc_config_parser.h" static int compare_strings(const void *a, const void *b) { return strcmp(*(const char **)a, *(const char **)b); } static void get_dsp_lib_path(const char *machine_name, const char *filepath, char *dsp_lib_paths) { yaml_parser_t parser; yaml_event_t event; int done = 0; int in_machines = 0; int in_target_machine = 0; int found_dsp_path = 0; char current_machine[PATH_MAX] = {0}; FILE *file = fopen(filepath, "r"); if (!file) return; if (!yaml_parser_initialize(&parser)) { FARF(ALWAYS, "Warning: Failed to initialize YAML parser for file %s\n", filepath); fclose(file); return; } yaml_parser_set_input_file(&parser, file); while (!done) { if (!yaml_parser_parse(&parser, &event)) { FARF(ALWAYS, "Warning: YAML parser error in file %s\n", filepath); break; } switch (event.type) { case YAML_SCALAR_EVENT: { const char *value = (const char *)event.data.scalar.value; if (!in_machines && strcmp(value, "machines") == 0) { in_machines = 1; } else if (in_machines && !in_target_machine) { // This is a machine name key strlcpy(current_machine, value, sizeof(current_machine)); if (strcmp(current_machine, machine_name) == 0) { in_target_machine = 1; } } else if (in_target_machine && strcmp(value, DSP_LIB_KEY) == 0) { // Next scalar will be the DSP_LIBRARY_PATH value yaml_event_delete(&event); if (yaml_parser_parse(&parser, &event) && event.type == YAML_SCALAR_EVENT) { strlcpy(dsp_lib_paths, (const char *)event.data.scalar.value, PATH_MAX); FARF(ALWAYS, "dsp_lib_paths is %s", dsp_lib_paths); found_dsp_path = 1; done = 1; } } break; } case YAML_MAPPING_END_EVENT: if (in_target_machine) { // Exiting the target machine mapping in_target_machine = 0; if (found_dsp_path) { done = 1; } } break; case YAML_STREAM_END_EVENT: done = 1; break; default: break; } yaml_event_delete(&event); } yaml_parser_delete(&parser); fclose(file); if (!found_dsp_path) { FARF(ALWAYS, "Warning: DSP_LIBRARY_PATH not found for machine [%s] in configuration file %s\n", machine_name, filepath); } } static void parse_config_dir(char *machine_name) { DIR *dir = opendir(CONFIG_DIR); struct dirent *entry; char *file_list[1024]; int file_count = 0; char dsp_lib_paths[PATH_MAX] = {0}; if (!dir) return; while ((entry = readdir(dir)) != NULL) { if (entry->d_type == DT_REG && (strstr(entry->d_name, ".yaml") || strstr(entry->d_name, ".yml"))) { file_list[file_count] = strdup(entry->d_name); file_count++; } } closedir(dir); qsort(file_list, file_count, sizeof(char *), compare_strings); for (int i = 0; i < file_count; i++) { char filepath[PATH_MAX]; snprintf(filepath, sizeof(filepath), "%s%s", CONFIG_DIR, file_list[i]); get_dsp_lib_path(machine_name, filepath, dsp_lib_paths); free(file_list[i]); } if (dsp_lib_paths[0] != '\0') { strlcpy(DSP_LIBS_LOCATION, CONFIG_BASE_DIR, sizeof(DSP_LIBS_LOCATION)); //append slash in case user passed config base dir doesn't end with slash '/' strlcat(DSP_LIBS_LOCATION, "/", sizeof(DSP_LIBS_LOCATION)); strlcat(DSP_LIBS_LOCATION, dsp_lib_paths, sizeof(DSP_LIBS_LOCATION)); strlcat(DSP_LIBS_LOCATION, DEFAULT_DSP_SEARCH_PATHS, sizeof(DSP_LIBS_LOCATION)); } else { FARF(ALWAYS, "Warning: No DSP library path found for machine [%s] in any configuration file\n", machine_name); } } void configure_dsp_paths() { char machine_name[PATH_MAX] = {0}; FILE *file = fopen(MACHINE_NAME_PATH, "r"); if (file == NULL) return; if (fgets(machine_name, sizeof(machine_name), file) != NULL) // Remove trailing newline if present machine_name[strcspn(machine_name, "\n")] = '\0'; fclose(file); parse_config_dir(machine_name); } fastrpc-1.0.2/src/fastrpc_context.c000066400000000000000000000215661512345705400173350ustar00rootroot00000000000000// 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 #include #include #include #include #include "verify.h" #include "fastrpc_context.h" #include "fastrpc_internal.h" #include "fastrpc_apps_user.h" /* Global context table */ static fastrpc_context_table gctx; /* Add context entry to global context table */ static inline void fastrpc_context_add_to_table(fastrpc_context *ctx) { pthread_mutex_lock(&gctx.mut); HASH_ADD(hh, gctx.table, ctxid, sizeof(ctx->ctxid), ctx); pthread_mutex_unlock(&gctx.mut); } /* Remove context entry from global context table */ static inline void fastrpc_context_remove_from_table(fastrpc_context *ctx) { pthread_mutex_lock(&gctx.mut); HASH_DELETE(hh, gctx.table, ctx); pthread_mutex_unlock(&gctx.mut); } /* Validate that context is present in global hash-table */ static inline fastrpc_context *fastrpc_context_validate(uint64_t ctxid) { fastrpc_context *ctx = NULL; // Search in hash-table pthread_mutex_lock(&gctx.mut); HASH_FIND(hh, gctx.table, &ctxid, sizeof(ctxid), ctx); pthread_mutex_unlock(&gctx.mut); return ctx; } /* * Initialize domains lists in context struct and validate. * * Effective domain ids passed by user are validated on the following * basis: * Context can either be created on multiple sessions on one domain * or multiple domains, but not both. * For example, context cannot be created on 2 sessions on CDSP + * 1 session on ADSP. * * returns 0 on success */ static int fastrpc_context_init_domains(fastrpc_context_create *create, fastrpc_context *ctx) { int nErr = AEE_SUCCESS, i = 0, j = 0; unsigned int effec_domain_id = 0, num_domain_ids = create->num_domain_ids; unsigned int *domain_ids = ctx->domains; bool multisess = true, multidom = true; for (i = 0; i < num_domain_ids; i++) { effec_domain_id = create->effec_domain_ids[i]; VERIFYC(IS_VALID_EFFECTIVE_DOMAIN_ID(effec_domain_id), AEE_EBADDOMAIN); ctx->effec_domain_ids[i] = effec_domain_id; domain_ids[i] = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(effec_domain_id); /* * If client is trying to create context on multiple sessions on * same domain, validate that all domain ids are the same. */ if (domain_ids[i] != domain_ids[0]) multisess = false; } if (multisess) goto bail; /* * If client is trying to create context on multiple domains, validate * that every domain id in the list is unique. */ for (i = 0; i < num_domain_ids; i++) { for (j = i + 1; j < num_domain_ids; j++) { if (domain_ids[j] == domain_ids[i]) { multidom = false; break; } } } if (multidom) goto bail; /* Context on multiple sessions on multiple domains is not allowed */ nErr = AEE_EBADPARM; FARF(ALWAYS, "Error 0x%x: %s: context cannot be both multi-session & multi-domain", nErr, __func__); return nErr; bail: if (nErr) FARF(ALWAYS, "Error 0x%x: %s failed", nErr, __func__); return nErr; } /** * Deinit context struct and free its resources * * @param[in] ctx : Context object * * Returns 0 on success */ static int fastrpc_context_deinit(fastrpc_context *ctx) { unsigned int domain = 0; if (!ctx) return AEE_EBADCONTEXT; pthread_mutex_lock(&ctx->mut); for (unsigned int i = 0; i < ctx->num_domain_ids; i++) { domain = ctx->effec_domain_ids[i]; // If no session was opened on domain, continue if (!ctx->devs[i]) continue; fastrpc_session_close(domain, INVALID_DEVICE); } free(ctx->devs); free(ctx->domains); free(ctx->effec_domain_ids); pthread_mutex_unlock(&ctx->mut); pthread_mutex_destroy(&ctx->mut); free(ctx); return 0; } /** * Allocate context struct and initialize it * * @param[in] num_domain_ids : Number of effective domain ids on which * context is being created. * * Returns valid context struct on success, NULL on failure */ static fastrpc_context *fastrpc_context_init(unsigned int num_domain_ids) { fastrpc_context *ctx = NULL; int nErr = AEE_SUCCESS; // Allocate memory for context struct and its members VERIFYC(NULL != (ctx = (fastrpc_context *)calloc(1, sizeof(fastrpc_context))), AEE_ENOMEMORY); pthread_mutex_init(&ctx->mut, 0); VERIFYC(NULL != (ctx->effec_domain_ids = (unsigned int *)calloc( num_domain_ids, sizeof(*ctx->effec_domain_ids))), AEE_ENOMEMORY); VERIFYC(NULL != (ctx->domains = (unsigned int *)calloc(num_domain_ids, sizeof(*ctx->domains))), AEE_ENOMEMORY); VERIFYC(NULL != (ctx->devs = (int *)calloc(num_domain_ids, sizeof(*ctx->devs))), AEE_ENOMEMORY); ctx->num_domain_ids = num_domain_ids; bail: if (nErr) { FARF(ALWAYS, "Error 0x%x: %s failed for num domain ids %u\n", nErr, __func__, num_domain_ids); fastrpc_context_deinit(ctx); ctx = NULL; } return ctx; } int fastrpc_destroy_context(uint64_t ctxid) { int nErr = AEE_SUCCESS, dev = -1; fastrpc_context *ctx = NULL; VERIFYC(gctx.init, AEE_ENOTINITIALIZED); FARF(ALWAYS, "%s called for context 0x%"PRIx64"", __func__, ctxid); VERIFYC(NULL != (ctx = fastrpc_context_validate(ctxid)), AEE_EBADCONTEXT); fastrpc_context_remove_from_table(ctx); /* * Deregister context id from kernel. The device fd for ioctl can * be that of any of the domains on which context was created. * Use the first domain's device fd. */ VERIFYC(-1 != (dev = get_device_fd(ctx->effec_domain_ids[0])), AEE_EINVALIDDEVICE); VERIFY(AEE_SUCCESS == (nErr = ioctl_mdctx_manage(dev, FASTRPC_MDCTX_REMOVE, NULL, NULL, 0, &ctx->ctxid))); VERIFY(AEE_SUCCESS == (nErr = fastrpc_context_deinit(ctx))); FARF(ALWAYS, "%s done for context 0x%"PRIx64"", __func__, ctxid); bail: if (nErr) { FARF(ALWAYS, "Error 0x%x: %s failed for ctx 0x%"PRIx64"", nErr, __func__, ctxid); } return nErr; } int fastrpc_create_context(fastrpc_context_create *create) { int nErr = AEE_SUCCESS, dev = -1; unsigned int num_domain_ids = 0, effec_domain_id = 0, i = 0; fastrpc_context *ctx = NULL; VERIFYC(gctx.init, AEE_ENOTINITIALIZED); num_domain_ids = create->num_domain_ids; FARF(ALWAYS, "%s called for %u domain ids", __func__, num_domain_ids); // Basic sanity checks on client inputs VERIFYC(create->effec_domain_ids && !create->flags, AEE_EBADPARM); VERIFYC(num_domain_ids && num_domain_ids < NUM_DOMAINS_EXTEND, AEE_EBADPARM); VERIFYC(NULL != (ctx = fastrpc_context_init(num_domain_ids)), AEE_EBADCONTEXT); VERIFYC(AEE_SUCCESS == (nErr = fastrpc_context_init_domains(create, ctx)), AEE_EBADPARM); // Create session on each domain id for (i = 0; i < num_domain_ids; i++) { effec_domain_id = ctx->effec_domain_ids[i]; // Create session on domain if not already created VERIFY(AEE_SUCCESS == (nErr = fastrpc_session_open(effec_domain_id, &ctx->devs[i]))); } /* * Generate unique context id from kernel. The device fd for ioctl can * be that of any of the domains on which context is being created. * Use the first domain's device fd. */ VERIFYC(-1 != (dev = get_device_fd(ctx->effec_domain_ids[0])), AEE_EINVALIDDEVICE); VERIFY(AEE_SUCCESS == (nErr = ioctl_mdctx_manage(dev, FASTRPC_MDCTX_SETUP, ctx, ctx->domains, num_domain_ids, &ctx->ctxid))); fastrpc_context_add_to_table(ctx); // Return context to user create->ctx = ctx->ctxid; FARF(ALWAYS, "%s done with context 0x%"PRIx64" on %u domain ids", __func__, ctx->ctxid, num_domain_ids); bail: if (nErr) { FARF(ALWAYS, "Error 0x%x: %s failed for %u domain ids\n", nErr, __func__, num_domain_ids); fastrpc_context_deinit(ctx); } return nErr; } int fastrpc_context_get_domains(uint64_t ctxid, unsigned int **effec_domain_ids, unsigned int *num_domain_ids) { int nErr = AEE_SUCCESS; fastrpc_context *ctx = NULL; VERIFYC(NULL != (ctx = fastrpc_context_validate(ctxid)), AEE_EBADCONTEXT); VERIFYC(effec_domain_ids && num_domain_ids, AEE_EMEMPTR); *effec_domain_ids = ctx->effec_domain_ids; *num_domain_ids = ctx->num_domain_ids; bail: if (nErr) FARF(ALWAYS, "Error 0x%x: %s failed\n", nErr, __func__); return nErr; } int fastrpc_context_table_init(void) { int nErr = AEE_SUCCESS; pthread_mutex_init(&gctx.mut, 0); gctx.init = true; if (nErr) FARF(ERROR, "Error 0x%x: %s failed\n", nErr, __func__); else FARF(RUNTIME_RPC_HIGH, "%s done", __func__); return nErr; } int fastrpc_context_table_deinit(void) { int nErr = AEE_SUCCESS; fastrpc_context *table = gctx.table, *ctx = NULL, *tmp = NULL; pthread_mutex_t *mut = &gctx.mut; VERIFYC(gctx.init, AEE_ENOTINITIALIZED); gctx.init = false; /* Delete all contexts */ pthread_mutex_lock(mut); HASH_ITER(hh, table, ctx, tmp) { HASH_DELETE(hh, table, ctx); fastrpc_context_deinit(ctx); } pthread_mutex_unlock(mut); pthread_mutex_destroy(mut); bail: if (nErr) FARF(ERROR, "Error 0x%x: %s failed\n", nErr, __func__); else FARF(RUNTIME_RPC_HIGH, "%s done", __func__); return nErr; }fastrpc-1.0.2/src/fastrpc_ioctl.c000066400000000000000000000153561512345705400167630ustar00rootroot00000000000000// 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 = GET_DOMAIN_FROM_EFFEC_DOMAIN_ID(domain_id); switch (domain) { case ADSP_DOMAIN_ID: name = ADSPRPC_SECURE_DEVICE; break; case SDSP_DOMAIN_ID: name = SDSPRPC_SECURE_DEVICE; break; case MDSP_DOMAIN_ID: name = MDSPRPC_SECURE_DEVICE; break; case CDSP_DOMAIN_ID: name = CDSPRPC_SECURE_DEVICE; break; case CDSP1_DOMAIN_ID: name = CDSP1RPC_SECURE_DEVICE; break; case GDSP0_DOMAIN_ID: name = GDSP0RPC_SECURE_DEVICE; break; case GDSP1_DOMAIN_ID: name = GDSP1RPC_SECURE_DEVICE; break; default: name = DEFAULT_DEVICE; break; } return name; } int ioctl_init(int dev, uint32_t flags, int attr, unsigned char *shell, int shelllen, int shellfd, char *mem, int memlen, int memfd, int tessiglen) { int ioErr = 0; 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 && attr < FASTRPC_MAX_ATTRIBUTES) { *capability = 0; 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) { if (mode == FASTRPC_SESSION_ID1) return AEE_SUCCESS; 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; } int ioctl_mdctx_manage(int dev, int req, void *user_ctx, unsigned int *domain_ids, unsigned int num_domain_ids, uint64_t *ctx) { // TODO: Implement this for opensource return AEE_EUNSUPPORTED; }fastrpc-1.0.2/src/fastrpc_latency.c000066400000000000000000000131241512345705400172770ustar00rootroot00000000000000// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause #include #include #include #include #include #include #include #include #include #ifndef FARF_ERROR #define FARF_ERROR 1 #endif #include "AEEStdErr.h" #include "AEEstd.h" #include "HAP_farf.h" #include "fastrpc_common.h" #include "fastrpc_internal.h" #include "fastrpc_latency.h" #include "verify.h" int fastrpc_latency_invoke_incr(struct fastrpc_latency *qp) { if (qp == NULL || qp->state == FASTRPC_LATENCY_STOP) goto bail; qp->invoke++; if (qp->vote == FASTRPC_LATENCY_VOTE_OFF) { pthread_mutex_lock(&qp->wmut); pthread_cond_signal(&qp->cond); pthread_mutex_unlock(&qp->wmut); } bail: return 0; } int fastrpc_latency_init(int dev, struct fastrpc_latency *qos) { int nErr = 0; VERIFYC(qos && dev != -1, AEE_ERPC); qos->dev = dev; qos->state = FASTRPC_LATENCY_STOP; qos->thread = 0; qos->wait_time = FASTRPC_LATENCY_WAIT_TIME_USEC; pthread_mutex_init(&qos->mut, 0); pthread_mutex_init(&qos->wmut, 0); pthread_cond_init(&qos->cond, NULL); bail: return nErr; } int fastrpc_latency_deinit(struct fastrpc_latency *qos) { int nErr = 0; VERIFYC(qos, AEE_ERPC); if (qos->state == FASTRPC_LATENCY_START) { pthread_mutex_lock(&qos->wmut); qos->exit = FASTRPC_LATENCY_EXIT; pthread_cond_signal(&qos->cond); pthread_mutex_unlock(&qos->wmut); if (qos->thread) { pthread_join(qos->thread, 0); qos->thread = 0; FARF(ALWAYS, "latency thread joined"); } pthread_mutex_destroy(&qos->mut); pthread_mutex_destroy(&qos->wmut); } bail: return nErr; } /* FastRPC QoS handler votes for pm_qos latency based on * RPC activity in a window of time. */ static void *fastrpc_latency_thread_handler(void *arg) { int nErr = 0; long ns = 0; struct timespec tw; struct timeval tp; int invoke = 0; struct fastrpc_ioctl_control qos = {0}; struct fastrpc_ctrl_latency lp = {0}; struct fastrpc_latency *qp = (struct fastrpc_latency *)arg; if (qp == NULL) { nErr = AEE_ERPC; FARF(ERROR, "Error 0x%x: %s failed \n", nErr, __func__); return NULL; } VERIFYC(qp->dev != -1, AEE_ERPC); FARF(ALWAYS, "%s started for QoS with activity window %d ms", __func__, FASTRPC_LATENCY_WAIT_TIME_USEC / MS_TO_US); // Look for RPC activity in 100 ms window qp->wait_time = FASTRPC_LATENCY_WAIT_TIME_USEC; qp->invoke++; while (1) { nErr = gettimeofday(&tp, NULL); /* valid values for "tv_nsec" are [0, 999999999] */ ns = ((tp.tv_usec + qp->wait_time) * US_TO_NS); tw.tv_sec = tp.tv_sec + (ns / SEC_TO_NS); tw.tv_nsec = (ns % SEC_TO_NS); pthread_mutex_lock(&qp->wmut); if (qp->wait_time) pthread_cond_timedwait(&qp->cond, &qp->wmut, &tw); else pthread_cond_wait(&qp->cond, &qp->wmut); pthread_mutex_unlock(&qp->wmut); if (qp->exit == FASTRPC_LATENCY_EXIT) { qp->exit = 0; break; } pthread_mutex_lock(&qp->mut); invoke = qp->invoke; qp->invoke = 0; pthread_mutex_unlock(&qp->mut); if (invoke) { // found RPC activity in window. vote for pm_qos. qp->wait_time = FASTRPC_LATENCY_WAIT_TIME_USEC; if (qp->vote == FASTRPC_LATENCY_VOTE_OFF) { lp.enable = FASTRPC_LATENCY_VOTE_ON; lp.latency = qp->latency; nErr = ioctl_control(qp->dev, DSPRPC_CONTROL_LATENCY, &lp); if (nErr == AEE_SUCCESS) { qp->vote = FASTRPC_LATENCY_VOTE_ON; } else if (nErr == AEE_EUNSUPPORTED) { goto bail; } else { FARF(ERROR, "Error %d: %s: PM QoS ON request failed with errno %d (%s)", nErr, __func__, errno, strerror(errno)); } } } else { // No RPC activity detected in a window. Remove pm_qos vote. qp->wait_time = 0; if (qp->vote == FASTRPC_LATENCY_VOTE_ON) { lp.enable = FASTRPC_LATENCY_VOTE_OFF; lp.latency = 0; nErr = ioctl_control(qp->dev, DSPRPC_CONTROL_LATENCY, &lp); if (nErr == AEE_SUCCESS) { qp->vote = FASTRPC_LATENCY_VOTE_OFF; } else if (nErr == AEE_EUNSUPPORTED) { goto bail; } else { FARF(ERROR, "Error %d: %s: PM QoS OFF request failed with errno %d (%s)", nErr, __func__, errno, strerror(errno)); } } } } FARF(ALWAYS, "FastRPC latency thread for QoS exited"); bail: if (nErr != AEE_SUCCESS) { FARF(ERROR, "Error 0x%x: %s failed for wait time %d latency control enable %d " "latency %d\n", nErr, __func__, qp->wait_time, qos.lp.enable, qos.lp.latency); } return NULL; } int fastrpc_set_pm_qos(struct fastrpc_latency *qos, uint32_t enable, uint32_t latency) { int nErr = AEE_SUCCESS; int state = 0; VERIFYC(qos != NULL, AEE_EBADPARM); if (qos->exit == FASTRPC_LATENCY_EXIT) goto bail; pthread_mutex_lock(&qos->mut); state = qos->state; qos->latency = latency; pthread_mutex_unlock(&qos->mut); if (!enable && state == FASTRPC_LATENCY_START) { qos->exit = FASTRPC_LATENCY_EXIT; pthread_mutex_lock(&qos->wmut); pthread_cond_signal(&qos->cond); pthread_mutex_unlock(&qos->wmut); } if (enable && state == FASTRPC_LATENCY_STOP) { qos->state = FASTRPC_LATENCY_START; VERIFY(AEE_SUCCESS == (nErr = pthread_create(&qos->thread, 0, fastrpc_latency_thread_handler, (void *)qos))); } bail: return nErr; } fastrpc-1.0.2/src/fastrpc_log.c000066400000000000000000000225701512345705400164260ustar00rootroot00000000000000// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause #define _GNU_SOURCE #include #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_internal.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 || \ level == HAP_LEVEL_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_internal( 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. */ 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); } fastrpc-1.0.2/src/fastrpc_mem.c000066400000000000000000000675051512345705400164320ustar00rootroot00000000000000// 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); memset(dhandles, 0, sizeof(dhandles)); FOR_EACH_EFFECTIVE_DOMAIN_ID(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_EACH_EFFECTIVE_DOMAIN_ID(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) { domain = get_current_domain(); } VERIFYC(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), AEE_EBADPARM); FASTRPC_GET_REF(domain); VERIFY(AEE_SUCCESS == (nErr = fastrpc_session_dev(domain, &dev))); VERIFYC(-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) { domain = get_current_domain(); } VERIFYC(fd >= 0 && IS_VALID_EFFECTIVE_DOMAIN_ID(domain), AEE_EBADPARM); FASTRPC_GET_REF(domain); VERIFY(AEE_SUCCESS == (nErr = fastrpc_session_dev(domain, &dev))); /** * Search for mapping in current static map list using 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) { domain = get_current_domain(); } VERIFYC(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), AEE_EBADPARM); FASTRPC_GET_REF(domain); VERIFY(AEE_SUCCESS == (nErr = fastrpc_session_dev(domain, &dev))); 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) { domain = get_current_domain(); } VERIFYC(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), AEE_EBADPARM); FASTRPC_GET_REF(domain); VERIFY(AEE_SUCCESS == (nErr = fastrpc_session_dev(domain, &dev))); 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(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), 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())); 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(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), 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) { 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_EACH_EFFECTIVE_DOMAIN_ID(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_EACH_EFFECTIVE_DOMAIN_ID(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_EACH_EFFECTIVE_DOMAIN_ID(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(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), 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(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), 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 (!IS_VALID_EFFECTIVE_DOMAIN_ID(domain)) { 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; } fastrpc-1.0.2/src/fastrpc_notif.c000066400000000000000000000164771512345705400167750ustar00rootroot00000000000000// 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" #include "fastrpc_hash_table.h" typedef struct { pthread_t thread; int init_done; int deinit_started; ADD_DOMAIN_HASH(); } notif_config; // 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; /* List of all clients who registered for process status notification */ static struct other_handle_list notif_list; void fastrpc_cleanup_notif_list(); DECLARE_HASH_TABLE(fastrpc_notif, notif_config); static void *notif_fastrpc_thread(void *arg) { notif_config *me = (notif_config *)arg; int nErr = AEE_SUCCESS, domain = me->domain; 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() { HASH_TABLE_INIT(notif_config); QList_Ctor(¬if_list.ql); pthread_mutex_init(&update_notif_list_mut, 0); } void fastrpc_notif_deinit() { HASH_TABLE_CLEANUP(notif_config); fastrpc_cleanup_notif_list(); pthread_mutex_destroy(&update_notif_list_mut); } void fastrpc_notif_domain_deinit(int domain) { notif_config *me = NULL; int err = 0; GET_HASH_NODE(notif_config, domain, me); if (!me) { FARF(RUNTIME_RPC_HIGH, "Warning: %s: unable to find hash-node for domain %d", __func__, domain); return; } 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) { notif_config *me = NULL; int nErr = AEE_SUCCESS; struct sigaction siga; GET_HASH_NODE(notif_config, domain, me); if (!me) { ALLOC_AND_ADD_NEW_NODE_TO_TABLE(notif_config, domain, me); } 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(IS_VALID_EFFECTIVE_DOMAIN_ID(domain), 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; } fastrpc-1.0.2/src/fastrpc_perf.c000066400000000000000000000236671512345705400166110ustar00rootroot00000000000000// 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) \ (!strncmp((name), "perf_invoke_count", 17) || \ !strncmp((name), "perf_mod_invoke", 15) || \ !strncmp((name), "perf_rsp", 8) || \ !strncmp((name), "perf_hdr_sync_flush", 19) || \ !strncmp((name), "perf_sync_flush", 15) || \ !strncmp((name), "perf_hdr_sync_inv", 17) || \ !strncmp((name), "perf_clean_cache", 16) || \ !strncmp((name), "perf_sync_inv", 13)) #define PERF_CAPABILITY_CHECK (1 << 1) extern bool fastrpc_config_is_perfkernel_enabled(void); extern bool fastrpc_config_is_perfdsp_enabled(void); int perf_v2_kernel = 0; int perf_v2_dsp = 0; struct perf_keys { int64_t 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 (!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); 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, _const_adsp_perf1_handle, NULL, 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; } fastrpc-1.0.2/src/fastrpc_pm.c000066400000000000000000000135271512345705400162630ustar00rootroot00000000000000// 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 "AEEstd.h" #include "AEEStdErr.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 atomic_bool wakelock_wmut_int = false; 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]; bool expected = false; if (wakelock.init_done) return nErr; wakelock.deinit_started = 0; if (atomic_compare_exchange_strong(&wakelock_wmut_int, &expected, true)) 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; } strlcpy(wakelock.wake_lock_name, prog_name_str, WAKELOCK_NAME_LEN); 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, nErr, __func__, strerror(errno)); else FARF(ALWAYS, "%s done", __func__); return nErr; } fastrpc-1.0.2/src/fastrpc_procbuf.c000066400000000000000000000232351512345705400173040ustar00rootroot00000000000000// 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 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, concat_len = 0; char* data_paths = NULL; char *saveptr = NULL; size_t dsp_search_path_len = strlen(DSP_LIBRARY_PATH) + 1; VERIFYC(*lib_names != NULL, AEE_ENOMEMORY); VERIFYC(NULL != (data_paths = calloc(1, sizeof(char) * dsp_search_path_len)), AEE_ENOMEMORY); VERIFYC(AEE_SUCCESS == apps_std_getenv(DSP_LIBRARY_PATH, data_paths, dsp_search_path_len, &env_list_len), AEE_EGETENV); 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, FILE_EXT) != NULL) { if (concat_len + strlen(file) > MAX_NON_PRELOAD_LIBS_LEN) { FARF(ALWAYS,"ERROR: Failed to pack library names in custom DSP_LIBRARY_PATH as required buffer size exceeds Max limit (%d).", MAX_NON_PRELOAD_LIBS_LEN); nErr = AEE_EBUFFERTOOSMALL; closedir(dir); goto bail; } strlcat(*lib_names, file, MAX_NON_PRELOAD_LIBS_LEN); concat_len = strlcat(*lib_names, ";", MAX_NON_PRELOAD_LIBS_LEN); } } } if (dir != NULL) { closedir(dir); } path = strtok_r(NULL,";", &saveptr); } *buffer_size = strlen(*lib_names) + 1; bail: if (data_paths) { free(data_paths); data_paths = NULL; } if (nErr && (nErr != AEE_EGETENV)) { 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++; memcpy(buf_write_addr, param_addr, STD_MIN(buf_last_addr - buf_write_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); } lib_names = (char *)malloc(sizeof(char) * MAX_NON_PRELOAD_LIBS_LEN); if (lib_names) { if (AEE_SUCCESS == get_non_preload_lib_names(&lib_names, &buffer_size, domain)) { 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; } } fastrpc-1.0.2/src/gpls.c000066400000000000000000000033111512345705400150600ustar00rootroot00000000000000// 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) fastrpc-1.0.2/src/listener_android.c000066400000000000000000000406341512345705400174510ustar00rootroot00000000000000// 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" #include "fastrpc_hash_table.h" typedef struct { pthread_t thread; int eventfd; int update_requested; int params_updated; sem_t *r_sem; remote_handle64 adsp_listener1_handle; ADD_DOMAIN_HASH(); } listener_config; DECLARE_HASH_TABLE(listener, listener_config); extern void set_thread_context(int domain); __QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_remotectl_open)(const char *name, uint32_t *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, NULL))); bail: return nErr; } __QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_remotectl_close)(uint32_t 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, 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_t 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(listener_config *me) { int nErr = AEE_SUCCESS, i = 0, domain = me->domain, ref = 0; adsp_listener1_invoke_ctx ctx = 0; uint8_t *outBufs = 0; int outBufsLen = 0, outBufsCapacity = 0; uint8_t *inBufs = 0; int inBufsLen = 0, inBufsLenReq = 0; int result = -1, bufs_len = 0; adsp_listener1_remote_handle handle = -1; uint32_t 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_t flags = eflags == 0 ? 0 : (uint32_t)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) { /* UserPD in CPZ migration. Keep retrying until migration is complete. * Also reset the context, as previous context is invalid after CPZ * migration */ ctx = 0; result = -1; goto invoke; } else if (nErr == (DSP_AEE_EOFFSET + AEE_EBADSTATE)) { /* UserPD in irrecoverable bad state. Exit listener */ goto bail; } /* For any other error, retry once and exit if error seen again */ 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", 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)); } FARF(ALWAYS, "%s thread exiting\n", __func__); dlerror(); } extern int apps_remotectl_skel_invoke(uint32_t _sc, remote_arg *_pra); extern int apps_std_skel_invoke(uint32_t _sc, remote_arg *_pra); extern int apps_mem_skel_invoke(uint32_t _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; listener_config *me = (listener_config *)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); if ((adsp_listener1_handle = get_adsp_listener1_handle(domain)) != INVALID_HANDLE) { nErr = __QAIC_HEADER(adsp_listener1_init2)(adsp_listener1_handle); if ((nErr == DSP_AEE_EOFFSET + AEE_ERPC) || nErr == DSP_AEE_EOFFSET + AEE_ENOSUCHMOD) { FARF(ERROR, "Error 0x%x: %s domains support not available in listener", nErr, __func__); fastrpc_update_module_list(DOMAIN_LIST_DEQUEUE, domain, _const_adsp_listener1_handle, NULL, NULL); adsp_listener1_handle = INVALID_HANDLE; VERIFY(AEE_SUCCESS == (nErr = __QAIC_HEADER(adsp_listener_init2)())); } else if (nErr == AEE_SUCCESS) { me->adsp_listener1_handle = adsp_listener1_handle; } } else { VERIFY(AEE_SUCCESS == (nErr = __QAIC_HEADER(adsp_listener_init2)())); } 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) { HASH_TABLE_CLEANUP(listener_config); PL_DEINIT(mod_table); PL_DEINIT(apps_std); } int listener_android_init(void) { int nErr = 0; HASH_TABLE_INIT(listener_config); 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) { listener_config *me = NULL; GET_HASH_NODE(listener_config, domain, me); if (!me) return; 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) { listener_config *me = NULL; int nErr = AEE_SUCCESS; GET_HASH_NODE(listener_config, domain, me); if (!me) { ALLOC_AND_ADD_NEW_NODE_TO_TABLE(listener_config, domain, me); } me->eventfd = -1; 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_t)h, dlerr, dlerrorLen, dlErr); } int listener_android_geteventfd(int domain, int *fd) { listener_config *me = NULL; int nErr = 0; GET_HASH_NODE(listener_config, domain, me); VERIFYC(me, AEE_ERESOURCENOTFOUND); 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) fastrpc-1.0.2/src/log_config.c000066400000000000000000000637451512345705400162420ustar00rootroot00000000000000// 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_t numPaths; pthread_attr_t attr; pthread_t thread; unsigned char stopThread; int asidToWatch; char *fileToWatch; char *asidFileToWatch; char *pidFileToWatch; bool adspmsgdEnabled; bool 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) * (strlen(filenames) + 1))), AEE_ENOMEMORY); strlcpy(tempFiles, filenames, 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)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 strlcpy(tempFiles, filenames, 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); 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_t len; unsigned char *buf = NULL; int readlen = 0, eof; unsigned int mask = 0; char *path = NULL; char *filenames = NULL; bool fileExists = false; int buf_addr = 0; remote_handle64 handle; uint64_t farf_logmask = 0; len = snprintf(0, 0, "%s/%s", base, file) + 1; VERIFYC(NULL != (path = malloc(sizeof(char) * len)), AEE_ENOMEMORY); 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(unsigned char) * (len + 1))), AEE_ENOMEMORY); // extra 1 unsigned char for null character VERIFYC(NULL != (filenames = malloc(sizeof(unsigned char) * 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 (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 (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 (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 ((strcmp(log_config_watcher[dom].fileToWatch, event->name) == 0) || (strcmp(log_config_watcher[dom].asidFileToWatch, event->name) == 0) || (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; const char *dsp_search_path = NULL; FARF(ALWAYS, "%s starting for domain %d\n", __func__, dom); dsp_search_path = get_dsp_search_path(); // 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; if (ret != 0) strlcpy(data_paths, dsp_search_path, ENV_PATH_LEN); 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_t 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_t)); if ((sz < (ssize_t)sizeof(uint64_t)) || (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_t) && 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_t len = 0; uint16_t 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; } fastrpc-1.0.2/src/mod_table.c000066400000000000000000001033731512345705400160520ustar00rootroot00000000000000// 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_t 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; bool bInit; }; struct open_mod_table { RW_MUTEX_T mut; struct open_mod *openMods; struct static_mod_table *smt; }; typedef int (*invoke_fn)(uint32_t, remote_arg *); typedef int (*handle_invoke_fn)(remote_handle64, uint32_t, 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_t 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_t 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(RUNTIME_RPC_HIGH, "%s: closed reverse module %s with handle 0x%x", __func__, dm->uri, (uint32_t)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_t sc, remote_arg *pra), int (*handle_invoke)(remote_handle64, uint32_t sc, remote_arg *pra)) { int nErr = AEE_SUCCESS; struct static_mod *sm = 0; int len = strlen(uri) + 1; VERIFYC(NULL != (sm = ((struct static_mod *)calloc( 1, sizeof(struct static_mod) + len))), AEE_ENOMEMORY); 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_t 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_t 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_t 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_t 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_t sc, remote_arg *pra), int (*handle_invoke)(remote_handle64, uint32_t sc, remote_arg *pra)) { int nErr = AEE_SUCCESS; int len = 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; 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 (!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_t *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_t is_reverse_handle_opened(struct open_mod_table *me, remote_handle *handle, const char *uri) { int ii = 0; uint32_t 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 (!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_t 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); 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 = snprintf(tmp, tmplen, "%.*s", dm->vals.filelen, dm->vals.file); VERIFYC((rv > 0) && (tmplen >= rv), AEE_EBADPARM); } else { int rv; rv = 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 = 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 = snprintf(tmp, tmplen, "%.*s", dm->vals.symlen, dm->vals.sym); VERIFYC((rv > 0) && (tmplen >= rv), AEE_EBADPARM); } else { int rv = 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 == 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_t)(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) { 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 = strlen(uri); int sz = len * 2 + sizeof("file:///lib_skel.so?_skel_handle_invoke&_modver=1.0") + 1; uint32_t 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); 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 = 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 = 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_t)(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_t)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_t)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) { 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_t 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_t 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_t 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_t 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_t 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_t 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_t 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_t 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); fastrpc-1.0.2/src/pl_list.c000066400000000000000000000005001512345705400155560ustar00rootroot00000000000000// 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}; fastrpc-1.0.2/src/platform_libs.c000066400000000000000000000032701512345705400167540ustar00rootroot00000000000000// 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 "AEEstd.h" #include "HAP_farf.h" #include "verify.h" #include #include extern struct platform_lib *(*pl_list[])(void); int pl_lib_init(struct platform_lib *(*plf)(void)) { int nErr = AEE_SUCCESS; struct platform_lib *pl = plf(); if (!atomic_fetch_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_fetch_sub(&pl->uRefs, 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; } fastrpc-1.0.2/src/remotectl1_stub.c000066400000000000000000000365651512345705400172500ustar00rootroot00000000000000// 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; }; //unsigned char 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_t phyAddr, uint32_t 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_t* 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 fastrpc-1.0.2/src/remotectl_stub.c000066400000000000000000000514011512345705400171510ustar00rootroot00000000000000// 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; }; //unsigned char 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_t phyAddr, uint32_t 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_t* 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 fastrpc-1.0.2/src/rpcmem_linux.c000066400000000000000000000157231512345705400166270ustar00rootroot00000000000000/* * 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 "fastrpc_ioctl.h" #include "rpcmem.h" #include "verify.h" #include "fastrpc_mem.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 int rpcfd = -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(ALWAYS, "Warning %d: Unable to open %s, falling back to fastrpc ioctl\n", errno, DMA_HEAP_NAME); /* * Application should link proper library as DEFAULT_DOMAIN_ID * is used to open rpc device node and not the uri passed by * user. */ rpcfd = open_device_node(DEFAULT_DOMAIN_ID); if (rpcfd < 0) FARF(ALWAYS, "Warning %d: Unable to open fastrpc dev node for domain: %d\n", errno, DEFAULT_DOMAIN_ID); } pthread_mutex_unlock(&rpcmt); } void rpcmem_deinit() { pthread_mutex_lock(&rpcmt); if (dmafd != -1) close(dmafd); if (rpcfd != -1) close(rpcfd); pthread_mutex_unlock(&rpcmt); pthread_mutex_destroy(&rpcmt); } int rpcmem_set_dmabuf_name(const char *name, int fd, int heapid, void *buf, uint32_t rpcflags) { // Dummy call where DMABUF is not used return 0; } int rpcmem_to_fd_internal(void *po) { struct rpc_info *rinfo, *rfree = 0; QNode *pn, *pnn; 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_t flags, size_t size) { struct rpc_info *rinfo; int nErr = 0, fd = -1; struct dma_heap_allocation_data dmabuf = { .len = size, .fd_flags = O_RDWR | O_CLOEXEC, }; if ((dmafd == -1 && rpcfd == -1) || size <= 0) { FARF(ERROR, "Error: Unable to allocate memory dmaheap fd %d, rpcfd %d, size " "%zu, flags %u", dmafd, rpcfd, size, flags); return NULL; } VERIFY(0 != (rinfo = calloc(1, sizeof(*rinfo)))); if (dmafd != -1) { 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; } fd = dmabuf.fd; } else { struct fastrpc_ioctl_alloc_dma_buf buf; buf.size = size + PAGE_SIZE; buf.fd = -1; buf.flags = 0; nErr = ioctl(rpcfd, FASTRPC_IOCTL_ALLOC_DMA_BUFF, (unsigned long)&buf); if (nErr) { FARF(ERROR, "Error %d: Unable to allocate memory fastrpc fd %d, heapid %d, size " "%zu, flags %u", errno, rpcfd, heapid, size, flags); goto bail; } fd = buf.fd; } VERIFY(0 != (rinfo->buf = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0))); rinfo->fd = 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); remote_register_buf(rinfo->buf, rinfo->size, rinfo->fd); 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) { remote_register_buf(rfree->buf, rfree->size, -1); 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_t flags, int size) { return rpcmem_alloc_internal(heapid, flags, size); } void rpcmem_deinit_internal() { rpcmem_deinit(); } void rpcmem_init_internal() { rpcmem_init(); } fastrpc-1.0.2/src/std_dtoa.c000066400000000000000000000310771512345705400157260ustar00rootroot00000000000000// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause #include "AEEStdDef.h" #include "AEEstd.h" #include "AEEStdErr.h" #include "std_dtoa.h" #include "math.h" // // Useful Macros // #define FAILED(b) ( (b) != AEE_SUCCESS ? true : false ) #define CLEANUP_ON_ERROR(b,l) if( FAILED( b ) ) { goto l; } #define FP_POW_10(n) fp_pow_10(n) static __inline uint32_t std_dtoa_clz32( uint32_t ulVal ) // // This function returns the number of leading zeroes in a uint32_t. // This is a naive implementation that uses binary search. This could be // replaced by an optimized inline assembly code. // { if( (int)ulVal <= 0 ) { return ( ulVal == 0 ) ? 32 : 0; } else { uint32_t uRet = 28; uint32_t uTmp = 0; uTmp = ( ulVal > 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_t std_dtoa_clz64( uint64_t ulVal ) // // This function returns the number of leading zeroes in a uint64_t. // { uint32_t ulCount = 0; if( !( ulVal >> 32 ) ) { ulCount += 32; } else { ulVal >>= 32; } return ulCount + std_dtoa_clz32( (uint32_t)ulVal ); } double fp_pow_10( int nPow ) { double dRet = 1.0; int nI = 0; bool 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. union { uint64_t ul; double d; } val; val.ul = STD_DTOA_FP_POSITIVE_INF; dRet = bNegative ? 0 : val.d; } 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_t ullValue = 0; uint64_t ullSign = 0; int64_t n64Exponent = 0; uint64_t ullMantissa = 0; union { uint64_t ul; double d; } val; val.d = dNumber; ullValue = val.ul; // 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; bool 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_t 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_t ullMantissa = 0; uint64_t ullSign = 0; int64_t n64Exponent = 0; static const char HexDigitsU[] = "0123456789ABCDEF"; static const char HexDigitsL[] = "0123456789abcde"; bool bFirstDigit = true; int nI = 0; int nF = 0; union { uint64_t ul; double d; } val; val.d = dNumber; uint64_t ullValue = val.ul; int nManShift = 0; const char *pcDigitArray = ( cFormat == 'A' ) ? HexDigitsU : HexDigitsL; bool 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_t 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; } fastrpc-1.0.2/src/std_path.c000066400000000000000000000064071512345705400157320ustar00rootroot00000000000000// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause /* ======================================================================= FILE: std_path.c ======================================================================= ======================================================================= */ /* To get memrchr on GNU/Linux */ #define _GNU_SOURCE #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[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+strlen(pszStart); /* preserve leading slash */ if ('/' == pszStart[0]) { pszStart++; } pc = pszStart; while ((char*)0 != (pc = 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 = memrchr(pszStart, '/', pc - pszStart); if (!pcDelFrom) pcDelFrom = pszStart; pc += 3; } else { pc += 2; continue; } memmove(pcDelFrom, pc, pcEnd-pcDelFrom); pc = pcDelFrom; } /* eliminate leading "../" */ while (pszStart == strstr(pszStart, "../")) { memmove(pszStart, pszStart+2, pcEnd-pszStart); } /* eliminate leading "./" */ while (pszStart == strstr(pszStart, "./")) { memmove(pszStart, pszStart+1, pcEnd-pszStart); } if (!strncmp(pszStart,"..",2) || !strncmp(pszStart,".",1)) { pszStart[0] = '\0'; } /* whack double '/' */ while ((char*)0 != (pc = strstr(pszPath, "//"))) { memmove(pc, pc+1, pcEnd-pc); } return pszPath; } char* std_basename(const char* cpszFile) { const char* cpsz; if ((char*)0 != (cpsz = strrchr(cpszFile,'/'))) { cpszFile = cpsz+1; } return (char*)cpszFile; } fastrpc-1.0.2/src/symbols.lst000066400000000000000000000026271512345705400161740ustar00rootroot00000000000000// 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_request; 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: *; }; fastrpc-1.0.2/test/000077500000000000000000000000001512345705400141415ustar00rootroot00000000000000fastrpc-1.0.2/test/Makefile.am000066400000000000000000000016241512345705400162000ustar00rootroot00000000000000# Define the test program bin_PROGRAMS = fastrpc_test # Define the source files for the test program fastrpc_test_SOURCES = fastrpc_test.c # Define the compiler flags for the test program fastrpc_test_CFLAGS = -I$(top_srcdir)/inc -DUSE_SYSLOG \ -Dtestlibdir=\"$(testlibdir)\" \ -Dtestdspdir=\"$(testdspdir)\" if ANDROID_CC USE_LOG = -llog endif # Define the linker flags for the test program fastrpc_test_LDADD = -ldl $(USE_LOG) # If compiling for Android, include the Android-specific flags if ANDROID_CC fastrpc_test_CFLAGS += -DANDROID endif TESTLIST = \ calculator \ hap_example \ multithreading DSPS = v68 v75 testlibdir = $(libdir)/fastrpc_test dist_testlib_DATA = $(foreach test,$(TESTLIST),linux/lib$(test).so) testdspdir = $(datadir)/fastrpc_test nobase_dist_testdsp_DATA = $(foreach test,$(TESTLIST),$(foreach dsp,$(DSPS),$(dsp)/lib$(test)_skel.so)) fastrpc-1.0.2/test/README.md000066400000000000000000000032461512345705400154250ustar00rootroot00000000000000# fastrpc_test This folder contains a test application (`fastrpc_test.c`) that demonstrates the usage of FastRPC (Fast Remote Procedure Call) to offload computations to different DSP (Digital Signal Processor) domains. The test application supports multiple examples, including a simple calculator service, a HAP example, and a multithreading example. ## Pushing Files to the Device After building the application, the following files and directories need to be pushed to the device: 1. **fastrpc_test Binary**: The compiled test application. 2. **android Directory**: Contains shared libraries for the Android platform. 3. **linux Directory**: Contains shared libraries for the Linux platform. 4. **v68 Directory**: Contains skeletons for the v68 architecture version. 5. **v75 Directory**: Contains skeletons for the v75 architecture version. ### Installing the Test Use `make install` to install the libraries and the executable to the appropriate directories: ```bash make install ``` ## Running the Test To run the test application, use the following command: ```bash fastrpc_test -d 3 -U 1 -t linux -a v68 ``` ### Options - `-d domain`: Run on a specific domain. - `0`: Run the example on ADSP - `1`: Run the example on MDSP - `2`: Run the example on SDSP - `3`: Run the example on CDSP - **Default Value**: `3` (CDSP) for targets having CDSP. - `-U unsigned_PD`: Run on signed or unsigned PD. - `0`: Run on signed PD. - `1`: Run on unsigned PD. - **Default Value**: `1` - `-t target`: Specify the target platform (android or linux). - **Default Value**: `linux` - `-a arch_version`: Specify the architecture version (e.g., v68, v75). - **Default Value**: `v68`fastrpc-1.0.2/test/android/000077500000000000000000000000001512345705400155615ustar00rootroot00000000000000fastrpc-1.0.2/test/android/libcalculator.so000066400000000000000000001400301512345705400207420ustar00rootroot00000000000000ELF@X@8 @@@@)))99((QqqVPPSssRtdQqqPPtd$$$Qtd7\ i {  >"& 09$ <P D S [`M T9P To TDT Vp L]x xW$& Kl ^$ HSD q8 TS C,Pb Xy X< Y  9, ?C E `\ KLc  @ @QP@0@  $+/$ΔK<[9D"#RELT#^mܥkʀ"ab&tr#HA @j|у峓-Ycalculator_openremote_handle64_opencalculator_closeremote_handle64_closecalculator_sumHAP_debug_v2HAP_debug_runtimememsetremote_handle64_invokecalculator_maxvsnprintfHAP_debugcalculator_slimmainoptarggetoptatoiprintfget_dsp_supportis_valid_domain_idis_unsignedpd_supportedcalculator_multisession_testcalculator_testpd_status_notifier_callbacklocal_calculator_sumlocal_calculator_maxremote_session_controlrpcmem_allocget_domainmallocsnprintfrequest_status_notifications_enable__errnosleepfreerpcmem_freerun_testis_CDSPsupported_domainsremote_handle_controlget_vtcm_infoget_unsignedpd_supportis_async_fastrpc_supportedis_status_notification_supportedget_hmx_support_infoget_hex_arch_verget_hvx_support_infolibc.soLIBClibadsprpc.solibm.solibdl.solibcalculator.soqrq0rqXrqrqqqqr rrHrrprrrrr@srsr@sr`srrrsr sHs0 u(u0u @u Pu8u&Hu'pu+xuuuuuuuuuuu u u u%uu u!v-vvv v(v0v8v@v"HvPvXv`vhv#pvxv*  closeopenmaxresvecsumurihmulti_session_test_1ERROR 0x%x: Failed to close handle_1 get_dsp_support failed with Error 0x%x ERROR 0x%x: remote_session_control failed to enable status notifications =============== DSP: local max result %d =============== Call calculator_sum on the handle_1 ERROR 0x%x: Failed to close handle_0 Usage: calculator [-d domain] [-U unsigned_PD] [-r run_locally] [-q multisession_test] -n array_size Options: -d domain: Run on a specific domain. 0: Run the example on ADSP 3: Run the example on CDSP 1: Run the example on MDSP 2: Run the example on SDSP Default Value: 3(CDSP) for targets having CDSP and 0(ADSP) for targets not having CDSP like Agatti. -U unsigned_PD: Run on signed or unsigned PD. 0: Run on signed PD. 1: Run on unsigned PD. Default Value: 1 -r run_locally: 1: Run locally on APPS. 0: Run on DSP. Default Value: 1 -q multisession_test: Test to create multiple sessions parallely calculating sums for predetermined arrays 0: Does not run the multisession tests 1: Run the multisession tests Default Value: 0 -n array_size: Natural number up to which sum is calculated from 0 to (n-1) Default Value: 1 Retry attempt unsuccessful. Timing out.... Sum for array 1 = %lld Latest targets have 128 byte HVX register, use HVX_SUPPORT_128B instead of HVX_SUPPORT_64B Unsupported attr. Only HVX_SUPPORT_128B supported _stub_method_1Please provide a valid run local value (0/1). ERROR 0x%x: Failed to compute sum on domain %d ERROR %d: failed to open handle FastRPC Capability API is not supported on this device Unsupported domain %d file:///libcalculator_skel.so?calculator_skel_handle_invoke&_modver=1.0&_idlver=1.2.3ERROR 0x%x returned from snprintf %sERROR 0x%x: local compute sum failed ERROR 0x%x: Invalid domain %d Attempting to run on %s PD on domain %d ERROR 0x%x: remote_session_control failed to reserve new session 0 Setting up Unsigned PD for session 0 Creating sequence of numbers from 0 to 10 Success HVX support is not available on domain %d is_status_notification_supported failed with Error 0x%x ERROR in get_dsp_support: 0x%x, defaulting to CDSP domain remote_dsp_capability interface is not supported on this device Unsupported attr. Only HMX_SUPPORT_SPATIAL and HMX_SUPPORT_DEPTH supported HMX support is not there for domain %d Compute sum locally FastRPC Capability API is not supported on this device. Falling back to signed pd. Find max locally _stub_method ERROR 0x%x: unable to get domain struct %d ERROR is: %d Starting calculator test ERROR 0x%x: Failed to close handleMax cdsp Allocate %d bytes from ION heap ERROR 0x%x: remote_session_control failed to get URI for session 0 ERROR 0x%x: remote_session_control failed to get URI for session 1 is_async_fastrpc_supported failed with Error 0x%x Overriding user request for unsigned PD. Only signed offload is allowed on domain %d. unable to allocate memory for uri of size: %u get_hex_arch_ver failed with Error 0x%x ERROR 0x%x: handle=0x%lx, scalar=0x%x, method ID=%d: %s failed Call calculator_sum on the DSP ERROR 0x%x: Failed to close handle PD exception Call calculator_max on the DSP ERROR 0x%x: Calculator example failed ERROR 0x%x: Failed to find max on domain %d unsignedERROR 0x%x: memory alloc failed ERROR 0x%x Failed to create URI for Session 0 DSP SSR Max value = %d multi_session_test_0d:U:q:r:n:signedERROR 0x%x: Calculator test failed PD force kill ERROR 0x%x: remote_session_control failed Sum = %lld get_hmx_support_info failed with Error 0x%x PD is up ERROR 0x%x: local find max failed Call calculator_sum on the handle_0 Creating sequence of numbers from 0 to 20 Unsupported attr. Only VTCM_PAGE and VTCM_COUNT supported Running the usecase without checking the capability get_vtcm_info failed with Error 0x%x ERROR 0x%x: FastRPC Capability API failed. Falling back to signed pd. get_hvx_support_info failed with Error 0x%x Async fastrpc is not supported on domain %d Compute sum on domain %d ERROR 0x%x: Failed to close handleSum unable to allocate memory for calculator_URI_domain of size: %d%s%s DSP domain is not provided. Retrieving DSP information using Remote APIs. ERROR 0x%x: Invalid unsigned PD flag %d =============== DSP: local sum result %lld =============== Creating sequence of numbers from 0 to %d ERROR 0x%x: request_status_notifications_enable failed remote_dsp_capability interface is not supported on this device. Falling back to signed pd. Please provide a valid array size value. ERROR 0x%x: remote_session_control interface is not supported on this device Running Multisession Tests: calculator_stub.cPD closed Sum for array 0 = %lld $l8X 0@P;x$DdL $D` d !'P'.//h04|1T2t4,4h5t67848:TzR| l,L <x$L \|PL |tL PL 0pL P  0L H <L \|L |L L X$LL $lP  +DD+D ,x,L L,-L l .pL p/$L t0H p0<L 1 L  x2`L ,3L L4xL l5L {C@@ {A_{C@ {A_{*CѡSѩ HR_@ @{C_{ (B(B CC*~ @?'+RC#'C]K *J}@J| i*C]) )(^@?A^@@(^ @R} @(_C_*(a*22 * *M '`4]@('@H4@h6:@(6'@_C_*(a*22 * *C_,(`R!'Rc4 @('@_C_*(a*22 * *C_,(`R!'Rc4'@{J_{*CѡSѩ hR_@ @{C_{ (B(BCC*@?;/+RC#'C]l *k}@k|*i+C]J)*(^@?A^@@(^ @R} @(_C_*(a*22 * */`4];@(/@H4@h6:@(6/@_C_*(a*22 * *C_(`R!"+Rc4&@(/@_C_*(a*22 * *C_(`R!"+Rc4N/@{J_{ C#====== ==WSOKCsCok^7=;=3=/= R*(@__^'C @{¨_C{(B(RC #o9k9__B,;1T@UquT@JIy @@#@@@@qk9@@ @@C^7^q-T^qaTE#@1!T^4^&#@*`7R^#@!ye@7@qmTR^@iU@qT#@o9o@97#@02C^q,T K7-^5@)Y;9Jq#@"rk@9qT#@o@9x^4^t;`^#@C^o@9l^4^t;P^4^7F%B^_{DC_{ 5{_{C @qT@JIy =@< 7t: R  @{B_{C@@C_ kT@@_)y @(@@@*{B_{C@C_ k T_yi@ kT_yi@@@@@(@@*{C_C{BC(Rh 38C( RHR#C} ].@(R@]  R^49|7C_q v]C_ kjT]^Ý(y*]_h4*`^C_t 4(R^!T8,P^C_h 4(R^>D_h@HR^_,5_03_86@h_S(R@RRB4^D<R^H ; HR]@@Bc,^q*T^l (R_ϊҁFBB4^qT^L @55@^C_^5#@<4^qT@qT\qR^qT^R r kT\ q@T@r4^p6\5^h4D^_@N`587|@^C_c5C]:p^4^_\8f@T@34^X@T@$4^.I@@^^~^{HC_{C(R( 8*__8}R;@{A_C{B(R( 8*Cc@ _/UHRCC__,@(RCC_H R+[R.CO+[o:wAc R;kk@e*K{k@*3 HRCk@3X3@k@*B cCC_q*TC_9(RCD{@*; HRC{@36RcRC4C_"*@_@cRRC4C_"~RCRC4C_@/r_86#k@c(R@RRC4C_D<\h$W_)qjT_c(y*_;@cC5>?^cBRCC_L4C_5]l,C_h-';@*N HRC;@3@;@*B c@CC_q*TC_9(RCK@*,# HRCK@3RRC4C_"@/@RRC4C_"wRRC4C_P0k_86#@C(R@RRC4C_D<U ?_QqjT_(y*_#@nC5^тRsCC_L-C_5]C_h-^T^QC4C_ v^T^BC4C_g3@3@;@;@@@#@#@C_@{[C_C@(R) q T@q  @C_R@@ kT |Bii@ kTB @@_{CRC_4_L8 @@ kT |Bii_ kT(R8 @*8_8{B_{BC_iRI @# @@RRCC_8qT#@(5# @RRC@4_C_4C_,  RC'C_{B_{B_^qT^qaTR?}>@_4_ qT_3^@RRc@9qATa^@5@_(@QR_H  R'A@{C_{BC_# (R@RRuCC_8qAT*!*8&C_h4C_(*8@qT(R8  RC, *8*8_8{B_{`R{_{BC_ qaT_# (R@RR!CC_8qATC#@qT(R8C_4C_`1RC_  RC'*8_8{B_{BCh_# HR@RRCC_8qATC@qT(R8C_4C_%l  RC'e*8_8{B_{B_^!qT^qTR(@;@H_ qT_3^@RR{c@9qAT'$@5@_(@ =R_)  R'@{C_{B  @?_R @RR83@9qAT@5 @ @(@D4  R'@{B_{B_^ qTRXE^ qTR;@H_ qT_3^@RRc@9qAT@5@_(@D~R_<%u  R'n@{C_C{C__^_(R 9@96`R#RoCC^4C^G RCC^{DC_{B    B B B B" BB Bb B B B B B B" BB Bb B B B B C C"  CB Cb C C C C "C &C" *CB .Cb 2C 6C :C >C   o8  o 0Xu8  -o8ooop_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_&_dom=adsp&_dom=mdsp&_dom=sdsp&_dom=cdsp&_dom=cdsp1%4I?: ;&II: ;  : ;  I: ; 8  I: ;8 $> I  : ;  : ;  : ; 4I: ;I!I7 $ > .@: ;'I : ;: ;I4: ;I : ;.@: ;'I?.@: ; ': ; I4: ; I!I7I9 %.@: ; 'I?: ; I4: ; I : ; .@: ; $> I%I : ;($> I : ; I.@: ; 'I? : ; I 4: ; I : ;   4: ;I : ; UI: ;&II: ;  : ;  I: ; 8 I!I7 $ >  : ; I: ;8 %4I?: ; I!I7 I: ;  : ;  I: ; 8 $> $ > I : ; ( .@: ; 'I? : ; I4: ; I : ;  .@: ; 'I?.@: ;'I?: ;I4: ;I : ;I : ; I: ;8 %I : ;($> .@: ; 'I?: ; I4: ; I I I' I I: ;  : ; I: ;8 _  `9@@ qEP8 2J  + (.0    (8 @l]w]  s\ !K AVJ)hU@7 ( x} Q Q ]   A A  @ @  ] = zF] f \@@H of]9   G 4 (qq ]H X  A A  @ @  ]  zF]  \@@H of]9  tyzF@@ @@   8E@f\] ]$](X ,- ./0123D  D Pq 2h<  ;%N   >+]'z 7@ AFQ D S , a kp{..  @ \]]]X     q 4 r lV rx x r  0 %  +   . "   @ F @9tm' +7$ % 7<$ 6 <x\+ tP+@h + ` +X+T, -$ <. 0f / ( 0 $D1=: W a h<pmFR$ % RW$ % Wx\F tPF@h F ` FXFTG H$ <I 8f J 0 K ,DLX= x 9,m%%d % 09$m (d ( T9PmBx\B pB lvBB  PC@<Pm]x\] p] lv]]  P^@>m-|D -p-l-`.9 / [ 0  F    6k0 ;  9 p d < } { 9 d   = .@  ] @@F 0     0 0 000 |`??m (x(p( l*h+d , -L.g/01 o,B0C|Cm@   p `CV'  4 VGJ "  V J   `  O 9 ^ ` CmU x ti  2  \ TDm1 x1 tv1 1  2Dm : x: tv: :  ; <EmD |D xD t D sgD  lE ` F \ G X G TqG PH Lp I J 8K 0y L (M  N9 ;T PK GD ~ }}KLmp  | {g  Klm | {g  t p  hU ` X P  } ~ ~ 9 B   '  '  e  eR v 4}@  q}*!76k ' D2S ,>Ii jv Xi  v vc(hj{l|npu{{  AVJ).{{ g 0{{ .M  (1 ^`HS|  ? KVi w~     }        K 4    T  1  9  2 AJ) HSDo  w So ww w Tm xw t w w !w Tm/w xi /t1wUU$U6 VpmYw |i Yw pz Y l Y'[whWV k xW$m  xwtwWXmM X<mH xi wtwYX Y m ܃ xi wtwZZ [`mw|i wpz l 'w.P\[ `\m/2w|i 2wz 2 4wR<]\:L]xmC Vw|i Vwpz Vl V'Xw^] cl Kw 8i ':_'<z '>' d`^V'  4 V J   `  O 9 ^ ` ^m":|:ph3Ad:l  F : : : ` *!7 FKMi :O:Q AC maxArgsroutSizePrimInnCasesinCaseAlignmentstringsint64h64print_usageunsignedpd_flagstatusremote_rpc_reserve_new_sessionDOMAIN_SUPPORTdsp_capability_async_supportarrayTypeSequenceTypeunionTyperoutCaseAlignmentPrimIniids_primInmaxandroid_Debug_aarch64/calculator_stub.cprimmethodStringsArraysremote_buf_nErrRPCMEM_HEAP_ID_SECUREFASTRPC_REMOTE_PROCESS_TYPEsession_namereserve_session_1_castbSigned__uint8_tparameterscontexthandle_1nMethodsbDefaultCasemodecalculator_sum_stub_method_1va_listDSPRPC_GET_DOMAINrequest_status_notifications_enablenMaxLenunsigned charprimInAlignmentparameterArrayssrc/calculator_main.ctest_array_1get_domainis_valid_domain_idget_vtcm_infoidsp_capability_arch_vervalue32scasescalculator_maxstd__vr_offsrunLocaleffective_domain_idremote_rpc_effective_domain_idmodule_uri_lenbFloatingcaseValuesvalue16sunsigned short__ARRAY_SIZE_TYPE___rout1fdremote_arg__gr_offslocal_calculator_sumcalculator_URI_domain_lenintnativeSizeparamroutCaseAlignmentPrimROutnativeCaseAlignmentStructTypebInterfaceNotNilmethodStringArray_handlepvis_unsignedpd_enabledtest_array_0notifroutSizePrimROutroutAlignmentPrimInlong longFASTRPC_SESSION_CLOSEidresult0STATUS_NOTIFICATION_SUPPORTfastrpc_notif_fn_turi_praargvFASTRPC_REMOTE_PROCESS_KILLFASTRPC_RESERVE_NEW_SESSIONhandle_0C:\Qualcomm\Hexagon_SDK\6.1.0.0/utils/examples/dsp_capabilities_utils.cARCH_VERmethodArraynumParamsunsigned long__copydomain_idFASTRPC_USER_PD_EXCEPTIONcalculator_URI_domaindomain_tsession_name_lenmodule_uriHMX_SUPPORT_SPATIALget_unsignedpd_supportC:\Qualcomm\Hexagon_SDK\6.1.0.0/utils/examples/pd_status_notification.cAndroid (9352603, based on r450784d1) clang version 14.0.7 (https://android.googlesource.com/toolchain/llvm-project 4c603efb0cca074e9238af8b4106c30add4418f6)__uint32_tint32_t__uint16_tvalue64sTypevecLendmalinemultisession_testcalculator_testsession_uri_1DSPRPC_SET_PATHDSPRPC_GET_PATHunsigned intcharremote_handle64vecres_nErrfarfbail__vr_top__va_listremote_rpc_status_flags_theapidreserve_session_0VTCM_COUNTattribute_IDprimInSizeprimROutSize__uintptr_tarrayinSizemethodscalculator_open_numInformat__gr_topFASTRPC_DSP_SSRFASTRPC_RESERVED_1HVX_SUPPORT_64Bsizeuint32_tparamsuint64_tMethodar_stub_methodFASTRPC_USER_PD_FORCE_KILLFASTRPC_PD_INITMEM_SIZEremote_rpc_get_uricapabilitydsp_capability_vtcm_dspstatus_notification_supportbNotNiluint16_t_in0LennLenstarttestFASTRPC_THREAD_PARAMSFASTRPC_RESERVED_2HVX_SUPPORT_128BnativeAlignmentmethodStringsbufsize_tlevelDSPRPC_CONTROL_UNSIGNED_MODULEdomainretrydata_0DSPRPC_RESERVEDDSPRPC_CONTROL_LATENCYASYNC_FASTRPC_SUPPORTdsp_capability_status_notification_supportUnionTypetypescalculator_closeoffsetFASTRPC_USER_PD_EXITRPCMEM_HEAP_ID_CONTIGuScalarsp2CaseValuePtrParameterargsFASTRPC_GET_URIrun_testhandleSummy_domainsession_uri_0testdata_effective_dom_id_0is_status_notification_supporteduintptr_tseqSimpleuint8_t_praInmainnumhandle_control_req_idattrdsp_capability_hmx_dsp__int32_tobjectseqComplex__uint64_tFASTRPC_GET_EFFECTIVE_DOMAIN_IDdatadata_effective_dom_id_1is_unsignedpd_supportedcompute_onlyp1nMembers_in0FASTRPC_REGISTER_STATUS_NOTIFICATIONSresult1uri_lensupported_domainsDSPRPC_CONTROL_WAKELOCKHMX_SUPPORT_DEPTHget_hvx_support_infoinAlignmenth_primROutsrc/calculator_test.clocal_calculator_maxiidata_1nItemsroutAlignmentPrimROutmembersnIIdsmethodArrays_BoolRPCMEM_HEAP_ID_SYSTEMlenenableremote_dsp_attributesget_hmx_support_infoget_hex_arch_vercalculator_slim_midpd_status_notifier_callbackresultMaxsession_idVTCM_PAGEis_CDSPget_dsp_supportdsp_capability_domainremote_handle__stack__builtin_va_listFASTRPC_CONTROL_PD_DUMPsession_control_req_idcalculator_multisession_testsessionnotifier_fnremote_rpc_notif_registerC:/Qualcomm/Hexagon_SDK/6.1.0.0/examples/calculator_copyiidstringMaxLentyperemote_dma_handleresulthandleMaxremote_dsp_capabilitystructTypeInterfaceoptionbailFASTRPC_USER_PD_UPremote_rpc_status_flagsUNSIGNED_PD_SUPPORTis_async_fastrpc_supporteddsp_capability_hvx_dspseqTypeprimROutAlignment_HAP_debug_v2fileargcnErrrpc_heap_idsFASTRPC_RELATIVE_THREAD_PRIORITYFASTRPC_RESERVED_3FASTRPC_REMOTE_PROCESS_EXCEPTIONdomain_nameDSPRPC_GET_DSP_INFOnotif_callback_fndescriptorvalue8sremote_rpc_control_unsigned_moduledomain_name_lenLinker: LLD 14.0.7Android (9352603, based on r450784d1) clang version 14.0.7 (https://android.googlesource.com/toolchain/llvm-project 4c603efb0cca074e9238af8b4106c30add4418f6)  android_Debug_aarch64C:/Qualcomm/Hexagon_SDK/6.1.0.0C:\Qualcomm\Hexagon_SDK\6.1.0.0/incsC:\Qualcomm\Hexagon_SDK\6.1.0.0/incs/stddefcalculator_stub.ctools/android-ndk-r25c/toolchains/llvm/prebuilt/windows-x86_64/bin/../sysroot/usr/include/stdint.hHAP_debug.hremote.hAEEStdDef.htools/android-ndk-r25c/toolchains/llvm/prebuilt/windows-x86_64/lib64/clang/14.0.7/include/stddef.htools/android-ndk-r25c/toolchains/llvm/prebuilt/windows-x86_64/lib64/clang/14.0.7/include/stdarg.h 9/ =4J JJ0  JJ 0K!JTJ JJg} 4= KKK KJJ! KJJ#KJ}J JKJKJJKJ0JKJ=J}JJJ}JJ}0}<}J}0}<}JJ}JJK KJ 0K#JVJ JJg} 4= KKK KJJ! KJJ#JKJ}J JKJKJJKJ0JKJ=J}JJJ}JJ}0}<}J}0}<}JJ}JJK KJ} T ,J,J JJK- srccalculator_main.c ?(W *tKKKKKLJ!JMJ3JJ JL4JLt#5JJJ KJJ)7J$J"J KHJ+9J&J$ FJ";JJJ KDJ=JJJ KLrJJJ KKMJMJ  J KJMJKKLJ J1K7JJKKMJJ J;KAJJKKMJ5JJ  JiJKKKzJ JJ KKJKJ9J9aJKL)4J J  KJ8JKKK&J1J6J J  KJ8~JK~JJ JJ9~JK~J J~s JX b C:\Qualcomm\Hexagon_SDK\6.1.0.0/incsC:\Qualcomm\Hexagon_SDK\6.1.0.0/ipc/fastrpc/rpcmem/incsrcC:\Qualcomm\Hexagon_SDK\6.1.0.0/incs/stddefC:/Qualcomm/Hexagon_SDK/6.1.0.0remote.hrpcmem.hcalculator_test.cAEEStdDef.htools/android-ndk-r25c/toolchains/llvm/prebuilt/windows-x86_64/bin/../sysroot/usr/include/stdint.h C  KJfJftKcJK`J"K]J%KZJ(KWJ+JK LJ uKJ KJJJJ  JJJJJJ JJIPLOJJJ6 v KJJJJ J JJ J JJ &J BJ >JJI LJJNKMJ@J (K KJ KK K KMJ1KJ'OEJJJJ J1KJK9M=JJ KJJJJJ JJJIMJ#K)J J J8KJKJ#K)J J J5KJKLLJJ KJ J@KFJJK*MJLJ J$"J JA~J KL~JJbK~J KL1L*J J J~JSK~J KM,J_JjJ~J  J KJ7~J  KCM~JJ JO~J  KKL2K" J J~ K*J0JJK L J ~J K L$J'   KJ(J,  K~JJ5$J"J J:~J  KKK JJ J~BKHJ~JK0L J J~1K<JBJ" J J$~J KK LJ?EJ~JK LJ3"J J J;~J KK LJ3"J J J;~J KK~JJJJ JKKJJK KJ K-J  KJ~  $K NK  KKJJ KJ~JBKHJ~J K~J~JbK}J K}JJkJKJ'JVK-JM(J}J{_C#}J$}J$A"JDKSJ3JBLQJ4J-J#J J}J]K}J K#L=J}  J KJC}J  K;MCJ-J&JJ J}J]K}J K}J J JX}J K2LJ<K( J JX}J K}J J JX}J KLJ}1L$"J JC}J KL}J K JJJJ JI>L J J} KJK7L}J K L J.}J K K}J BQJ4J-J#J J}J]K}J K#L=J}  J KJC}J  K;LCJ-J&JJ J}J]K}J K}J J JX}J K2LJ<K( J JX}J K}J J JX}J KLJ} 1L$"J JC}J KL}J K JJJJ JI>N J J} KJK7L|J K L J.|J K K|J J3"J J J:|J KK KJ3"J J J:|J KKFQJJKKJJKLJJKKJJK KJ * C:\Qualcomm\Hexagon_SDK\6.1.0.0/incsC:/Qualcomm/Hexagon_SDK/6.1.0.0C:\Qualcomm\Hexagon_SDK\6.1.0.0/utils/examplesremote.hdomain_default.htools/android-ndk-r25c/toolchains/llvm/prebuilt/windows-x86_64/bin/../sysroot/usr/include/stdint.hdsp_capabilities_utils.c HS ),6J)mJJ  L JJJJ JhJ"(J J'gJ JGO =LJJ J  JJJJ JXJ"((J JX)JGYJ,J?P  1K LL&6J K JH :K"M JB*J0K.KJ&KJJ K K LJBJ KLJJJ b "JJ  tKJLJJJJJ KJJ %J( J8,4K2J0KJKJJKKLJ7JJ KDLJKJ JJJ/KJ KL~JJ~J _ %JJ~  K?>uJ K J~  J_~J " J~ J~JJ~J ~J? J~  K J=175KJKJ~~JKK3LJ~J~JJQ~JK L~JJEK~J KL~JJ~J _~JJ>~  LG;A?KJ K J~ ~J K K=LJ~ J~ JJS~J KL~JJ~J f~JJ?}  tKJL$J'J}J}J K}JJ J7+3K1J/KJKJ}}JKKLJ6JJ KKL}JK}J J}JJ@K}J KL}JJ}J _ %JJ}  KJK4(.,KJ K J} }J K KLJ3JJ KCL}J K}JJ}JJ}J g JJ}  tKJKJ}J}J KMJ}J}J K}JJ J7+3K1J/KJKJ}}JKKLJ6JJ KKL}JK}J J}JJCK|J KL|JJ|J _ %JJ  C:\Qualcomm\Hexagon_SDK\6.1.0.0/incsC:\Qualcomm\Hexagon_SDK\6.1.0.0/utils/examplesremote.hpd_status_notification.c ^ uNJKJKJAL JJs  J KJ\pJKKnJJ J  P X d P X  9 9t% >3 h<pB q O qT r\pu" r8 r0 # x% ? |CO#pc  x% COl$pv x% HSOp$u1Q x% ^Op x% s1 9,AV 09$g} T9P   <P  q8 ? T+ T> xW$V Kls E C TD D S ^,4:?K KLT HSD\Pn" Vp X X< Y  [` `\  L]x.dynsym.gnu.version.gnu.version_r.gnu.hash.dynstr.rela.dyn.rela.plt.rodata.eh_frame_hdr.eh_frame.text.plt.data.rel.ro.dynamic.got.got.plt.data.debug_abbrev.debug_info.debug_str.comment.debug_line.debug_ranges.symtab.shstrtab.strtabcalculator_stub.c$x.0_stub_method_HAP_debug_v2_stub_method_1methodArrays$d.1methodsmethodStringsArrays$d.2methodStringsstringsparameterArraysparameterstypes$d.3$d.4$d.5$d.6$d.7$d.8$d.9calculator_main.cprint_usagecalculator_test.cdsp_capabilities_utils.cpd_status_notification.ccalculator_openremote_handle64_opencalculator_closeremote_handle64_closecalculator_sumHAP_debug_v2HAP_debug_runtimememsetremote_handle64_invokecalculator_maxvsnprintfHAP_debugcalculator_slimmainoptarggetoptatoiprintfget_dsp_supportis_valid_domain_idis_unsignedpd_supportedcalculator_multisession_testcalculator_testpd_status_notifier_callbacklocal_calculator_sumlocal_calculator_maxremote_session_controlrpcmem_allocget_domainmallocsnprintfrequest_status_notifications_enable__errnosleepfreerpcmem_freerun_testis_CDSPsupported_domainsremote_handle_controlget_vtcm_infoget_unsignedpd_supportis_async_fastrpc_supportedis_status_notification_supportedget_hmx_support_infoget_hex_arch_verget_hvx_support_info_DYNAMIC 88 o`o %o88/-78 8 AB 0K2S$$ax%x%k9)h&qp_pO@vqQsS u U8XuXU(VPV5\0x0]p B(*)fastrpc-1.0.2/test/android/libhap_example.so000066400000000000000000001411701512345705400211020ustar00rootroot00000000000000ELF@@8 @@@@---==((Vvv[PPXXXxXxRtdVvvp Ptd((($$Qtd9g t   X"o"""" ?8 DPY dG8x G0 ,H0! ,Y5 ]L ]< w8 Wg _  `` Xbx =, ?0 Z| X TXDO =0> 4G0 G0 ,I BP G04 \$P' =$! EDL L ' [p lac ! @ !0("B`H$`H @ "',048bLg (5gREHA6X8D^ܺ4v7b<[kʀXc ߕk|l!Jmur#bHԱT#-hap_example_openremote_handle64_openhap_example_closeremote_handle64_closehap_example_compute_resHAP_debug_v2HAP_debug_runtimeremote_handle64_invokehap_example_compute_resv2hap_example_farf_runtimehap_example_mem_dmahandleremote_register_dma_handlehap_example_mem_dmahandlev2hap_example_mem_fastrpc_mmaphap_example_mem_reserve_vahap_example_mem_map_reserve_vahap_example_perfhap_example_powerhap_example_sysmon_cachelockhap_example_vtcm_mgrvsnprintfHAP_debughap_example_slimmainoptarggetoptatoiprintfget_dsp_supportis_valid_domain_idis_unsignedpd_supportedhap_exampleremote_session_controlfastrpc_mmapget_domainmallocsnprintfrpcmem_allocrpcmem_to_fdrpcmem_freefastrpc_munmaprpcmem_alloc2freerun_teststderrfprintfis_CDSPsupported_domainsremote_handle_controlget_vtcm_infoget_unsignedpd_supportis_async_fastrpc_supportedis_status_notification_supportedget_hmx_support_infoget_hex_arch_verget_hvx_support_infolibc.soLIBClibadsprpc.solibm.solibdl.solibhap_example.sov8wv`wvwvwvwvwvwvxvwvwvwvwvwvwwv w(w0wPw8xxwPxw(xwHxx(x(x0xH8x@xHx(Pxyyy y yzzz30z'8z@z4HzPz,Xz`zhz(pzxz0zzz5z-zzz.z1zzzz z z z)z{2{6{ { {*({0{8{@{H{P{X{`{h{p{+x{ ;kwLyw*\runtime_logging_enablemem_map_reserve_vasysmon_cachelockmem_fastrpc_mmapmem_dmahandlev2mem_reserve_vabuffer_lengthmem_dmahandlecompute_resv2farf_runtimecompute_resvtcm_mgrbufferpowercloseperfopenurifd Usage: hap_example [-d domain] [-U unsigned_PD] [-f example_selector] Options: -d domain: Run on a specific domain. 0: Run the example on ADSP 3: Run the example on CDSP Default Value: 3(CDSP) for targets having CDSP and 0(ADSP) for targets not having CDSP like Agatti. -U unsigned_PD: Run on signed or unsigned PD. 0: Run on signed PD. 1: Run on unsigned PD. Default Value: 1 -f example_selector: 0-6 select HAP API type 0: HAP_compute_res (Default) 1: HAP_farf 2: HAP_mem 3: HAP_perf 4: HAP_power 5: sysmon_cachelock 6: HAP_vtcm_mgr 7: REMOTE_PROCESS_TYPE 8: RESERVE_VA 9: HAP_memv2 10: HAP_compute_resv2 hap_example PASSED Demonstrating HAP_mem.h APIs Please select a number ranging from 0 to 10 get_dsp_support failed with Error 0x%x ERROR Code 0x%x : hap_example_mem_reserve_va failed Error Code 0x%x : returned from the fastrpc_mmap() API Latest targets have 128 byte HVX register, use HVX_SUPPORT_128B instead of HVX_SUPPORT_64B Unsupported attr. Only HVX_SUPPORT_128B supported _stub_method_1 Demonstrating sysmon_cachelock.h APIs FastRPC Capability API is not supported on this device Unsupported domain %d ERROR 0x%x returned from snprintf d:f:U:unable to allocated memory for uri of size: %d Demonstrating HAP_power.h APIs ERROR 0x%x: Invalid domain %d Attempting to run on %s PD on domain %d HVX support is not available on domain %d hap_example function FAILED is_status_notification_supported failed with Error 0x%x remote_dsp_capability interface is not supported on this device Unsupported attr. Only HMX_SUPPORT_SPATIAL and HMX_SUPPORT_DEPTH supported HMX support is not there for domain %d _stub_method_3 Demonstrating FARF run-time logging FastRPC Capability API is not supported on this device. Falling back to signed pd. Demonstrating HAP_compute_res.h APIs _stub_methodERROR 0x%x: Test FAILED ERROR 0x%x: unable to get domain struct %d ERROR: Rpcmem Alloc for size 0x%zu failed for iteration %d Demonstrating HAP_perf.h APIs HAP_compute_res.h APIs are not supported on this target ERROR: sysmon_cachelock.h APIs supported only on signed CDSP Error Code 0x%x : returned from hap_example_mem_dmahandlev2(handle, fd, offset, buffer_length) _stub_method_2fastrpc_mmap APIs are not supported on this target Demonstrating HAP_mem.h v2 APIs Please look at the mini-dm logs or the adb logcat logs for DSP output is_async_fastrpc_supported failed with Error 0x%x Overriding user request for unsigned PD. Only signed offload is allowed on domain %d. Error Code 0x%x : returned from hap_example_mem_dmahandle(handle, fd, offset, buffer_length) Demonstrating Reserve VA APIs get_hex_arch_ver failed with Error 0x%x ERROR 0x%x: handle=0x%lx, scalar=0x%x, method ID=%d: %s failed ERROR 0x%x: Unable to create FastRPC session on domain %d ERROR: HAP_compute_res.h APIs are supported only on CDSP ERROR Code 0x%x : Fastrpc mmap buffers fd %d FAILED Demonstrating HAP_vtcm_mgr.h APIs Demonstrating HAP_compute_res.h v2 APIs unsigned hap_example FAILED with nErr = 0x%x Error Code 0x%x : returned from the fastrpc_munmap() API Error in get_dsp_support: 0x%x, defaulting to CDSP domain signedERROR 0x%x: remote_session_control failed ERROR: HAP_vtcm_mgr.h APIs supported only on CDSP ERROR: The PD type doesnt match hap_example function PASSED get_hmx_support_info failed with Error 0x%x Error Code 0x%x : returned from hap_example_mem_fastrpc_mmap(handle, fd, buffer_length) Unsupported attr. Only VTCM_PAGE and VTCM_COUNT supported Running the usecase without checking the capability get_vtcm_info failed with Error 0x%x ERROR 0x%x: FastRPC Capability API failed. Falling back to signed pd. get_hvx_support_info failed with Error 0x%x Error occurred with selector %d: %d Async fastrpc is not supported on domain %d file:///libhap_example_skel.so?hap_example_skel_handle_invoke&_modver=1.0ERROR Code 0x%x : hap_example_mem_map_reserve_va failed -----------------------HAP API Example-------------------------------- %s%sERROR: Failed to allocate ION memory DSP domain is not provided. Retrieving DSP information using Remote APIs. ERROR 0x%x: Invalid unsigned PD flag %d The PD type is %d (%s)remote_dsp_capability interface is not supported on this device. Falling back to signed pd. ERROR 0x%x: remote_session_control interface is not supported on this device hap_example_stub.c8t;$#@` <@`4L @ `D !##t/<0 081P1p2l455670T9P@:pzR| L,L <X$L \\0L |lL 0L 8L L PL dL <8PL \hDL |L T0L d8L |0L 0L 0L <0L \P  |lL  H  P  l+L ,DD@,D ,,L Lp-L ld.pL /$L 0H 0<L 1 L  2`L ,3L L4xL {C@@ {A_{C@ {A_{CHR@@{A_C{(D(DCC_C_*(a* * * * *^o C`4C^H4@h6:@(6C^_C_*(a* * * * *C_I7(`R!4&RcJ@(C^_C_*(a* * * * *C_I7(`R!4&Rc) C^{DC_{ChR@@{A_{CR@@{A_{CDDC'#^@'_C_*(a*2 * * *#`4#@H4@h6:@(6#@_C_*(a*2 * * *C_}*(`R!4(Rc@(#@_C_*(a*2 * * *C_}*(`R!4(Rc#@{E_{**3ѡCC3R _ @{B_{DD C@^@(@^@(^@]@h*q R* kh4*h6_C_*(a* * *2 *9`4@h4@H4@h6:@(6@_C_*(a* * *2 *C_a=(`R!4B+Rc @(@_C_*(a* * *2 *C_a=(`R!4B+Rc@{F_{**3ѡCC3R _ @W{B_{*3ѡCCR_@{B_{DDC'^@+^@/_C_*(a*2 * * *'`4'@H4@h6:@(6'@_C_*(a*2 * * *C_4(`R!4.Rcp@('@_C_*(a*2 * * *C_4(`R!4.RcO'@{F_{CR@@{A_{C(R@@*{A_{CHR@@{A_{ChR@@{A_{CR@@{A_{CR@@x{A_{ C#====== ==WSOKCsCok^7=;=3=/= R*@__^C @{¨_C{D C#(Ro9__B$-1`T^UqT@qT@qT @@C @@#  @@yrC^1!TTs^4^d C^*`7R^C^.UA@7@qmTR^@E1@qTC^o9o@97C^o@9 )Q  JqC^/|C^o@9#@^4^|7s^5`$k^ f^_{DC_{Y{_{C )D) )D)R) 8C  RC  _W@  @HR__7/_86@h6_Ѩ(R@RR44_l R_C-@ HRC^@-r@ @C @Bcp_q*T_,(R\@ @cь_4__NC_q)GT@JIy ֠_!R7(R36@@u_R r kT: 4@@*q@@!Rm$ R!RR@@ R@@[1T@@@H_!R6@_[@*ER_(5@ R@[[C_4_g_[CC[4C[| Y_QqT=P_`'K=D@ R@[[Z_4_<2@@^*7ggg@ q*T7@**RD//@7@g@8/@<W/@g { i*W@gJ I 7@gJ I g* Ig  (R(g@ggg@ qJTg* iRIg) *?g) ?q9_g) ! @g){iig) $ g @_4_gJ I_g  @ g) ?g  (R(q9g@g@@_4_&gg@ qT@@g  @o_4_g@ggg@ q Tg ;;@q@9h4_;@ @;@@;@ _4_;@( ;@q9;@;@@g@g9U@@2-M@@._!RM6_8qT:;(R*5@@_!R57 ((R"@@ @6_3O@RR'4_l _8S@ kTS@S@) Q Jq, R_Wl>##@ R!R@ RH@77@1T@:@3#@/@7@3@/@_4_;@%_!R7(R @@h_R r kT:0%@@>@ @@ @_5dP0>{_@{Q_{C @)qT@!qT@%qaT_ @q@j@h4E@@@!(@@{A_C@(R) q T@q  @C_R@@ kT |Eii@ kTE @@_{CRC_4_E8 @@ kT |Eii_ kT(R8 @*8_8{B_{ EC_iRI1 @# @@RR CC_8qTX+#@(5# @RRC@4_C_4C_%  RC1C_{B_{ E_^qT^qaTRz>@_4_ qT_3^@RRc@9qATX+^[@5@_(@NR_<,E  R1>@{C_{ EC_# (R@RRnCC_8qATX5*8&C_h4C_T*8@qT(R8  RC*8*8_8{B_{`R{_{ EC_ qaT_# (R@RRCC_8qATX+C#@qT(R8C_4C_RC_  RC1*8_8{B_{ ECh_# HR@RRCC_8qATX+|C@qT(R8C_4C_0i  RC1b*8_8{B_{ E_^!qT^qTR2=;@H_ qT_3^@RRtc@9qATX+$!@5@_(@R_3   R1@{C_{ E  @?_R @RR13@9qATX+@5 @ @(@4  R1@{B_{ E_^ qTR@(E^ qTR);@H_ qT_3^@RRc@9qATX+@5@_(@p{R_/r  R1k@{C_{E(    E( E( "E) &E") *EB) .Eb) 2E) 6E) :E) >E) BE* FE"* JEB* NEb* RE* VE* ZE* ^E* bE+ fE"+ jEB+ nEb+ rE+ vE+ zE+ ~E+ E, E", EB, Eb, E, E, E, E, E- E"- EB- Eb- E- E- E- E- o x oz8  o(ooocccccccccccccccccccccccccccccccccccccccccc&_dom=adsp&_dom=mdsp&_dom=sdsp&_dom=cdsp&_dom=cdsp1%4I?: ;&II: ;  : ;  I: ; 8  I: ;8 $> I  : ;  : ;  : ; 4I: ;I!I7 $ > .@: ;'I : ;: ;I4: ;I : ;.@: ;'I?.@: ; ': ; I4: ; I!I7I9 %.@: ; 'I?: ; I4: ; I : ; .@: ; '$> I%I : ;($> I : ; I.@: ; 'I? : ; I 4: ; I : ; U 4: ;II: ;  : ;  I: ; 8 .@: ;'I?: ;II!I7 $ >  : ; I: ;8 %4I?: ; I!I7 I: ;  : ;  I: ; 8 $> $ > I : ; ( .@: ; 'I? : ; I4: ; I : ;  .@: ; 'I?.@: ;'I?: ;I4: ;I : ;I : ; I: ;8 0  = @ wEP--8 4"   (.0  ( B~__ uU !MAX)j@y ( z   _      BvB  _ ? ?_,h BB q"h_ v G4 * _J Z     BvB  _  ?_, BB q"h_  v{?BB BfB   8B^_ _$f_( ,w- ./0123   ( 4>  ;%G "~>-'1 9B CHS D , c mr}  B ^__f_ w  !  v@ 6 8w eX (xz z  1     .  B 4@m<BBxE<t <Bh <(=$> P?ED@  TBdm* MRRSSxEMt MBhM` MXM(N - OPPaXCEYC  LEm&fllmmxEft fBh f`f0g(h$PiEoF =,mV %% %=$m( (=0m 4E4 5B,>m+xE+t +Bh,dP-E/>?0m 8E8 9B?8mIEII JBBPm^xE^t& ^ ^ ^ _BDPm;bxEbt& b b b cBEDm@txEttTtVt uB4G0mg xEx yBdG8m|E|T| }BG0m4E BG0mE BG0m E B,H0mE B\Hm-|D -p--l-`.9 /: 06 H5 W 9 4 g]r?E M\= .BW} T_ BBB JBm\ e00S0b0 0  74,I,Im Bx2BpBl7DhREdF <GwHPIYKKmk%!   zLL J Mn d  )   ? G   Au lO   ^  /    8!DL m 4D |4D {P4 t<4D p6D h7 d8D X93 Po :@ Y$W H E 0 @2 TD  ט Vؘ Ot V p D p i 824TD0 ,V PT 9     D P #? TDN0  #? DTD D(DDWmf D|DPD7D W<D #5. D9 ,EPi Dq8} @i D D9= . i Dy DC}%EGC8  0TX| : ? KVi w~ ! @ G  t   L  -    K u    f x d    2A) TXDo   w Xo ww w ,Ym xw t w w !w Zm/w xi /t71wYU[0Z%6 [pmYw |i Yw pSY l] Y'7[wYt\[ ^k \$m  xwt7w\%]m ]<m xi wt7wY^] _ m ܃ xi wt7wY_$_  ``m0 w|i wpSl] '7wY.\a` b lamE 2w|i 2wS2 74wYRHba:Xbxmv Vw|i VwpSVl] V'7XwYcb l Kw  8i ':q'<S'>'maxArgsroutSizePrimInnCasesinCaseAlignmentstringsAEEResulthap_example_mem_fastrpc_mmaph64_nErrbailprint_usageunsignedpd_flagFASTRPC_MAP_FD_NOMAPDOMAIN_SUPPORTdsp_capability_async_supportarrayTypeSequenceTypeunionTyperoutCaseAlignmentPrimIniidshap_example_vtcm_mgr_primInaddrerrprimmethodStringsArraysremote_buf_nErrbuffer_lengthFASTRPC_REMOTE_PROCESS_TYPERPCMEM_HEAP_ID_SECUREFASTRPC_MAP_RESERVED_6FASTRPC_MAP_RESERVED_13_castbSigned__uint8_tparametersnMethodsbDefaultCasemode_stub_method_1_in1va_listflagsbooleanDSPRPC_GET_DOMAINnMaxLenunsigned charprimInAlignmentparameterArraysFASTRPC_MAP_STATICFASTRPC_MAP_RESERVED_4handleget_domainis_valid_domain_idget_vtcm_infoidsp_capability_arch_vervalue32scasesbufferLenstd__vr_offsbFloatingcaseValuesvalue16sunsigned short__ARRAY_SIZE_TYPE__fdremote_arg__gr_offsFASTRPC_MAP_FD_DELAYEDallocC:/Qualcomm/Hexagon_SDK/6.1.0.0/examples/hap_example_copyintnativeSizeparamroutCaseAlignmentPrimROutnativeCaseAlignmentStructTypebInterfaceNotNilmethodStringArrayhap_example_perf_handlepvis_unsignedpd_enabledroutSizePrimROutroutAlignmentPrimInFASTRPC_SESSION_CLOSEretValidion_bufferSTATUS_NOTIFICATION_SUPPORTuri_praargvFASTRPC_REMOTE_PROCESS_KILLFASTRPC_RESERVE_NEW_SESSIONFASTRPC_MAP_RESERVED_14C:\Qualcomm\Hexagon_SDK\6.1.0.0/utils/examples/dsp_capabilities_utils.cARCH_VERmethodArraynumParamsunsigned long__copyhap_example_mem_map_reserve_vadomain_iddomain_tHMX_SUPPORT_SPATIALget_unsignedpd_supportAndroid (9352603, based on r450784d1) clang version 14.0.7 (https://android.googlesource.com/toolchain/llvm-project 4c603efb0cca074e9238af8b4106c30add4418f6)hap_example_slim__uint32_tint32_t__uint16_tvalue64sTypedma_in0FdlineDSPRPC_SET_PATHDSPRPC_GET_PATHunsigned intchar_stub_method_3remote_handle64_nErrfarfbail__vr_top__va_listVTCM_COUNTattribute_IDprimInSizeprimROutSize__uintptr_tarrayinSizemethodsformat__gr_topFASTRPC_RESERVED_1sizemappedmbHVX_SUPPORT_64Buint32_tparamsuint64_tMethodar_stub_methodFASTRPC_PD_INITMEM_SIZEfastrpc_map_flagscapabilitydsp_capability_vtcm_dspbNotNiluint16_thap_example_powernLen_in0LenFASTRPC_THREAD_PARAMSFASTRPC_RESERVED_2FASTRPC_MAP_RESERVEDhap_example_URI_domainHVX_SUPPORT_128BnativeAlignmentmethodStrings_stub_method_2bufsize_tlevelDSPRPC_CONTROL_UNSIGNED_MODULEdomainretDSPRPC_RESERVEDDSPRPC_CONTROL_LATENCYASYNC_FASTRPC_SUPPORTdsp_capability_status_notification_supportUnionTypeoffsetRPCMEM_HEAP_ID_CONTIGuScalarsp2CaseValuePtrParameterbuffer_praHandleInargsFASTRPC_GET_URIFASTRPC_MAP_RESERVED_5run_testmy_domainprocess_typehap_example_compute_reshap_example_sysmon_cachelockis_status_notification_supporteduintptr_tseqSimpleuint8_thap_example_compute_resv2mainFASTRPC_MAP_RESERVED_10FASTRPC_MAP_RESERVED_11handle_control_req_idattrdsp_capability_hmx_dsp__int32_tobjectseqComplex__uint64_tFASTRPC_GET_EFFECTIVE_DOMAIN_IDFASTRPC_MAP_FDdatais_unsignedpd_supportedcompute_onlyp1nMembers_in0FASTRPC_REGISTER_STATUS_NOTIFICATIONSmap_buf_tsupported_domainsDSPRPC_CONTROL_WAKELOCKHMX_SUPPORT_DEPTHget_hvx_support_infoinAlignmenthiinItemsroutAlignmentPrimROutmembersnIIdsmethodArrays_in0Offset_BoolRPCMEM_HEAP_ID_SYSTEMenableremote_process_typelenremote_dsp_attributesget_hmx_support_infoget_hex_arch_verhap_example_openhap_example_mem_reserve_va_midbufferOffsetuint32src_app/hap_example.cFASTRPC_MAP_RESERVED_7FASTRPC_MAP_RESERVED_8FASTRPC_MAP_RESERVED_15hap_exampleVTCM_PAGEis_CDSPget_dsp_supportdsp_capability_domainhap_example_mem_dmahandlev2remote_handle__stack__builtin_va_listFASTRPC_CONTROL_PD_DUMPsession_control_req_idandroid_Debug_aarch64/hap_example_stub.ciidstringMaxLentyperemote_dma_handlemap_buf_inforemote_dsp_capabilitystructTypeInterfacesrc_app/hap_example_main.coptionbailFASTRPC_MAP_RESERVED_9UNSIGNED_PD_SUPPORTis_async_fastrpc_supporteddsp_capability_hvx_dspseqTypeprimROutAlignmenthap_example_farf_runtimehap_example_mem_dmahandle_HAP_debug_v2runtime_logging_enablefileargcnErrexample_selectorFASTRPC_RELATIVE_THREAD_PRIORITYFASTRPC_RESERVED_3FASTRPC_REMOTE_PROCESS_EXCEPTIONrpc_heap_idsDSPRPC_GET_DSP_INFOdescriptorvalue8shap_example_closeFASTRPC_MAP_RESERVED_12hap_example_URI_domain_lenremote_rpc_control_unsigned_moduleLinker: LLD 14.0.7Android (9352603, based on r450784d1) clang version 14.0.7 (https://android.googlesource.com/toolchain/llvm-project 4c603efb0cca074e9238af8b4106c30add4418f6)0  android_Debug_aarch64C:/Qualcomm/Hexagon_SDK/6.1.0.0C:\Qualcomm\Hexagon_SDK\6.1.0.0/incsC:\Qualcomm\Hexagon_SDK\6.1.0.0/incs/stddefhap_example_stub.ctools/android-ndk-r25c/toolchains/llvm/prebuilt/windows-x86_64/bin/../sysroot/usr/include/stdint.hHAP_debug.hAEEStdDef.hremote.htools/android-ndk-r25c/toolchains/llvm/prebuilt/windows-x86_64/lib64/clang/14.0.7/include/stddef.htools/android-ndk-r25c/toolchains/llvm/prebuilt/windows-x86_64/lib64/clang/14.0.7/include/stdarg.h =/ =4J JJ0  JJ  =K!J JJu} (KKJ0JJ}JJJ}JJ}0}<}J}0}<}JJ}JJK KJ =K!J JJ K#J JJq} , KKKJJ0JJ}JJJ}JJ}0}<}J}0}<}JJ}JJK KJ 4K#J JJm} 8KKKJ=J=J4JLJJKJ0JJJKJ}JJJ}JJ}0}<}J}0}<}JJ}JJK KJ 4K#J JJ (K#J JJp} 0 KKKJJJ0JJ}JJJ}JJ}0}<}J}0}<}JJ}JJK KJ =K!J JJ K#J JJ =K!J JJ =K!J JJ =K!J JJ =K!J JJ} T ,J,J JJKB2 src_apphap_example_main.c ,I  tKK KLJ"JJJJ JJ)J$J"JKJ0J+J)JKJ/J*J(JKLuJJ J KJSJ  KKL  JJ5K;JJ KKMJ  JJ?KEJJ KKMJ9!JJ JoJ K KK9K9jJJK#J:J J  KJ-J KHPJ~ K;M~J  JZ 'J  C:\Qualcomm\Hexagon_SDK\6.1.0.0/incsC:\Qualcomm\Hexagon_SDK\6.1.0.0/ipc/fastrpc/rpcmem/incsrc_appC:/Qualcomm/Hexagon_SDK/6.1.0.0C:\Qualcomm\Hexagon_SDK\6.1.0.0/incs/stddefremote.hrpcmem.hhap_example.ctools/android-ndk-r25c/toolchains/llvm/prebuilt/windows-x86_64/bin/../sysroot/usr/include/stdint.htools/android-ndk-r25c/toolchains/llvm/prebuilt/windows-x86_64/lib64/clang/14.0.7/include/stddef.hAEEStdDef.h L4Kt  64  K KLJ KJC>JBKJJAJ ?KMJ J*(JJGJK LJJfKJ KL2L+J! JJBKJ KJJ/JdJoJJ J KJ7J  KJJ JKJOWJJ K NJJ${JKJ .JJLK KLJ & & K~J  LJ~K~J#JJJMJ~JJK~JJ(J~+J6J:JJLJ~&?MGJKJ"J JKJ~JK.L9JJKJb~JKK JJ~K\K~J~J K~J~J0L8JJFJJJKJ|J KL JK$ JJ|K|J 0JJL|K KL|J  K|JJJ| JJ|J JKLJ| K|J | LJ =K J$JJJ J7K'J>J KJ|FJXJ|J  KK<zJ QJ  * C:\Qualcomm\Hexagon_SDK\6.1.0.0/incsC:/Qualcomm/Hexagon_SDK/6.1.0.0C:\Qualcomm\Hexagon_SDK\6.1.0.0/utils/examplesremote.hdomain_default.htools/android-ndk-r25c/toolchains/llvm/prebuilt/windows-x86_64/bin/../sysroot/usr/include/stdint.hdsp_capabilities_utils.c TX ),6J)mJJ  L JJJJ JhJ"(J J'gJ JGO =LJJ J  JJJJ JXJ"((J JX)JGYJ,J?P  1K LL&6J K JH :K"M JB*J0K.KJ&KJJ K K LJBJ KLJJJ b "JJ  tKJLJJJJJ KJJ %J( J8,4K2J0KJKJJKKLJ7JJ KDLJKJ JJJ/KJ KL~JJ~J _ %JJ~  K?>uJ K J~  J_~J " J~ J~JJ~J ~J? J~  K J=175KJKJ~~JKK3LJ~J~JJQ~JK L~JJEK~J KL~JJ~J _~JJ>~  LG;A?KJ K J~ ~J K K=LJ~ J~ JJS~J KL~JJ~J f~JJ?}  tKJL$J'J}J}J K}JJ J7+3K1J/KJKJ}}JKKLJ6JJ KKL}JK}J J}JJ@K}J KL}JJ}J _ %JJ}  KJK4(.,KJ K J} }J K KLJ3JJ KCL}J K}JJ}JJ}J g JJ}  tKJKJ}J}J KMJ}J}J K}JJ J7+3K1J/KJKJ}}JKKLJ6JJ KKL}JK}J J}JJCK|J KL|JJ|J _ %JJ ,L  x  = ,>& \H4 4@C TBdR LEa vpn vs 8w{. (x0'  @) ,I KnI4  @)4 Ln',  @)z TXn (8'  @)Xx. =,?T =$f| =0   ?0 ?8 BP2 DPN EDk 4G0 dG8 G0 G0 G0 ,H0  w8 ,I$+27> ZN ,Ya \$y L "" X""  W$ TXD,P>"T [pb ]y ]< _  `` la Xbx.dynsym.gnu.version.gnu.version_r.gnu.hash.dynstr.rela.dyn.rela.plt.rodata.eh_frame_hdr.eh_frame.text.plt.data.rel.ro.dynamic.got.got.plt.data.debug_abbrev.debug_info.debug_str.comment.debug_line.debug_ranges.symtab.shstrtab.strtabhap_example_stub.c$x.0_stub_method_HAP_debug_v2_stub_method_1_stub_method_2_stub_method_3methodArrays$d.1methodsmethodStringsArrays$d.2methodStringsstringsparameterArraysparameters$d.3$d.4$d.5$d.6$d.7$d.8$d.9hap_example_main.cprint_usagehap_example.cdsp_capabilities_utils.chap_example_openremote_handle64_openhap_example_closeremote_handle64_closehap_example_compute_resHAP_debug_v2HAP_debug_runtimeremote_handle64_invokehap_example_compute_resv2hap_example_farf_runtimehap_example_mem_dmahandleremote_register_dma_handlehap_example_mem_dmahandlev2hap_example_mem_fastrpc_mmaphap_example_mem_reserve_vahap_example_mem_map_reserve_vahap_example_perfhap_example_powerhap_example_sysmon_cachelockhap_example_vtcm_mgrvsnprintfHAP_debughap_example_slimmainoptarggetoptatoiprintfget_dsp_supportis_valid_domain_idis_unsignedpd_supportedhap_exampleremote_session_controlfastrpc_mmapget_domainmallocsnprintfrpcmem_allocrpcmem_to_fdrpcmem_freefastrpc_munmaprpcmem_alloc2freerun_teststderrfprintfis_CDSPsupported_domainsremote_handle_controlget_vtcm_infoget_unsignedpd_supportis_async_fastrpc_supportedis_status_notification_supportedget_hmx_support_infoget_hex_arch_verget_hvx_support_info_DYNAMIC 88X oro %o((/  7  xABK2S(($a@)@)lk=-$&qcSvvVXxXXyY@zZh[P[[`0M|>0= J 9fastrpc-1.0.2/test/android/libmultithreading.so000066400000000000000000001011001512345705400216240ustar00rootroot00000000000000ELF@{@8 @@@@--tt4TT7ggPP4TTRtd4TT PtdQtd?q ~   l"" -,- 7 6DgP= >` /0 0T@ :$ <<<R ? x8 6D x= * -$ (T8 <U -0 /0X L3< 7 9pc @xxc  @BD@ @ !]@REjʀtr#9Dtj|mA-bX`~AHFÿ?plA<[T#^multithreading_openremote_handle64_openmultithreading_closeremote_handle64_closemultithreading_parallel_sumHAP_debug_v2HAP_debug_runtimeremote_handle64_invokemultithreading_barriersmultithreading_mutexesvsnprintfHAP_debugmultithreading_slimmaingetoptoptargatoiprintfget_dsp_supportis_valid_domain_idis_unsignedpd_supportedmultithreading_testremote_session_controlget_domainmallocsnprintffreerun_testis_CDSPsupported_domainsremote_handle_controlget_vtcm_infoget_unsignedpd_supportis_async_fastrpc_supportedis_status_notification_supportedget_hmx_support_infoget_hex_arch_verget_hvx_support_infolibc.soLIBClibadsprpc.solibm.solibdl.solibmultithreading.soT`TTTTTTT TT0TTHTPT XTxTTTTTPTpTpVxVV V VVVVVVV!VVVV"WWWW W (W0W8W@W#HW PW$XW `WhWpWxW$)-- parallel_sumbarriersmutexescloseopenurihERROR 0x%x: returned from function : multithreading_parallel_sum get_dsp_support failed with Error 0x%x multithreading_stub.cLatest targets have 128 byte HVX register, use HVX_SUPPORT_128B instead of HVX_SUPPORT_64B Unsupported attr. Only HVX_SUPPORT_128B supported Test FAILED FastRPC Capability API is not supported on this device Unsupported domain %d file:///libmultithreading_skel.so?multithreading_skel_handle_invoke&_modver=1.0ERROR 0x%x returned from snprintf unable to allocated memory for uri of size: %d ERROR 0x%x: Invalid domain %d Attempting to run on %s PD on domain %d Exiting... HVX support is not available on domain %d is_status_notification_supported failed with Error 0x%x ERROR in get_dsp_support: 0x%x, defaulting to CDSP domain remote_dsp_capability interface is not supported on this device Unsupported attr. Only HMX_SUPPORT_SPATIAL and HMX_SUPPORT_DEPTH supported HMX support is not there for domain %d Setting relative thread priority is not supported on this device ERROR 0x%x: returned from function : multithreading_mutexes FastRPC Capability API is not supported on this device. Falling back to signed pd. _stub_methodERROR 0x%x: Test FAILED ERROR 0x%x: unable to get domain struct %d ERROR 0x%x: returned from function : multithreading_barriers Test PASSED Please look at the mini-dm logs or the adb logcat logs for DSP output is_async_fastrpc_supported failed with Error 0x%x Overriding user request for unsigned PD. Only signed offload is allowed on domain %d. get_hex_arch_ver failed with Error 0x%x ERROR 0x%x: handle=0x%lx, scalar=0x%x, method ID=%d: %s failed ERROR 0x%x: Unable to create FastRPC session on domain %d d:U:unsignedsignedERROR 0x%x: remote_session_control failed get_hmx_support_info failed with Error 0x%x Unsupported attr. Only VTCM_PAGE and VTCM_COUNT supported Running the usecase without checking the capability get_vtcm_info failed with Error 0x%x ERROR 0x%x: FastRPC Capability API failed. Falling back to signed pd. get_hvx_support_info failed with Error 0x%x Async fastrpc is not supported on domain %d %s%s DSP domain is not provided. Retrieving DSP information using Remote APIs. ERROR 0x%x: Invalid unsigned PD flag %d remote_dsp_capability interface is not supported on this device. Falling back to signed pd. ERROR 0x%x: remote_session_control interface is not supported on this device Usage: multithreading [-d domain] [-U unsigned_PD] Options: -d domain: Run on a specific domain. 0: Run the example on ADSP 3: Run the example on CDSP 2: Run the example on SDSP Default Value: 3(CDSP) for targets having CDSP and 0(ADSP) for targets not having CDSP like Agatti. -U unsigned_PD: Run on signed or unsigned PD. 0: Run on signed PD. 1: Run on unsigned PD. Default Value: 1 ;0<\|0Tp<4Tl !D"`" #,$L&l&zR| ,L <$L \0L |L l0L |0L P  <TL pH <l<L \DL |DDD TL L pL  L$L ,PH LL<L lh L T!`L "L `#xL {C@@6{A_{C@5{A_{CHR@@{A_C{9C=CCC_C_*(a* * * * *^C`4C^H4@h6:@(6C^_C_*(a* * * * *C_ (`R!p<%Rch>@(C^_C_*(a* * * * *C_ (`R!p<%RchC^{DC_{ChR@@{A_{CR@@{A_{ C#====== ==WSOKCsCok^7=;=3=/= R*@__^C @{¨_{(R?9__BT1T@ UqT @qTAC@r AC@lib@1!TbSd^4^X@*[`7R^@JE=@7@qmTR^@4:5-@qT@>?9?@97@d)?@9 )iJq@@?@9&^4^0 ^_{C_{ {_{CEC(R( 8Ch RC_@HRCC__ _86@h6_c(R@RRC4C_RCC_Py@(6_C(RRCC_QqTC_qT  C_4C_XC HRCC^DJ@C@BcxCC_q*TC_~(RC5@cDCC_h4C__ho$l%^ECC_4C_:a^FCC_4C_HV^?CC_4C_ K^@@fC_5D;?7x3C_{E_{C(R( 8__83@{A_C@(R) q T@q  @C_R@@ kT |ICii@ kTIC @@_{CRC_4_8 @@ kT |ICii_ kT(R8 @*8_8{B_{MCC_iRIA' @# @@RRCC_8qT8?#@(5# @RRC@4_C_4C_;{  RCtC_{B_{MC_^qT^qaTR T>@_4_ qT_3^@RRlc@9qAT8?85@5@_(@(R_  R@{C_{MCC_# (R@RR,CC_8qAT *8&C_h4C_h*8@qT(R8  RC*8*8_8{B_{`R{_{MCC_ qaT_# (R@RRCC_8qAT8?C#@qT(R8C_4C_RC_<  RC*8_8{B_{MCCh_# HR@RRCC_8qAT8?YVC@qT(R8C_4C_C  RC<*8_8{B_{MC_^!qT^qTR;@H_ qT_3^@RR2c@9qAT8?@5@_(@TR_  R@{C_{MC  @?_R @RR3@9qAT8?@5 @ @(@  R@{B_{MC_^ qTR<E^ qTR8>~;@H_ qT_3^@RRc@9qAT8?eb@5@_(@UR_TL  RE@{C_{ZC    ^C bC fC" jCB nCb rC vC zC ~C C C" CB Cb C C C C C C" CB Cb C C C C xo  o XV8   oPoo0oPBPBPBPBPBPBPBPBPBPBPBPBPBPBPBPBPBPBPBPBPBPBPBPBPB&_dom=adsp&_dom=mdsp&_dom=sdsp&_dom=cdsp&_dom=cdsp1%4I?: ;&II: ;  : ;  I: ; 8  I: ;8 $> I  : ;  : ;  : ; 4I: ;I!I7 $ > .@: ;'I?: ;I4: ;I.@: ;'I : ;.@: ; ': ; I4: ; I!I7I9 %I : ;($> I.@: ; 'I?: ; I 4: ; I : ;  .@: ; ' U I: ;  : ;  I: ; 8 I!I7 $ >  : ; I: ;8 %4I?: ; I!I7 I: ;  : ;  I: ; 8 $> $ > I : ; ( .@: ; 'I? : ; I4: ; I : ;  .@: ; 'I?.@: ;'I?: ;I4: ;I : ;I : ; I: ;8  & -PW@ (TEP, , 8Kx 0$  a (.0  (\>([3[ q  !IATx)f@2 ( v{ uu [ (  e<   >>L ` [;  [d l>.>C m! d [ QaG @4 & [F (V  e<   >>L ` [  [ l>.>C m! d [ Q rw >R> >k> 8< >v*ZR[ [$k[(R ,|-g ./012T3h hG  !0: ;6%  >)' 5> ?DOD N , _ iny  >} ZR[[k[R |g    T Y2 `T T Tv @v P   a   . 0-,m8 !!^ ! -$m$^ $ -0mL 0 60  1> .m'x6' t '>h( d)+./0m4 64  5>/0m8 68  9> 0m -|z-p -l-`a.o/ 0 6 D   o* ^ ^ @ i 5  >R S  s.>h t  [> f ~ 0 v R 0hR 0R 0040w >U0 q-         Y 0Tm'Cx 'Cp"'J l# )C J *C +C P,C A-O Q `3 03mDL3<m6 dC|dC{AdO tfC hgV dnhC ( i  j~ Q (6 y u 0 y 6DmC|C{AO # C  a lD wN , C O C C CSCv 'b6|  ? gKVw~      (      K ` V   @   o     2Ax) 6Do   w 7o ww w 7m xw t w w !w x8m /w x/t# 1wQ U|98" 6 9pmYw |Yw pY l Y'# [wQ : : k :$m~  xwt# w ;"  <m <<<mj  xwt# wQ P=p<o x= m܃ xwt# wQ \>=>`m w|wpl '# wQ .??  ?m 2w|2w2 # 4wQ R@@ :@xm Vw|VwpVl V'# XwQ 8BlA l Kw 8':'<'>'maxArgsroutSizePrimInnCasesinCaseAlignmentstringsAEEResulth64print_usageunsignedpd_flagDOMAIN_SUPPORTdsp_capability_async_supportarrayTypeSequenceTypeunionTyperoutCaseAlignmentPrimIniidsprimmethodStringsArraysmultithreading_barriersremote_buf_nErrFASTRPC_REMOTE_PROCESS_TYPE_castbSigned__uint8_tparametersnMethodsbDefaultCasemodeva_listmultithreading_URI_domain_lenDSPRPC_GET_DOMAINnMaxLenunsigned charprimInAlignmentparameterArrayshandleget_domainis_valid_domain_idget_vtcm_infoidsp_capability_arch_vervalue32scasesstd__vr_offssrc/multithreading.crelative_thread_prioritybFloatingcaseValuesvalue16sunsigned short__ARRAY_SIZE_TYPE__fdremote_arg__gr_offsintnativeSizeparamroutCaseAlignmentPrimROutnativeCaseAlignmentStructTypebInterfaceNotNilmethodStringArray_handlepvis_unsignedpd_enabledmultithreading_slimroutSizePrimROutroutAlignmentPrimInmultithreading_closeFASTRPC_SESSION_CLOSEretValidSTATUS_NOTIFICATION_SUPPORTuri_praFASTRPC_REMOTE_PROCESS_KILLFASTRPC_RESERVE_NEW_SESSIONargvC:\Qualcomm\Hexagon_SDK\6.1.0.0/utils/examples/dsp_capabilities_utils.cARCH_VERmethodArraynumParamsunsigned longdomain_iddomain_tHMX_SUPPORT_SPATIALget_unsignedpd_supportAndroid (9352603, based on r450784d1) clang version 14.0.7 (https://android.googlesource.com/toolchain/llvm-project 4c603efb0cca074e9238af8b4106c30add4418f6)__uint32_tint32_t__uint16_tvalue64sTypedmalineDSPRPC_SET_PATHDSPRPC_GET_PATHunsigned intcharremote_handle64_nErrfarfbail__vr_top__va_listVTCM_COUNTattribute_IDprimInSizeprimROutSize__uintptr_tarrayinSizemethodsformat__gr_topFASTRPC_RESERVED_1HVX_SUPPORT_64Bsizeuint32_tparamsuint64_tMethod_stub_methodFASTRPC_PD_INITMEM_SIZEcapabilitydsp_capability_vtcm_dspbNotNiluint16_tnLenFASTRPC_THREAD_PARAMSFASTRPC_RESERVED_2HVX_SUPPORT_128BnativeAlignmentmethodStringsbufsize_tlevelDSPRPC_CONTROL_UNSIGNED_MODULEdomainDSPRPC_RESERVEDDSPRPC_CONTROL_LATENCYASYNC_FASTRPC_SUPPORTdsp_capability_status_notification_supportUnionTypeoffsetC:/Qualcomm/Hexagon_SDK/6.1.0.0/examples/multithreading_copyuScalarsp2CaseValuePtrParameterargsFASTRPC_GET_URIrun_testmy_domainmultithreading_mutexesis_status_notification_supporteduintptr_tseqSimpleuint8_tmainhandle_control_req_idattrdsp_capability_hmx_dsp__int32_tobjectseqComplex__uint64_tFASTRPC_GET_EFFECTIVE_DOMAIN_IDdatais_unsignedpd_supportedcompute_onlyp1nMembersFASTRPC_REGISTER_STATUS_NOTIFICATIONSsupported_domainsDSPRPC_CONTROL_WAKELOCKHMX_SUPPORT_DEPTHget_hvx_support_infoandroid_Debug_aarch64/multithreading_stub.cinAlignmenthnItemsroutAlignmentPrimROutmembersnIIdsmethodArrays_Boolmultithreading_URI_domainenableremote_dsp_attributesget_hmx_support_infoget_hex_arch_ver_midVTCM_PAGEis_CDSPget_dsp_supportdsp_capability_domainmultithreading_openmultithreading_parallel_sumremote_handle__stack__builtin_va_listFASTRPC_CONTROL_PD_DUMPsession_control_req_idiidstringMaxLentyperemote_dma_handleremote_rpc_relative_thread_priorityremote_dsp_capabilitystructTypeInterfacemultithreading_testoptionbailUNSIGNED_PD_SUPPORTis_async_fastrpc_supporteddsp_capability_hvx_dspseqTypeprimROutAlignment_HAP_debug_v2fileFASTRPC_RELATIVE_THREAD_PRIORITYFASTRPC_RESERVED_3FASTRPC_REMOTE_PROCESS_EXCEPTIONargcnErrDSPRPC_GET_DSP_INFOdescriptorvalue8sremote_rpc_control_unsigned_moduleLinker: LLD 14.0.7Android (9352603, based on r450784d1) clang version 14.0.7 (https://android.googlesource.com/toolchain/llvm-project 4c603efb0cca074e9238af8b4106c30add4418f6)Q android_Debug_aarch64C:/Qualcomm/Hexagon_SDK/6.1.0.0C:\Qualcomm\Hexagon_SDK\6.1.0.0/incsC:\Qualcomm\Hexagon_SDK\6.1.0.0/incs/stddefmultithreading_stub.ctools/android-ndk-r25c/toolchains/llvm/prebuilt/windows-x86_64/bin/../sysroot/usr/include/stdint.hHAP_debug.hAEEStdDef.hremote.htools/android-ndk-r25c/toolchains/llvm/prebuilt/windows-x86_64/lib64/clang/14.0.7/include/stddef.htools/android-ndk-r25c/toolchains/llvm/prebuilt/windows-x86_64/lib64/clang/14.0.7/include/stdarg.h -/ =4J JJ0  JJ  =K!J JJu} (KKJ0JJ}JJJ}JJ}0}<}J}0}<}JJ}JJK KJ =K!J JJ =K!J JJ} T ,J,J JJK  C:\Qualcomm\Hexagon_SDK\6.1.0.0/incssrcC:/Qualcomm/Hexagon_SDK/6.1.0.0remote.hmultithreading.ctools/android-ndk-r25c/toolchains/llvm/prebuilt/windows-x86_64/bin/../sysroot/usr/include/stdint.h 0' uK KLJ"JQJ/JJ P0JP)1$J"JKNJ/3*J(JKLx JJE <J KJSAJ ? KKL JJ5K;JJ KKMJJJ?KEJJ KKMJ9!JJ JoJ K KK9L9jJ K+J J  KJ-J KH PJi  J  $  K KLJJ KJJBKJJJ KMJ J*(JJGJK LJJfKJ KL~JJ'JK*J. J~  KKJC~J K~JJ5L.J$J J~JBK~J KM2JmJxJ~J J KJ7~J  K"M JLJOWJ~J ~J K*MJ J KJW~J K&MJ JKJS~J K%MJ JKJR~J KMJ J JKLJ~ K~J ~ LJ K(J J KJ  * C:\Qualcomm\Hexagon_SDK\6.1.0.0/incsC:/Qualcomm/Hexagon_SDK/6.1.0.0C:\Qualcomm\Hexagon_SDK\6.1.0.0/utils/examplesremote.hdomain_default.htools/android-ndk-r25c/toolchains/llvm/prebuilt/windows-x86_64/bin/../sysroot/usr/include/stdint.hdsp_capabilities_utils.c 6 ),6J)mJJ  L JJJJ JhJ"(J J'gJ JGO =LJJ J  JJJJ JXJ"((J JX)JGYJ,J?P  1K LL&6J K JH :K"M JB*J0K.KJ&KJJ K K LJBJ KLJJJ b "JJ  tKJLJJJJJ KJJ %J( J8,4K2J0KJKJJKKLJ7JJ KDLJKJ JJJ/KJ KL~JJ~J _ %JJ~  K?>uJ K J~  J_~J " J~ J~JJ~J ~J? J~  K J=175KJKJ~~JKK3LJ~J~JJQ~JK L~JJEK~J KL~JJ~J _~JJ>~  LG;A?KJ K J~ ~J K K=LJ~ J~ JJS~J KL~JJ~J f~JJ?}  tKJL$J'J}J}J K}JJ J7+3K1J/KJKJ}}JKKLJ6JJ KKL}JK}J J}JJ@K}J KL}JJ}J _ %JJ}  KJK4(.,KJ K J} }J K KLJ3JJ KCL}J K}JJ}JJ}J g JJ}  tKJKJ}J}J KMJ}J}J K}JJ J7+3K1J/KJKJ}}JKKLJ6JJ KKL}JK}J J}JJCK|J KL|JJ|J _ %JJ  <DP<D| - .) 07 T(D TI `TxQ ej x0 TP`  0 03DUew  U 6Dgev bkT -, -$2H -0d q  /0 /0  (T8 0T  x8  73 :$K L3<_"v 7 6D 6DgP" 9p < <<< x= 0 >`E ?V @x.dynsym.gnu.version.gnu.version_r.gnu.hash.dynstr.rela.dyn.rela.plt.rodata.eh_frame_hdr.eh_frame.text.plt.data.rel.ro.dynamic.got.got.plt.data.debug_abbrev.debug_info.debug_str.comment.debug_line.debug_ranges.symtab.shstrtab.strtabmultithreading_stub.c$x.0_stub_method_HAP_debug_v2methodArrays$d.1methodsmethodStringsArrays$d.2methodStringsstringsparameterArraysparameters$d.3$d.4$d.5$d.6$d.7$d.8$d.9multithreading.cprint_usagedsp_capabilities_utils.cmultithreading_openremote_handle64_openmultithreading_closeremote_handle64_closemultithreading_parallel_sumHAP_debug_v2HAP_debug_runtimeremote_handle64_invokemultithreading_barriersmultithreading_mutexesvsnprintfHAP_debugmultithreading_slimmaingetoptoptargatoiprintfget_dsp_supportis_valid_domain_idis_unsignedpd_supportedmultithreading_testremote_session_controlget_domainmallocsnprintffreerun_testis_CDSPsupported_domainsremote_handle_controlget_vtcm_infoget_unsignedpd_supportis_async_fastrpc_supportedis_status_notification_supportedget_hmx_support_infoget_hex_arch_verget_hvx_support_info_DYNAMIC 88 oNo00 %oPP/  7 AB XK2 Sak-qPBP2vT4T4pVp60V6g7P7;0kOr 0\]gn`Xo,w xtfastrpc-1.0.2/test/fastrpc_test.c000066400000000000000000000142361512345705400170140ustar00rootroot00000000000000// 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 // For PATH_MAX #define DSP_AEE_EUNSUPPORTED 0x80000414 typedef int (*run_test_t)(int domain_id, bool is_unsignedpd_enabled); static void print_usage() { printf("Usage:\n" " fastrpc_test [-d domain] [-U unsigned_PD] [-t target] [-a arch_version]\n\n" "Options:\n" "-d domain: Run on a specific domain.\n" " 0: Run the example on ADSP\n" " 1: Run the example on MDSP\n" " 2: Run the example on SDSP\n" " 3: Run the example on CDSP\n" " Default Value: 3(CDSP) for targets having CDSP.\n" "-U unsigned_PD: Run on signed or unsigned PD.\n" " 0: Run on signed PD.\n" " 1: Run on unsigned PD.\n" " Default Value: 1\n" "-t target: Specify the target platform (android or linux).\n" " Default Value: linux\n" "-a arch_version: Specify the architecture version (v68 or v75).\n" " Default Value: v68\n" ); } int main(int argc, char *argv[]) { int domain_id = 3; // Default domain ID for CDSP bool is_unsignedpd_enabled = true; // Default to unsigned PD const char *target = "linux"; // Default target platform const char *arch_version = "v68"; // Default architecture version char ld_lib_path[PATH_MAX]; char dsp_lib_path[PATH_MAX]; char *current_ld_lib_path; char *current_dsp_lib_path; DIR *dir; struct dirent *entry; char full_lib_path[PATH_MAX]; void *lib_handle = NULL; run_test_t run_test = NULL; int nErr = 0; int tests_run = 0; int tests_passed = 0; int tests_failed = 0; int tests_skipped = 0; int opt; while ((opt = getopt(argc, argv, "d:U:t:a:")) != -1) { switch (opt) { case 'd': domain_id = atoi(optarg); break; case 'U': is_unsignedpd_enabled = atoi(optarg) != 0; break; case 't': target = optarg; if (strcmp(target, "linux") != 0 && strcmp(target, "android") != 0) { printf("\nERROR: Invalid target platform (-t). Must be linux or android.\n"); print_usage(); return -1; } break; case 'a': arch_version = optarg; if (strcmp(arch_version, "v68") != 0 && strcmp(arch_version, "v75") != 0) { printf("\nERROR: Invalid architecture version (-a). Must be v68 or v75.\n"); print_usage(); return -1; } break; default: print_usage(); return -1; } } current_ld_lib_path = getenv("LD_LIBRARY_PATH"); if (current_ld_lib_path) { snprintf(ld_lib_path, sizeof(ld_lib_path), "%s;%s", current_ld_lib_path, testlibdir); } else { snprintf(ld_lib_path, sizeof(ld_lib_path), "%s", testlibdir); } if (setenv("LD_LIBRARY_PATH", ld_lib_path, 1) != 0) { fprintf(stderr, "Error setting LD_LIBRARY_PATH: %s\n", strerror(errno)); return -1; } current_dsp_lib_path = getenv("DSP_LIBRARY_PATH"); if (current_dsp_lib_path) { snprintf(dsp_lib_path, sizeof(dsp_lib_path), "%s;%s/%s", current_dsp_lib_path, testdspdir, arch_version); } else { snprintf(dsp_lib_path, sizeof(dsp_lib_path), "%s/%s", testdspdir, arch_version); } if (setenv("DSP_LIBRARY_PATH", dsp_lib_path, 1) != 0) { fprintf(stderr, "Error setting DSP_LIBRARY_PATH: %s\n", strerror(errno)); return -1; } dir = opendir(testlibdir); if (!dir) { fprintf(stderr, "Error opening directory %s: %s\n", testlibdir, strerror(errno)); return -1; } while ((entry = readdir(dir)) != NULL) { if (entry->d_type == DT_REG && strstr(entry->d_name, ".so")) { snprintf(full_lib_path, sizeof(full_lib_path), "%s/%s", testlibdir, entry->d_name); lib_handle = dlopen(full_lib_path, RTLD_LAZY); if (!lib_handle) { fprintf(stderr, "Error loading %s: %s\n", full_lib_path, dlerror()); continue; } run_test = (run_test_t)dlsym(lib_handle, "run_test"); if (!run_test) { fprintf(stderr, "Symbol 'run_test' not found in %s\n", full_lib_path); dlclose(lib_handle); continue; } nErr = run_test(domain_id, is_unsignedpd_enabled); tests_run++; if (nErr == 0) { tests_passed++; printf("[PASS] %s\n\n", entry->d_name); } else if (nErr == DSP_AEE_EUNSUPPORTED) { tests_skipped++; printf("[SKIP] %s (not applicable to this hardware)\n\n", entry->d_name); } else { tests_failed++; printf("[FAIL] %s (error code: 0x%x)\n\n", entry->d_name, nErr); } dlclose(lib_handle); } } closedir(dir); printf("\n========================================\n"); printf("Test Summary:\n"); printf(" Total tests run: %d\n", tests_run); printf(" Passed: %d\n", tests_passed); printf(" Failed: %d\n", tests_failed); printf(" Skipped: %d\n", tests_skipped); printf("========================================\n"); if (tests_run == 0) { printf("\nERROR: No tests were found or executed.\n"); return -1; } if (tests_failed > 0) { printf("\nRESULT: %d test(s) FAILED\n", tests_failed); return tests_failed; } if (tests_passed == 0 && tests_skipped > 0) { printf("\nWARNING: All tests were skipped. No applicable tests for this hardware.\n"); return -1; } printf("\nRESULT: All applicable tests PASSED\n"); return 0; } fastrpc-1.0.2/test/linux/000077500000000000000000000000001512345705400153005ustar00rootroot00000000000000fastrpc-1.0.2/test/linux/libcalculator.so000066400000000000000000001542701512345705400204740ustar00rootroot00000000000000ELFp@@8@ZLZL\\\HH^^^$$QtdRtd\\\GNU燦 yRYڐ%980+376%)4 *- 1 /5#'  "&($.2!, pa 87I H 1[c 3 % .  38H 2 D.# /D`a1 1  C ' (`a`a %8X xm`a aP5`a -<z -  5P 5% 8$'`aq ]8^ H`a "J \ xvsnprintfHAP_debugcalculator_slimcalculator_openremote_handle64_opencalculator_closeremote_handle64_closeremote_handle64_invokeHAP_debug_v2HAP_debug_runtimeputsoptargatoigetoptget_dsp_supportis_valid_domain_idis_unsignedpd_supportedcalculator_multisession_testcalculator_testpd_status_notifier_callbacklocal_calculator_sumlocal_calculator_maxrpcmem_allocget_domainremote_session_controlmallocrequest_status_notifications_enable__errno_locationsleeprpcmem_freerun_testsupported_domainsis_CDSPremote_handle_controlget_vtcm_infoget_unsignedpd_supportis_async_fastrpc_supportedis_status_notification_supportedget_hmx_support_infoget_hex_arch_verget_hvx_support_infolibcdsprpc.so.1libm.so.6libc.so.6libstdc++.so.6_edata__bss_start__bss_start____bss_end____end___endlibcalculator.soGLIBC_2.17=\7\x\\\\x\\\\\]8\]X\(]\P]]x]\]\]]]8]]`]]]]]]08]8^7_ __!_"_&_'_5```` `(`0` 8` @` H` P`X```h`p`x`````!`#`%`'`(`)`,`-`/`1`2`3`5a6a7{G?    հ@ ְ@" ְ @B ְ@b ְ@ ְ@ ְ@ ְ@ ְ"@ ְ&@" ְ*@B ְ.@b ְ2@ ְ6@ ְ:@ ְ>@ ְB@ ְF@" ְJ@B ְN@b ְR@ ְV@ ְZ@ ְ^@ ְb@ ְf@" ְj@B ְn@b ְr@ ְv@ ְz@ ְ~@ ְ@ ְ@" C{O#K_=c=g=k=o=s=w={=C+C/3koCC`@@`A@C@ ҴK@#@O@ {@C_{ @@{¨_{@I{¨_{C7K#G R#+Ҡ/@|@|ӡC"h @|@|ӡc"h #@!@C@G@@G@@@tS*G@7@S R@r *C*@c@qT@!@ ՠ@q@TGTGT7@S R@r#* !#7@*@@'R`RUGT7@S R@r#* !#7@*@@'R`R ՠ@{A_{ @R?s @?@@g{Ĩ_{C7KCG R#+Ҡ/@|@|ӡC"h @|@|ӡc"h #@!@C@G@@G@@@tS*G@7@S R@r *C*@@qT@!@ ՠ@q@TGTGT7@S R@r#* !#7@*@@"+R`RGT7@S R@r#* !#7@*@@"+R`Rc ՠ@{A_{ `R?s @?@@g{Ĩ_{$n {_{ ?; R7' R399+3+@qTqTTqTqT&qTqT!G@'G@3G@q9G@; G@7@2 @@++@1T;@qT;@q T2?;@q`T'@1T@3 ??@qT4?@ '@RRq`TR?'@5*?@|a3@qT3@qMTR?63@?@mR3@q!T'@q9@9Rq T'@63  ՠ7@q T 8?O48;@qT3@qT`99'@#9@9qT'@@9N??@qT:?@'@@97@*;@S??@qT:?@ ՠ?@qT ;?@;?@{Ĩ_{'#?@qTqTq Tq`T qTq@TR{Ĩ_{O93_K R[@Rw#7+tS_ ?_@ RO_@!RO@33@T R?@,@Q`{ {~ӡ3@ {@{@{{@@?kT@q`T @3@qT R@ #@3@vq@T R@@++@!TR @@@O@9qTG`T@+ R/R@Rc@qT`@R @|[A77@T@R`[@o[+@`7@@q T@Z RGϊҁF@@qT@qT @E7@)@qaT` .@@3@@qT#@ ,)@qaT@qTw@QwR @qT@Rr?kTw@Qw@`T@@qT @w@qT@q T @@7@@qAT@ @#@3@@qTK@ @qT@@@`T@@qT@@T@@qT`@ ՠ7@`T7@3@`T3@m@{Ȩ_{o9/o@9}R@RT//@{è_{o96712345@b@!TR @A{kGTR AmRCC@ss@@R@R@ OO@[[@@77@gg@{o RSS@@dcc@@*??@T@R@`2h?@@*` Aq T@A RR@*GG@T@R@` CRRAqTA5AwARRAqTA#RRAqT Ao@9qT@@3 R7R@RAqT`A ~ӡA"h AA$qTG@AqT@cBR.AqT@A@`AS@*W''@T@RS@`'@S@*` Aq T@Aq Rc@*2//@T@Rc@``#RR2AqTAR@G@cRR AqTA@vRRAqTA2ho@9qT@@+ R/R@RAqT`AP  ~ӡcA"h AALqT/@AqT@CcRAqT@A&@ `A@`T@AqTA@T@AqT@A ՠ?@`T?@G@`TG@'@`T'@/@`T/@A{ܨ_C@ qT@qaT RRC_RG| @@?kT|ӀG @@@?kkT_{/R+@qT@L/G/| @@?kaT R /@//@+@?kTR{è_{/@aRGT`R#'+R@RG//@qT7 +@qT#'+R@R3/+@q`T@/@qT/@*  R//@{è_{ / @@q@T@qTR/;G@T@qT@ qT@#@'+R@R//@q!T //@qT+@ @`!/@  R/"@ R//@{è_{/G`T@# R'+R@R//@qT`"R/@qT#/@R+@qAT R  R/$RR{è_{`R#{_{/GT@ qT@# R'+R@R{//@q!Tk h/+@qaT R/@q`T`&/@f  R/@'@^ R/LR{è_{/GT@#@R'+R@R?//@q!T/ ,/+@qaT R/@qT(/@*  R/R{è_{ / @@ q@T@qTR/)8GT@ qT@#@'+R@R//@q!T //@qT+@ @@*/@  R/+@ R//@{è_{ / @GT@#R'+R@R//@q!T //@qT+@ @ +/@  R//@{è_{ / @@qTR/`,A@ qTR/-v8GT@ qT@#@'+R@Rl//@q!T\ Y//@qT+@ @./@X  R//@P R/>/@{è_{/O@/@;@#/@/9/A9qTR`ROO@qT@0O@( ROO@{Ũ_closeopenmaxresvecsumurih  ERROR 0x%x: handle=0x%lx, scalar=0x%x, method ID=%d: %s failed C:/Qualcomm/Hexagon_SDK/6.1.0.0/examples/calculator_copy/UbuntuARM_Debug_aarch64/calculator_stub.c_stub_method_stub_method_1Usage: calculator [-d domain] [-U unsigned_PD] [-r run_locally] [-q multisession_test] -n array_size Options: -d domain: Run on a specific domain. 0: Run the example on ADSP 3: Run the example on CDSP 1: Run the example on MDSP 2: Run the example on SDSP Default Value: 3(CDSP) for targets having CDSP and 0(ADSP) for targets not having CDSP like Agatti. -U unsigned_PD: Run on signed or unsigned PD. 0: Run on signed PD. 1: Run on unsigned PD. Default Value: 1 -r run_locally: 1: Run locally on APPS. 0: Run on DSP. Default Value: 1 -q multisession_test: Test to create multiple sessions parallely calculating sums for predetermined arrays 0: Does not run the multisession tests 1: Run the multisession tests Default Value: 0 -n array_size: Natural number up to which sum is calculated from 0 to (n-1) Default Value: 1d:U:q:r:n:Please provide a valid run local value (0/1). DSP domain is not provided. Retrieving DSP information using Remote APIs.ERROR in get_dsp_support: 0x%x, defaulting to CDSP domain ERROR 0x%x: Invalid domain %d ERROR 0x%x: Invalid unsigned PD flag %d Overriding user request for unsigned PD. Only signed offload is allowed on domain %d. Please provide a valid array size value. Starting calculator testunsignedsignedAttempting to run on %s PD on domain %d ERROR 0x%x: Calculator test failed ERROR 0x%x: Calculator example failed Success PD is upPD closedPD force killPD exceptionDSP SSR=============== DSP: local sum result %lld =============== =============== DSP: local max result %d =============== Allocate %d bytes from ION heap ERROR 0x%x: memory alloc failed Creating sequence of numbers from 0 to %d Compute sum locallyERROR 0x%x: local compute sum failed Find max locallyERROR 0x%x: local find max failed ERROR 0x%x: unable to get domain struct %d Compute sum on domain %d ERROR 0x%x: remote_session_control failed ERROR 0x%x: remote_session_control interface is not supported on this device unable to allocate memory for calculator_URI_domain of size: %dfile:///libcalculator_skel.so?calculator_skel_handle_invoke&_modver=1.0&_idlver=1.2.3%s%sERROR 0x%x returned from snprintf ERROR 0x%x: request_status_notifications_enable failed Call calculator_sum on the DSPSum = %lld ERROR 0x%x: Failed to close handle Retry attempt unsuccessful. Timing out....ERROR 0x%x: Failed to compute sum on domain %d Call calculator_max on the DSPMax value = %d ERROR 0x%x: Failed to find max on domain %d ERROR 0x%x: Failed to close handleSum ERROR 0x%x: Failed to close handleMax Running Multisession Tests:cdspmulti_session_test_0multi_session_test_1unable to allocate memory for uri of size: %u%sERROR 0x%x Failed to create URI for Session 0 ERROR 0x%x: remote_session_control failed to reserve new session 0 ERROR 0x%x: remote_session_control failed to get URI for session 0 Setting up Unsigned PD for session 0Creating sequence of numbers from 0 to 10Call calculator_sum on the handle_0 ERROR %d: failed to open handle Sum for array 0 = %lld ERROR is: %dERROR 0x%x: remote_session_control failed to get URI for session 1 Creating sequence of numbers from 0 to 20Call calculator_sum on the handle_1Sum for array 1 = %lld ERROR 0x%x: Failed to close handle_0 ERROR 0x%x: Failed to close handle_1 FastRPC Capability API is not supported on this device get_dsp_support failed with Error 0x%x remote_dsp_capability interface is not supported on this deviceUnsupported attr. Only VTCM_PAGE and VTCM_COUNT supportedRunning the usecase without checking the capability get_vtcm_info failed with Error 0x%x Unsupported domain %d FastRPC Capability API is not supported on this device. Falling back to signed pd. ERROR 0x%x: FastRPC Capability API failed. Falling back to signed pd.remote_dsp_capability interface is not supported on this device. Falling back to signed pd. is_async_fastrpc_supported failed with Error 0x%x Async fastrpc is not supported on domain %d is_status_notification_supported failed with Error 0x%x Unsupported attr. Only HMX_SUPPORT_SPATIAL and HMX_SUPPORT_DEPTH supported get_hmx_support_info failed with Error 0x%x HMX support is not there for domain %d get_hex_arch_ver failed with Error 0x%x Latest targets have 128 byte HVX register, use HVX_SUPPORT_128B instead of HVX_SUPPORT_64BUnsupported attr. Only HVX_SUPPORT_128B supported get_hvx_support_info failed with Error 0x%x HVX support is not available on domain %d ERROR 0x%x: remote_session_control failed to enable status notifications 7 x\\x\\\8\X\\]\\]8]`]]]0887,8 H _0p  oP oo o^0000000000000000000000000000000000&_dom=adsp&_dom=mdsp&_dom=sdsp&_dom=cdsp&_dom=cdsp1GCC: (Linaro GCC 7.5-2019.12) 7.5.0,p,X,(`,- ,,)87 pFA+intW&ccc(W2-345;9B!|Bk!<B# BC Y pv 9  fd Z(d bufYh#h64.dmä́Ώ^k[ r W     ( l0 v8 Y@UHPX`(hWp/ WtUjx74I5 Y!u)*+,.}/Wm1k B (v+ :WaW& 0  <W  B B;/<S=- Pk*  K  W   g <  z  8Ǹ A ɿ  & e̔ ͔$ \Δ( ϟ, VП- ?џ. ҟ/ ӟ0 ԟ1 ՟2 `֟3 5 Mڿ & eܔ ݔ \ޔ ߟ V ?E5 X  e  \  p1 p2  iid   " !  X  <   #WBV@;;< <,  g 4   z ~   p1 p2  iid   " !  X  4    #W BV  (( D j H W W (   !4 7. LI 9 L8 W   6Wu (0    B Q 77 B c \4 % B x% \ P B@ P ] { Bk m{ ] B!  7 B   8 B 1 08mD ] ]WH 2].hvec]`]W\res] P^|WFW( 2F.FF 4F 5F G pLH@,InJK#xzLWtX 9 8!x "R#arR[$"W#arW[W B B# B9 B)BWH2B.hvecB`BW\resBPC|+Wx(2+.++ 4+ 5+, pL-@,.n/0#xz1Wt=  8!"7#ar7[$"<#ar< B B (W\Sh(.xt%W8$uri%xh%p.%r-p&E-W|&S-|&-W|&R.|'(buf/|)0H|* Ba6 VXFA+int&^c^!<Bk0 r W } } } } }( l}0 v}8 Y}@ U}H }P }X h` (nh Wp / Wt Uex 74 I t 5 Y!p ){ *{ +{ ,{ . }/W m1 &h 0h n <W7  B0  B;/<S=*nnKnW "}9}GWLWPW 4m  6W K 7WHm/ (WxD(W\(P{*W|B+Wxnum,Wt|-Wd.Wp%/Do? 0Dn;1Who X S o (`FA+intW&ccc5;9Bk!<B  idW uri  B - C K - W HWa ;'|  q   7K (h ~ j l n p u g { & ~   g   0 ~   g  C Y uri ` (B ; O )  <  y   ~    r n ^kr W (l0v8Y@ UH P X ` (h Wp / Wt Ujx 74 I  5 Y!u ) * + , . }/W m1&0<W  B  B;/<S=*K W OD O ; G9 h   " 9 GW LW PW 4 6WK 7W4 W%h|W|%h|{W|iiWx  h `( X0 P o ~O p,-' ~9 ~$}Y } &} &| (TE 4#|!+T q#| W B W B W%8|Wl%hk{W|Q DW & BDW|DW"numDW%Dh{EW|L F& `iiGWxlenGW\ GWH HWX IWt<J@8 K  L  MhO NP TWL#h%!"H4 }#W :Wx "vec:h:Wd"res:& Xii;W|max M KJ  }z Y M Eu "' 9 Gb Lb Pb 4~  6b K 7bY~ I 8  a5Vb5P2- VblV2`Vh{Xb|,7lTp2b 5- 2bl22`{4b|R5`:Tpb381- bl2`h{b|.50Tp\ܞ3- bl{b| 3! 3Tp*2- bl{b| 2!02Tp"1[1|bl{b|!81TpYb/D - YblY2`Yh{[b|  1bkTp/b.w- /wh{1b| U/!/6TpbsD.|blbh#i b|!bx$ - |bl#ib|bxI%-<|b|m U87 8AF+int&icik r b     ( l0 v8 Y@ UH P X O` (Uh bp / bt Upx 7F T [ 5k Y!{ ) * + , .- }/b m1q &O 0O U <b k 8  8;/<S=*UUKUb <!a M';  q   7 CSYbwbb;K M - Ob QGB M O )  <  y   ~    r n +b87|b\ PSH{b|Ow`{% $ > $ > &I: ; I  II !I/  : ;  : ; I8 : ; I8  : ;  : ; I : ;  : ;I8  I8 4: ; <4: ;I?<4: ; I?<! : ; I : ; 4: ;I4: ;I?.?: ;'I@B: ;I: ;I.: ;'I@B : ; 4I4! " : ;# : ;I8 $ %.: ; '@B&: ; I'(4: ; I)4: ; I*I% $ > $ > : ; I  I&I : ;  : ; I8 : ;I8 : ; I !I/ <4: ;I?<4: ; I?<!7I.?: ; 'I@B: ; I4: ; I4: ; I : ; .: ; @B% $ > $ > &I: ; I  I : ;  : ; I8 I !I/  : ; : ;I8 > I: ;( : ;I : ;I8  : ; I8 : ; <4: ;I?<4: ; I?<!> I: ; 7I.?: ; 'I@B: ; I4: ; I4: ; I : ;4: ;I ! ": ; I# : ; $.?: ; 'I@B% : ; I$ > $ >   I&I : ;  : ; I8 : ;I8 : ; I !I/ <4: ;I?<4: ; I?<! : ; I8  : ;> I: ;( 7I4: ; I?.?: ;'I@B: ;I4: ;I : ; U.?: ; 'I@B: ; I4: ; I : ; ! ".?: ; 'I@B#4: ; I$.?: ; 'I@B%.?: ; 'I@B% : ; I$ > $ >   I&I : ;  : ; I8 : ;I8 : ; I !I/ <4: ;I?<4: ; I?<!> I: ;( : ;I'II : ;.?: ; 'I@B: ; I4: ; IX C:/Qualcomm/Hexagon_SDK/6.1.0.0/incsC:/Qualcomm/Hexagon_SDK/6.1.0.0/examples/calculator_copy/UbuntuARM_Debug_aarch64c:\qualcomm\hexagon_sdk\6.1.0.0\tools\linaro64\aarch64-linux-gnu\libc\usr\include\bitsc:\qualcomm\hexagon_sdk\6.1.0.0\tools\linaro64\aarch64-linux-gnu\libc\usr\includeC:/Qualcomm/Hexagon_SDK/6.1.0.0/incs/stddefc:\qualcomm\hexagon_sdk\6.1.0.0\tools\linaro64\lib\gcc\aarch64-linux-gnu\7.5.0\includeHAP_debug.hcalculator_stub.ctypes.hstdint.hAEEStdDef.hstddef.hremote.hlibio.hstdarg.hstdio.hsys_errlist.h p-1YJK=/=//!=!!!!///uuK=KgW"=JJXJX"!=g//!=!!!!///uuK=KgW"=JJXJX"!=g/ C:/Qualcomm/Hexagon_SDK/6.1.0.0/examples/calculator_copy/srcc:\qualcomm\hexagon_sdk\6.1.0.0\tools\linaro64\aarch64-linux-gnu\libc\usr\include\bitsc:\qualcomm\hexagon_sdk\6.1.0.0\tools\linaro64\lib\gcc\aarch64-linux-gnu\7.5.0\includec:\qualcomm\hexagon_sdk\6.1.0.0\tools\linaro64\aarch64-linux-gnu\libc\usr\includec:\qualcomm\hexagon_sdk\6.1.0.0\tools\linaro64\aarch64-linux-gnu\libc\usr\include\syscalculator_main.ctypes.hstddef.hlibio.hstdio.hsys_errlist.hunistd.hgetopt.htime.h X /==[=N=[=gN=g]!=0=0!0K!g!0L!$!!Y!==/Y"=K/K%KK=>KZ/K"=K/#/K"K"/0K"K"=>//^=/W<>u=zGK#ZN/K"=K/"/K"K"/0K"K"=>//\=/W<@u=zGK#ZM=gM=g\!=0=1=0=0!e C:/Qualcomm/Hexagon_SDK/6.1.0.0/incsC:/Qualcomm/Hexagon_SDK/6.1.0.0/utils/examplesc:\qualcomm\hexagon_sdk\6.1.0.0\tools\linaro64\lib\gcc\aarch64-linux-gnu\7.5.0\includec:\qualcomm\hexagon_sdk\6.1.0.0\tools\linaro64\aarch64-linux-gnu\libc\usr\include\bitsc:\qualcomm\hexagon_sdk\6.1.0.0\tools\linaro64\aarch64-linux-gnu\libc\usr\includec:\qualcomm\hexagon_sdk\6.1.0.0\tools\linaro64\aarch64-linux-gnu\libc\usr\include\sysdomain_default.hdsp_capabilities_utils.cstddef.htypes.hlibio.hstdio.hsys_errlist.hstdint.hremote.hunistd.hgetopt.htime.h -/<<. /-/!0/d<O!0K!0=M/,<O!1=!>LKgL=#>!!!g>2=K3/@!1Y!0<?/="K<B//!gK==!"=o< K2/K$/@!1=!LYgL=0>K0>3/=0!1/=1=!KB//!gK==!"=0=K2/K$/@!0="P//!gK==!"=0=K2/@!1Y!0<=/="KB//!gK==!"=MK2/K$/@!1K!/O//!gK==!"=MK2/@!1Y!/=/=#=/=#KB//!gK==!"=MK2/K$/@! C:/Qualcomm/Hexagon_SDK/6.1.0.0/utils/examplesc:\qualcomm\hexagon_sdk\6.1.0.0\tools\linaro64\lib\gcc\aarch64-linux-gnu\7.5.0\includec:\qualcomm\hexagon_sdk\6.1.0.0\tools\linaro64\aarch64-linux-gnu\libc\usr\include\bitsc:\qualcomm\hexagon_sdk\6.1.0.0\tools\linaro64\aarch64-linux-gnu\libc\usr\includeC:/Qualcomm/Hexagon_SDK/6.1.0.0/incspd_status_notification.cstddef.htypes.hlibio.hstdio.hsys_errlist.hremote.h 87Y$//0==g=\0! x ,pAABAA n $8$A A F $\A A D ,x(AAA  $HA@A O ,(AAA  $HA@A O  x $@X AA E ,@xA@A   x $(A@A m $A@A a $xA@A a , AA b $%8A0A K ,%A87A   x -<AM-A ^$D.A0A b $.A0A | ,/DA0A N $1A0A q $1AA D $2A0A | $3A0A r ,38A0A K $ 5A0A t ,5PA0A Q  x $87AP A b params_shortbufseqComplexnumParams_IO_lock_tmethodStringsArrayslevelstderrformat_IO_buf_endinSize_IO_write_endnativeAlignment_praIn_castnCases_markersstructTypestringsroutSizePrimInbFloatingvalue64sprimROutAlignmentremote_bufmethodArrayuint32_tstdout_IO_save_endarrayType_primIn_in0Lenlong long unsigned intfileseqTypebDefaultCasemethodArrays_nErrStructTypesys_errlist_IO_backup_base_stub_method_1sys_nerr_in0value16s_fileno__pad4caseValues__gnuc_va_list_nErrfarfbailsize_tUnionType_IO_read_baseobjectstdin_nextnIIds_posdescriptor_pratypesprimroutSizePrimROutcalculator_slim_modeinAlignmentint64_IO_marker_IO_read_ptr__gr_offsuint8_tiidsmethodStringsbNotNilMethod_IO_write_basecalculator_close__copyParameter_IO_2_1_stdin_long long int_IO_2_1_stdout_routAlignmentPrimROut_IO_save_baseparameters_primROutparameterArraysparambSigned__pad1__pad2__pad3remote_arg__pad5_stub_method_mid_vtable_offsetarrayargsprimInAlignmentuint16_tnativeCaseAlignmentmembers_IO_read_endshort int_rout1value8suScalarsnMembersbInterfaceNotNilnativeSize_HAP_debug_v2uint64_tmethodsvecLen_IO_FILE_plusnMaxLen_numInGNU C99 7.5.0 -march=armv8-a -mlittle-endian -mabi=lp64 -g -std=gnu99 -fPICnMethodscasesmaxArgs__gr_topuintptr_t__va_list_lockCaseValuePtrprimROutSize_old_offset__vr_offs_IO_FILEcalculator_openSequenceTypeinCaseAlignmentroutCaseAlignmentPrimIn__vr_topseqSimplevalue32stypestringMaxLenunsigned char_sbuflineroutCaseAlignmentPrimROut_IO_write_ptrremote_dma_handle__stackunionTypeInterfaceroutAlignmentPrimInprimInSizemethodStringArray__off_tnLenshort unsigned intremote_handle__func__C:/Qualcomm/Hexagon_SDK/6.1.0.0/examples/calculator_copy/UbuntuARM_Debug_aarch64/calculator_stub.cnItems_chain_flags2_cur_columnremote_handle64_IO_2_1_stderr___off64_t_unused2_IO_buf_baseC:\Qualcomm\Hexagon_SDK\6.1.0.0\examples\calculator_copy\UbuntuARM_Debug_aarch64optindoptargstarttest__environtimezoneunsignedpd_flagopterrtz_minuteswestis_unsignedpd_enabledoptionrunLocaltz_dsttimeC:/Qualcomm/Hexagon_SDK/6.1.0.0/examples/calculator_copy/src/calculator_main.cargvprint_usageargc_BooloptoptFASTRPC_PD_INITMEM_SIZEFASTRPC_DSP_SSRFASTRPC_THREAD_PARAMSFASTRPC_REMOTE_PROCESS_EXCEPTIONreserve_session_0reserve_session_1pd_status_notifier_callbacksession_idFASTRPC_GET_EFFECTIVE_DOMAIN_IDsession_uri_0session_uri_1FASTRPC_USER_PD_UPcalculator_URI_domain_lendomain_ttest_array_0heapidFASTRPC_RESERVE_NEW_SESSIONhandleSumcalculator_URI_domaindataRPCMEM_HEAP_ID_SECUREDSPRPC_CONTROL_UNSIGNED_MODULEFASTRPC_GET_URIFASTRPC_REMOTE_PROCESS_TYPEremote_rpc_status_flags_tFASTRPC_USER_PD_EXCEPTIONFASTRPC_CONTROL_PD_DUMPremote_rpc_get_urilocal_calculator_maxFASTRPC_REGISTER_STATUS_NOTIFICATIONScalculator_multisession_testcalculator_testremote_rpc_status_flagsFASTRPC_SESSION_CLOSEtest_array_1FASTRPC_USER_PD_EXITdomain_name_lenretryC:/Qualcomm/Hexagon_SDK/6.1.0.0/examples/calculator_copy/src/calculator_test.cFASTRPC_RESERVED_1FASTRPC_RESERVED_2FASTRPC_RESERVED_3my_domaindata_effective_dom_id_1FASTRPC_USER_PD_FORCE_KILLRPCMEM_HEAP_ID_SYSTEMrpc_heap_idssession_name_lenFASTRPC_REMOTE_PROCESS_KILLFASTRPC_RELATIVE_THREAD_PRIORITYremote_rpc_control_unsigned_modulecontextresult0result1handleMaxsession_control_req_idmodule_uri_lenRPCMEM_HEAP_ID_CONTIGdomain_namestatusrun_testremote_rpc_effective_domain_iddata_0data_1session_nameresultMaxremote_rpc_reserve_new_sessionhandle_0handle_1local_calculator_sumdata_effective_dom_id_0resultmodule_uriattribute_IDis_unsignedpd_supportedis_valid_domain_idDSPRPC_GET_DSP_INFOdsp_capability_arch_verdsp_capability_async_supportremote_dsp_capabilityhandle_control_req_idget_dsp_supportUNSIGNED_PD_SUPPORTdsp_capability_domainget_hvx_support_infoDOMAIN_SUPPORTSTATUS_NOTIFICATION_SUPPORTDSPRPC_SET_PATHdsp_capability_status_notification_supportDSPRPC_GET_PATHHVX_SUPPORT_64Bdsp_capability_hvx_dspget_hex_arch_verdsp_capability_hmx_dspget_domainC:/Qualcomm/Hexagon_SDK/6.1.0.0/utils/examples/dsp_capabilities_utils.cdsp_capability_vtcm_dspHMX_SUPPORT_DEPTHget_unsignedpd_supportis_CDSPHVX_SUPPORT_128BASYNC_FASTRPC_SUPPORTget_vtcm_infoDSPRPC_CONTROL_WAKELOCKsupported_domainsremote_dsp_attributesVTCM_PAGEis_async_fastrpc_supportedDSPRPC_CONTROL_LATENCYis_status_notification_supportedARCH_VERVTCM_COUNTsizeattrcompute_onlyDSPRPC_RESERVEDDSPRPC_GET_DOMAINget_hmx_support_infoHMX_SUPPORT_SPATIALnotifier_fnnotif_callback_fnremote_rpc_notif_registerrequest_status_notifications_enablenotifC:/Qualcomm/Hexagon_SDK/6.1.0.0/utils/examples/pd_status_notification.cfastrpc_notif_fn_t8<T,0H$(@X \ t 8 P p  0 p 7 \ ^__a p p$ 7' 7 $ \- \8 \8H ]P ] ] 7"e 8s 08 x( 8  ( 8$$ 9 X X $P$ ? ($$a -$ 8G$$ L 87$!_7^ 0@ 87d Hw 1 3 % .  38+ 2F D.Y /Dg`au 1    (`a`a  %8 x(5H`aT faPx`a -< -  5P 5 8$ `a%< ]8L] Hn`au" \ xcalculator_stub.c$x_HAP_debug_v2$dtypesparametersparameterArraysmethodsmethodArraysstringsmethodStringsmethodStringsArrays_stub_method__func__.4899_stub_method_1__func__.4926calculator_main.cprint_usagecalculator_test.cdsp_capabilities_utils.cpd_status_notification.c_GLOBAL_OFFSET_TABLE__DYNAMICrequest_status_notifications_enablegetopt@@GLIBC_2.17is_unsignedpd_supportedremote_handle64_closeis_status_notification_supportedatoi@@GLIBC_2.17calculator_multisession_testget_dsp_supportsleep@@GLIBC_2.17get_hmx_support_infois_async_fastrpc_supportedis_valid_domain_idget_vtcm_info__bss_start__get_unsignedpd_supportcalculator_test__errno_location@@GLIBC_2.17local_calculator_sumrpcmem_freepd_status_notifier_callback__end____bss_end__run_testlocal_calculator_maxrpcmem_allocmalloc@@GLIBC_2.17__bss_startHAP_debug_runtimesupported_domainsremote_handle64_openis_CDSPoptarg@@GLIBC_2.17remote_session_controlget_domainHAP_debugget_hvx_support_infoget_hex_arch_vervsnprintf@@GLIBC_2.17calculator_open_endremote_handle64_invokecalculator_slimfree@@GLIBC_2.17puts@@GLIBC_2.17_edataremote_handle_controlcalculator_close.symtab.strtab.shstrtab.note.gnu.build-id.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.text.rodata.data.rel.ro.dynamic.got.got.plt.data.comment.debug_aranges.debug_info.debug_abbrev.debug_line.debug_frame.debug_str.debug_ranges$.4 88X<HDo rQoP P `p p jB0o00@tpp\#z77\\^^__@__(aaP0`a$atb-=0p ( A fastrpc-1.0.2/test/linux/libhap_example.so000066400000000000000000001565701512345705400206330ustar00rootroot00000000000000ELF@x@8@OO0\0\0\xx]]]$$QtdRtd0\0\0\GNU `Ąt,my<CHG@B?34&C +: =D%, E*(0)"9$/.<';AF   !21-678#>5 @a& $ 4"H t4^ \6 H(  42  078 "(@an `5  LL 5 .I 03DV"+aF 4"@ #( "(W D5Ea9a - ]8 p(wac t"( XaP7:a \/8 .<~"* h Ll H. % D9P h8Mat~ "4a3""` d( 1,r h#vsnprintfHAP_debughap_example_slimhap_example_openremote_handle64_openhap_example_closeremote_handle64_closeremote_handle64_invokeHAP_debug_v2HAP_debug_runtimehap_example_compute_reshap_example_compute_resv2hap_example_farf_runtimeremote_register_dma_handlehap_example_mem_dmahandlehap_example_mem_dmahandlev2hap_example_mem_fastrpc_mmaphap_example_mem_reserve_vahap_example_mem_map_reserve_vahap_example_perfhap_example_powerhap_example_sysmon_cachelockoptargatoigetoptstrcmpget_domains_infoputsget_dsp_supportget_effective_domain_idis_valid_domain_idis_unsignedpd_supportedhap_exampleget_domainmallocremote_session_controlrpcmem_allocrpcmem_to_fdrpcmem_freefastrpc_munmapexample_case_namesrun_teststderrfprintfsupported_domainsis_CDSPremote_system_requestcallocstrlenremote_handle_controlget_vtcm_infoget_unsignedpd_supportis_async_fastrpc_supportedis_status_notification_supportedget_hmx_support_infoget_hex_arch_verget_hvx_support_infolibcdsprpc.so.1libm.so.6libc.so.6libstdc++.so.6_edata__bss_start__bss_start____bss_end____end___endlibhap_example.soGLIBC_2.17d0\:8\8;@\:H\:P\;X\:x\@\\X\\0\]P\@]0\P]`\X]\`]\h]\p]\x]]]]](]]\]\]\]\]\]P]]`<]0<]X;@a`IHapIPaxI______*_+_0_2_@```` `(`0` 8` @` H`P`X```h`p`x``` `&`'`*`,`.`/`1`2`4`5`6`9`;`<a=a@aAaB aC(aD0aE8aG{G?    հ@ ְ@" ְ @B ְ@b ְ@ ְ@ ְ@ ְ@ ְ"@ ְ&@" ְ*@B ְ.@b ְ2@ ְ6@ ְ:@ ְ>@ ְB@ ְF@" ְJ@B ְN@b ְR@ ְV@ ְZ@ ְ^@ ְb@ ְf@" ְj@B ְn@b ְr@ ְv@ ְz@ ְ~@ ְ@ ְ@" ְ@B ְ@b ְ@ ְ@ ְ@ ְ@ C{O#K_=c=g=k=o=s=w={=C+C/3koCC`@@`A@C@ ҬK@#@O@ {@C_{ @@|{¨_{@5{¨_{C'@S@*@''@q ՠ'@qTGTGT@S23`3@*@'@&R`RGT@S23`3@*@'@&R`R) ՠ'@{A_{@R//@@{è_{`R//@@{è_{C'3OҠ#@!@'@S2*@OO@q ՠO@qTG@TGT'@S2233'@*@O@(R`R#GT'@S2233'@*@O@(R`R ՠO@{A_{R/S/@@{è_{C7+_++@@!@+@@!@@@*@@**^q`TRR__@qaT__@q!T7@S2*@__@qT   ՠ_@qTG@TGT7@S22337@*@_@B+R`RGT7@S22337@*@_@B+R`R4 ՠ_@{A_{'#R?s?@@v{Ĩ_{'#R?s?@@c{Ĩ_{C' OҠ#@!@ @!@'@S2*@OO@q ՠO@qTG@TGT'@S223 4'@*@O@.R`RGT'@S223 4'@*@O@.R`R ՠO@{A_{R/CS/@@{è_{R//@@"{è_{ R/S/@@u{è_{@R//@@ {è_{`R//@@{è_{R//@@{è_{`4 {_{ _;3[ RWO9O#?'70;@TqTTqTq T$qT#qTq`TG@#G@?G@3G@[ G@W  @@;;@1T3@1T#@ T`#@qT#@ qT#@qT#@*#@__@PqT__@qT _@B_@qT ?@1`T?@qT'@?@?kT'@Q@ *#@?@R_? RO@?{@ 7@__@q`T@ _@s t__@qT _@O@qaT3@RvRq`TR_3@ *_@QW@qT RO9W@qaTO9 R_W@_@ =OA9RqT3@$RqT3@` R_*OA9qT @3@#@w3@@?{@O@[@OA9*y__@qT_@m ՠ_@qTY`_@`@`T@K_@{ƨ_{/9'## RwC7?#@qT/@ 77@T/@<7@???@T@RR+@ Ҡ?@GT/@;@9qT R??R@R@qT@R@wCC@T@Rw@w?@C@u@q T@ RC@J@qT/@@'@qTqTq!T#@R7#@!R4u@R!R Rp33@T Rf3@__@1T3@Z[GTERR3@_@/@F@qTR[#@[@_@@@qT`@ҡ_@/@{WW@qTW@w@PqTd @k[SRO#@O@S@_@@qT @W3@  "E#@"> ՠ#@C@`TC@0@qT`#.#*`$'@{ɨ_{'/+5@qR+@*@"''@qT'@PqTG@G+xa&+@G@G+xa&'@+@'@/+@++@qMT/@{è_C@ qT@qaT RRC_RG| @@?kT|ӀG @@@?kkT_{/R+@qT@/G/| @@?kaT R /@//@+@?kTR{è_{ok@T'@_qT@Rk '@UqTRk Rk;#/k@qT+@k@*@ ++G Too@qT'o@\EO@KO@|@ 9##@T@Ro(L5oo@qT'o@A*g#@g{@//@(@k@?k@T@To@)g@gO@g@?kT#@@O@@Ro ՠo@qT#@aT#@o@{Ǩ_{'O#@@ ;'@?RROO@q@T@ *'@O@O@C@*@O@{Ũ_{/@aRGT`R#'+R@R//@qT@+ +@qT#'+R@R/+@q`T@/@qT ,/@  R/,/@{è_{ / @@q@T@qTR/-;G@T@qT@ qT@#@'+R@Ru//@q!T@+i.f//@qT+@ @//@e  R/`0@] R/,K/@{è_{/G`T@# R'+R@R://@qT0.R/@qT 2/@1R+@qAT R  R/@3RR{è_{`R{_{/GT@ qT@# R'+R@R//@q!T@+./+@qaT R/@q`T4/@  R/5@ R/,R{è_{/GT@#@R'+R@R//@q!T@+./+@qaT R/@qT`6/@  R/,R{è_{ / @@ q@T@qTR/`78GT@ qT@#@'+R@Rx//@q!T@+l.i//@qT+@ @8/@h  R/`9@` R/,N/@{è_{ / @GT@#R'+R@R://@q!T@+..+//@qT+@ @ :/@*  R/,/@{è_{ / @@qTR/:A@ qTR/@<8GT@ qT@#@'+R@R//@q!T@+.//@qT+@ @ =/@  R/=@ R/,/@{è_ runtime_logging_enablemem_map_reserve_vasysmon_cachelockmem_fastrpc_mmapmem_dmahandlev2mem_reserve_vabuffer_lengthmem_dmahandlecompute_resv2farf_runtimecompute_resbufferpowercloseperfopenurifd;kwLyw*\ ERROR 0x%x: handle=0x%lx, scalar=0x%x, method ID=%d: %s failed hap_example_stub.c_stub_method_stub_method_1_stub_method_2_stub_method_3Usage: hap_example [-d domain] [-U unsigned_PD] [-f example_selector] [-D domain_type] [-I core_id] Options: -d domain: Run on a specific domain. 0: Run the example on ADSP 3: Run the example on CDSP Default Value: 3(CDSP) for targets having CDSP and 0(ADSP) for targets not having CDSP like Agatti. -U unsigned_PD: Run on signed or unsigned PD. 0: Run on signed PD. 1: Run on unsigned PD. Default Value: 1 -f example_selector: 0-2 select HAP API type 0: HAP_farf 1: HAP_mem 2: HAP_perf -D domain_type: Run on domain of specified type. NSP: Run on NSP subsystem. HPASS: Run on HPASS subsystem. If -D is passed the information of all the cores of specified domain type is fetched from the device. If -D is used with -d, -d will be given the priority -I core_id: Run on ith core starting from zero from the number of available cores of specified domain_type. -I is use to specify which core from all the available cores of specified domain type should be used. Default Value: 0 D:I:d:f:U:NSPHPASSLPASS Invalid domain_type %s. Possible values are "NSP" or "HPASS" or "LPASS" .Remote_system_request API is not supported on this target so cannot get domains info from the device. Falling back to legacy approach of using default domain idERROR in get_dsp_support: 0x%x, defaulting to CDSP domain Error in getting domains informationInvalid core_id = %d for %s. Core_id should be between 0 to %d ERROR in get_effective_domain_id: 0x%x DSP domain is not provided. Retrieving DSP information using Remote APIs. ERROR 0x%x: Invalid domain %d ERROR 0x%x: Invalid unsigned PD flag %d Unsigned PD is not supported on domain %d. signedunsignedAttempting to run on %s PD on domain %d -----------------------HAP API Example-------------------------------- ERROR 0x%x: Test FAILED hap_example PASSED hap_example FAILED with nErr = 0x%x ERROR : unable to get domain struct %d unable to allocated memory for uri of size: %d&_dom=%s%sERROR 0x%x: remote_session_control failed ERROR 0x%x: remote_session_control interface is not supported on this device file:///libhap_example_skel.so?hap_example_skel_handle_invoke&_modver=1.0ERROR 0x%x returned from snprintf ERROR 0x%x: Unable to create FastRPC session on domain %d Demonstrating FARF run-time logging Demonstrating HAP_mem.h APIsERROR: Failed to allocate ION memoryError Code 0x%x : returned from hap_example_mem_fastrpc_mmap(handle, fd, buffer_length) Error Code 0x%x : returned from the fastrpc_munmap() API fastrpc_mmap APIs are not supported on this targetError Code 0x%x : returned from the fastrpc_mmap() API Error Code 0x%x : returned from hap_example_mem_dmahandle(handle, fd, offset, buffer_length) Demonstrating HAP_perf.h APIsPlease select a number ranging from 0 to 2 hap_example function PASSED hap_example function FAILEDPlease look at the mini-dm logs or the adb logcat logs for DSP outputFARF_RUNTIMEMEMPERFSkipping unsupported selector %s (id: %d) Error occurred with selector %s (id: %d): %d LPASSHPASSFailure in remote_system_request call: %d. Unable to allocate memory for req.sys.domainsIncorrect data received from remote_system_request.Error 0x%x: failed to get effective domain id for %s, session id %d FastRPC Capability API is not supported on this device get_dsp_support failed with Error 0x%x remote_dsp_capability interface is not supported on this deviceUnsupported attr. Only VTCM_PAGE and VTCM_COUNT supportedRunning the usecase without checking the capability get_vtcm_info failed with Error 0x%x Unsupported domain %d FastRPC Capability API is not supported on this device. Falling back to signed pd. ERROR 0x%x: FastRPC Capability API failed. Falling back to signed pd.remote_dsp_capability interface is not supported on this device. Falling back to signed pd. is_async_fastrpc_supported failed with Error 0x%x Async fastrpc is not supported on domain %d is_status_notification_supported failed with Error 0x%x Unsupported attr. Only HMX_SUPPORT_SPATIAL and HMX_SUPPORT_DEPTH supported get_hmx_support_info failed with Error 0x%x HMX support is not there for domain %d get_hex_arch_ver failed with Error 0x%x Latest targets have 128 byte HVX register, use HVX_SUPPORT_128B instead of HVX_SUPPORT_64BUnsupported attr. Only HVX_SUPPORT_128B supported get_hvx_support_info failed with Error 0x%x HVX support is not available on domain %d :8;::;:@\X\0\P\0\`\\\\\]](]\\\\\ P]`<0<X; R  o _ ooo o]pppppppppppppppppppppppppppppppppppppppp`IpIxI&_dom=adsp&_dom=mdsp&_dom=sdsp&_dom=cdsp&_dom=cdsp1GCC: (Linaro GCC 7.5-2019.12) 7.5.0,8 ,$H#,d(," .  z8 [" intoN^^(W2-345;}9B|BJjW BnO pv{ Vo/z fdʏ ̺Z ڸ bufO h h64$ dmazk *Q W } } -} ;} }( }0 }8 }@}Hs}P}X`hWp Wtex4I>!p){*{d+{,{v./W1aB (l  {{{W W]  H  TWBB[;x<= PaB    Wug X X  d 2 :  # #8ɮ Y ˺   Ώ ;Ϗ$ Џ( њ, Қ- Ӛ. ]Ԛ/ m՚0 ֚1 ך2 <ؚ3\ \ + Jܺ  ޏ ;ߏ    P;+ P 4   ;  p1 p2 iid ,   4 2 J  ;H S69 TQ2" Q  d *  :    , p1 p2 iid ,   4 * J   ; H S4  4( A 1  W SW 7   ]!* -$ ? / 8 W NW<   ("0   - B  :* B  0\  B  `\ H B 8 IH P]s Bc "s X; B  0< B  h `<: ] #(; $h|"(| $h|"( $h|i|"4 |$hfd|Wd}|xt"(M x$hy|3t4"@ t$hfdtWdt`u|fW f$XfTfHf@dghh`ViW|oD! | =! "Jl#arlQ$ "Jm#armQBBBbh LQb$hBbWdb`/b\c|^ L^$hB^Wd^`/^\_|MW4M$XMTMHM@MdN`OpVPW|X$Y, | <!h"JR#arRQ$x"JS#arSQI48I$hIWdJ|<Wh<$X<T<Hd=h>`V?W|D | <$"JB#arBQB8p(Q8$h9|4H(4$h5|}+W0+$h+dd,xV-Wt/` |$ <$B (WYh($x*%W$uri%xh%p$%o-&|-W|&/-|&-W|&.|'(buf/|)0>|*By6 H#"[" intoN^^5;j B; 5  S  (  F  P  +  `n idW u W n : ( W, e 0 4 ~8~BB * W}}-};} }(}0}8}@ }H s}P }X U` [h Wp  Wt ex 4 I >a q !p ){ *{ d+{ ,{ v. /W 1w]UHU[TW$qBB[;x<=B[[[Wg "} 9} GW? LW^ PW"  4ZA 6W 7W5Z BWh#\ BW BWDW|n EWXZFWP GWxa HWtj I\s JWl3 K}` LW\MH NWD OWT(  %H# ^ ) d([" intoN^^5;}9Bj Bc  idW uri B   I;  W  Wl;M  * ` s    l     I   l \ ;WY          DK  ; 5 S ( F P + W`idW u W  : ( W, e 0 4 8  B ' B  '* W}}-};} }(}0}8}@ }H s}P }X ` h Wp  Wt ex 4 I >   !p ){ *{ d+{ ,{ v. /W 1]HTW9  B  B[; x< = BW ug|; G  . "} 9} GW? LW^ PW"  4A 6W 7W ;&FMEM  V BF @aW-ZWl Wh WWt W|!-" Wx,Wd(TZ,W ,T ,W ,W? ,3 .W| / 2 0Wd 1}p 2[X#uri3}h$,%\)\  G!* >{P#fdWL ;@ ;!|+p ;H#retWD   \ .  8[" intoNii* b   - ; ( 0 8 @ H sP X O` Uh bp  bt px F T >[ k !{ ) * d+ , v.- /b 1q ]O HO U Tb k 8  8[;x<=BUUUb g5M}98jc  Did buri D T 8   _ a ^ c ) eM r kJD$f^#     4M Po -)z         PlM 5M  * ` s    l     I   l \M h 5 S ( F P + 5` id b u b   : h( b, e 0 4 8  8  8  t O  O  b b  M v a sys U id v  " 9 Gb? Lb^ Pb"  4# A 6b 7b# T> 8 . XaIbD9P bl )` h!Wb|":#!_prbh8L bl )`!Wb|"89#`!|_pQ\b078 \bl )\` \h!W^b|"\8#0!l_p(8B \6B 8bl!W9b|"X$7$|6!@_p B `5 bl!Wb|"4P6$5!?_p%B D5&9B t47 'Zbl(Wb|$4(_p&b03D ' bl')`'h(Wb|)h4#(_p&4b42! ' ! h(Wb|)$3$`2(_pb&wb1 'wX' wbT'Tw! H*errxb|(y`&0b\/8C '3 0' 0! '0C (W1b|(2bx*req>H( AOh)ph1$0|*i`btO& B . 'Z bl'o bh*i!b|(/"bx+d H. 'Zbl*ib|(/bxT,!B .<'Zb|% $ > $ > : ; I  I&I : ;  : ; I8 : ; I8  : ;  : ; I  : ;  : ;I8 I!I/  I8 4: ; <4: ;I?<4: ; I?<! : ; I : ; 4: ;I4: ;I?.?: ;'I@B: ;I: ;I.: ;'I@B : ; 4I4! " : ;# : ;I8 $ %.: ; '@B&: ; I'(4: ; I)4: ; I*I% $ > $ > : ; I  I&I> I: ; ( : ;I  : ; : ;I8 : ;I8 I!I/  : ;  : ; I8 : ; <4: ;I?<4: ; I?<!7I.?: ; 'I@B: ; I4: ; I : ; .: ; '@B% $ > $ > : ; I  I&I : ;  : ; I8 I !I/  : ; : ;I8 > I: ;( > I: ;: ;I : ; : ;I8  : ; I8 : ; <4: ;I?<4: ; I?<!> I: ; 7I( 4: ; I?.?: ; 'I@B: ; I 4: ; I! "4: ;I#4: ; I$ : ; % % : ; I$ > $ >   I&I : ;  : ; I8 : ;I8 : ; I !I/ <4: ;I?<4: ; I?<! : ; I8  : ;> I: ;( : ;I> I: ; : ; : ;I8  : ; : ;I I8 7I4: ; I?.?: ;'I@B : ;I!4: ;I" : ;# U$ %.?: ;'I@B&.?: ; 'I@B': ; I(4: ; I) : ; *4: ; I+.?: ; 'I@B,.?: ; 'I@B  C:\Qualcomm\Hexagon_SDK\6.4.0.1/incsUbuntuARM_Debug_aarch64c:\qualcomm\hexagon_sdk\6.4.0.1\tools\linaro64\aarch64-linux-gnu\libc\usr\include\bitsc:\qualcomm\hexagon_sdk\6.4.0.1\tools\linaro64\aarch64-linux-gnu\libc\usr\includeC:\Qualcomm\Hexagon_SDK\6.4.0.1/incs/stddefc:\qualcomm\hexagon_sdk\6.4.0.1\tools\linaro64\lib\gcc\aarch64-linux-gnu\7.5.0\includeHAP_debug.hhap_example_stub.ctypes.hstdint.hAEEStdDef.hstddef.hremote.hlibio.hstdarg.hstdio.hsys_errlist.h -1YJK=/=//Y!!KJJ.J."!==/=/=/=/g!!!//KKJJ<J<"!=K/Y/!!!/KY. LK0#"=JJ<J<"!=g//g//u!!!//KYKJJ<J<"!=Y/u/=/=/K/Y/=/=/=/=/=/=$ src_appc:\qualcomm\hexagon_sdk\6.4.0.1\tools\linaro64\aarch64-linux-gnu\libc\usr\include\bitsc:\qualcomm\hexagon_sdk\6.4.0.1\tools\linaro64\aarch64-linux-gnu\libc\usr\includec:\qualcomm\hexagon_sdk\6.4.0.1\tools\linaro64\lib\gcc\aarch64-linux-gnu\7.5.0\includeC:\Qualcomm\Hexagon_SDK\6.4.0.1/incsc:\qualcomm\hexagon_sdk\6.4.0.1\tools\linaro64\aarch64-linux-gnu\libc\usr\include\syshap_example_main.ctypes.hstdint.hstddef.hremote.hlibio.hstdio.hsys_errlist.hunistd.hgetopt.htime.h H#%/<@K!!/!/!!!/!/#"K!Y!Y!Y!Y"!q.==ttuK#u====[==#=<K/$"/=K&===O=/g!$===0/Y!#YuK/#<<.k==K#!>NL=1!b src_appc:\qualcomm\hexagon_sdk\6.4.0.1\tools\linaro64\aarch64-linux-gnu\libc\usr\include\bitsc:\qualcomm\hexagon_sdk\6.4.0.1\tools\linaro64\aarch64-linux-gnu\libc\usr\includec:\qualcomm\hexagon_sdk\6.4.0.1\tools\linaro64\lib\gcc\aarch64-linux-gnu\7.5.0\includeC:\Qualcomm\Hexagon_SDK\6.4.0.1/incsC:\Qualcomm\Hexagon_SDK\6.4.0.1/ipc/fastrpc/rpcmem/incc:\qualcomm\hexagon_sdk\6.4.0.1\tools\linaro64\aarch64-linux-gnu\libc\usr\include\syshap_example.ctypes.hstdint.hstddef.hremote.hlibio.hstdio.hsys_errlist.hrpcmem.hunistd.hgetopt.htime.h d(,u!//!!"===K"Mg/K"L/=>"]/K#g/K#=K/#Y>Y$|===&DZ>=/&?>/ L=1Y>Mg>Z=L[B!0g>M/(==%=/$1=1>N>>!6K!!/==y.< u?1/!!!=w&K==K#//=#==K#0X=/=z < J=M/#<=0!0Y!0/=0h=v1K!1=!>LKgL=#>!!!g>2=K3/@!1Y!0<?/="K<B//!gK==!"=o< K2/K$/@!1=!LYgL=0>K0>3/=0!1/=1=!KB//!gK==!"=0=K2/K$/@!0="P//!gK==!"=0=K2/@!1Y!0<=/="KB//!gK==!"=MK2/K$/@!1K!/O//!gK==!"=MK2/@!1Y!/=/=#=/=#KB//!gK==!"=MK2/K$/@! x ,AABAA n $$A A F $A A D ,0A@AA 0H $H(A0A G $p(A0A G ,hA`A A PV $4A0A J ,4ApA A `v $ LA@A P $h LA@A P , A`A A P\ $4"@A0A M $t"(A0A G $"4A0A J $"(A0A G $"(A0A G $ #(A0A G  x $H# AA E ,h#A` A <  x ,pd(AA % $p-A0A   x  .<AMH.A ^$.A0A b ,\/8Ap A  $1AP A e $42A0A | ,03DA0A N $t4A0A q $D5AA D $`5A0A | $\6A0A r ,078A0A K $h8A0A t ,D9PA0A Q C:\Qualcomm\Hexagon_SDK\6.4.0.1\examples\hap_example_0params_shortbufseqComplexnumParams_IO_lock_tmethodStringsArrayslevelstderrformat_IO_buf_endinSize_IO_write_endnativeAlignment_in0Offset_cast_in0Fdhap_example_sysmon_cachelocknCaseshap_example_slim_markersstructTypestringshap_example_openroutSizePrimInbFloatingvalue64sprimROutAlignmentremote_bufUbuntuARM_Debug_aarch64/hap_example_stub.chap_example_perfmethodArrayuint32_tstdout_IO_save_endhap_example_power_praHandleInarrayType_primIn_in0Lenlong long unsigned intfileseqTypebDefaultCasemethodArrays_nErrStructTypesys_errlist_IO_backup_base_stub_method_1_stub_method_2_stub_method_3sys_nerr_in0_in1value16s_fileno__pad2__pad4caseValues__gnuc_va_list_nErrfarfbailsize_thap_example_closeUnionType_IO_read_baseobjectstdin_nextnIIds_posdescriptor_prahap_example_mem_map_reserve_vahap_example_mem_dmahandleprimroutSizePrimROut_modeinAlignment_IO_markerhap_example_compute_resbufferOffset_IO_read_ptr__gr_offsuint8_tiidsmethodStringsbNotNilMethod_IO_write_base__copyParameter_IO_2_1_stdin_long long int_IO_2_1_stdout_routAlignmentPrimROut_IO_save_baseparametershap_example_mem_reserve_vaparamhap_example_compute_resv2parameterArraysuint32bSigned__pad1GNU C99 7.5.0 -march=armv8-a -mlittle-endian -mabi=lp64 -g -std=gnu99 -fpic__pad3remote_arg__pad5_stub_method_mid_vtable_offsetAEEResultarrayargsprimInAlignmentuint16_tnativeCaseAlignmentruntime_logging_enablemembers_IO_read_endshort inthap_example_farf_runtimebufferLenvalue8suScalarsnMembersbInterfaceNotNilnativeSize_HAP_debug_v2uint64_tmethods_IO_FILE_plusnMaxLenhap_example_mem_dmahandlev2nMethodscasesmaxArgs__gr_topuintptr_t__va_list_lockCaseValuePtrprimROutSize_old_offset__vr_offs_IO_FILEhap_example_mem_fastrpc_mmapSequenceTypeinCaseAlignmentroutCaseAlignmentPrimIn__vr_topseqSimplevalue32sstringMaxLenunsigned char_sbuflineroutCaseAlignmentPrimROut_IO_write_ptrremote_dma_handle__stackunionTypeInterfaceroutAlignmentPrimInprimInSizemethodStringArray__off_tnLenshort unsigned intremote_handle__func__buffer_lengthnItems_chain_nErrbail_flags2_cur_columnremote_handle64_IO_2_1_stderr___off64_t_unused2_IO_buf_baseoptindoptargsession_id__environtimezonefastrpc_domain_typeopterrFASTRPC_MDSPFASTRPC_LPASSrequested_pdoptioninstance_idtz_dsttimefastrpc_domainFASTRPC_ALL_DOMAINSargvprint_usageargcsoc_idcore_idsrc_app/hap_example_main.cnum_domainsstatususe_logical_id_Boolexample_selectorFASTRPC_SDSPFASTRPC_NSPtz_minuteswestFASTRPC_HPASSoptoptcardis_signedpd_requestedreservedretValexample_caseFASTRPC_PD_INITMEM_SIZEFASTRPC_THREAD_PARAMSFASTRPC_REMOTE_PROCESS_EXCEPTIONPERFFASTRPC_MAP_RESERVED_10FASTRPC_GET_EFFECTIVE_DOMAIN_IDsrc_app/hap_example.cdomain_infoFASTRPC_MAP_FD_EXTENDEDdomain_tFASTRPC_REMOTE_PROCESS_STATE_DUMPRPCMEM_HEAP_ID_CONTIGoverallErrhap_example_URI_domainFASTRPC_RESERVE_NEW_SESSIONis_unsignedpd_enabledFASTRPC_CONTEXT_CREATEdataRPCMEM_HEAP_ID_SECUREDSPRPC_CONTROL_UNSIGNED_MODULEFASTRPC_GET_URIFASTRPC_MAP_STATICFASTRPC_REMOTE_PROCESS_TYPEFASTRPC_MAP_MAXFASTRPC_CONTROL_PD_DUMPFASTRPC_REGISTER_STATUS_NOTIFICATIONSFASTRPC_CONTEXT_DESTROYFASTRPC_MAP_RESERVED_8FASTRPC_MAP_FD_DELAYEDFASTRPC_SESSION_CLOSEhap_example_URI_domain_lenFASTRPC_RESERVED_1FASTRPC_RESERVED_2FASTRPC_RESERVED_3is_unsignedpd_requestedFASTRPC_MAP_RESERVED_4my_domainFASTRPC_MAP_RESERVEDfastrpc_map_flagsFASTRPC_MAP_RESERVED_11FASTRPC_MAP_RESERVED_12FASTRPC_MAP_RESERVED_13RPCMEM_HEAP_ID_SYSTEMFASTRPC_MAP_RESERVED_15FASTRPC_MANAGE_DSP_LIBRARY_PATHrpc_heap_idsFASTRPC_MAP_FDFASTRPC_MAP_RESERVED_5FASTRPC_MAP_RESERVED_6FASTRPC_MAP_RESERVED_7FARF_RUNTIMEFASTRPC_MAP_RESERVED_9FASTRPC_REMOTE_PROCESS_KILLFASTRPC_RELATIVE_THREAD_PRIORITYion_bufferremote_rpc_control_unsigned_modulesession_control_req_idhap_examplerun_testFASTRPC_MAX_THREAD_PARAMFASTRPC_MAP_RESERVED_14FASTRPC_MAP_FD_DELAYED_EXTENDEDexample_case_namesFASTRPC_MAP_FD_NOMAPSTATUS_NOTIFICATION_SUPPORTDSPRPC_GET_DOMAINdsp_capability_async_supportC:\Qualcomm\Hexagon_SDK\6.4.0.1/utils/examples/dsp_capabilities_utils.cis_valid_domain_idremote_rpc_effective_domain_id_tDSPRPC_RESERVED_1get_domains_infoget_unsignedpd_supportHVX_SUPPORT_128BASYNC_FASTRPC_SUPPORTis_unsignedpd_supportedget_hmx_support_infoARCH_VERcompute_onlydsp_capability_arch_versessDSPRPC_CONTROL_LATENCYdsp_capability_vtcm_dspget_effective_domain_idfastrpc_domains_infoattrHMX_SUPPORT_DEPTHDSPRPC_CONTROL_WAKELOCKVTCM_COUNTsizeget_dsp_supportHVX_SUPPORT_64Beffec_domain_idget_domainDSPRPC_RESERVEDdsp_capability_hmx_dspdsp_capability_hvx_dspdomain_name_lendsp_capability_domainsystem_req_payloadVTCM_PAGEMCID_MULTICASTDSPQUEUE_SUPPORTsystem_req_idremote_dsp_capabilityhandle_control_req_idUNSIGNED_PD_SUPPORTHMX_SUPPORT_SPATIALget_hex_arch_verremote_dsp_attributesFASTRPC_MAX_DSP_ATTRIBUTESdomain_nameis_async_fastrpc_supportedHANDLE_PRIORITY_SUPPORTEXTENDED_MAP_SUPPORTmax_domainsDSPRPC_GET_DSP_INFOis_status_notification_supportedget_hvx_support_infoattribute_IDDOMAIN_SUPPORTremote_rpc_effective_domain_idFASTRPC_GET_DOMAINSget_vtcm_infosupported_domainsdsp_capability_status_notification_supportss_infoDSP_IMAGE_CONFIGDSPRPC_SET_PATHis_CDSPDSPRPC_GET_PATH,    0 4 L    p  : 0\ ]__@a  % :( :% 0\3 0\0C `\K P]hX X;` 0<,n `< 0 <  h < 4 <  =%% = H# H# %% E d(%@a%!%Xa .% I%:_P] pY $j 4" t4 \6   H(8S 42 c 078x "(@a `5  L  . 03D5"a% 4"@B #(_ "(q D5aa - ]8 p(a t"(# 5XaPGa\ \/8m .<u" h L H.  D9P  h82a7N_p "4a""  d( 1 h#hap_example_stub.c$x_HAP_debug_v2$dparametersparameterArraysmethodsmethodArraysstringsmethodStringsmethodStringsArrays_stub_method__func__.5035_stub_method_1__func__.5056_stub_method_2__func__.5079_stub_method_3__func__.5109hap_example_main.cprint_usagehap_example.cdsp_capabilities_utils.c_GLOBAL_OFFSET_TABLE__DYNAMIChap_example_openhap_example_farf_runtimegetopt@@GLIBC_2.17remote_system_requestis_unsignedpd_supportedremote_handle64_closeis_status_notification_supportedatoi@@GLIBC_2.17fprintf@@GLIBC_2.17hap_example_compute_resremote_register_dma_handleget_dsp_supportget_hmx_support_infohap_example_perfexample_case_namesis_async_fastrpc_supportedhap_example_mem_dmahandlehap_example_closeis_valid_domain_idget_vtcm_infostderr@@GLIBC_2.17__bss_start__hap_example_mem_fastrpc_mmaphap_example_sysmon_cachelockhap_example_powerget_unsignedpd_supportrpcmem_free__end____bss_end__run_testhap_example_slimhap_example_compute_resv2rpcmem_allocmalloc@@GLIBC_2.17__bss_starthap_example_mem_reserve_vaHAP_debug_runtimesupported_domainsremote_handle64_openget_domains_infois_CDSPoptarg@@GLIBC_2.17strcmp@@GLIBC_2.17remote_session_controlhap_example_mem_dmahandlev2get_domainHAP_debugcalloc@@GLIBC_2.17get_hvx_support_infoget_hex_arch_vervsnprintf@@GLIBC_2.17_endremote_handle64_invokefree@@GLIBC_2.17puts@@GLIBC_2.17hap_example_mem_map_reserve_va_edataremote_handle_controlfastrpc_munmaphap_exampleget_effective_domain_idstrlen@@GLIBC_2.17rpcmem_to_fd.symtab.strtab.shstrtab.note.gnu.build-id.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.text.rodata.data.rel.ro.dynamic.got.got.plt.data.comment.debug_aranges.debug_info.debug_abbrev.debug_line.debug_frame.debug_str.debug_ranges$.44 < oDo  Qo `jBoppt z:: 0\0\]]__X__X@a@ah0a$ab!/ (0ج9 A hgfastrpc-1.0.2/test/linux/libmultithreading.so000066400000000000000000001176101512345705400213600ustar00rootroot00000000000000ELF@@8@33===>>>$$QtdRtd===GNUƠpȜK蠘Q%75$6 * +2"'0 )3!4. -1%#& ,/(  @"9 g` " R    #8E !& P  D0A =8 8(Q . !) x$ (0A0A d00A @P=0A 8 <p"e   %P $$0A}0A "  (k $vsnprintfHAP_debugmultithreading_slimmultithreading_openremote_handle64_openmultithreading_closeremote_handle64_closeremote_handle64_invokeHAP_debug_v2HAP_debug_runtimemultithreading_parallel_summultithreading_barriersmultithreading_mutexesputsoptargatoigetoptget_dsp_supportis_valid_domain_idis_unsignedpd_supportedmultithreading_testget_domainremote_session_controlmallocfreerun_testsupported_domainsis_CDSPget_domains_infostrcmpremote_system_requestcallocget_effective_domain_idstrlenremote_handle_controlget_vtcm_infoget_unsignedpd_supportis_async_fastrpc_supportedis_status_notification_supportedget_hmx_support_infoget_hex_arch_verget_hvx_support_infolibcdsprpc.so.1libm.so.6libc.so.6libstdc++.so.6_edata__bss_start__bss_start____bss_end____end___endlibmultithreading.soGLIBC_2.17>= ' =@'(=`'H==p=(==0==X=========='='>'?? ???#?%?1@@@@ @(@ 0@ 8@ @@H@P@X@`@h@p@x@"@$@%@&@'@(@+@-@.@/@1@2@4{G?    Ր@ ֐@" ֐ @B ֐@b ֐@ ֐@ ֐@ ֐@ ֐"@ ֐&@" ֐*@B ֐.@b ֐2@ ֐6@ ֐:@ ֐>@ ֐B@ ֐F@" ֐J@B ֐N@b ֐R@ ֐V@ ֐Z@ ֐^@ ֐b@ ֐f@" ֐j@B ֐n@b C{O#K_=c=g=k=o=s=w={=C+C/3koCC`@@`A@C@ ҼK@#@O@ {@C_{ @@{¨_{@]{¨_{C'@S@*@''@q ՠ'@qTGTGT@S@@ @*@'@%R`RGT@S@@ @*@'@%R`R= ՠ'@{A_{@R//@@{è_{`R//@@{è_{R//@@{è_{ @ {_{ ?3/ R;93@Tq TqTG@/ G@;h' @@33@1aT/@1T' ??@qT)?@ /@RRq`TR?/@**?@;;@qT;@qMTR?*;@?@,;@qT/@9@9RqT/@@+;@9qT,,/@#-/@@9??@qT-?@ ՠ?@{Ĩ_{o9_` RO+#@##@!TR_@.@_@o@9qTG`T@3 R7R@Ro__@qT/_@jR_/_@cGT@+ /RRR__@PqT_@qT1d _@qT/_@dCO)++@T@R_ 2O@W6O#@2 4+@__@q T@4_@B R_+@__@q@T4@_@25'@__@qT 6_@$@+@`T+@_@qT@77 7_@{ƨ_{o9/o@9@//@{è_C@ qT@qaT RRC_RG| @@?kT|ӀG @@@?kkT_{/R+@qT@/G/| @@?kaT R /@//@+@?kTR{è_{ok@T8@uqT@Rk 9@kqTRk Rk;#/k@qT+@k@*@ ++G Too@qT 9o@nEO@KO@|@ O##@T@Ro9^5oo@qT 9o@S*g#@g{@//@(@k@?k@T@To:3g@gO@g@?kT#@@O@@Ro ՠo@qT#@aT#@o@{Ǩ_{'O#@@;'@?RROO@q@T@;'@O@O@C@*@O@{Ũ_{/@aRGT`R#'+R@R//@qT< +@qT#'+R@R/+@q`T@/@qT=/@  R/@>/@{è_{ / @@q@T@qTR/@?;G@T@qT@ qT@#@'+R@R//@q!T<@|//@qT+@ @ /@w  R/@o R/@>a/@{è_{/G`T@# R'+R@RP//@qT DR/@qT/@CR+@qAT R  R//RR{è_{`R{_{/GT@ qT@# R'+R@R//@q!T<@/+@qaT R/@q`T /@  R/@ R/@>R{è_{/GT@#@R'+R@R//@q!T<@/+@qaT R/@qT/@  R/@>R{è_{ / @@ q@T@qTR/8GT@ qT@#@'+R@R//@q!T<@//@qT+@ @ /@z  R/ @r R/@>d/@{è_{ / @GT@#R'+R@RP//@q!T-/@{è_{ / @@qTR/ A@ qTR/ 8GT@ qT@#@'+R@R//@q!T<@//@qT+@ @/@  R/@@ R/@>/@{è_parallel_sumbarriersmutexescloseopenurih$)-- ERROR 0x%x: handle=0x%lx, scalar=0x%x, method ID=%d: %s failed multithreading_stub.c_stub_methodUsage: multithreading [-d domain] [-U unsigned_PD] Options: -d domain: Run on a specific domain. 0: Run the example on ADSP 3: Run the example on CDSP 2: Run the example on SDSP Default Value: 3(CDSP) for targets having CDSP and 0(ADSP) for targets not having CDSP like Agatti. -U unsigned_PD: Run on signed or unsigned PD. 0: Run on signed PD. 1: Run on unsigned PD. Default Value: 1d:U: DSP domain is not provided. Retrieving DSP information using Remote APIs.ERROR in get_dsp_support: 0x%x, defaulting to CDSP domain ERROR 0x%x: Invalid domain %d ERROR 0x%x: Invalid unsigned PD flag %d Overriding user request for unsigned PD. Only signed offload is allowed on domain %d. unsignedsignedAttempting to run on %s PD on domain %d ERROR 0x%x: Test FAILED ERROR 0x%x: unable to get domain struct %d ERROR 0x%x: remote_session_control failed ERROR 0x%x: remote_session_control interface is not supported on this device Setting relative thread priority is not supported on this deviceunable to allocated memory for uri of size: %dfile:///libmultithreading_skel.so?multithreading_skel_handle_invoke&_modver=1.0%s%sERROR 0x%x returned from snprintf ERROR 0x%x: Unable to create FastRPC session on domain %d Exiting...ERROR 0x%x: returned from function : multithreading_parallel_sum Test PASSEDTest FAILEDPlease look at the mini-dm logs or the adb logcat logs for DSP outputLPASSHPASSFailure in remote_system_request call: %d. Unable to allocate memory for req.sys.domainsIncorrect data received from remote_system_request.Error 0x%x: failed to get effective domain id for %s, session id %d FastRPC Capability API is not supported on this device get_dsp_support failed with Error 0x%x remote_dsp_capability interface is not supported on this deviceUnsupported attr. Only VTCM_PAGE and VTCM_COUNT supportedRunning the usecase without checking the capability get_vtcm_info failed with Error 0x%x Unsupported domain %d FastRPC Capability API is not supported on this device. Falling back to signed pd. ERROR 0x%x: FastRPC Capability API failed. Falling back to signed pd.remote_dsp_capability interface is not supported on this device. Falling back to signed pd. is_async_fastrpc_supported failed with Error 0x%x Async fastrpc is not supported on domain %d is_status_notification_supported failed with Error 0x%x Unsupported attr. Only HMX_SUPPORT_SPATIAL and HMX_SUPPORT_DEPTH supported get_hmx_support_info failed with Error 0x%x HMX support is not there for domain %d get_hex_arch_ver failed with Error 0x%x Latest targets have 128 byte HVX register, use HVX_SUPPORT_128B instead of HVX_SUPPORT_64BUnsupported attr. Only HVX_SUPPORT_128B supported get_hvx_support_info failed with Error 0x%x HVX support is not available on domain %d '@'`'=(=0=X=====''')X0 I ?(0  o oo o>&_dom=adsp&_dom=mdsp&_dom=sdsp&_dom=cdsp&_dom=cdsp1GCC: (Linaro GCC 7.5-2019.12) 7.5.0,,0`4, , />NI@int^n^G(W2-345;F9B|BDGWBND pv{ $o fdʏ ̺O ڭ bufD h h64 dmaoz @ W } } } } }( l}0 }8 Y}@!}H}P-}X`3hWp: WtexB48I!p){*{ +{,{.g/Wx1 (K  {{{WW& y + L 7WBBW;<^= P@% & K  W_T _o   -   z 8ō < Ǻ ȥ v eʏ ˏ$ V̏( m͚, Κ- Ϛ. К/ њ0 nҚ1 Ӛ2 hԚ3    غ  eڏ ۏ V܏ mݚ ޚ ߚ  c ` e e  V p1 p2 iid  : ,z ` e   cQQ1(  f -    z h  p1 p2 iid  : , ` e    fQQ1  (    |W W   s !     8 mW   1W   (0     B i  ' B  = B O 0= # B u# =N B/> N 'y Bi y ' B 1 't =W88( 8h39|4(W 4h35|W0( 0h31|&'W0 'h3'dG( x)Wt+#0 ((0 B  $We h$x!Wx$ uri!x h! p!8-#"E-W|"[-|"R-W|"R.|#$buf/#|%L0|&B /`4}>NI@int^n^GF9BDB2  idW uri B | N 0 |  W  W FX | W QW_ ;  %   ;    t   fW}}}} }(l}0}8Y}@ !}H }P -}X ` 3h Wp : Wt ex B4 8I   !p ){ *{ +{ ,{ . g/W x1&y+L7Wm  Bf  BW;<^=%&KW 0%0j "L} 9} GW LW PW 4 6Wv 7W~ Wd0 Wl kW|c dW dW d fW|gXE hWli i}p. j`$H uPp 0H~ 'W$s& 'W\ 'LP)W|+ *Wp +Wl5 ,Wx -w`S `   / T8I>N@intiniG b     ( l0 8 Y@ !H P -X O` 3Uh bp : bt px BF 8T [ k !{ ) * + , .- g/b x1q &yO +O LU 7b k 8  8W;<^=%U&UKUb 5MF98D2  Did buri D T 8 |  _ | a ) c  eM r 6 S ]  W d 8 g  ~ v0M P  i _  L  K  $  T  W  P_ M 5  %   ;    t   M hW  5` id b  b R   h( E b, 0  4 I 8  8  8  t O  O  b b 4 M vk a sys U id vJ j " 9 Gb Lb Pb 4#  6b v 7b# T> 8 . @b%P | bl ` R h!b|"'#! _p b$L | bl `!b|"%#`! _p \b#8 | \bl \` R \h!^b|"$#0! l_p8B "B | 8bl!9b|"X#$#!@_pc cB ! | bl!b|"4"$"!q _p%< B !&z B 7 ' bl(b|$!(4_p&bD '| bl'`'R h(b|) #( _p& b! '| ! h(b|)$(4_pb& wb 'KwX'T wbT' w! H*errxb|( y`&+ 0b8C '0' 0! '< 0C (1b|(2bx*req>H(| AOh)p$L|*i`btO&  B P '  bl'  bh*i!b|( "bx+   ' bl*ib|( bxT,B <' b|% $ > $ > : ; I  I&I : ;  : ; I8 : ; I8  : ;  : ; I  : ;  : ;I8  I8 4: ; I!I/ <4: ;I?<4: ; I?<! : ; I : ; 4: ;I4: ;I?.?: ;'I@B: ;I.: ;'I@B : ;4I4 : ;I!.: ; '@B": ; I#$4: ; I%4: ; I&I% $ > $ > : ; I  I&I : ;  : ; I8 I !I/  : ; : ;I8 > I: ;(  : ; I8 : ; <4: ;I?<4: ; I?<!7I.?: ; 'I@B: ; I4: ; I : ;   .: ; '@B% : ; I$ > $ >   I&I : ;  : ; I8 : ;I8 : ; I !I/ <4: ;I?<4: ; I?<! : ; I8  : ;> I: ;( : ;I> I: ; : ; : ;I8  : ; : ;I I8 7I4: ; I?.?: ;'I@B : ;I!4: ;I" : ;# U$ %.?: ;'I@B&.?: ; 'I@B': ; I(4: ; I) : ; *4: ; I+.?: ; 'I@B,.?: ; 'I@By# C:\Qualcomm\Hexagon_SDK\6.4.0.1/incsUbuntuARM_Debug_aarch64c:\qualcomm\hexagon_sdk\6.4.0.1\tools\linaro64\aarch64-linux-gnu\libc\usr\include\bitsc:\qualcomm\hexagon_sdk\6.4.0.1\tools\linaro64\aarch64-linux-gnu\libc\usr\includeC:\Qualcomm\Hexagon_SDK\6.4.0.1/incs/stddefc:\qualcomm\hexagon_sdk\6.4.0.1\tools\linaro64\lib\gcc\aarch64-linux-gnu\7.5.0\includeHAP_debug.hmultithreading_stub.ctypes.hstdint.hAEEStdDef.hstddef.hremote.hlibio.hstdarg.hstdio.hsys_errlist.h -1YJK=/=//Y!!KJJ.J."!==/=/=/=/=/= srcc:\qualcomm\hexagon_sdk\6.4.0.1\tools\linaro64\aarch64-linux-gnu\libc\usr\include\bitsc:\qualcomm\hexagon_sdk\6.4.0.1\tools\linaro64\aarch64-linux-gnu\libc\usr\includec:\qualcomm\hexagon_sdk\6.4.0.1\tools\linaro64\lib\gcc\aarch64-linux-gnu\7.5.0\includeC:\Qualcomm\Hexagon_SDK\6.4.0.1/incsc:\qualcomm\hexagon_sdk\6.4.0.1\tools\linaro64\aarch64-linux-gnu\libc\usr\include\sysmultithreading.ctypes.hstdint.hstddef.hremote.hlibio.hstdio.hsys_errlist.hunistd.hgetopt.htime.h `/ Y=#==K 1=1>N>>!0K!K!e C:\Qualcomm\Hexagon_SDK\6.4.0.1/incsC:\Qualcomm\Hexagon_SDK\6.4.0.1/utils/examplesc:\qualcomm\hexagon_sdk\6.4.0.1\tools\linaro64\lib\gcc\aarch64-linux-gnu\7.5.0\includec:\qualcomm\hexagon_sdk\6.4.0.1\tools\linaro64\aarch64-linux-gnu\libc\usr\include\bitsc:\qualcomm\hexagon_sdk\6.4.0.1\tools\linaro64\aarch64-linux-gnu\libc\usr\includec:\qualcomm\hexagon_sdk\6.4.0.1\tools\linaro64\aarch64-linux-gnu\libc\usr\include\sysdomain_default.hdsp_capabilities_utils.cstddef.htypes.hlibio.hstdio.hsys_errlist.hstdint.hremote.hunistd.hgetopt.htime.h /<<. /./!0/d<O!0K!0=M/,<O!0Y!!=u>u?1/!!!=w&K==K#//=#==K#0X=/=z < J=M/#<=0!0Y!0/=0h=v1K!1=!>LKgL=#>!!!g>2=K3/@!1Y!0<?/="K<B//!gK==!"=o< K2/K$/@!1=!LYgL=0>K0>3/=0!1/=1=!KB//!gK==!"=0=K2/K$/@!0="P//!gK==!"=0=K2/@!1Y!0<=/="KB//!gK==!"=MK2/K$/@!1K!/O//!gK==!"=MK2/@!1Y!/=/=#=/=#KB//!gK==!"=MK2/K$/@! x ,AABAA n $x$A A F $A A D ,0A@AA 0H $(A0A G $(A0A G $8(A0A G  x $8` AA E ,8$A@A  ,8A` A  $8d0A0A I  x <AMA ^$PA0A b ,8Ap A  $AP A e $A0A | ,DA0A N $ A0A q $!AA D $!A0A | $"A0A r ,#8A0A K $$A0A t ,%PA0A Q params_shortbufseqComplexnumParams_IO_lock_tmethodStringsArrayslevelstderrformat_IO_buf_endinSize_IO_write_endnativeAlignment_flags_castmultithreading_barriersnCases_markersstructTypestringsroutSizePrimInbFloatingvalue64sprimROutAlignmentremote_bufmethodArrayuint32_tstdout_IO_save_endarrayTypelong long unsigned intfileseqTypebDefaultCasemethodArrays_nErrStructTypesys_errlist_IO_backup_basesys_nerrvalue16s_fileno__pad2__pad4caseValues__gnuc_va_list_nErrfarfbailsize_tUnionType_IO_read_baseobjectstdin_nextnIIds_posdescriptor_praargsprimroutSizePrimROut_modeinAlignment_IO_marker_IO_read_ptr__gr_offsuint8_tiidsmethodStringsbNotNilMethod_IO_write_baseParameter_IO_2_1_stdin_long long int_IO_2_1_stdout_routAlignmentPrimROut_IO_save_baseC:\Qualcomm\Hexagon_SDK\6.4.0.1\examples\multithreading_0parametersmultithreading_slimmultithreading_openparameterArraysparambSigned__pad1GNU C99 7.5.0 -march=armv8-a -mlittle-endian -mabi=lp64 -g -std=gnu99 -fpic__pad3remote_arg__pad5_stub_method_mid_vtable_offsetAEEResultarraymultithreading_parallel_sumprimInAlignmentuint16_tnativeCaseAlignmentUbuntuARM_Debug_aarch64/multithreading_stub.cmultithreading_closemembers_IO_read_endshort intvalue8suScalarsnMembersbInterfaceNotNilnativeSize_HAP_debug_v2uint64_tmethods_IO_FILE_plusnMaxLennMethodscasesmaxArgs__gr_topuintptr_t__va_list_lockCaseValuePtrprimROutSize_old_offset__vr_offs_IO_FILESequenceTypeinCaseAlignmentroutCaseAlignmentPrimIn__vr_topseqSimplevalue32sstringMaxLenunsigned char_sbuflinemultithreading_mutexesroutCaseAlignmentPrimROut_IO_write_ptrremote_dma_handle__stackunionTypeInterfaceroutAlignmentPrimInprimInSizemethodStringArray__off_tnLenshort unsigned intremote_handle__func__nItems_chain_flags2_cur_columnremote_handle64_IO_2_1_stderr___off64_t_unused2_IO_buf_baseoptindremote_rpc_control_unsigned_moduleoptargFASTRPC_CONTEXT_CREATEFASTRPC_SESSION_CLOSEFASTRPC_RESERVED_1FASTRPC_RESERVED_2FASTRPC_RESERVED_3FASTRPC_RELATIVE_THREAD_PRIORITYremote_rpc_relative_thread_priority__environFASTRPC_MAX_THREAD_PARAMmultithreading_testtimezonesrc/multithreading.cenableFASTRPC_CONTROL_PD_DUMPopterrFASTRPC_REMOTE_PROCESS_KILLtz_minuteswestis_unsignedpd_enabledargcoptiondomain_tFASTRPC_PD_INITMEM_SIZEprint_usagesession_control_req_idtz_dsttimeargvFASTRPC_REMOTE_PROCESS_STATE_DUMPFASTRPC_GET_URIrun_testFASTRPC_CONTEXT_DESTROYFASTRPC_RESERVE_NEW_SESSIONFASTRPC_MANAGE_DSP_LIBRARY_PATHFASTRPC_GET_EFFECTIVE_DOMAIN_IDunsignedpd_flagmultithreading_URI_domain_len_Boolmultithreading_URI_domaindataDSPRPC_CONTROL_UNSIGNED_MODULEFASTRPC_REMOTE_PROCESS_TYPEFASTRPC_REGISTER_STATUS_NOTIFICATIONSretValoptoptFASTRPC_REMOTE_PROCESS_EXCEPTIONFASTRPC_THREAD_PARAMSmy_domainSTATUS_NOTIFICATION_SUPPORTsession_idDSPRPC_GET_DOMAINdsp_capability_async_supportfastrpc_domainC:\Qualcomm\Hexagon_SDK\6.4.0.1/utils/examples/dsp_capabilities_utils.cis_valid_domain_idremote_rpc_effective_domain_id_tDSPRPC_RESERVED_1get_domains_infoget_unsignedpd_supportHVX_SUPPORT_128BASYNC_FASTRPC_SUPPORTis_unsignedpd_supportedget_hmx_support_infoARCH_VERcompute_onlydsp_capability_arch_versessFASTRPC_LPASScardDSPRPC_CONTROL_LATENCYdsp_capability_vtcm_dspget_effective_domain_idfastrpc_domains_inforeservedattrHMX_SUPPORT_DEPTHDSPRPC_CONTROL_WAKELOCKVTCM_COUNTnum_domainssizeget_dsp_supportHVX_SUPPORT_64Beffec_domain_idget_domainDSPRPC_RESERVEDdsp_capability_hmx_dspdsp_capability_hvx_dspFASTRPC_HPASSdomain_name_lendsp_capability_domainsystem_req_payloadVTCM_PAGEMCID_MULTICASTDSPQUEUE_SUPPORTsystem_req_idFASTRPC_MDSPremote_dsp_capabilityhandle_control_req_idinstance_idUNSIGNED_PD_SUPPORTHMX_SUPPORT_SPATIALsoc_idget_hex_arch_verremote_dsp_attributesFASTRPC_MAX_DSP_ATTRIBUTESdomain_nameFASTRPC_NSPis_async_fastrpc_supportedHANDLE_PRIORITY_SUPPORTEXTENDED_MAP_SUPPORTmax_domainsfastrpc_domain_typeFASTRPC_ALL_DOMAINSDSPRPC_GET_DSP_INFOis_status_notification_supportedget_hvx_support_infoattribute_IDDOMAIN_SUPPORTstatusremote_rpc_effective_domain_idFASTRPC_GET_DOMAINSget_vtcm_infosupported_domainsdsp_capability_status_notification_supportss_infoDSP_IMAGE_CONFIGDSPRPC_SET_PATHFASTRPC_SDSPis_CDSPDSPRPC_GET_PATH,    0 4 L 0X  0 (   ' = >??@  ( '+ '`( =6 =F 0=xN =([ '0c 'q '  0 (( (( 8( ` ` (H(@ ( 8.(?> " 6L "m~    #8 ! P D0A =8 8(- A !X x$l (0A0A d00A @P0A 8 <)<"S ^ h{ %P $0A0A" *= (Y $multithreading_stub.c$x_HAP_debug_v2$dparametersparameterArraysmethodsmethodArraysstringsmethodStringsmethodStringsArrays_stub_method__func__.5004multithreading.cprint_usagedsp_capabilities_utils.c_GLOBAL_OFFSET_TABLE__DYNAMICgetopt@@GLIBC_2.17remote_system_requestis_unsignedpd_supportedremote_handle64_closeis_status_notification_supportedatoi@@GLIBC_2.17multithreading_closeget_dsp_supportget_hmx_support_infois_async_fastrpc_supportedis_valid_domain_idget_vtcm_info__bss_start__multithreading_slimmultithreading_mutexesmultithreading_testget_unsignedpd_supportmultithreading_openmultithreading_parallel_sum__end____bss_end__run_testmalloc@@GLIBC_2.17__bss_startHAP_debug_runtimesupported_domainsremote_handle64_openget_domains_infois_CDSPoptarg@@GLIBC_2.17strcmp@@GLIBC_2.17remote_session_controlget_domainHAP_debugcalloc@@GLIBC_2.17get_hvx_support_infoget_hex_arch_vervsnprintf@@GLIBC_2.17_endremote_handle64_invokefree@@GLIBC_2.17puts@@GLIBC_2.17_edataremote_handle_controlget_effective_domain_idstrlen@@GLIBC_2.17multithreading_barriers.symtab.strtab.shstrtab.note.gnu.build-id.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.text.rodata.data.rel.ro.dynamic.got.got.plt.data.comment.debug_aranges.debug_info.debug_abbrev.debug_line.debug_frame.debug_str.debug_ranges$.x4 00(<XXIDo nQo  `0 0 jB((otlz ' ' ==>>??@??@@P00A$TAA!ci] sH0Xwp0 6  Uufastrpc-1.0.2/test/qnn_run.md000066400000000000000000000334721512345705400161540ustar00rootroot00000000000000# Document for Running QNN Models ## For Linux Host (Setup) ### Step 1: Install Qualcomm AI Engine Direct (QNN SDK) 1. Download the QNN SDK: * Go to the QNN SDK product [page](https://www.qualcomm.com/developer/software/qualcomm-ai-engine-direct-sdk). * Click **Get Software** to download the QNN SDK. * Unzip the downloaded SDK. 2. Set Up Your Environment: * Open a terminal. * Navigate to `qairt/` inside the unzipped QNN SDK. * Run the following commands to set up the environment: + `cd bin` + `source ./envsetup.sh` * This will automatically set the environment variables `QNN_SDK_ROOT` and `SNPE_ROOT`. * To save this for future bash terminals, run: + `echo 'export QNN_SDK_ROOT="${QNN_SDK_ROOT}"' >> ~/.bashrc` 3. Check Dependencies: * Run: + `sudo ${QNN_SDK_ROOT}/bin/check-linux-dependency.sh` * When all necessary dependencies are installed, the script will display “Done!!”. 4. Verify Toolchain Installation: * Run: + `${QNN_SDK_ROOT}/bin/envcheck -c` * This will verify that the required toolchain is installed successfully. ### Step 2: Install QNN SDK Dependencies 1. Install Python 3.10: * Run the following commands: + `sudo apt-get update && sudo apt-get install python3.10 python3-distutils libpython3.10` * Verify the installation by running: + `python3 --version` 2. Navigate to QNN SDK Root: * Run: + `cd ${QNN_SDK_ROOT}` 3. Create and Activate a Virtual Environment: * Run the following commands (you may rename `MY_ENV_NAME` to any name you prefer): + `python3 -m venv MY_ENV_NAME` + `source MY_ENV_NAME/bin/activate` 4. Update Dependencies: * Run: + `python "${QNN_SDK_ROOT}/bin/check-python-dependency"` ### Step 3: Install Model Frameworks 1. Identify Relevant Frameworks: * QNN supports multiple model frameworks. Install only the ones relevant for the AI model files you want to use. * **Warning:** You do not need to install all packages listed here. 2. Note: * You can install a package by running: + `pip3 install package==version` * Example Installations: + `pip3 install torch==1.13.1` + `pip3 install tensorflow==2.10.1` + `pip3 install tflite==2.3.0` + `pip3 install torchvision==0.14.1` + `pip3 install onnx==1.12.0` + `pip3 install onnxruntime==1.17.1` + `pip3 install onnxsim==0.4.36` ### Step 4: Install Target Device OS-Specific Toolchain Code #### Working with an Android Target Device: 1. Install Android NDK: * Download the [Android NDK r26c](https://dl.google.com/android/repository/android-ndk-r26c-linux.zip). * Unzip the file. 2. Set Up Environment Variables: * Open a terminal. * Replace `` with the path to the unzipped `android-ndk-r26c` folder, then run: + `echo 'export ANDROID_NDK_ROOT=""' >> ~/.bashrc` * Add the location of the unzipped file to your PATH by running: + `echo 'export PATH="${ANDROID_NDK_ROOT}:${PATH}"' >> ~/.bashrc` + `source ~/.bashrc` 3. Verify Environment Variables: * Run: + `${QNN_SDK_ROOT}/bin/envcheck -n` #### Working with a Linux Target Device: 1. Verify Clang++14 Installation: * For Linux target devices, you will likely need to use clang++14 to build models for them using the QNN SDK. * You can verify if you have clang++14 by running: + `${QNN_SDK_ROOT}/bin/envcheck -c` 2. Set Up Cross Compiler (for **Linux Embedded**): * Open a new terminal * Follow these steps to set up the cross compiler: + `wget https://artifacts.codelinaro.org/artifactory/qli-ci/flashable-binaries/qimpsdk/qcm6490/x86/qcom-6.6.28-QLI.1.1-Ver.1.1_qim-product-sdk-1.1.3.zip` + `unzip qcom-6.6.28-QLI.1.1-Ver.1.1_qim-product-sdk-1.1.3.zip` + `umask a+rx` + `cd /path/to/unzip/target/qcm6490/sdk` + `sh qcom-wayland-x86_64-qcom-multimedia-image-armv8-2a-qcm6490-toolchain-ext-1.0.sh` + `export ESDK_ROOT=` + `cd $ESDK_ROOT` + `source environment-setup-armv8-2a-qcom-linux` ## CNN to QNN for Linux Host ### Step 1: Set Up The Example TensorFlow Model 1. Verify TensorFlow Installation: * Run: + `python3 -m pip show tensorflow` 2. Set the TENSORFLOW_HOME Environment Variable: * Run the following commands: ``` tensorflowLocation=$(python -m pip show tensorflow | grep '^Location: ' | awk '{print $2}') export TENSORFLOW_HOME="$tensorflowLocation/tensorflow" echo "export TENSORFLOW_HOME=$tensorflowLocation/tensorflow" >> ~/.bashrc ``` 3. Verify Environment Variable: * Run: + `${TENSORFLOW_HOME}` 4. Create Test Data: * Run: + `python3 ${QNN_SDK_ROOT}/examples/Models/InceptionV3/scripts/setup_inceptionv3.py -a ~/tmpdir -d` * This will create the test data for this tutorial: + Model file at: `${QNN_SDK_ROOT}/examples/Models/InceptionV3/tensorflow/inception_v3_2016_08_28_frozen.pb` + Raw images at: `${QNN_SDK_ROOT}/examples/Models/InceptionV3/data/cropped` ### Step 2: Convert the CNN Model into a QNN Model 1. Quantized Model Conversion: * To use a quantized model, pass in the `--input_list` flag to specify the input. * Run the following command: ``` python ${QNN_SDK_ROOT}/bin/x86_64-linux-clang/qnn-tensorflow-converter \ --input_network "${QNN_SDK_ROOT}/examples/Models/InceptionV3/tensorflow/inception_v3_2016_08_28_frozen.pb" \ --input_dim input 1,299,299,3 \ --input_list "${QNN_SDK_ROOT}/examples/Models/InceptionV3/data/cropped/raw_list.txt" \ --out_node "InceptionV3/Predictions/Reshape_1" \ --output_path "${QNN_SDK_ROOT}/examples/Models/InceptionV3/model/Inception_v3.cpp" ``` 2. Flags Explanation: * `--input_network`: Path to the source framework model. * `--input_dim`: Input name followed by dimensions. * `--input_list`: Absolute path to input data (required for quantization). * `--out_node`: Name of the graph’s output Tensor Names. * `--output_path`: Indicates where to put the output files. 3. Artifacts Produced: * `Inception_v3.cpp`: Contains the sequence of API calls. * `Inception_v3.bin`: Static data associated with the model. * `Inception_v3_net.json`: Describes the model data in a standardized manner (not needed to build the QNN model later on). 4. Location of Artifacts: * You can find the artifacts in the `${QNN_SDK_ROOT}/examples/Models/InceptionV3/model` directory. ### Other Model Types: If you are using another type of model, you can refer to the [Tools page](https://docs.qualcomm.com/bundle/publicresource/topics/80-63442-50/tools.html) for a table of potential scripts to help convert them into QNN format. These scripts will have a similar qnn-model-type-converter naming convention. ### Step 3: Model Build on Linux Host 1. Choose Target Architecture: * Select the most relevant supported target architecture from the following list: + 64-bit Linux targets: `x86_64-linux-clang` + 64-bit Android devices: `aarch64-android` + Qualcomm’s QNX OS: `aarch64-qnx` (Note: This architecture is not supported by default in the QNN SDK.) + OpenEmbedded Linux (GCC 11.2): `aarch64-oe-linux-gcc11.2` + OpenEmbedded Linux (GCC 9.3): `aarch64-oe-linux-gcc9.3` + OpenEmbedded Linux (GCC 8.2): `aarch64-oe-linux-gcc8.2` + Ubuntu Linux (GCC 9.4): `aarch64-ubuntu-gcc9.4` + Ubuntu Linux (GCC 7.5): `aarch64-ubuntu-gcc7.5` 2. Set Target Architecture: * On your host machine, set the target architecture of your target device by running: + `export QNN_TARGET_ARCH="your-target-architecture-from-above"` * For **Android**: + `export QNN_TARGET_ARCH="aarch64-android"` * For **Linux Embedded**: + `export QNN_TARGET_ARCH="aarch64-oe-linux-gcc11.2"` 3. Generate Model Library: * Run the following command on your host machine: ``` python3 "${QNN_SDK_ROOT}/bin/x86_64-linux-clang/qnn-model-lib-generator" \ -c "${QNN_SDK_ROOT}/examples/Models/InceptionV3/model/Inception_v3.cpp" \ -b "${QNN_SDK_ROOT}/examples/Models/InceptionV3/model/Inception_v3.bin" \ -o "${QNN_SDK_ROOT}/examples/Models/InceptionV3/model_libs" \ -t ${QNN_TARGET_ARCH} ``` * `-c`: Path to the `.cpp` QNN model file. * `-b`: Path to the `.bin` QNN model file (optional but recommended). * `-o`: Path to the output folder. * `-t`: Target architecture to build for. 4. Verify Output File: * Run: + `ls ${QNN_SDK_ROOT}/examples/Models/InceptionV3/model_libs/${QNN_TARGET_ARCH}` * Verify that the output file `libInception_v3.so` is inside. This file will be used on the target device to execute inferences. The output `.so` file will be located in the `model_libs` directory, named according to the target architecture. ### Step 4: Model Build on Linux Host Users can set custom options and different performance modes to the HTP Backend through the backend config. Follow these steps to create the necessary JSON files: 1. Create Backend Config File (`be.json`): * For **Android** with the following content: ```json { "graphs": [ { "graph_names": [ "Inception_v3" ], "vtcm_mb": 8 } ], "devices": [ { "htp_arch": "v79" } ] } ``` * For **Linux Embedded** with the following content: ```json { "graphs": [ { "graph_names": [ "Inception_v3" ], "vtcm_mb": 8 } ], "devices": [ { "htp_arch": "v73" } ] } ``` 2. Create Backend Extensions Config File (`config.json`): * The config file with minimum parameters specified through JSON is given below: ```json { "backend_extensions": { "shared_library_path": "./libQnnHtpNetRunExtensions.so", "config_file_path": "./be.json" } } ``` 3. Place JSON Files in the Model Libraries Path: * Ensure that the `be.json` and `config.json` files are located in the following path: + `${QNN_SDK_ROOT}/examples/Models/InceptionV3/model_libs/${QNN_TARGET_ARCH}` ### Step 5: Prepare the Target Device 1. Open a Terminal on the Target Device: * Run the following commands to create a destination folder and set the necessary permissions: ``` adb shell "mkdir -p /data/local/tmp" adb shell "ln -s /etc/ /data/local/tmp" adb shell "chmod -R 777 /data/local/tmp" adb shell "mkdir -p /data/local/tmp/inception_v3" ``` 2. Push Necessary Files: * Push `libQnnHtp.so` and other necessary executables, input data, and input list from your host machine to `/data/local/tmp/inception_v3` on the target device: ``` adb push \path\to\qairt\2.32.0.250228\lib\${QNN_TARGET_ARCH} /data/local/tmp/inception_v3 adb shell "cd /data/local/tmp/inception_v3; mv ./${QNN_TARGET_ARCH}/* ./; rmdir ${QNN_TARGET_ARCH}" ``` * For **Android**: + `adb push \path\to\qairt\2.32.0.250228\lib\hexagon-v79\unsigned /data/local/tmp/inception_v3` * For **Linux Embedded**: + `adb push \path\to\qairt\2.32.0.250228\lib\hexagon-v73\unsigned /data/local/tmp/inception_v3` * Continue remaining steps on the target device: ``` adb shell "cd /data/local/tmp/inception_v3; mv ./unsigned/* ./; rmdir unsigned" adb push \path\to\qairt\2.32.0.250228\examples\Models\InceptionV3\model_libs\${QNN_TARGET_ARCH}\ /data/local/tmp/inception_v3 adb shell "cd /data/local/tmp/inception_v3; mv ./${QNN_TARGET_ARCH}/* ./; rmdir ${QNN_TARGET_ARCH}" ``` ``` adb push \path\to\qairt\2.32.0.250228\examples\Models\InceptionV3\data\cropped /data/local/tmp/inception_v3 adb push \path\to\qairt\2.32.0.250228\examples\Models\InceptionV3\data\target_raw_list.txt /data/local/tmp/inception_v3 adb push \path\to\qairt\2.32.0.250228\bin\${QNN_TARGET_ARCH}\qnn-net-run /data/local/tmp/inception_v3 adb shell "chmod 777 /data/local/tmp/inception_v3/qnn-net-run" ``` 3. Run the Model & Pull Output Directory to Host Machine: * On the target device, run the following command to execute the model: ``` adb shell "LD_LIBRARY_PATH=/data/local/tmp/inception_v3 DSP_LIBRARY_PATH=/data/local/tmp/inception_v3; cd /data/local/tmp/inception_v3; ./qnn-net-run --model ./libInception_v3.so --input_list ./target_raw_list.txt --backend ./libQnnHtp.so --output_dir ./output --config_file ./config.json" ``` * Run the following command to pull the output directory from the target device to your host machine: + `adb pull /data/local/tmp/inception_v3/output \path\to\qairt\2.32.0.250228\examples\Models\InceptionV3` ### Step 6: View Classification Result 1. Navigate to the Example Directory on Host Machine: * Run: + `cd ${QNN_SDK_ROOT}/examples/Models/InceptionV3` 2. Run the Script to View Classification Results: * Execute the following command to view the classification results: ``` python3 "./scripts/show_inceptionv3_classifications.py" \ -i "./data/cropped/raw_list.txt" \ -o "./output" \ -l "./data/imagenet_slim_labels.txt" ``` * Ensure that the classification results in the output match the following: ``` ${QNN_SDK_ROOT}/examples/Models/InceptionV3/data/cropped/notice_sign.raw 0.152344 459 brass ${QNN_SDK_ROOT}/examples/Models/InceptionV3/data/cropped/chairs.raw 0.281250 832 studio couch ${QNN_SDK_ROOT}/examples/Models/InceptionV3/data/cropped/trash_bin.raw 0.800781 413 ashcan ${QNN_SDK_ROOT}/examples/Models/InceptionV3/data/cropped/plastic_cup.raw 0.988281 648 measuring cup ``` ### References * [Linux Setup](https://docs.qualcomm.com/bundle/publicresource/topics/80-63442-50/linux_setup.html) * [CNN to QNN for Linux Host](https://docs.qualcomm.com/bundle/publicresource/topics/80-63442-50/qnn_tutorial_linux_host.html) * [CNN to QNN for Linux Host on Linux Target](https://docs.qualcomm.com/bundle/publicresource/topics/80-63442-50/qnn_tutorial_linux_host_linux_target.html)fastrpc-1.0.2/test/v68/000077500000000000000000000000001512345705400145645ustar00rootroot00000000000000fastrpc-1.0.2/test/v68/libcalculator_skel.so000066400000000000000000000612641512345705400207760ustar00rootroot00000000000000ELF4h4 (@@ 0##`00`000||(@@AGl]glP%56| #9nU$?<q,8< S!;{!͉ҟX2+꟢RC9rõVnm~z=auuz>1}'AU ȋbъ|qH,in3 [ [e[zӕ.x^'ցsbWe.vtхD#'\cIa70X A6LgU<~ɠ;֖EPD?~Yh +F+2Oh~Cw<@]mDbpD)UdL͡77]=|+ӿXosB0 4!3HokV,p~-NxvFmE 5+ AS߸УjѢ0u0]h')}8D_?1. 0  *H  0j1$0"U Qualcomm Technologies, Inc.1*0(U !Qualcomm Cryptographic Operations10U QDSR Sub-CA 10 250605082337Z 350603082437Z0'1 0 UUS1 0 U CA10U San Diego10U 07 0001 SHA25610U 06 0000 MODEL_ID10U 05 00000020 SW_SIZE10U 04 0000 OEM_ID1"0 U 03 0000000000000002 DEBUG1"0 U 02 0000000000000000 HW_ID1"0 U 01 0000000000000000 SW_ID10U QUALCOMM1 0 U CASS0 0  *H  0vl^v߮J!3,A]F+N"[Ȕނ٬ *ESmRXvfbr0FJ \uJãffiИ/)g)X+v$) 0KAxi1h UÞz|V!g%9HVpaAZY8$ 9#[>kV0T0U#0N^bE3{>fu0 U00U0 +) @@0  *H  (nAd2Ur1,,VitK'>IO! 0sl||z! Uc:\#hمLDH( O$ʇSqaͮgmcꔌȺ{fSfq iu3C6]o|pKqD0#k.NrG6C?K/B;D(4#ԗkX|q7{~kA1m@Kqgk,ڟHBOL008JYaȐ_ 0  *H  0i1$0"U Qualcomm Technologies, Inc.1*0(U !Qualcomm Cryptographic Operations10U QDSR Root CA0 130503194249Z 230501194249Z0j1$0"U Qualcomm Technologies, Inc.1*0(U !Qualcomm Cryptographic Operations10U QDSR Sub-CA 10 0  *H  0*>6ATk*O!b xSeRFDu.ŀfbCwR"`a 5w1Xa̔9tƒДZETS_pZsn pdLC(_7$*Mэ(B=A'䧣`v.#ӌu*'8D bFRS/Hh % Z:T{+{p8c]EK 4ɋh~0|0U#0Fju* (xc$Y0UN^bE3{>fu0U00U0 +) 0  *H  8psD ţ-E0|iec+% %zE IX \RyҶY4gk_JdȾRq!Z[eDqI<szÉ*ђo%͂PNNne B?M8&Qm1p[[3U ٷWiEүU@A!li^t-)stӁ x2\[2X00HFx!`RhF0  *H  0i1$0"U Qualcomm Technologies, Inc.1*0(U !Qualcomm Cryptographic Operations10U QDSR Root CA0 130503000001Z 430502235959Z0i1$0"U Qualcomm Technologies, Inc.1*0(U !Qualcomm Cryptographic Operations10U QDSR Root CA0 0  *H  0 %)ȓbv15Fzz<xg`5x|CZr7gwr=A/.on% O/(S#F%>/􉚀z*j#<{!{bOra[7IbX#ԇ]7"QNa }#qؽ-CnP 5j#ˆhA)?0oEpxj恌vg`Yӂ(lD5mPm4kWah_r]1s,DE0C0U00U0UFju* (xc$Y0  *H  36BeQYoiuBqxowC;5$2g La$kt'eXp1V|e+{+E%<N5lc\RܸВGh`P<DkEEȆjcv,_"gb9re ݼ8(}JqݗE0C&&xS|Տ@!9=*l^쎣U\"S?{]1GT>ldYχY|Uؐn– ELF4 vh4 (##000000||dlib.ver.1.0.0.libcalculator_skel.so:4.5.0  & !@ 5|<  IQH8 `1V0  01 ,>G Q ^`"D dh tlz" strlencalculator_skel_handle_invokecalculator_maxso_ver__dso_handlestrtoulcalculator_sumcalculator_skel_handle_invoke_uricalculator_close__cxa_finalize_stubcalculator_slimcalculator_skel_handle_invoke_qaic_version__register_frame_info_basesvsnprintfstrstr__stack_chk_fail__wrap_free__stack_chk_guardstrtok_rHAP_debugHAP_debug_v2_finicalculator_open_init_Assertmemcpy__wrap_malloc__cxa_finalizeHAP_debug_runtimelibc.solibgcc.solibcalculator_skel.so    0#00#00#10#410#00#"0#"0#"0#`11#h1,1#X1H1#P1P1#1T1#1X1#1\1#1`1#p1d1#1h1#11#"<2# H2#L2#P2#HT2# !`2!X2!D2!\2!x2" |2"2"2"2"2"2"2"2"2"2"2"2"2"2"ݡ؝@ jVx*x@x((4ZxPYX@ݑR@IjBO@<BR@IjR@IjR@IjR@IjR@IjR@IjR@IjR@IjR@IjR@IjR@IjR@IjR@IjR@IjR@IjR@ j\x!xu_S jrYާ➧㞧bb➧u\X" u&\X"@u0\X"`u<\NXaB@IjăLZDXaB@IjăZ2XޗdE@IjņZXޗdE@IjņZ X@B<X ឧ➧B<B<B<|ާBC>#>>XX"u\XX  ឧB\Xbk\XBB<B<2Xk\Xb\XBB<B<XXXXBB<B<XឧB< x["s¡‘|€\X X@Ij@Ij[xާޗ|€ \X[Xxާ➧㞧䞧C[k\X4[ާ➧㞧䞧B<B<B<XCBk2\XC:#Bk\XC:➧X"➧X➧XB"➧Y#bÂXB@IjƂuk\Xb}pÂ@Ij@Ij@xx<[Xb}pÂ@Ij@Ij@xx[XXx۝ j x*xPY@R  closeopenmaxresvecsumurih_idlver=1.2.3.src/calculator_imp.c:21 *handlecalculator_opencalculator_imp.c=============== DSP: sum result %lld ============================== DSP: maximum result %d ==============  `"0  h2poH\ 001410"""`1h1X1P11111p111" @'file:///libcalculator_skel.so?calculator_skel_handle_invoke&_modver=1.0&_idlver=1.2.3 H !pppppppppppppppfastrpc-1.0.2/test/v68/libhap_example_skel.so000066400000000000000000001715601512345705400211310ustar00rootroot00000000000000ELF4h4 ( 0ĺĺpp(jN7\|j@TS!ڤAP AcKǢ r5 hA .'F9tHIKҲ'K?o؁h {wC<)@1l!-rC495µ ^KJ.|Cn rN-l#+]󙖥 M#/_] `rvm֜s:`ECDWš~Z]]{:l4tb9ZN<ך7-0Bx:{9َ3r%axiN:Zg@,B#p1Tv ' Ÿ߷cq-C_=ሎұrz]C?cu!Dqm0u0]NF0  *H  0j1$0"U Qualcomm Technologies, Inc.1*0(U !Qualcomm Cryptographic Operations10U QDSR Sub-CA 10 251203081301Z 351201081401Z0'1 0 UUS1 0 U CA10U San Diego10U 07 0001 SHA25610U 06 0000 MODEL_ID10U 05 00000020 SW_SIZE10U 04 0000 OEM_ID1"0 U 03 0000000000000002 DEBUG1"0 U 02 0000000000000000 HW_ID1"0 U 01 0000000000000000 SW_ID10U QUALCOMM1 0 U CASS0 0  *H  0v {[XS8N^ @##~4ܡL[KDlfrY"mOx7#ko—p?kkvYנNd"vG7qӥErV|@k.6h!un8ZV#_V)9c&m&YٰtlTl ;5P(xfJ7Kmrob(AQ5[`rz/Lp]\rXװU2T@K y͋876ܛ",͞~AV0T0U#0N^bE3{>fu0 U00U0 +) @@0  *H  (H/ /IJQBEuu Asi;ȨckoZgD6ATk*O!b xSeRFDu.ŀfbCwR"`a 5w1Xa̔9tƒДZETS_pZsn pdLC(_7$*Mэ(B=A'䧣`v.#ӌu*'8D bFRS/Hh % Z:T{+{p8c]EK 4ɋh~0|0U#0Fju* (xc$Y0UN^bE3{>fu0U00U0 +) 0  *H  8psD ţ-E0|iec+% %zE IX \RyҶY4gk_JdȾRq!Z[eDqI<szÉ*ђo%͂PNNne B?M8&Qm1p[[3U ٷWiEүU@A!li^t-)stӁ x2\[2X00HFx!`RhF0  *H  0i1$0"U Qualcomm Technologies, Inc.1*0(U !Qualcomm Cryptographic Operations10U QDSR Root CA0 130503000001Z 430502235959Z0i1$0"U Qualcomm Technologies, Inc.1*0(U !Qualcomm Cryptographic Operations10U QDSR Root CA0 0  *H  0 %)ȓbv15Fzz<xg`5x|CZr7gwr=A/.on% O/(S#F%>/􉚀z*j#<{!{bOra[7IbX#ԇ]7"QNa }#qؽ-CnP 5j#ˆhA)?0oEpxj恌vg`Yӂ(lD5mPm4kWah_r]1s,DE0C0U00U0UFju* (xc$Y0  *H  36BeQYoiuBqxowC;5$2g La$kt'eXp1V|e+{+E%<N5lc\RܸВGh`P<DkEEȆjcv,_"gb9re ݼ8(}JqݗE0C&&xS|Տ@!9=*l^쎣U\"S?{]1GT>ldYχY|Uؐn– ELF4h4 (ĺĺpp 90,($7@l'~@h` l | cH#1C \il{    H*   5Odw&J`  !,Hd     L^h(:T T ^ k`D q  (  wHl 5TTSm eH " HAP_cache_unlockhap_example_compute_resv2release_cbHAP_mmaphap_example_skel_handle_invoke_qaic_versionhap_example_closehap_example_mem_reserve_vaHAP_mmap_gethap_example_mem_dmahandlev2hap_example_perfHAP_timer_sleepcompute_resource_query_VTCMtest_unmap_reserved_va__dso_handleHAP_power_setHAP_mem_get_statscompute_resource_acquirehap_example_mem_map_reserve_vacompute_resource_attr_get_vtcm_ptr_v2HAP_mmap_puthap_example_slimHAP_mmap2HAP_get_userpd_paramshap_example_compute_resmemsetHAP_cache_lockcompute_resource_attr_set_vtcm_param_v2HAP_query_total_cachelockadsp_mmap_fd_getinfoqurt_thread_get_idhap_example_openhap_example_skel_handle_invoke_uri__cxa_finalize_stubtest_map_reserved_vahap_example_sysmon_cachelockHAP_query_avail_cachelockHAP_mem_set_grow_sizeHAP_munmap__register_frame_info_basesHAP_perf_qtimer_count_to_uscompute_resource_attr_set_release_callbackvsnprintfcompute_resource_attr_get_vtcm_ptrHAP_mem_available_stackcompute_resource_check_release_request__stack_chk_fail__wrap_freetest_reserve_va__stack_chk_guardhap_example_mem_dmahandleHAP_debugHAP_debug_v2_finicompute_resource_attr_set_serializeHAP_power_destroy_clientrelease_cb_callbackcompute_resource_attr_set_vtcm_paramHAP_mem_requesthap_example_mem_fastrpc_mmap_initcompute_resource_attr_inithap_example_skel_handle_invokehap_example_farf_runtimecompute_resource_releasetest_unreserve_vahap_example_powermemcpy__wrap_malloc__cxa_finalizequrt_thread_set_priorityHAP_power_getHAP_munmap2libc.solibgcc.solibhap_example_skel.soII>'2+A/)B?C=<G(51. 04F8E-D%:"*H; $  &# ,673@9 !###8#8#T#p#p##8#T#8#8#8####0#0#h####8#X###H#(,#8#&<#'@#H*D# 9H#SL#TP# lT#wX#@h\#i`#|d#h##(! !!!!!)!+!,t!-p!1l!4|!6!7!9x!=!@4!E"'"E"C""D"4"*"3"."/"-"="6"9""+"@""F " ")""" "$",(","&0":4"8"<"%@"HD"(H"L" P"GT"X"\"7`"d"h"$l"ݡ؝@ j?}x*x@x((4ZxPYX@ݑRBIjBO@<BRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjR@ jL}x!xu_S jYާ➧㞧bb➧u\"BIj:RaBBIjZXaBBIjZXޗdEBIj†ZXޗdEBIj†zZXޗdEBIjÆ6ZXޗdEBIjÆ6ZXޗdEBIjĆ"ZXޗdEBIjĆTZnXޗdEBIjņZZXޗdEBIjņZFXޗdEBIjƆZ2XޗdEBIjƆZXޗdEBIjdžZ X@B<Xឧ➧B<B<B<|ާBZbu:\XXTBIjǂuk\XAIjAIj`xx[XAIjAIj`xx[XXXXRBIjǂuk\XAIjAIj@xx[XAIjAIj@xx[XXB<XBuZ\XXPBIjǂuk \X:}p¡ÂAIjAIj@xbxF[X:}p¡ÂAIjAIj@xbx*[XXX"➧YXMBIjǂuk\XAIjAIj@xBx[XAIjAIj@xBx[XXDB<"x> Zbu:\XXKBIjǂuk\XAIjAIj`xBx[XAIjAIj`xBx[XXXXIBIjǂuk\X>}pĂÂAIjAIj@xxl[X>}pĂÂAIjAIj@xxR[XXB<XBuZ\XXFBIjǂuk \X:}p¡ÂAIjAIj@x"x[X:}p¡ÂAIjAIj@x"x[XXX"➧YXDBIjǂuk\XAIjAIj@xx[XAIjAIj@xx[XX@B\XX;BIjǂuk\XAIjAIj`x"x[XAIjAIj`x"x[XXB<XX:BIjǂuk\X#}pÂAIjAIj@xx~[X#}pÂAIjAIj@xxh[XXX8BIjǂuk\XAIjAIj@xxD[XAIjAIj@xx4[XX@ZbuF\XX5BIjǂuk\XC}pÂAIjAIj`xBx[XC}pÂAIjAIj`xBx[XXDXX3BIjǂuk\XC}pÂAIjAIj@xx[XC}pÂAIjAIj@xx[XXXbuk:\XX1BIjǂuk\XAIjAIj@x"xt[XAIjAIj@x"xd[XX8XX/BIjǂuk\XAIjAIj@xx>[XAIjAIj@xx.[XXXb➧X-BIju \X8[ X@B<Xap,BIju\X>[ X@B<Xbpឧ+BIj‚u\Xb>[ X@B<Xឧ)BIj‚u\X[XB<X(BIjÂu \X[XB<X'BIjÂu \X[ X@B<X:ާx➧X%BIjǂuk\XAIjAIj@xbx[XAIjAIj@xbx[XXxPZX#BIjǂuk\XAIjAIj@xBx[XAIjAIj@xBx[XXX"BIjǂuk"\X}płĂÂAIjAIj@xx|[ X}płĂÂAIjAIj@xx^[XXXBIjǂuk\X#d}pĂÂAIjAIj@xx0[X#d}pĂÂAIjAIj@xx[XXXBIjǂuk.\XCd󞗅}pȂǂƂłĂÂAIjAIj@xx[,XCd󞗅}pȂǂƂłĂÂAIjAIj@xx[XXBIjuk@\XXBIjǂuk\XAIjAIj@xbxz[XAIjAIj@xbxj[XX@x➧X>[:[6[XBIjǂuk\XAIjAIj@xx2[XAIjAIj@xx"[XXBIjĂឧZZBZXBIjǂuk\XAIjAIj@xbx[XAIjAIj@xbx[XX@@x➧ZA"xx㞧Zc@xcpvZXBIjǂuk\XAIjAIj@xx[XAIjAIj@xxr[XXx[uk@\XXBIjǂuk\XAIjAIj`xx<[XAIjAIj`xx,[XX@x➧XX BIjǂuk\X}pÂ}AIjAIj@xBx[X}pÂ}AIjAIj@xBx[XX"xXZu \Xx➧XX BIjǂuk\XC$}pĂÂzAIjAIj@xx[XC$}pĂÂzAIjAIj@xx~[XXXB➧x➧X""bk\X:➧X"➧YXBIjǂuk\X}pÂwAIjAIj@xx$[X}pÂvAIjAIj@xx[XXxnZXBIjǂuk\XtAIjAIj@xbx[XtAIjAIj@xbx[XXXBIjǂuk"\X}płĂÂrAIjAIj@xx[ X}płĂÂqAIjAIj@xx|[XXXBIjǂuk\X#d}pĂÂpAIjAIj@xxN[X#d}pĂÂoAIjAIj@xx4[XXXAIjǂuk.\XCd󞗅}pȂǂƂłĂÂmAIjAIj@xx[,XCd󞗅}pȂǂƂłĂÂlAIjAIj@xx[XXx([uk@\XXAIjǂuk\XjAIjAIj`xx[XjAIjAIj`xx[XX@x➧jXXAIjǂuk\X}pÂhAIjAIj@xBxT[X}pÂhAIjAIj@xBx>[XX"xX2Zu \Xx➧ XXAIjǂuk\XC$}pĂÂeAIj}AIj@xx[XC$}pĂÂdAIj}AIj@xx[XXXB➧x➧X""bk\X:➧X"➧YXAIjǂuk\X}pÂbAIjyAIj@xx~[X}pÂaAIjxAIj@xxh[XXxZXAIjǂuk\X_AIjpAIj@x"x6[X_AIjpAIj@x"x&[XXXAIjǂuk"\X}płĂÂ]AIjoAIj@xbx[ X}płĂÂ\AIjnAIj@xbx[XXXAIjǂuk\X#d}pĂÂ[AIjnAIj@xx[X#d}pĂÂZAIjmAIj@xx[XXXAIjǂuk.\XCd󞗅}pȂǂƂłĂÂXAIjlAIj@xxP[,XCd󞗅}pȂǂƂłĂÂWAIjkAIj@xx&[XX[x[Fxz[buk\XXAIjǂuk\XUAIjnAIj`xx[XTAIjmAIj`xx[XX uk\XXAIjǂuk\XSAIjlAIj@xx[XRAIjlAIj@xx[XXD[XAIjǂuk\X}pĂÂQAIjkAIj@xxf[X}pĂÂPAIjjAIj@xxL[XXuk \XxXX uk\XXAIjǂuk\XNAIjiAIj@xx [XMAIjhAIj@xx[XX[XAIjǂuk\X}pĂÂLAIjfAIj@xBx[X}pĂÂKAIjeAIj@xBx[XXuk \XxXXFx[buk \Xx➧nXXAIjǂuk\Xc}pÂHAIjdAIj@x"xX[Xc}pÂHAIjcAIj@x"xB[XX"xXHXXAIjǂuk\Xc}pÂFAIjbAIj@xx[Xc}pÂEAIjaAIj@xx[XX"xXZuJ\XXAIjǂuk\X}pÂCAIj_AIj`xx[X}pÂCAIj^AIj`xx[XXx➧XXAIjǂuk\XC$}pĂÂAAIj]AIj@xbxn[XC$}pĂÂ@AIj\AIj@xbxT[XXXB➧x➧X""bk\X:➧X"➧YXAIjǂuk\X}pÂ=AIjUAIj@xx[X}pÂ=AIjTAIj@xx[XX uk>\XXAIjǂuk\X;AIjUAIj@xx[X;AIjTAIj@xx[XXP[X uk>\XXAIjǂuk\X9AIjTAIj@xxr[X9AIjSAIj@xxb[XX [XB uk>\XXAIjǂuk\X7AIjTAIj@xx.[X7AIjSAIj@xx[XX`[XX"uk:\XXAIjǂuk\X5AIjRAIj@xx[X4AIjRAIj@xx[XX8XXAIjǂuk\X3AIjQAIj@xBx[X3AIjPAIj@xBx[XXX"➧Xឧ➧㞧䞧AIjĂu\XcD[ X@B<Xឧ➧AIjłu\X[ X@B<Xឧ➧㞧AIjłu\Xc[ X@B<Xឧ➧AIjƂu\Xf[ X@B<Xާ➧x ާ➧㞧䞧B<XAIjǂuk\XHAIjIAIj@xxZXHAIjHAIj@xx|[XXB<B<B\XXAIjǂuk\XFAIjFAIj`xxZZXEAIjFAIj`xx"[XXB<XXAIjǂuk.\Xc(}pȂǂƂłĂÂCAIjEAIj@xxZ,Xc(}pȂǂƂłĂÂBAIjCAIj@xx[XXXAIjǂuk\XAAIjCAIj@xbxZX@AIjCAIj@xbx[XXx [BuF\XXAIjǂuk\XC}pÂ>AIjAAIj`xbxlZXC}pÂ=AIjAAIj`xbx.[XXXXAIjǂuk\X@ޗ}p¡ÂAIj`xbx[XXX([`p➧@`u\X@ukF\XXAIjǂuk\X}pÂ6AIj=AIj`xBxpZX}pÂ6AIjޗޗ}p¡Ă¡ÂAIj,AIj@xxb[$X>ޗޗ}p¡Ă¡ÂAIj+AIj@xx[XX[uZ\XXAIjǂuk$\Xޗ}pĂ¡¡ÂAIj*AIj`xBx["Xޗ}pĂ¡¡ÂAIj)AIj`xBx[XXNXޗ¡XAIjǂuk\X‘}p¡AIj(AIj@xx[X‘}p¡AIj'AIj@xxj[XXXCާ➧ާB<ޗާ➧ޗާB➧B<|ާާbxޗާ`ޗާ@ޗާ ޗާޗާޗާXAIjǂuk:\X>ޗޗfhޗޗN}p➧΂¡¡ ǂƂ¡¡¡ÂAIj#AIj@xx[8X>ޗޗfhޗޗN}p➧΂¡¡ ǂƂ¡¡¡ÂAIj"AIj@xx[XXP[uj\XXAIjǂuk,\XޗޗޗH}p Ȃ¡¡¡¡ÂAIj!AIj`xbx~[*XޗޗޗH}p Ȃ¡¡¡¡Â AIj AIj`xbx.[XXDXX~AIjǂuk\Xޗ}p¡ AIj AIj@xx*[Xޗ}p¡ AIj AIj@xx[XXXާާB<ޗާޗާxޗާޗާX{AIjǂuk"\X>ޗޗ}p¡¡Â AIjAIj@xBx[ X>ޗޗ}p¡¡ÂAIjAIj@xBxx[XX(["uZ\XXxAIjǂuk$\X#ޗޗ}p¡¡¡ÂAIjAIj`xx^["X#ޗޗ}p¡¡¡ÂAIjAIj`xx[XXPXXuAIjǂuk \Xޗޗ}p¡¡¡AIjAIj@xBx [Xޗޗ}p¡¡¡AIjAIj@xBx[XXX ާާB<ޗާޗާxޗާޗާXqAIjǂuk"\X>ޗޗ}p¡¡ÂAIjAIj@xx[ X>ޗޗ}p¡¡Â@IjAIj@xxT[XX["uZ\XXnAIjǂuk$\X#ޗޗ}p¡¡¡Â@IjAIj`x"x:["X#ޗޗ}p¡¡¡Â@IjAIj`x"x[XXPXXlAIjǂuk \Xޗޗ}p¡¡¡@IjAIj@xx[Xޗޗ}p¡¡¡@IjAIj@xx[XXX ާB<B<@xxbpާޗ[uJ\XXhAIjǂuk\Xޗ}p¡¡@IjAIj`xxr[Xޗ}p¡¡@IjAIj`xx2[XX@XޗcAIj¡XfAIjǂuk\X@IjAIj@x"x,[X@IjAIj@x"x[XXX ާ➧B<B\XXWAIjǂuk\X@IjAIj`xxX[X@IjAIj`xx [XXB<XXUAIjǂuk.\Xc}pȂǂƂłĂÂ@Ij@Ij@xbx[,Xc}pȂǂƂłĂÂ@Ij@Ij@xbx[XXXRAIjǂuk\X@Ij@Ij@x"x[X@Ij@Ij@x"x~[XXx [BuF\XXPAIjǂuk\XC}pÂ@Ij@Ij`x"xj[XC}pÂ@Ij@Ij`x"x,[XXXXNAIjǂuk\Xޗ}p¡Â@Ij@Ij@xx$[Xޗ}p¡Â@Ij@Ij@xx[XX[BuF\XXKAIjǂuk\XC}pÂ@Ij@Ij`xx[XC}pÂ@Ij@Ij`xx[XXHXXIAIjǂuk*\Xޗ$ޗFޗhޗޗ}p¡¡¡¡¡@Ij@Ij@xbx[(Xޗ$ޗFޗhޗޗ}p¡¡¡¡¡@Ij@Ij@xbx2[XXXޗ@ާޗ@ާޗbޗ[BuF\XXEAIjǂuk\XC}pÂ@Ij@Ij`xx[XC}pÂ@Ij@Ij`xx[XXX[BuF\XXBAIjǂuk\XC}pÂ@Ij@Ij`xx[XC}pÂ@Ij@Ij`xx[XX8XX@AIjǂuk*\Xޗ$ޗFޗhޗޗ}p¡¡¡¡¡@Ij@Ij@xxp[(Xޗ$ޗFޗhޗޗ}p¡¡¡¡¡@Ij@Ij@xx"[XXXޗޗ€:\XX=AIjǂuk\X@Ij@Ij`xx[X@Ij@Ij`xx[XXXX;AIjǂuk\X@Ij@Ij@xbx[X@Ij@Ij@xbx[XXL[BuF\XX9AIjǂuk\XC}pÂ@Ij@Ij`x"x[XC}pÂ@Ij@Ij`x"x^[XXXX7AIjǂuk\X}pÂ@Ij@Ij@xxZ[X}pÂ@Ij@Ij@xx[XXX5AIjǂuk\X@Ij@Ij@xBx [X@Ij@Ij@xBx[XXa[BuF\XX3AIjǂuk\XC}pÂ@Ij@Ij`xx[XC}pÂ@Ij@Ij`xx[XXLXX1AIjǂuk\Xd}pĂÂ@Ij@Ij@xx[Xd}pĂÂ@Ij@Ij@xxN[XXXBuk:\XX.AIjǂuk\X@Ij@Ij@xBxF[X@Ij@Ij@xBx[XX8XX-AIjǂuk\X@Ij@Ij@xx[X@Ij@Ij@xx[XXX@ާ➧㞧B<X*AIjǂuk\X@Ij@Ij@x"xZX@Ij@Ij@x"x[XX[buF\XX(AIjǂuk\Xc}pÂ@Ij@Ij`x"xZXc}pÂ@Ij@Ij`x"x<[XXXX&AIjǂuk"\XDޗ}p¡ĂÂ@Ij@Ij@xxdZ XDޗ}p¡ĂÂ@Ij@Ij@xx[XXX$AIjǂuk\X@Ij@Ij@xx"ZX@Ij@Ij@xx[XXV[buF\XX"AIjǂuk\Xc}pÂ@Ij@Ij`xxZXc}pÂ@Ij@Ij`xxh[XXDXXAIjǂuk\X}pÂ@Ij@Ij@xBxZX}pÂ@Ij@Ij@xBx&[XXXbuk:\XXAIjǂuk\X@Ij@Ij@x"xRZX@Ij@Ij@x"x[XX8XXAIjǂuk\X@Ij@Ij@xxZX@Ij@Ij@xx[XXX`&AIj䞧䞧ឧ➧㞧➧x[`paB#[k\Xx[ ާB<XAIjǂuk\X@Ij@Ij@xx.ZX@Ij@Ij@xx"[XX^ZާXAIjǂuk\Xޗ}p¡@Ij@Ij@x"xZXޗ}p¡@Ij@Ij@x"x[XXXAIjǂuk\X@Ij@Ij@xxZX@Ij@Ij@xx[XX.ZާXAIjǂuk\X`ޗ}p¡@Ij@Ij@xbxxZX`ޗ}p¡@Ij@Ij@xbxf[XXXAIjǂuk\X@Ij@Ij@x"x>ZX@Ij@Ij@x"x2[XX`ޗ [ާXAIjǂuk\X`ޗޗ}p¡¡@Ij@Ij@xxZX`ޗޗ}p¡¡@Ij@Ij@xx[XXX AIjǂuk\X@Ij@Ij@xbxZX@Ij@Ij@xbx[XX>ZާX AIjǂuk\X@ޗ}p¡@Ij@Ij@xx~ZX@ޗ}p¡@Ij@Ij@xxl[XXAIjǂukJ\XXAIjǂuk\X@Ij}pÂ@Ij@Ij`xx,ZX@Ij}pÂ@Ij@Ij`xx[XXXXAIjǂuk\X@Ij@Ij@xbxZX@Ij@Ij@xbx[XX|ާ<[buF\XXAIjǂuk\Xc}pÂ@Ij@Ij`xBxZXc}pÂ@Ij@Ij`xBx[XXXXAIjǂuk\Xc}pÂ@Ij@Ij@xx\ZXc}pÂ@Ij@Ij@xxJ[XXXX@Ijǂuk\X@Ij@Ij@xx ZX@Ij@Ij@xx[XX }xxbpާޗ[bu:\XX@Ijǂuk\X@Ij@Ij`xxZX@Ij@Ij`xx[XXDXX@Ijǂuk\Xޗ}p¡@Ij@Ij@x"xZXޗ}p¡@Ij@Ij@x"x[XXXbuk:\XX@Ijǂuk\X@Ij@Ij@xxRZX@Ij@Ij@xxF[XX8XX@Ijǂuk\X@Ij@Ij@xBxZX@Ij@Ij@xBx[XXX`&@Ij䞧䞧ឧ➧㞧➧x[`paB#[k\X[hާޗ|hpfpEcpipgpbpap`pj cxj GxcpfpB DgpBbp&s D" hާޗhާޗާB<B<X@Ijǂuk\X@Ij@Ij@xBxBZX@Ij@Ij@xBx&[XXrZ|ާާ"x[bu@\XX@Ijǂuk\X@Ij@Ij`x"xZX@Ij@Ij`x"x[XX@B<XB➧|ާާBx[bu@\XX@Ijǂuk\X@Ij@Ij`x"xZX@Ij@Ij`x"xz[XX@BX@Ijǂuk*\XC$g>}pǂƂłĂÂ@Ij@Ij@xx0Z(XC$g>}pǂƂłĂÂ@Ij@Ij@xx[XXX@Ijǂuk\X@Ij@Ij@xbxZX@Ij@Ij@xbx[XXxx[xH"xQxRS@(C\XX@Ijǂuk\X@Ij@Ij@xbxtZX@Ij@Ij@xbxX[XXB<XbuF\XX@Ijǂuk\Xc}pÂ@Ij@Ij`xBx,ZXc}pÂ@Ij@Ij`xBx [XX~XX@Ijǂuk\X@Ij@Ij@xxZX@Ij@Ij@xx[XXX@Ijǂuk\XC>}pÂ@Ij@Ij@xxZXC>}pÂ@Ij@Ij@xx[XXX@Ijǂuk\X}pÂ@Ij@Ij@xxvZX}pÂ@Ij@Ij@xxT[XXX@Ijǂuk"\X#>D>>}płĂÂ@Ij@Ij@xBx.Z X#>D>>}płĂÂ@Ij@Ij@xBx[XXX@Ijǂuk\XC>}pÂ@Ij@Ij@xxZXC>}pÂ@Ij@Ij@xx[XXxx[xH"xQxR[buF\XX@Ijǂuk\Xc}pÂ@Ij@Ij`xBxZXc}pÂ@Ij@Ij`xBx^[XXX"xG>Zb"uk>\XX@Ijǂuk\X@Ij@Ij@xx.ZX@Ij@Ij@xx[XXB<XbuF\XX@Ijǂuk\Xc}pÂ@Ij@Ij`xxZXc}pÂ@Ij@Ij`xx[XX8XX@Ijǂuk\X@Ij@Ij@xbxZX@Ij@Ij@xbx[XXXu\XZB<Xbuk:\XX@Ijǂuk\X@Ij@Ij@xxXZX@Ij@Ij@xx<[XX8XX@Ijǂuk\X@Ij@Ij@xx"ZX@Ij@Ij@xx[XXXb➧X&@Ij䞧䞧ឧ➧㞧➧x[`paB#[k\X[ x[apxx[x"xb>[@Ijǂu \X|[ X@,B<XާB<X@Ijǂuk\X@Ij@Ij@xx`ZX@Ij@Ij@xx"[XX@@B<*["uk>\XX@Ijǂuk\X@Ij@Ij`xxZX@Ij@Ij`xx[XXB<XX@Ijǂuk"\X$ޗ}p¡ĂÂ@Ij@Ij@xxZ X$ޗ}p¡ĂÂ@Ij@Ij@xx[XXX@Ijǂuk\X@Ij@Ij@xBxZX@Ij@Ij@xBxL[XXf[bu>\XX@Ijǂuk\X@Ij@Ij`xBxJZX@Ij@Ij`xBx [XXB<XX@Ijǂuk\X}pÂ@Ij@Ij@xx ZX}pÂ@Ij@Ij@xx[XXX@Ijǂuk\X~@Ij@Ij@xxZX}@Ij@Ij@xx[XX[bu>\XX@Ijǂuk\X|@Ij@Ij`xxZX{@Ij@Ij`xxR[XXB<XX@Ijǂuk\X}pÂz@Ij@Ij@xBxPZX}pÂy@Ij@Ij@xBx [XXX@Ijǂuk\Xx@Ij@Ij@xxZXw@Ij@Ij@xx[XX [u:\XX@Ijǂuk\Xv@Ij@Ij`xxZXu@Ij~@Ij`xx[XXDXX@Ijǂuk\X#}pÂt@Ij~@Ij@x"xZX#}pÂs@Ij}@Ij@x"xT[XXXuk:\XX@Ijǂuk\Xr@Ij}@Ij@xxRZXq@Ij|@Ij@xx[XX8XX@Ijǂuk\Xp@Ij{@Ij@xbxZXp@Ij{@Ij@xbx[XXX&@Ij䞧䞧ឧ➧㞧➧x[`paB#[k\X[۝ jf x*xPY@Ryyyz9~ÚQ8}_/,\(e˰rt^ k,e2`> Mi=k$)gTTeeXވik0u0]}FBa.G50  *H  0j1$0"U Qualcomm Technologies, Inc.1*0(U !Qualcomm Cryptographic Operations10U QDSR Sub-CA 10 251203081333Z 351201081433Z0'1 0 UUS1 0 U CA10U San Diego10U 07 0001 SHA25610U 06 0000 MODEL_ID10U 05 00000020 SW_SIZE10U 04 0000 OEM_ID1"0 U 03 0000000000000002 DEBUG1"0 U 02 0000000000000000 HW_ID1"0 U 01 0000000000000000 SW_ID10U QUALCOMM1 0 U CASS0 0  *H  0WۑXO}[xgⱟ9&v_V9xc;g؟NUh>|- Y(L? 'iş"٠sI|D YɴdU25cFR{a w{5^8:uTs}>p)lh3*NJ)%p0[L0_cW4j]8* xMe$#*§ dW|U%fh屯H[h1trgXA+J9V0T0U#0N^bE3{>fu0 U00U0 +) @@0  *H  R+GW$LCEMzV<E 9}+6tt -o;ɖPշجoiKjw%ĖN]؄FZpq[@pZNWk.C).p1>m &iWV>9mS0S_ƀL/MZY+ cȿDYJ7pa( `PcΟ0ұ_嶹xF?޷008JYaȐ_ 0  *H  0i1$0"U Qualcomm Technologies, Inc.1*0(U !Qualcomm Cryptographic Operations10U QDSR Root CA0 130503194249Z 230501194249Z0j1$0"U Qualcomm Technologies, Inc.1*0(U !Qualcomm Cryptographic Operations10U QDSR Sub-CA 10 0  *H  0*>6ATk*O!b xSeRFDu.ŀfbCwR"`a 5w1Xa̔9tƒДZETS_pZsn pdLC(_7$*Mэ(B=A'䧣`v.#ӌu*'8D bFRS/Hh % Z:T{+{p8c]EK 4ɋh~0|0U#0Fju* (xc$Y0UN^bE3{>fu0U00U0 +) 0  *H  8psD ţ-E0|iec+% %zE IX \RyҶY4gk_JdȾRq!Z[eDqI<szÉ*ђo%͂PNNne B?M8&Qm1p[[3U ٷWiEүU@A!li^t-)stӁ x2\[2X00HFx!`RhF0  *H  0i1$0"U Qualcomm Technologies, Inc.1*0(U !Qualcomm Cryptographic Operations10U QDSR Root CA0 130503000001Z 430502235959Z0i1$0"U Qualcomm Technologies, Inc.1*0(U !Qualcomm Cryptographic Operations10U QDSR Root CA0 0  *H  0 %)ȓbv15Fzz<xg`5x|CZr7gwr=A/.on% O/(S#F%>/􉚀z*j#<{!{bOra[7IbX#ԇ]7"QNa }#qؽ-CnP 5j#ˆhA)?0oEpxj恌vg`Yӂ(lD5mPm4kWah_r]1s,DE0C0U00U0UFju* (xc$Y0  *H  36BeQYoiuBqxowC;5$2g La$kt'eXp1V|e+{+E%<N5lc\RܸВGh`P<DkEEȆjcv,_"gb9re ݼ8(}JqݗE0C&&xS|Տ@!9=*l^쎣U\"S?{]1GT>ldYχY|Uؐn– ELF4h4 (HHPPPPPPPR P -5+@QZHg|18@T T7 KRWp,k0Tv3XPQP"5?DUar07,P  @;D HQ8 l>FM[n"}barriermultithreading_slimmultithreading_barrierssquare_sumqurt_thread_joinsnprintf__dso_handlequrt_barrier_destroyqurt_signal_waitbarrier_threadstrcmpmultithreading_closetestsignal2testmutexqurt_anysignal_setqurt_thread_get_namequrt_barrier_initqurt_thread_get_idmultithreading_parallel_sum__cxa_finalize_stubthread_infomultithreading_opentestsignalqurt_barrier_waitqurt_mutex_initqurt_thread_get_priorityqurt_mutex_lock__register_frame_info_basesmultithreading_mutexesstrlcpymultithreading_skel_handle_invoke_uriqurt_thread_createvsnprintfatoi__stack_chk_fail__wrap_freequrt_signal_init__stack_chk_guardmutex_threadsquare_sum_l2prefetchqurt_thread_exitmultithreading_skel_handle_invokequrt_mutex_unlockHAP_debugHAP_debug_v2_finimultithreading_skel_handle_invoke_qaic_version_init_Assertmemcpy__wrap_mallocqurt_mutex_destroy__cxa_finalizequrt_signal_destroylibc.solibgcc.solibmultithreading_skel.so772&%1 5*/.4'$ + )!,3(0-6"  # P#PP#PP#QP#QP#QP#PP#;P#;P#;P#8QQ#@Q8Q#;@IjW@Ij@xBx[XXBuk\X XV@IjU@Ij[Xb"➧Y@IjĂB[B<XbBu\Xb@IjĂÂ:[Bu\XBuk\X XT@IjS@Ij[X@Ij‚uk\Xc$}pĂÂ9@IjT@Ij@xx[Xc$}pĂÂ8@IjS@Ij@xxf[XXBuk*\X"c@Ijăă:k\X XR@IjO@Ij,[Xc@IjĂ:[Xb"➧6Y@Ij➧Ăl[‚k\Xx[@Ij‚㞧c㞧Ă2[Ax:[:[Buk\X XO@IjP@Ij[X@Ij‚uk\X}pÂ1@IjO@Ij@xx [X}pÂ1@IjN@Ij@xxv[XX["k\X XM@IjM@IjL[ [k\X XM@IjL@Ij,[X{@Ij‚uk\X}pÂ-@IjM@Ij@xx[X}pÂ-@IjL@Ij@xx[XX 0[y@Ij‚k\X[x@Ij➧‚➧ާB<B<[ł:[ƂZƂxZx[u\X XI@IjJ@Ij[J@IjAx[a[[x[x[u@IjǂxZ[uk\X XH@IjG@Ij2[t@IjƂ!xZB<XBu\Xx [;:u\X XG@IjE@Ij[}pÂ=@IjAx>[!&[@:0[@x8[@Bvp<[A@p@Ijǂx[uk\X XD@IjB@Ij[X"➧pYn@IjƂ!x[B<XBu \X:[:[X"➧Ym@Ij➧ł[Ƃ*ZƂ"Z‚k\XxL[[k@Ij‚➧Axt[[Xj@Ij‚uk\X}pÂ@Ij?@Ij@xx`[X}pÂ@Ij>@Ij@xx[XXh@Ijłl[Xh@Ij‚uk"\Xf@Ij}pÂÂ@Ij=@Ij@xBx[ Xe@Ij}pÂÂ@Ij<@Ij@xBxp[XXuk8\Xe@IjƂ!x[c@Ijuk\X X;@Ij<@Ij4[d@IjƂ!xZ"Xb@IjCvk\X X;@Ij:@Ij[Xa@Ij#ÂB<XB@Bu^\XB<B<B<X"`Bu>\X"➧"➧#k\X#k\X X9@Ij7@Ij[X""➧YXB"➧Y_@IjłH[X^@Ij‚uk\X}pÂ@Ij7@Ij@xx[X}pÂ@Ij7@Ij@xxT[XXx[\@Ij‚k\XT[ឧx[[۝ j x*xPY@R(Lt$)-- parallel_sumbarriersmutexescloseopenurihsrc/multithreading_imp.c:93 thread_stack_addr[0]!=NULLmultithreading_parallel_sumcntr1src/multithreading_imp.c:101 thread_stack_addr[1]!=NULLcntr2src/multithreading_imp.c:109 thread_stack_addr[2]!=NULLcntr3src/multithreading_imp.c:117 thread_stack_addr[3]!=NULLcntr4src/multithreading_imp.c:125 thread_stack_addr[4]!=NULLcntr5src/multithreading_imp.c:133 thread_stack_addr[5]!=NULLcntr6src/multithreading_imp.c:149 array_1!=NULLsrc/multithreading_imp.c:152 array_2!=NULLsrc/multithreading_imp.c:155 array_3!=NULLsrc/multithreading_imp.c:158 array_4!=NULLsrc/multithreading_imp.c:161 array_5!=NULLsrc/multithreading_imp.c:164 array_6!=NULLmultithreading_imp.cCreating thread 1 src/multithreading_imp.c:204 retcode==QURT_EOKsrc/multithreading_imp.c:207 (status==QURT_EOK) || (status==QURT_ENOTHREAD)Thread 1 returned with status 0x%x Creating thread 2 Creating thread 3 src/multithreading_imp.c:225 retcode==QURT_EOKsrc/multithreading_imp.c:228 retcode==QURT_EOKsrc/multithreading_imp.c:231 (status==QURT_EOK) || (status==QURT_ENOTHREAD)src/multithreading_imp.c:234 (status==QURT_EOK) || (status==QURT_ENOTHREAD)Thread 2 returned with status 0x%x Thread 3 returned with status 0x%x Creating thread 4 src/multithreading_imp.c:251 retcode==QURT_EOKsrc/multithreading_imp.c:254 (status==QURT_EOK) || (status==QURT_ENOTHREAD)Thread 4 returned with status 0x%x Creating thread 5 Creating thread 6 src/multithreading_imp.c:272 retcode==QURT_EOKsrc/multithreading_imp.c:275 retcode==QURT_EOKsrc/multithreading_imp.c:278 (status==QURT_EOK) || (status==QURT_ENOTHREAD)src/multithreading_imp.c:281 (status==QURT_EOK) || (status==QURT_ENOTHREAD)Thread 5 returned with status 0x%x Thread 6 returned with status 0x%x Without L2 prefetch - Single Thread - sum_1: %d execution time for 1 array : %d micro seconds Without L2 prefetch - Two Threads - sum_2: %d, sum_3: %d execution time for 2 arrays: %d micro seconds With L2 prefetch - Single Thread - sum_4: %d execution time for 1 array : %d micro seconds With L2 prefetch - Two Threads - sum_5: %d, sum_6: %d execution time for 2 arrays: %d micro seconds src/multithreading_imp.c:394 thread_info[i].stack_addr != NULLmultithreading_barriersthread%dthread%d created id = 0x%x src/multithreading_imp.c:403 status==QURT_EOKsrc/multithreading_imp.c:411 (status==QURT_EOK) || (status==QURT_ENOTHREAD)thread%d return status 0x%x src/multithreading_imp.c:414 thread_exit_status==thread_info[i].idsrc/multithreading_imp.c:437 status==0barrier_thread%s starts src/multithreading_imp.c:442 id==ptr_thread_info->idsrc/multithreading_imp.c:445 prio==ptr_thread_info->prio%s exiting src/multithreading_imp.c:486 thread_stack[0]!=NULLmultithreading_mutexesthread0src/multithreading_imp.c:495 status==QURT_EOKsrc/multithreading_imp.c:506 thread_stack[i]!=NULLsrc/multithreading_imp.c:515 status==QURT_EOK thread%d starts Mutex Lock acquired by %s, Access Order = %d src/multithreading_imp.c:559 access_order == 0mutex_threadsrc/multithreading_imp.c:564 access_order == (THREAD_NUM_MUTEX-thread_index)src/multithreading_imp.c:579 counter1==j&&counter2==j Mutex Released by %s  @;  Rpo t  PPQQQP;;;8Q@Q;<<A'file:///libmultithreading_skel.so?multithreading_skel_handle_invoke&_modver=1.0 p-3+,RR1 T0T@T07 fastrpc-1.0.2/test/v75/000077500000000000000000000000001512345705400145625ustar00rootroot00000000000000fastrpc-1.0.2/test/v75/libcalculator_skel.so000066400000000000000000000612641512345705400207740ustar00rootroot00000000000000ELF4u4 (@@ 0##`00`000||(@@AZPjc\>Kt*}J_7P㈲ H04`CvV ;? 9IX2+꟢RC9rõVnm~z=auuz>1}'AU ȋbъ|qH,in3ĘW q*HLWJ TjbluL{撷 y3elNۗ"7 &o'~@BBuSsw'?PX-JPO{>5I}V1ǡOKb} .L$2$ BKU.P`.T lGUɦxg`BͶLs4kD.WߦE$bq$.R0流QQmx%HSIN\M䅓>y\ag?5 Ђۊ]"rAcܵV?_ca0ǪFFȬ5:.s%zӡV0T0U#0N^bE3{>fu0 U00U0 +) @@0  *H  PrH~%| 6=L.l߈*rwIzc!3]= f=\o)-,]Vdx?>yŖmȑVS1$X̭d{ q&!wsmգlZf%O籕T }_"Bnfk!pXB+[q_j8 TM$E6ATk*O!b xSeRFDu.ŀfbCwR"`a 5w1Xa̔9tƒДZETS_pZsn pdLC(_7$*Mэ(B=A'䧣`v.#ӌu*'8D bFRS/Hh % Z:T{+{p8c]EK 4ɋh~0|0U#0Fju* (xc$Y0UN^bE3{>fu0U00U0 +) 0  *H  8psD ţ-E0|iec+% %zE IX \RyҶY4gk_JdȾRq!Z[eDqI<szÉ*ђo%͂PNNne B?M8&Qm1p[[3U ٷWiEүU@A!li^t-)stӁ x2\[2X00HFx!`RhF0  *H  0i1$0"U Qualcomm Technologies, Inc.1*0(U !Qualcomm Cryptographic Operations10U QDSR Root CA0 130503000001Z 430502235959Z0i1$0"U Qualcomm Technologies, Inc.1*0(U !Qualcomm Cryptographic Operations10U QDSR Root CA0 0  *H  0 %)ȓbv15Fzz<xg`5x|CZr7gwr=A/.on% O/(S#F%>/􉚀z*j#<{!{bOra[7IbX#ԇ]7"QNa }#qؽ-CnP 5j#ˆhA)?0oEpxj恌vg`Yӂ(lD5mPm4kWah_r]1s,DE0C0U00U0UFju* (xc$Y0  *H  36BeQYoiuBqxowC;5$2g La$kt'eXp1V|e+{+E%<N5lc\RܸВGh`P<DkEEȆjcv,_"gb9re ݼ8(}JqݗE0C&&xS|Տ@!9=*l^쎣U\"S?{]1GT>ldYχY|Uؐn– ELF4 vu4 (##000000||dlib.ver.1.0.0.libcalculator_skel.so:4.5.0  & !@ 5|<  IQH8 `1V0  01 ,>G Q ^`"D dh tlz" strlencalculator_skel_handle_invokecalculator_maxso_ver__dso_handlestrtoulcalculator_sumcalculator_skel_handle_invoke_uricalculator_close__cxa_finalize_stubcalculator_slimcalculator_skel_handle_invoke_qaic_version__register_frame_info_basesvsnprintfstrstr__stack_chk_fail__wrap_free__stack_chk_guardstrtok_rHAP_debugHAP_debug_v2_finicalculator_open_init_Assertmemcpy__wrap_malloc__cxa_finalizeHAP_debug_runtimelibc.solibgcc.solibcalculator_skel.so    0#00#00#10#410#00#"0#"0#"0#`11#h1,1#X1H1#P1P1#1T1#1X1#1\1#1`1#p1d1#1h1#11#"<2# H2#L2#P2#HT2# !`2!X2!D2!\2!x2" |2"2"2"2"2"2"2"2"2"2"2"2"2"2"ݡ؝@ jVx*x@x((4ZxPYX@ݑR@IjBO@<BR@IjR@IjR@IjR@IjR@IjR@IjR@IjR@IjR@IjR@IjR@IjR@IjR@IjR@IjR@IjR@ j\x!xu_S jrYާ➧㞧bb➧u\X" u&\X"@u0\X"`u<\NXaB@IjăLZDXaB@IjăZ2XޗdE@IjņZXޗdE@IjņZ X@B<X ឧ➧B<B<B<|ާBC>#>>XX"u\XX  ឧB\Xbk\XBB<B<2Xk\Xb\XBB<B<XXXXBB<B<XឧB< x["s¡‘|€\X X@Ij@Ij[xާޗ|€ \X[Xxާ➧㞧䞧C[k\X4[ާ➧㞧䞧B<B<B<XCBk2\XC:#Bk\XC:➧X"➧X➧XB"➧Y#bÂXB@IjƂuk\Xb}pÂ@Ij@Ij@xx<[Xb}pÂ@Ij@Ij@xx[XXx۝ j x*xPY@R  closeopenmaxresvecsumurih_idlver=1.2.3.src/calculator_imp.c:21 *handlecalculator_opencalculator_imp.c=============== DSP: sum result %lld ============================== DSP: maximum result %d ==============  `"0  h2poH\ 001410"""`1h1X1P11111p111" @'file:///libcalculator_skel.so?calculator_skel_handle_invoke&_modver=1.0&_idlver=1.2.3 H !pppppppppppppppfastrpc-1.0.2/test/v75/libhap_example_skel.so000066400000000000000000001715601512345705400211270ustar00rootroot00000000000000ELF4u4 ( 0ĺĺpp(& DQuA͛ R>=-SSں鋇m KQ}ĐS29# .'F9tHIKҲ'K?o؁h {wC<)@1l!-rC46u) 7y?rpO {Fod@D P<8N P43 .IޠG>c,@5kivlP-Ob`;7"zʏV! HnϟvŲQƱxo,#yK| dS;󸬊0_]!L1H(J3bnڢ( tu* +m6u0u0]q9yW?H 0  *H  0j1$0"U Qualcomm Technologies, Inc.1*0(U !Qualcomm Cryptographic Operations10U QDSR Sub-CA 10 251203081441Z 351201081541Z0'1 0 UUS1 0 U CA10U San Diego10U 07 0001 SHA25610U 06 0000 MODEL_ID10U 05 00000020 SW_SIZE10U 04 0000 OEM_ID1"0 U 03 0000000000000002 DEBUG1"0 U 02 0000000000000000 HW_ID1"0 U 01 0000000000000000 SW_ID10U QUALCOMM1 0 U CASS0 0  *H  0K%y݉u8 lݯ3\ӊ6MV{=a@^3)jQǥkߋ%kY0m0|u(~롙/rhp:= ̞;rG4fvf}&=R 4>!z\xWɅ * VPoT*\zCppCهh%[*EV0T0U#0N^bE3{>fu0 U00U0 +) @@0  *H  =H{ߪTXRqc-e"kO[ Dz&gH}YLtvgq<0zs-{ pxs\f?D>gJJ2Sa¨1[@ xo\+z.GR@t#cظ~,ǥ EG K{ͷZHO#؋ Ck(&~-]n@Č{"qDS}WW:r'T+:ӾVT#}^!O1$ 茎ZseX008JYaȐ_ 0  *H  0i1$0"U Qualcomm Technologies, Inc.1*0(U !Qualcomm Cryptographic Operations10U QDSR Root CA0 130503194249Z 230501194249Z0j1$0"U Qualcomm Technologies, Inc.1*0(U !Qualcomm Cryptographic Operations10U QDSR Sub-CA 10 0  *H  0*>6ATk*O!b xSeRFDu.ŀfbCwR"`a 5w1Xa̔9tƒДZETS_pZsn pdLC(_7$*Mэ(B=A'䧣`v.#ӌu*'8D bFRS/Hh % Z:T{+{p8c]EK 4ɋh~0|0U#0Fju* (xc$Y0UN^bE3{>fu0U00U0 +) 0  *H  8psD ţ-E0|iec+% %zE IX \RyҶY4gk_JdȾRq!Z[eDqI<szÉ*ђo%͂PNNne B?M8&Qm1p[[3U ٷWiEүU@A!li^t-)stӁ x2\[2X00HFx!`RhF0  *H  0i1$0"U Qualcomm Technologies, Inc.1*0(U !Qualcomm Cryptographic Operations10U QDSR Root CA0 130503000001Z 430502235959Z0i1$0"U Qualcomm Technologies, Inc.1*0(U !Qualcomm Cryptographic Operations10U QDSR Root CA0 0  *H  0 %)ȓbv15Fzz<xg`5x|CZr7gwr=A/.on% O/(S#F%>/􉚀z*j#<{!{bOra[7IbX#ԇ]7"QNa }#qؽ-CnP 5j#ˆhA)?0oEpxj恌vg`Yӂ(lD5mPm4kWah_r]1s,DE0C0U00U0UFju* (xc$Y0  *H  36BeQYoiuBqxowC;5$2g La$kt'eXp1V|e+{+E%<N5lc\RܸВGh`P<DkEEȆjcv,_"gb9re ݼ8(}JqݗE0C&&xS|Տ@!9=*l^쎣U\"S?{]1GT>ldYχY|Uؐn– ELF4u4 (ĺĺpp 90,($7@l'~@h` l | cH#1C \il{    H*   5Odw&J`  !,Hd     L^h(:T T ^ k`D q  (  wHl 5TTSm eH " HAP_cache_unlockhap_example_compute_resv2release_cbHAP_mmaphap_example_skel_handle_invoke_qaic_versionhap_example_closehap_example_mem_reserve_vaHAP_mmap_gethap_example_mem_dmahandlev2hap_example_perfHAP_timer_sleepcompute_resource_query_VTCMtest_unmap_reserved_va__dso_handleHAP_power_setHAP_mem_get_statscompute_resource_acquirehap_example_mem_map_reserve_vacompute_resource_attr_get_vtcm_ptr_v2HAP_mmap_puthap_example_slimHAP_mmap2HAP_get_userpd_paramshap_example_compute_resmemsetHAP_cache_lockcompute_resource_attr_set_vtcm_param_v2HAP_query_total_cachelockadsp_mmap_fd_getinfoqurt_thread_get_idhap_example_openhap_example_skel_handle_invoke_uri__cxa_finalize_stubtest_map_reserved_vahap_example_sysmon_cachelockHAP_query_avail_cachelockHAP_mem_set_grow_sizeHAP_munmap__register_frame_info_basesHAP_perf_qtimer_count_to_uscompute_resource_attr_set_release_callbackvsnprintfcompute_resource_attr_get_vtcm_ptrHAP_mem_available_stackcompute_resource_check_release_request__stack_chk_fail__wrap_freetest_reserve_va__stack_chk_guardhap_example_mem_dmahandleHAP_debugHAP_debug_v2_finicompute_resource_attr_set_serializeHAP_power_destroy_clientrelease_cb_callbackcompute_resource_attr_set_vtcm_paramHAP_mem_requesthap_example_mem_fastrpc_mmap_initcompute_resource_attr_inithap_example_skel_handle_invokehap_example_farf_runtimecompute_resource_releasetest_unreserve_vahap_example_powermemcpy__wrap_malloc__cxa_finalizequrt_thread_set_priorityHAP_power_getHAP_munmap2libc.solibgcc.solibhap_example_skel.soII>'2+A/)B?C=<G(51. 04F8E-D%:"*H; $  &# ,673@9 !###8#8#T#p#p##8#T#8#8#8####0#0#h####8#X###H#(,#8#&<#'@#H*D# 9H#SL#TP# lT#wX#@h\#i`#|d#h##(! !!!!!)!+!,t!-p!1l!4|!6!7!9x!=!@4!E"'"E"C""D"4"*"3"."/"-"="6"9""+"@""F " ")""" "$",(","&0":4"8"<"%@"HD"(H"L" P"GT"X"\"7`"d"h"$l"ݡ؝@ j?}x*x@x((4ZxPYX@ݑRBIjBO@<BRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjRBIjR@ jL}x!xu_S jYާ➧㞧bb➧u\"BIj:RaBBIjZXaBBIjZXޗdEBIj†ZXޗdEBIj†zZXޗdEBIjÆ6ZXޗdEBIjÆ6ZXޗdEBIjĆ"ZXޗdEBIjĆTZnXޗdEBIjņZZXޗdEBIjņZFXޗdEBIjƆZ2XޗdEBIjƆZXޗdEBIjdžZ X@B<Xឧ➧B<B<B<|ާBZbu:\XXTBIjǂuk\XAIjAIj`xx[XAIjAIj`xx[XXXXRBIjǂuk\XAIjAIj@xx[XAIjAIj@xx[XXB<XBuZ\XXPBIjǂuk \X:}p¡ÂAIjAIj@xbxF[X:}p¡ÂAIjAIj@xbx*[XXX"➧YXMBIjǂuk\XAIjAIj@xBx[XAIjAIj@xBx[XXDB<"x> Zbu:\XXKBIjǂuk\XAIjAIj`xBx[XAIjAIj`xBx[XXXXIBIjǂuk\X>}pĂÂAIjAIj@xxl[X>}pĂÂAIjAIj@xxR[XXB<XBuZ\XXFBIjǂuk \X:}p¡ÂAIjAIj@x"x[X:}p¡ÂAIjAIj@x"x[XXX"➧YXDBIjǂuk\XAIjAIj@xx[XAIjAIj@xx[XX@B\XX;BIjǂuk\XAIjAIj`x"x[XAIjAIj`x"x[XXB<XX:BIjǂuk\X#}pÂAIjAIj@xx~[X#}pÂAIjAIj@xxh[XXX8BIjǂuk\XAIjAIj@xxD[XAIjAIj@xx4[XX@ZbuF\XX5BIjǂuk\XC}pÂAIjAIj`xBx[XC}pÂAIjAIj`xBx[XXDXX3BIjǂuk\XC}pÂAIjAIj@xx[XC}pÂAIjAIj@xx[XXXbuk:\XX1BIjǂuk\XAIjAIj@x"xt[XAIjAIj@x"xd[XX8XX/BIjǂuk\XAIjAIj@xx>[XAIjAIj@xx.[XXXb➧X-BIju \X8[ X@B<Xap,BIju\X>[ X@B<Xbpឧ+BIj‚u\Xb>[ X@B<Xឧ)BIj‚u\X[XB<X(BIjÂu \X[XB<X'BIjÂu \X[ X@B<X:ާx➧X%BIjǂuk\XAIjAIj@xbx[XAIjAIj@xbx[XXxPZX#BIjǂuk\XAIjAIj@xBx[XAIjAIj@xBx[XXX"BIjǂuk"\X}płĂÂAIjAIj@xx|[ X}płĂÂAIjAIj@xx^[XXXBIjǂuk\X#d}pĂÂAIjAIj@xx0[X#d}pĂÂAIjAIj@xx[XXXBIjǂuk.\XCd󞗅}pȂǂƂłĂÂAIjAIj@xx[,XCd󞗅}pȂǂƂłĂÂAIjAIj@xx[XXBIjuk@\XXBIjǂuk\XAIjAIj@xbxz[XAIjAIj@xbxj[XX@x➧X>[:[6[XBIjǂuk\XAIjAIj@xx2[XAIjAIj@xx"[XXBIjĂឧZZBZXBIjǂuk\XAIjAIj@xbx[XAIjAIj@xbx[XX@@x➧ZA"xx㞧Zc@xcpvZXBIjǂuk\XAIjAIj@xx[XAIjAIj@xxr[XXx[uk@\XXBIjǂuk\XAIjAIj`xx<[XAIjAIj`xx,[XX@x➧XX BIjǂuk\X}pÂ}AIjAIj@xBx[X}pÂ}AIjAIj@xBx[XX"xXZu \Xx➧XX BIjǂuk\XC$}pĂÂzAIjAIj@xx[XC$}pĂÂzAIjAIj@xx~[XXXB➧x➧X""bk\X:➧X"➧YXBIjǂuk\X}pÂwAIjAIj@xx$[X}pÂvAIjAIj@xx[XXxnZXBIjǂuk\XtAIjAIj@xbx[XtAIjAIj@xbx[XXXBIjǂuk"\X}płĂÂrAIjAIj@xx[ X}płĂÂqAIjAIj@xx|[XXXBIjǂuk\X#d}pĂÂpAIjAIj@xxN[X#d}pĂÂoAIjAIj@xx4[XXXAIjǂuk.\XCd󞗅}pȂǂƂłĂÂmAIjAIj@xx[,XCd󞗅}pȂǂƂłĂÂlAIjAIj@xx[XXx([uk@\XXAIjǂuk\XjAIjAIj`xx[XjAIjAIj`xx[XX@x➧jXXAIjǂuk\X}pÂhAIjAIj@xBxT[X}pÂhAIjAIj@xBx>[XX"xX2Zu \Xx➧ XXAIjǂuk\XC$}pĂÂeAIj}AIj@xx[XC$}pĂÂdAIj}AIj@xx[XXXB➧x➧X""bk\X:➧X"➧YXAIjǂuk\X}pÂbAIjyAIj@xx~[X}pÂaAIjxAIj@xxh[XXxZXAIjǂuk\X_AIjpAIj@x"x6[X_AIjpAIj@x"x&[XXXAIjǂuk"\X}płĂÂ]AIjoAIj@xbx[ X}płĂÂ\AIjnAIj@xbx[XXXAIjǂuk\X#d}pĂÂ[AIjnAIj@xx[X#d}pĂÂZAIjmAIj@xx[XXXAIjǂuk.\XCd󞗅}pȂǂƂłĂÂXAIjlAIj@xxP[,XCd󞗅}pȂǂƂłĂÂWAIjkAIj@xx&[XX[x[Fxz[buk\XXAIjǂuk\XUAIjnAIj`xx[XTAIjmAIj`xx[XX uk\XXAIjǂuk\XSAIjlAIj@xx[XRAIjlAIj@xx[XXD[XAIjǂuk\X}pĂÂQAIjkAIj@xxf[X}pĂÂPAIjjAIj@xxL[XXuk \XxXX uk\XXAIjǂuk\XNAIjiAIj@xx [XMAIjhAIj@xx[XX[XAIjǂuk\X}pĂÂLAIjfAIj@xBx[X}pĂÂKAIjeAIj@xBx[XXuk \XxXXFx[buk \Xx➧nXXAIjǂuk\Xc}pÂHAIjdAIj@x"xX[Xc}pÂHAIjcAIj@x"xB[XX"xXHXXAIjǂuk\Xc}pÂFAIjbAIj@xx[Xc}pÂEAIjaAIj@xx[XX"xXZuJ\XXAIjǂuk\X}pÂCAIj_AIj`xx[X}pÂCAIj^AIj`xx[XXx➧XXAIjǂuk\XC$}pĂÂAAIj]AIj@xbxn[XC$}pĂÂ@AIj\AIj@xbxT[XXXB➧x➧X""bk\X:➧X"➧YXAIjǂuk\X}pÂ=AIjUAIj@xx[X}pÂ=AIjTAIj@xx[XX uk>\XXAIjǂuk\X;AIjUAIj@xx[X;AIjTAIj@xx[XXP[X uk>\XXAIjǂuk\X9AIjTAIj@xxr[X9AIjSAIj@xxb[XX [XB uk>\XXAIjǂuk\X7AIjTAIj@xx.[X7AIjSAIj@xx[XX`[XX"uk:\XXAIjǂuk\X5AIjRAIj@xx[X4AIjRAIj@xx[XX8XXAIjǂuk\X3AIjQAIj@xBx[X3AIjPAIj@xBx[XXX"➧Xឧ➧㞧䞧AIjĂu\XcD[ X@B<Xឧ➧AIjłu\X[ X@B<Xឧ➧㞧AIjłu\Xc[ X@B<Xឧ➧AIjƂu\Xf[ X@B<Xާ➧x ާ➧㞧䞧B<XAIjǂuk\XHAIjIAIj@xxZXHAIjHAIj@xx|[XXB<B<B\XXAIjǂuk\XFAIjFAIj`xxZZXEAIjFAIj`xx"[XXB<XXAIjǂuk.\Xc(}pȂǂƂłĂÂCAIjEAIj@xxZ,Xc(}pȂǂƂłĂÂBAIjCAIj@xx[XXXAIjǂuk\XAAIjCAIj@xbxZX@AIjCAIj@xbx[XXx [BuF\XXAIjǂuk\XC}pÂ>AIjAAIj`xbxlZXC}pÂ=AIjAAIj`xbx.[XXXXAIjǂuk\X@ޗ}p¡ÂAIj`xbx[XXX([`p➧@`u\X@ukF\XXAIjǂuk\X}pÂ6AIj=AIj`xBxpZX}pÂ6AIjޗޗ}p¡Ă¡ÂAIj,AIj@xxb[$X>ޗޗ}p¡Ă¡ÂAIj+AIj@xx[XX[uZ\XXAIjǂuk$\Xޗ}pĂ¡¡ÂAIj*AIj`xBx["Xޗ}pĂ¡¡ÂAIj)AIj`xBx[XXNXޗ¡XAIjǂuk\X‘}p¡AIj(AIj@xx[X‘}p¡AIj'AIj@xxj[XXXCާ➧ާB<ޗާ➧ޗާB➧B<|ާާbxޗާ`ޗާ@ޗާ ޗާޗާޗާXAIjǂuk:\X>ޗޗfhޗޗN}p➧΂¡¡ ǂƂ¡¡¡ÂAIj#AIj@xx[8X>ޗޗfhޗޗN}p➧΂¡¡ ǂƂ¡¡¡ÂAIj"AIj@xx[XXP[uj\XXAIjǂuk,\XޗޗޗH}p Ȃ¡¡¡¡ÂAIj!AIj`xbx~[*XޗޗޗH}p Ȃ¡¡¡¡Â AIj AIj`xbx.[XXDXX~AIjǂuk\Xޗ}p¡ AIj AIj@xx*[Xޗ}p¡ AIj AIj@xx[XXXާާB<ޗާޗާxޗާޗާX{AIjǂuk"\X>ޗޗ}p¡¡Â AIjAIj@xBx[ X>ޗޗ}p¡¡ÂAIjAIj@xBxx[XX(["uZ\XXxAIjǂuk$\X#ޗޗ}p¡¡¡ÂAIjAIj`xx^["X#ޗޗ}p¡¡¡ÂAIjAIj`xx[XXPXXuAIjǂuk \Xޗޗ}p¡¡¡AIjAIj@xBx [Xޗޗ}p¡¡¡AIjAIj@xBx[XXX ާާB<ޗާޗާxޗާޗާXqAIjǂuk"\X>ޗޗ}p¡¡ÂAIjAIj@xx[ X>ޗޗ}p¡¡Â@IjAIj@xxT[XX["uZ\XXnAIjǂuk$\X#ޗޗ}p¡¡¡Â@IjAIj`x"x:["X#ޗޗ}p¡¡¡Â@IjAIj`x"x[XXPXXlAIjǂuk \Xޗޗ}p¡¡¡@IjAIj@xx[Xޗޗ}p¡¡¡@IjAIj@xx[XXX ާB<B<@xxbpާޗ[uJ\XXhAIjǂuk\Xޗ}p¡¡@IjAIj`xxr[Xޗ}p¡¡@IjAIj`xx2[XX@XޗcAIj¡XfAIjǂuk\X@IjAIj@x"x,[X@IjAIj@x"x[XXX ާ➧B<B\XXWAIjǂuk\X@IjAIj`xxX[X@IjAIj`xx [XXB<XXUAIjǂuk.\Xc}pȂǂƂłĂÂ@Ij@Ij@xbx[,Xc}pȂǂƂłĂÂ@Ij@Ij@xbx[XXXRAIjǂuk\X@Ij@Ij@x"x[X@Ij@Ij@x"x~[XXx [BuF\XXPAIjǂuk\XC}pÂ@Ij@Ij`x"xj[XC}pÂ@Ij@Ij`x"x,[XXXXNAIjǂuk\Xޗ}p¡Â@Ij@Ij@xx$[Xޗ}p¡Â@Ij@Ij@xx[XX[BuF\XXKAIjǂuk\XC}pÂ@Ij@Ij`xx[XC}pÂ@Ij@Ij`xx[XXHXXIAIjǂuk*\Xޗ$ޗFޗhޗޗ}p¡¡¡¡¡@Ij@Ij@xbx[(Xޗ$ޗFޗhޗޗ}p¡¡¡¡¡@Ij@Ij@xbx2[XXXޗ@ާޗ@ާޗbޗ[BuF\XXEAIjǂuk\XC}pÂ@Ij@Ij`xx[XC}pÂ@Ij@Ij`xx[XXX[BuF\XXBAIjǂuk\XC}pÂ@Ij@Ij`xx[XC}pÂ@Ij@Ij`xx[XX8XX@AIjǂuk*\Xޗ$ޗFޗhޗޗ}p¡¡¡¡¡@Ij@Ij@xxp[(Xޗ$ޗFޗhޗޗ}p¡¡¡¡¡@Ij@Ij@xx"[XXXޗޗ€:\XX=AIjǂuk\X@Ij@Ij`xx[X@Ij@Ij`xx[XXXX;AIjǂuk\X@Ij@Ij@xbx[X@Ij@Ij@xbx[XXL[BuF\XX9AIjǂuk\XC}pÂ@Ij@Ij`x"x[XC}pÂ@Ij@Ij`x"x^[XXXX7AIjǂuk\X}pÂ@Ij@Ij@xxZ[X}pÂ@Ij@Ij@xx[XXX5AIjǂuk\X@Ij@Ij@xBx [X@Ij@Ij@xBx[XXa[BuF\XX3AIjǂuk\XC}pÂ@Ij@Ij`xx[XC}pÂ@Ij@Ij`xx[XXLXX1AIjǂuk\Xd}pĂÂ@Ij@Ij@xx[Xd}pĂÂ@Ij@Ij@xxN[XXXBuk:\XX.AIjǂuk\X@Ij@Ij@xBxF[X@Ij@Ij@xBx[XX8XX-AIjǂuk\X@Ij@Ij@xx[X@Ij@Ij@xx[XXX@ާ➧㞧B<X*AIjǂuk\X@Ij@Ij@x"xZX@Ij@Ij@x"x[XX[buF\XX(AIjǂuk\Xc}pÂ@Ij@Ij`x"xZXc}pÂ@Ij@Ij`x"x<[XXXX&AIjǂuk"\XDޗ}p¡ĂÂ@Ij@Ij@xxdZ XDޗ}p¡ĂÂ@Ij@Ij@xx[XXX$AIjǂuk\X@Ij@Ij@xx"ZX@Ij@Ij@xx[XXV[buF\XX"AIjǂuk\Xc}pÂ@Ij@Ij`xxZXc}pÂ@Ij@Ij`xxh[XXDXXAIjǂuk\X}pÂ@Ij@Ij@xBxZX}pÂ@Ij@Ij@xBx&[XXXbuk:\XXAIjǂuk\X@Ij@Ij@x"xRZX@Ij@Ij@x"x[XX8XXAIjǂuk\X@Ij@Ij@xxZX@Ij@Ij@xx[XXX`&AIj䞧䞧ឧ➧㞧➧x[`paB#[k\Xx[ ާB<XAIjǂuk\X@Ij@Ij@xx.ZX@Ij@Ij@xx"[XX^ZާXAIjǂuk\Xޗ}p¡@Ij@Ij@x"xZXޗ}p¡@Ij@Ij@x"x[XXXAIjǂuk\X@Ij@Ij@xxZX@Ij@Ij@xx[XX.ZާXAIjǂuk\X`ޗ}p¡@Ij@Ij@xbxxZX`ޗ}p¡@Ij@Ij@xbxf[XXXAIjǂuk\X@Ij@Ij@x"x>ZX@Ij@Ij@x"x2[XX`ޗ [ާXAIjǂuk\X`ޗޗ}p¡¡@Ij@Ij@xxZX`ޗޗ}p¡¡@Ij@Ij@xx[XXX AIjǂuk\X@Ij@Ij@xbxZX@Ij@Ij@xbx[XX>ZާX AIjǂuk\X@ޗ}p¡@Ij@Ij@xx~ZX@ޗ}p¡@Ij@Ij@xxl[XXAIjǂukJ\XXAIjǂuk\X@Ij}pÂ@Ij@Ij`xx,ZX@Ij}pÂ@Ij@Ij`xx[XXXXAIjǂuk\X@Ij@Ij@xbxZX@Ij@Ij@xbx[XX|ާ<[buF\XXAIjǂuk\Xc}pÂ@Ij@Ij`xBxZXc}pÂ@Ij@Ij`xBx[XXXXAIjǂuk\Xc}pÂ@Ij@Ij@xx\ZXc}pÂ@Ij@Ij@xxJ[XXXX@Ijǂuk\X@Ij@Ij@xx ZX@Ij@Ij@xx[XX }xxbpާޗ[bu:\XX@Ijǂuk\X@Ij@Ij`xxZX@Ij@Ij`xx[XXDXX@Ijǂuk\Xޗ}p¡@Ij@Ij@x"xZXޗ}p¡@Ij@Ij@x"x[XXXbuk:\XX@Ijǂuk\X@Ij@Ij@xxRZX@Ij@Ij@xxF[XX8XX@Ijǂuk\X@Ij@Ij@xBxZX@Ij@Ij@xBx[XXX`&@Ij䞧䞧ឧ➧㞧➧x[`paB#[k\X[hާޗ|hpfpEcpipgpbpap`pj cxj GxcpfpB DgpBbp&s D" hާޗhާޗާB<B<X@Ijǂuk\X@Ij@Ij@xBxBZX@Ij@Ij@xBx&[XXrZ|ާާ"x[bu@\XX@Ijǂuk\X@Ij@Ij`x"xZX@Ij@Ij`x"x[XX@B<XB➧|ާާBx[bu@\XX@Ijǂuk\X@Ij@Ij`x"xZX@Ij@Ij`x"xz[XX@BX@Ijǂuk*\XC$g>}pǂƂłĂÂ@Ij@Ij@xx0Z(XC$g>}pǂƂłĂÂ@Ij@Ij@xx[XXX@Ijǂuk\X@Ij@Ij@xbxZX@Ij@Ij@xbx[XXxx[xH"xQxRS@(C\XX@Ijǂuk\X@Ij@Ij@xbxtZX@Ij@Ij@xbxX[XXB<XbuF\XX@Ijǂuk\Xc}pÂ@Ij@Ij`xBx,ZXc}pÂ@Ij@Ij`xBx [XX~XX@Ijǂuk\X@Ij@Ij@xxZX@Ij@Ij@xx[XXX@Ijǂuk\XC>}pÂ@Ij@Ij@xxZXC>}pÂ@Ij@Ij@xx[XXX@Ijǂuk\X}pÂ@Ij@Ij@xxvZX}pÂ@Ij@Ij@xxT[XXX@Ijǂuk"\X#>D>>}płĂÂ@Ij@Ij@xBx.Z X#>D>>}płĂÂ@Ij@Ij@xBx[XXX@Ijǂuk\XC>}pÂ@Ij@Ij@xxZXC>}pÂ@Ij@Ij@xx[XXxx[xH"xQxR[buF\XX@Ijǂuk\Xc}pÂ@Ij@Ij`xBxZXc}pÂ@Ij@Ij`xBx^[XXX"xG>Zb"uk>\XX@Ijǂuk\X@Ij@Ij@xx.ZX@Ij@Ij@xx[XXB<XbuF\XX@Ijǂuk\Xc}pÂ@Ij@Ij`xxZXc}pÂ@Ij@Ij`xx[XX8XX@Ijǂuk\X@Ij@Ij@xbxZX@Ij@Ij@xbx[XXXu\XZB<Xbuk:\XX@Ijǂuk\X@Ij@Ij@xxXZX@Ij@Ij@xx<[XX8XX@Ijǂuk\X@Ij@Ij@xx"ZX@Ij@Ij@xx[XXXb➧X&@Ij䞧䞧ឧ➧㞧➧x[`paB#[k\X[ x[apxx[x"xb>[@Ijǂu \X|[ X@,B<XާB<X@Ijǂuk\X@Ij@Ij@xx`ZX@Ij@Ij@xx"[XX@@B<*["uk>\XX@Ijǂuk\X@Ij@Ij`xxZX@Ij@Ij`xx[XXB<XX@Ijǂuk"\X$ޗ}p¡ĂÂ@Ij@Ij@xxZ X$ޗ}p¡ĂÂ@Ij@Ij@xx[XXX@Ijǂuk\X@Ij@Ij@xBxZX@Ij@Ij@xBxL[XXf[bu>\XX@Ijǂuk\X@Ij@Ij`xBxJZX@Ij@Ij`xBx [XXB<XX@Ijǂuk\X}pÂ@Ij@Ij@xx ZX}pÂ@Ij@Ij@xx[XXX@Ijǂuk\X~@Ij@Ij@xxZX}@Ij@Ij@xx[XX[bu>\XX@Ijǂuk\X|@Ij@Ij`xxZX{@Ij@Ij`xxR[XXB<XX@Ijǂuk\X}pÂz@Ij@Ij@xBxPZX}pÂy@Ij@Ij@xBx [XXX@Ijǂuk\Xx@Ij@Ij@xxZXw@Ij@Ij@xx[XX [u:\XX@Ijǂuk\Xv@Ij@Ij`xxZXu@Ij~@Ij`xx[XXDXX@Ijǂuk\X#}pÂt@Ij~@Ij@x"xZX#}pÂs@Ij}@Ij@x"xT[XXXuk:\XX@Ijǂuk\Xr@Ij}@Ij@xxRZXq@Ij|@Ij@xx[XX8XX@Ijǂuk\Xp@Ij{@Ij@xbxZXp@Ij{@Ij@xbx[XXX&@Ij䞧䞧ឧ➧㞧➧x[`paB#[k\X[۝ jf x*xPY@RyyyzRhGSH a}7(+2{+s|ЁWDн510u0]}H£TȽ& pHoV0  *H  0j1$0"U Qualcomm Technologies, Inc.1*0(U !Qualcomm Cryptographic Operations10U QDSR Sub-CA 10 251203081506Z 351201081606Z0'1 0 UUS1 0 U CA10U San Diego10U 07 0001 SHA25610U 06 0000 MODEL_ID10U 05 00000020 SW_SIZE10U 04 0000 OEM_ID1"0 U 03 0000000000000002 DEBUG1"0 U 02 0000000000000000 HW_ID1"0 U 01 0000000000000000 SW_ID10U QUALCOMM1 0 U CASS0 0  *H  0՘6ɏѭ&٩nռ`&zm3L_p<`U.ZZ:+a|1VPzX>ONv }+$ mHPn74'7ӳ|zfo}h TޟY6KqAxґY<:&(XZ 6Q'X`+ `Rru U{EctA 9IlKAUV گ:C}6XT?vQ)׭GV0T0U#0N^bE3{>fu0 U00U0 +) @@0  *H  +fJ {Ue>6$ZmJ$:7O)zF}Łwq8%ĉ9{xl$anwվ 0&K@nwbD wY<%.i^iu;a}B&et mh23gbtv8݄sVB5lg̭6kkРZW#ueOK#|yS2Tkk?$`bw42008JYaȐ_ 0  *H  0i1$0"U Qualcomm Technologies, Inc.1*0(U !Qualcomm Cryptographic Operations10U QDSR Root CA0 130503194249Z 230501194249Z0j1$0"U Qualcomm Technologies, Inc.1*0(U !Qualcomm Cryptographic Operations10U QDSR Sub-CA 10 0  *H  0*>6ATk*O!b xSeRFDu.ŀfbCwR"`a 5w1Xa̔9tƒДZETS_pZsn pdLC(_7$*Mэ(B=A'䧣`v.#ӌu*'8D bFRS/Hh % Z:T{+{p8c]EK 4ɋh~0|0U#0Fju* (xc$Y0UN^bE3{>fu0U00U0 +) 0  *H  8psD ţ-E0|iec+% %zE IX \RyҶY4gk_JdȾRq!Z[eDqI<szÉ*ђo%͂PNNne B?M8&Qm1p[[3U ٷWiEүU@A!li^t-)stӁ x2\[2X00HFx!`RhF0  *H  0i1$0"U Qualcomm Technologies, Inc.1*0(U !Qualcomm Cryptographic Operations10U QDSR Root CA0 130503000001Z 430502235959Z0i1$0"U Qualcomm Technologies, Inc.1*0(U !Qualcomm Cryptographic Operations10U QDSR Root CA0 0  *H  0 %)ȓbv15Fzz<xg`5x|CZr7gwr=A/.on% O/(S#F%>/􉚀z*j#<{!{bOra[7IbX#ԇ]7"QNa }#qؽ-CnP 5j#ˆhA)?0oEpxj恌vg`Yӂ(lD5mPm4kWah_r]1s,DE0C0U00U0UFju* (xc$Y0  *H  36BeQYoiuBqxowC;5$2g La$kt'eXp1V|e+{+E%<N5lc\RܸВGh`P<DkEEȆjcv,_"gb9re ݼ8(}JqݗE0C&&xS|Տ@!9=*l^쎣U\"S?{]1GT>ldYχY|Uؐn– ELF4u4 (HHPPPPPPPR P -5+@QZHg|18@T T7 KRWp,k0Tv3XPQP"5?DUar07,P  @;D HQ8 l>FM[n"}barriermultithreading_slimmultithreading_barrierssquare_sumqurt_thread_joinsnprintf__dso_handlequrt_barrier_destroyqurt_signal_waitbarrier_threadstrcmpmultithreading_closetestsignal2testmutexqurt_anysignal_setqurt_thread_get_namequrt_barrier_initqurt_thread_get_idmultithreading_parallel_sum__cxa_finalize_stubthread_infomultithreading_opentestsignalqurt_barrier_waitqurt_mutex_initqurt_thread_get_priorityqurt_mutex_lock__register_frame_info_basesmultithreading_mutexesstrlcpymultithreading_skel_handle_invoke_uriqurt_thread_createvsnprintfatoi__stack_chk_fail__wrap_freequrt_signal_init__stack_chk_guardmutex_threadsquare_sum_l2prefetchqurt_thread_exitmultithreading_skel_handle_invokequrt_mutex_unlockHAP_debugHAP_debug_v2_finimultithreading_skel_handle_invoke_qaic_version_init_Assertmemcpy__wrap_mallocqurt_mutex_destroy__cxa_finalizequrt_signal_destroylibc.solibgcc.solibmultithreading_skel.so772&%1 5*/.4'$ + )!,3(0-6"  # P#PP#PP#QP#QP#QP#PP#;P#;P#;P#8QQ#@Q8Q#;@IjW@Ij@xBx[XXBuk\X XV@IjU@Ij[Xb"➧Y@IjĂB[B<XbBu\Xb@IjĂÂ:[Bu\XBuk\X XT@IjS@Ij[X@Ij‚uk\Xc$}pĂÂ9@IjT@Ij@xx[Xc$}pĂÂ8@IjS@Ij@xxf[XXBuk*\X"c@Ijăă:k\X XR@IjO@Ij,[Xc@IjĂ:[Xb"➧6Y@Ij➧Ăl[‚k\Xx[@Ij‚㞧c㞧Ă2[Ax:[:[Buk\X XO@IjP@Ij[X@Ij‚uk\X}pÂ1@IjO@Ij@xx [X}pÂ1@IjN@Ij@xxv[XX["k\X XM@IjM@IjL[ [k\X XM@IjL@Ij,[X{@Ij‚uk\X}pÂ-@IjM@Ij@xx[X}pÂ-@IjL@Ij@xx[XX 0[y@Ij‚k\X[x@Ij➧‚➧ާB<B<[ł:[ƂZƂxZx[u\X XI@IjJ@Ij[J@IjAx[a[[x[x[u@IjǂxZ[uk\X XH@IjG@Ij2[t@IjƂ!xZB<XBu\Xx [;:u\X XG@IjE@Ij[}pÂ=@IjAx>[!&[@:0[@x8[@Bvp<[A@p@Ijǂx[uk\X XD@IjB@Ij[X"➧pYn@IjƂ!x[B<XBu \X:[:[X"➧Ym@Ij➧ł[Ƃ*ZƂ"Z‚k\XxL[[k@Ij‚➧Axt[[Xj@Ij‚uk\X}pÂ@Ij?@Ij@xx`[X}pÂ@Ij>@Ij@xx[XXh@Ijłl[Xh@Ij‚uk"\Xf@Ij}pÂÂ@Ij=@Ij@xBx[ Xe@Ij}pÂÂ@Ij<@Ij@xBxp[XXuk8\Xe@IjƂ!x[c@Ijuk\X X;@Ij<@Ij4[d@IjƂ!xZ"Xb@IjCvk\X X;@Ij:@Ij[Xa@Ij#ÂB<XB@Bu^\XB<B<B<X"`Bu>\X"➧"➧#k\X#k\X X9@Ij7@Ij[X""➧YXB"➧Y_@IjłH[X^@Ij‚uk\X}pÂ@Ij7@Ij@xx[X}pÂ@Ij7@Ij@xxT[XXx[\@Ij‚k\XT[ឧx[[۝ j x*xPY@R(Lt$)-- parallel_sumbarriersmutexescloseopenurihsrc/multithreading_imp.c:93 thread_stack_addr[0]!=NULLmultithreading_parallel_sumcntr1src/multithreading_imp.c:101 thread_stack_addr[1]!=NULLcntr2src/multithreading_imp.c:109 thread_stack_addr[2]!=NULLcntr3src/multithreading_imp.c:117 thread_stack_addr[3]!=NULLcntr4src/multithreading_imp.c:125 thread_stack_addr[4]!=NULLcntr5src/multithreading_imp.c:133 thread_stack_addr[5]!=NULLcntr6src/multithreading_imp.c:149 array_1!=NULLsrc/multithreading_imp.c:152 array_2!=NULLsrc/multithreading_imp.c:155 array_3!=NULLsrc/multithreading_imp.c:158 array_4!=NULLsrc/multithreading_imp.c:161 array_5!=NULLsrc/multithreading_imp.c:164 array_6!=NULLmultithreading_imp.cCreating thread 1 src/multithreading_imp.c:204 retcode==QURT_EOKsrc/multithreading_imp.c:207 (status==QURT_EOK) || (status==QURT_ENOTHREAD)Thread 1 returned with status 0x%x Creating thread 2 Creating thread 3 src/multithreading_imp.c:225 retcode==QURT_EOKsrc/multithreading_imp.c:228 retcode==QURT_EOKsrc/multithreading_imp.c:231 (status==QURT_EOK) || (status==QURT_ENOTHREAD)src/multithreading_imp.c:234 (status==QURT_EOK) || (status==QURT_ENOTHREAD)Thread 2 returned with status 0x%x Thread 3 returned with status 0x%x Creating thread 4 src/multithreading_imp.c:251 retcode==QURT_EOKsrc/multithreading_imp.c:254 (status==QURT_EOK) || (status==QURT_ENOTHREAD)Thread 4 returned with status 0x%x Creating thread 5 Creating thread 6 src/multithreading_imp.c:272 retcode==QURT_EOKsrc/multithreading_imp.c:275 retcode==QURT_EOKsrc/multithreading_imp.c:278 (status==QURT_EOK) || (status==QURT_ENOTHREAD)src/multithreading_imp.c:281 (status==QURT_EOK) || (status==QURT_ENOTHREAD)Thread 5 returned with status 0x%x Thread 6 returned with status 0x%x Without L2 prefetch - Single Thread - sum_1: %d execution time for 1 array : %d micro seconds Without L2 prefetch - Two Threads - sum_2: %d, sum_3: %d execution time for 2 arrays: %d micro seconds With L2 prefetch - Single Thread - sum_4: %d execution time for 1 array : %d micro seconds With L2 prefetch - Two Threads - sum_5: %d, sum_6: %d execution time for 2 arrays: %d micro seconds src/multithreading_imp.c:394 thread_info[i].stack_addr != NULLmultithreading_barriersthread%dthread%d created id = 0x%x src/multithreading_imp.c:403 status==QURT_EOKsrc/multithreading_imp.c:411 (status==QURT_EOK) || (status==QURT_ENOTHREAD)thread%d return status 0x%x src/multithreading_imp.c:414 thread_exit_status==thread_info[i].idsrc/multithreading_imp.c:437 status==0barrier_thread%s starts src/multithreading_imp.c:442 id==ptr_thread_info->idsrc/multithreading_imp.c:445 prio==ptr_thread_info->prio%s exiting src/multithreading_imp.c:486 thread_stack[0]!=NULLmultithreading_mutexesthread0src/multithreading_imp.c:495 status==QURT_EOKsrc/multithreading_imp.c:506 thread_stack[i]!=NULLsrc/multithreading_imp.c:515 status==QURT_EOK thread%d starts Mutex Lock acquired by %s, Access Order = %d src/multithreading_imp.c:559 access_order == 0mutex_threadsrc/multithreading_imp.c:564 access_order == (THREAD_NUM_MUTEX-thread_index)src/multithreading_imp.c:579 counter1==j&&counter2==j Mutex Released by %s  @;  Rpo t  PPQQQP;;;8Q@Q;<<A'file:///libmultithreading_skel.so?multithreading_skel_handle_invoke&_modver=1.0 p-3+,RR1 T0T@T07