├── VERSION ├── lib ├── utils │ ├── CMakeLists.txt │ └── utilities.c ├── proxy │ ├── CMakeLists.txt │ └── rpmsg_retarget.c ├── rpmsg │ ├── CMakeLists.txt │ ├── rpmsg_internal.h │ └── rpmsg.c ├── virtio │ ├── CMakeLists.txt │ └── virtio.c ├── service │ └── rpmsg │ │ └── rpc │ │ ├── CMakeLists.txt │ │ ├── rpmsg_rpc_server.c │ │ └── rpmsg_rpc_client.c ├── virtio_mmio │ ├── CMakeLists.txt │ └── virtio_mmio_drv.c ├── remoteproc │ ├── CMakeLists.txt │ ├── rsc_table_parser.h │ ├── rsc_table_parser.c │ └── remoteproc_virtio.c ├── include │ ├── openamp │ │ ├── open_amp.h │ │ ├── version.h │ │ ├── remoteproc_loader.h │ │ ├── rpmsg_retarget.h │ │ ├── remoteproc_virtio.h │ │ ├── rpmsg_rpc_client_server.h │ │ ├── virtio_mmio.h │ │ ├── virtio_ring.h │ │ ├── virtqueue.h │ │ ├── rpmsg_virtio.h │ │ └── elf_loader.h │ └── internal │ │ └── utilities.h ├── version.c ├── version.h.in └── CMakeLists.txt ├── doc ├── openamp.png ├── readthedocs-conf.py └── CMakeLists.txt ├── cmake ├── platforms │ ├── zynqmp_a53_generic.cmake │ ├── zynqmp_linux.cmake │ ├── cross_linux_gcc.cmake │ ├── zynqmp_r5_generic.cmake │ └── cross_generic_gcc.cmake ├── syscheck.cmake ├── depends.cmake ├── modules │ └── FindLibmetal.cmake ├── collect.cmake └── options.cmake ├── .gitignore ├── .github ├── actions │ └── build_ci │ │ ├── action.yml │ │ ├── Dockerfile │ │ ├── README.md │ │ └── entrypoint.sh └── workflows │ ├── stales.yml │ ├── heathcheck.yml │ ├── compliance.yml │ └── continuous-integration.yml ├── .checkpatch.conf ├── MAINTAINERS.md ├── CMakeLists.txt ├── scripts ├── do_checkpatch.sh └── gitlint │ └── commit_rules.py ├── .readthedocs.yaml ├── .gitlint ├── LICENSE.md └── README.md /VERSION: -------------------------------------------------------------------------------- 1 | VERSION_MAJOR = 1 2 | VERSION_MINOR = 9 3 | VERSION_PATCH = 0 4 | -------------------------------------------------------------------------------- /lib/utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | collect (PROJECT_LIB_SOURCES utilities.c) 2 | -------------------------------------------------------------------------------- /lib/proxy/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | collect (PROJECT_LIB_SOURCES rpmsg_retarget.c) 2 | -------------------------------------------------------------------------------- /doc/openamp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenAMP/open-amp/HEAD/doc/openamp.png -------------------------------------------------------------------------------- /lib/rpmsg/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | collect (PROJECT_LIB_SOURCES rpmsg.c) 2 | collect (PROJECT_LIB_SOURCES rpmsg_virtio.c) 3 | -------------------------------------------------------------------------------- /lib/virtio/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | collect (PROJECT_LIB_SOURCES virtio.c) 2 | collect (PROJECT_LIB_SOURCES virtqueue.c) 3 | -------------------------------------------------------------------------------- /lib/service/rpmsg/rpc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | collect (PROJECT_LIB_SOURCES rpmsg_rpc_client.c) 2 | collect (PROJECT_LIB_SOURCES rpmsg_rpc_server.c) 3 | -------------------------------------------------------------------------------- /lib/virtio_mmio/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if (WITH_VIRTIO_MMIO_DRV) 2 | collect (PROJECT_LIB_SOURCES virtio_mmio_drv.c) 3 | endif (WITH_VIRTIO_MMIO_DRV) 4 | -------------------------------------------------------------------------------- /cmake/platforms/zynqmp_a53_generic.cmake: -------------------------------------------------------------------------------- 1 | set (CMAKE_SYSTEM_PROCESSOR "arm64") 2 | set (CROSS_PREFIX "aarch64-none-elf-") 3 | 4 | include (cross_generic_gcc) 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *~ 3 | !libs/system/zc702evk/linux/lib/*/*.a 4 | *.bin 5 | *.map 6 | *.out 7 | *.log 8 | *.d 9 | 10 | /tags 11 | /TAGS 12 | 13 | # cscope files 14 | cscope.* 15 | ncscope.* 16 | -------------------------------------------------------------------------------- /cmake/platforms/zynqmp_linux.cmake: -------------------------------------------------------------------------------- 1 | set (CMAKE_SYSTEM_PROCESSOR "arm64") 2 | set (CROSS_PREFIX "aarch64-linux-gnu-") 3 | set (MACHINE "zynqmp" CACHE STRING "") 4 | 5 | include (cross_linux_gcc) 6 | -------------------------------------------------------------------------------- /lib/remoteproc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | collect (PROJECT_LIB_SOURCES elf_loader.c) 2 | collect (PROJECT_LIB_SOURCES remoteproc.c) 3 | collect (PROJECT_LIB_SOURCES remoteproc_virtio.c) 4 | collect (PROJECT_LIB_SOURCES rsc_table_parser.c) 5 | -------------------------------------------------------------------------------- /.github/actions/build_ci/action.yml: -------------------------------------------------------------------------------- 1 | # action.yml 2 | name: 'Target Build' 3 | description: 'Compile for a specified target' 4 | 5 | inputs: 6 | target: 7 | description: 'build target' 8 | default: 'linux' 9 | runs: 10 | using: 'docker' 11 | image: 'Dockerfile' 12 | args: 13 | - ${{ inputs.target }} -------------------------------------------------------------------------------- /cmake/platforms/cross_linux_gcc.cmake: -------------------------------------------------------------------------------- 1 | set (CMAKE_SYSTEM_NAME "Linux") 2 | set (CMAKE_C_COMPILER "${CROSS_PREFIX}gcc") 3 | set (CMAKE_CXX_COMPILER "${CROSS_PREFIX}g++") 4 | 5 | set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 6 | set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER) 7 | set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER) 8 | -------------------------------------------------------------------------------- /lib/include/openamp/open_amp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Mentor Graphics Corporation 3 | * All rights reserved. 4 | * 5 | * SPDX-License-Identifier: BSD-3-Clause 6 | */ 7 | 8 | #ifndef OPEN_AMP_H_ 9 | #define OPEN_AMP_H_ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #endif /* OPEN_AMP_H_ */ 17 | -------------------------------------------------------------------------------- /cmake/platforms/zynqmp_r5_generic.cmake: -------------------------------------------------------------------------------- 1 | set (CMAKE_SYSTEM_PROCESSOR "arm" CACHE STRING "") 2 | set (MACHINE "zynqmp_r5" CACHE STRING "") 3 | set (CROSS_PREFIX "armr5-none-eabi-" CACHE STRING "") 4 | 5 | # Xilinx SDK version earlier than 2017.2 use mfloat-abi=soft by default to generate libxil 6 | set (CMAKE_C_FLAGS "-mfloat-abi=hard -mfpu=vfpv3-d16 -mcpu=cortex-r5" CACHE STRING "") 7 | 8 | include (cross_generic_gcc) 9 | -------------------------------------------------------------------------------- /.github/actions/build_ci/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:24.04 2 | 3 | ENV LANG C.UTF-8 4 | ENV LC_ALL C.UTF-8 5 | 6 | # Install prerequisites 7 | RUN apt-get --quiet=2 update && apt-get install --quiet=2 --assume-yes sudo git python3 python3-pip python3-venv wget 8 | 9 | # Copies your code file from your action repository to the filesystem path `/` of the container 10 | COPY entrypoint.sh /entrypoint.sh 11 | 12 | # Code file to execute when the docker container starts up (`entrypoint.sh`) 13 | ENTRYPOINT ["/entrypoint.sh"] 14 | -------------------------------------------------------------------------------- /lib/version.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, STMicroelectronics 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | */ 6 | 7 | #include 8 | 9 | int openamp_version_major(void) 10 | { 11 | return OPENAMP_VERSION_MAJOR; 12 | } 13 | 14 | int openamp_version_minor(void) 15 | { 16 | return OPENAMP_VERSION_MINOR; 17 | } 18 | 19 | int openamp_version_patch(void) 20 | { 21 | return OPENAMP_VERSION_PATCH; 22 | } 23 | 24 | const char *openamp_version(void) 25 | { 26 | return OPENAMP_VERSION; 27 | } 28 | -------------------------------------------------------------------------------- /cmake/syscheck.cmake: -------------------------------------------------------------------------------- 1 | # use "Generic" as CMAKE_SYSTEM_NAME 2 | 3 | if (WITH_ZEPHYR) 4 | set (CMAKE_SYSTEM_NAME "Generic" CACHE STRING "") 5 | string (TOLOWER "Zephyr" PROJECT_SYSTEM) 6 | string (TOUPPER "Zephyr" PROJECT_SYSTEM_UPPER) 7 | if (NOT WITH_ZEPHYR_LIB) 8 | include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) 9 | endif () 10 | if (CONFIG_CPU_CORTEX_M) 11 | set (MACHINE "cortexm" CACHE STRING "") 12 | endif (CONFIG_CPU_CORTEX_M) 13 | endif (WITH_ZEPHYR) 14 | -------------------------------------------------------------------------------- /.checkpatch.conf: -------------------------------------------------------------------------------- 1 | --emacs 2 | --no-tree 3 | --summary-file 4 | --show-types 5 | --max-line-length=100 6 | --min-conf-desc-length=1 7 | 8 | --ignore BRACES 9 | --ignore PRINTK_WITHOUT_KERN_LEVEL 10 | --ignore SPLIT_STRING 11 | --ignore VOLATILE 12 | --ignore CONFIG_EXPERIMENTAL 13 | --ignore AVOID_EXTERNS 14 | --ignore NETWORKING_BLOCK_COMMENT_STYLE 15 | --ignore DATE_TIME 16 | --ignore MINMAX 17 | --ignore CONST_STRUCT 18 | --ignore FILE_PATH_CHANGES 19 | --ignore BIT_MACRO 20 | --ignore PREFER_KERNEL_TYPES 21 | --ignore NEW_TYPEDEFS 22 | --ignore ARRAY_SIZE -------------------------------------------------------------------------------- /cmake/platforms/cross_generic_gcc.cmake: -------------------------------------------------------------------------------- 1 | set (CMAKE_SYSTEM_NAME "Generic" CACHE STRING "") 2 | 3 | set (CMAKE_C_COMPILER "${CROSS_PREFIX}gcc") 4 | set (CMAKE_CXX_COMPILER "${CROSS_PREFIX}g++") 5 | # _exit is in the BSP rather than in libgcc, leaving this out 6 | # causes errors in try_compile on ARM generic. 7 | set (CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) 8 | 9 | set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER CACHE STRING "") 10 | set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER CACHE STRING "") 11 | set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER CACHE STRING "") 12 | -------------------------------------------------------------------------------- /MAINTAINERS.md: -------------------------------------------------------------------------------- 1 | # OpenAMP Maintainers 2 | 3 | The OpenAMP project is maintained by the OpenAMP open source 4 | community. Everyone is encouraged to submit issues and changes to 5 | improve OpenAMP. 6 | 7 | The intention of this file is to provide a set of names that developers 8 | can consult when they have a question about OpenAMP and to provide a 9 | set of names to be CC'd when submitting a patch. 10 | 11 | 12 | ## Project Administration 13 | Ed Mooring 14 | Arnaud Pouliquen 15 | 16 | ### All patches CC here 17 | openamp-rp@lists.openampproject.org 18 | -------------------------------------------------------------------------------- /lib/version.h.in: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, STMicroelectronics. 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | */ 6 | 7 | /* 8 | * @file version_def.h 9 | * @brief generated version definition for OpenAMP library. 10 | */ 11 | 12 | #ifndef __OPENAMP_VERSION_DEF__H__ 13 | #define __OPENAMP_VERSION_DEF__H__ 14 | 15 | /* @templates@ values come from cmake/option.cmake */ 16 | 17 | #define OPENAMP_VERSION_MAJOR @PROJECT_VERSION_MAJOR@ 18 | #define OPENAMP_VERSION_MINOR @PROJECT_VERSION_MINOR@ 19 | #define OPENAMP_VERSION_PATCH @PROJECT_VERSION_PATCH@ 20 | #define OPENAMP_VERSION "@PROJECT_VERSION@" 21 | 22 | #endif /* __OPENAMP_VERSION_DEF__H__ */ 23 | -------------------------------------------------------------------------------- /doc/readthedocs-conf.py: -------------------------------------------------------------------------------- 1 | # Although RTDs now requires sphinx: configuration: it does not pass it to the 2 | # build command and it still looks for conf.py in the current dir. It is 3 | # confusing to have a conf.py that will only work in the very specific RTDs 4 | # dir structure so we don't do that. 5 | 6 | # So we supply a no-op config file and override the build command to run in the 7 | # openamp-docs dir 8 | 9 | # Since we have our own build command now, we could eliminate this file 10 | # completely but that also disables the predefined sphinx steps of 11 | # create_environment and install. The current setup keeps the build 12 | # environment closer to that used by the real openamp-docs build 13 | 14 | print("readthedocs-conf.py does nothing") 15 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.16) 2 | 3 | set (OPENAMP_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}") 4 | set (OPENAMP_BIN_ROOT "${CMAKE_CURRENT_BINARY_DIR}") 5 | 6 | list (APPEND CMAKE_MODULE_PATH 7 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake" 8 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" 9 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake/platforms") 10 | 11 | include (syscheck) 12 | project (open_amp C) 13 | 14 | include (CheckIncludeFiles) 15 | include (CheckCSourceCompiles) 16 | include (collect) 17 | include (options) 18 | include (depends) 19 | enable_testing () 20 | 21 | 22 | if (WITH_OBSOLETE) 23 | add_subdirectory (obsolete) 24 | endif (WITH_OBSOLETE) 25 | 26 | add_subdirectory (lib) 27 | 28 | if (WITH_DOC) 29 | add_subdirectory (doc) 30 | endif (WITH_DOC) 31 | -------------------------------------------------------------------------------- /lib/utils/utilities.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-3-Clause 3 | * 4 | * Copyright (c) 2024, STMicroelectronics 5 | * 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | size_t safe_strcpy(char *dst, size_t d_size, const char *src, size_t s_size) 13 | { 14 | size_t size = metal_min(s_size, d_size); 15 | size_t nleft = size + 1; 16 | char *d = dst; 17 | 18 | if (!d_size) 19 | return 0; 20 | 21 | /* Copy as many bytes as will fit. */ 22 | while (--nleft != 0) { 23 | *dst = *src++; 24 | if (*dst++ == '\0') 25 | break; 26 | } 27 | 28 | /* Fill last characters with '\0' */ 29 | if (size < d_size) 30 | memset(dst, '\0', d_size - size + nleft); 31 | else 32 | d[d_size - 1] = '\0'; 33 | 34 | return size - nleft; 35 | } 36 | -------------------------------------------------------------------------------- /cmake/depends.cmake: -------------------------------------------------------------------------------- 1 | if (WITH_DOC) 2 | find_package (Doxygen) 3 | endif (WITH_DOC) 4 | 5 | if (WITH_LIBMETAL_FIND) 6 | find_package (Libmetal REQUIRED) 7 | collect (PROJECT_INC_DIRS "${LIBMETAL_INCLUDE_DIR}") 8 | collect (PROJECT_LIB_DIRS "${LIBMETAL_LIB_DIR}") 9 | collect (PROJECT_LIB_DEPS "${LIBMETAL_LIB}") 10 | endif (WITH_LIBMETAL_FIND) 11 | 12 | if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") 13 | check_include_files (stdatomic.h HAVE_STDATOMIC_H) 14 | check_include_files (fcntl.h HAVE_FCNTL_H) 15 | else ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") 16 | set (_saved_cmake_required_flags ${CMAKE_REQUIRED_FLAGS}) 17 | set (CMAKE_REQUIRED_FLAGS "-c") 18 | check_include_files (stdatomic.h HAVE_STDATOMIC_H) 19 | check_include_files (fcntl.h HAVE_FCNTL_H) 20 | set (CMAKE_REQUIRED_FLAGS ${_saved_cmake_required_flags}) 21 | endif ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") 22 | 23 | if (NOT HAVE_FCNTL_H) 24 | unset (WITH_PROXY CACHE) 25 | endif (NOT HAVE_FCNTL_H) 26 | -------------------------------------------------------------------------------- /.github/workflows/stales.yml: -------------------------------------------------------------------------------- 1 | name: 'Stale issues and pull requests with no recent activity' 2 | on: 3 | schedule: 4 | - cron: "15 00 * * *" 5 | 6 | permissions: 7 | issues: write 8 | pull-requests: write 9 | 10 | jobs: 11 | stale: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/stale@v4.1.0 15 | with: 16 | repo-token: ${{ secrets.GITHUB_TOKEN }} 17 | stale-issue-message: 'This issue has been marked as a stale issue because it has been open (more than) 45 days with no activity.' 18 | stale-pr-message: 'This pull request has been marked as a stale pull request because it has been open (more than) 45 days with no activity.' 19 | stale-issue-label: Stale 20 | stale-pr-label: Stale 21 | exempt-issue-labels: bug,enhancement 22 | exempt-pr-labels: bug,enhancement 23 | days-before-stale: 45 24 | remove-stale-when-updated: true 25 | remove-issue-stale-when-updated: true 26 | remove-pr-stale-when-updated: true 27 | days-before-close: -1 -------------------------------------------------------------------------------- /scripts/do_checkpatch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright (c) 2019 STMicroelectronics . 5 | # Copyright (c) 2015 Intel Corporation. 6 | # 7 | # SPDX-License-Identifier: Apache-2.0 8 | # 9 | 10 | res=$1 11 | [ -z "$res" ] && res="checkpatch_log" 12 | [ -f ${res} ] && rm ${res} 13 | [ -f ${res}_error.types ] && rm ${res}_error.types 14 | [ -f ${res}_warning.types ] && rm ${res}_warning.types 15 | 16 | dirs_to_check="lib" 17 | files=$(for d in ${dirs_to_check}; do find $d/ -type f -name '*.[ch]'; done) 18 | 19 | for i in $files; do 20 | ./scripts/checkpatch.pl --no-tree -f --emacs --summary-file --show-types --ignore BRACES,PRINTK_WITHOUT_KERN_LEVEL,SPLIT_STRING,PREFER_KERNEL_TYPES,NEW_TYPEDEFS --max-line-length=90 $i >> ${res} 21 | done 22 | grep ERROR: ${res} |cut -d : -f 3,4 |sort -u > ${res}_error.types 23 | grep WARNING: ${res} |cut -d : -f 3,4 |sort -u > ${res}_warning.types 24 | for i in `cat ${res}_error.types`; do 25 | echo -n $i ' '; grep $i ${res} | wc -l 26 | done 27 | for i in `cat ${res}_warning.types`; do 28 | echo -n $i ' '; grep $i ${res} | wc -l 29 | done 30 | -------------------------------------------------------------------------------- /doc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if (DOXYGEN_FOUND) 2 | 3 | if (EXISTS ${CMAKE_SOURCE_DIR}/../_doxygen/openamp/Doxyfile-openamp.in) 4 | set (OAMP_DOX_DIR ${CMAKE_SOURCE_DIR}/../_doxygen/openamp) 5 | configure_file (Doxyfile.in Doxyfile1 @ONLY) 6 | configure_file (${OAMP_DOX_DIR}/Doxyfile-openamp.in Doxyfile2 @ONLY) 7 | 8 | add_custom_target (doc ALL 9 | COMMAND cat Doxyfile1 Doxyfile2 >Doxyfile 10 | COMMAND ${DOXYGEN_EXECUTABLE} Doxyfile 11 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 12 | ) 13 | else () 14 | configure_file (Doxyfile.in Doxyfile @ONLY) 15 | 16 | add_custom_target (doc ALL 17 | ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile 18 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 19 | ) 20 | endif () 21 | 22 | install (DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html 23 | DESTINATION share/doc/${PROJECT_NAME}) 24 | install (FILES ${PROJECT_SOURCE_DIR}/README.md 25 | DESTINATION share/doc/${PROJECT_NAME}) 26 | install (FILES ${PROJECT_SOURCE_DIR}/LICENSE.md 27 | DESTINATION share/doc/${PROJECT_NAME}) 28 | 29 | endif (DOXYGEN_FOUND) 30 | -------------------------------------------------------------------------------- /.github/actions/build_ci/README.md: -------------------------------------------------------------------------------- 1 | # OpenAMP lib build check docker action 2 | 3 | This action test builds for a specified target. 4 | 5 | ## Inputs 6 | 7 | ### `target` 8 | 9 | **Required** the build target. Default `"linux"`. 10 | The supported targets are: 11 | linux 12 | generic arm 13 | zephyr 14 | 15 | 16 | ## Example usage 17 | 18 | Inside a github action use: 19 | ``` 20 | uses: ./.github/actions/build_ci 21 | with: 22 | target: linux 23 | ``` 24 | 25 | ## Desktop testing 26 | 27 | Right now the directory expectations of the CI script are very messy. 28 | This should be cleaned up in a future PR. 29 | 30 | Desktop testing is possible but is likewise messy right now. 31 | 32 | One time setup, starting in open-amp directory: 33 | ``` 34 | $ git clone https://github.com/OpenAMP/libmetal.git 35 | ``` 36 | 37 | A sequence like below will work, change the "zephyr" at the end of the docker command line to "linux" or "generic" for the other working tests 38 | ``` 39 | $ docker build -t openamp-ci .github/actions/build_ci/ && docker run -it --rm -v$PWD:/prj -w /prj openamp-ci zephyr 40 | $ sudo rm -rf build* zephyr* 41 | ``` 42 | -------------------------------------------------------------------------------- /cmake/modules/FindLibmetal.cmake: -------------------------------------------------------------------------------- 1 | # FindLibmetal 2 | # -------- 3 | # 4 | # Find Libmetal 5 | # 6 | # Find the native Libmetal includes and library this module defines 7 | # 8 | # :: 9 | # 10 | # LIBMETAL_INCLUDE_DIR, where to find metal/sysfs.h, etc. 11 | # LIBSYSFS_LIB_DIR, where to find libmetal library. 12 | 13 | # FIX ME, CMAKE_FIND_ROOT_PATH doesn't work 14 | # even use the following 15 | # set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) 16 | # set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) 17 | # set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH) 18 | find_path(LIBMETAL_INCLUDE_DIR NAMES metal/sys.h PATHS ${CMAKE_FIND_ROOT_PATH}) 19 | find_library(LIBMETAL_LIB NAMES metal PATHS ${CMAKE_FIND_ROOT_PATH}) 20 | get_filename_component(LIBMETAL_LIB_DIR ${LIBMETAL_LIB} DIRECTORY) 21 | 22 | # handle the QUIETLY and REQUIRED arguments and set HUGETLBFS_FOUND to TRUE if 23 | # all listed variables are TRUE 24 | include (FindPackageHandleStandardArgs) 25 | FIND_PACKAGE_HANDLE_STANDARD_ARGS (Libmetal DEFAULT_MSG LIBMETAL_LIB LIBMETAL_INCLUDE_DIR) 26 | 27 | if (LIBMETAL_FOUND) 28 | set (LIBMETAL_LIBS ${LIBMETAL_LIB}) 29 | endif (LIBMETAL_FOUND) 30 | 31 | mark_as_advanced (LIBMETAL_LIB LIBMETAL_INCLUDE_DIR LIBMETAL_LIB_DIR) 32 | -------------------------------------------------------------------------------- /cmake/collect.cmake: -------------------------------------------------------------------------------- 1 | function (collector_create name base) 2 | set_property (GLOBAL PROPERTY "COLLECT_${name}_LIST") 3 | set_property (GLOBAL PROPERTY "COLLECT_${name}_BASE" "${base}") 4 | endfunction (collector_create) 5 | 6 | function (collector_list var name) 7 | get_property (_list GLOBAL PROPERTY "COLLECT_${name}_LIST") 8 | set (${var} "${_list}" PARENT_SCOPE) 9 | endfunction (collector_list) 10 | 11 | function (collector_base var name) 12 | get_property (_base GLOBAL PROPERTY "COLLECT_${name}_BASE") 13 | set (${var} "${_base}" PARENT_SCOPE) 14 | endfunction (collector_base) 15 | 16 | function (collect name) 17 | collector_base (_base ${name}) 18 | string(COMPARE NOTEQUAL "${_base}" "" _is_rel) 19 | set (_list) 20 | foreach (s IN LISTS ARGN) 21 | if (_is_rel) 22 | get_filename_component (s "${s}" ABSOLUTE) 23 | file (RELATIVE_PATH s "${_base}" "${s}") 24 | else (_is_rel) 25 | get_filename_component (ts "${s}" ABSOLUTE) 26 | if (EXISTS "${ts}") 27 | set (s "${ts}") 28 | endif (EXISTS "${ts}") 29 | endif (_is_rel) 30 | list (APPEND _list "${s}") 31 | endforeach () 32 | set_property (GLOBAL APPEND PROPERTY "COLLECT_${name}_LIST" "${_list}") 33 | endfunction (collect) 34 | 35 | # Create global collectors 36 | collector_create (PROJECT_INC_DIRS "") 37 | collector_create (PROJECT_LIB_DIRS "") 38 | collector_create (PROJECT_LIB_DEPS "") 39 | -------------------------------------------------------------------------------- /lib/remoteproc/rsc_table_parser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Mentor Graphics Corporation 3 | * All rights reserved. 4 | * 5 | * SPDX-License-Identifier: BSD-3-Clause 6 | */ 7 | 8 | #ifndef RSC_TABLE_PARSER_H 9 | #define RSC_TABLE_PARSER_H 10 | 11 | #include 12 | 13 | #if defined __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | /** 18 | * @internal 19 | * 20 | * @brief This function parses resource table. 21 | * 22 | * @param rproc Pointer to remote remoteproc 23 | * @param rsc_table Resource table to parse 24 | * @param len Size of rsc table 25 | * @param io Pointer to the resource table I/O region 26 | * It can be NULL if the resource table 27 | * is in the local memory. 28 | * 29 | * @return Execution status 30 | */ 31 | int handle_rsc_table(struct remoteproc *rproc, 32 | struct resource_table *rsc_table, size_t len, 33 | struct metal_io_region *io); 34 | 35 | /** 36 | * @internal 37 | * 38 | * @brief Find out location of a resource type in the resource table. 39 | * 40 | * @param rsc_table Pointer to the resource table 41 | * @param rsc_type Type of the resource 42 | * @param index Index of the resource of the specified type 43 | * 44 | * @return The offset to the resource on success, or 0 on failure 45 | */ 46 | size_t find_rsc(void *rsc_table, unsigned int rsc_type, unsigned int index); 47 | 48 | #if defined __cplusplus 49 | } 50 | #endif 51 | 52 | #endif /* RSC_TABLE_PARSER_H */ 53 | -------------------------------------------------------------------------------- /lib/include/internal/utilities.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-3-Clause 3 | * 4 | * Copyright (c) 2024, STMicroelectronics 5 | * 6 | */ 7 | 8 | #include 9 | 10 | /** 11 | * @internal 12 | * 13 | * @brief Copies a string to a destination buffer with size limitation and returns the length of 14 | * the destination string. 15 | * 16 | * This function copies up to `s_size - 1` characters from the source string `src` 17 | * to the destination buffer `dst`, ensuring that the destination buffer is 18 | * null-terminated. The function returns the length of the `dst` string. 19 | * If the length of `src` string is greater than or equal to `d_size`, the destination 20 | * buffer will be truncated. 21 | * 22 | * @param dst Destination buffer where the string will be copied. 23 | * @param d_size Size of the destination buffer. 24 | * @param src Source string to be copied. 25 | * @param s_size Size of the source buffer. 26 | * @return The length of the string contained in the `dst` buffer. 27 | * 28 | * @note If the size of the destination buffer is 0, the function does not copy any characters and 29 | * the destination buffer is not null-terminated. 30 | * @note The function ensures that the destination buffer is always null-terminated if `size` is 31 | * greater than 0. 32 | * @note The function ensures that no data is read past the end of the 'src' buffer. 33 | */ 34 | size_t safe_strcpy(char *dst, size_t d_size, const char *src, size_t s_size); 35 | 36 | -------------------------------------------------------------------------------- /.github/workflows/heathcheck.yml: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright (c) 2024 Linaro Limited. 3 | 4 | # The focus of this flow is to check for external changes that will effect 5 | # the project. Even if no code changes are happening, changes in external 6 | # distros or projects can invalidate our work and this flow lets us know 7 | 8 | name: open-amp Heath Check 9 | 10 | on: 11 | push: 12 | branches: [ main ] 13 | pull_request: 14 | branches: [ main ] 15 | paths-ignore: 16 | - docs/** 17 | 18 | # Allows you to run this workflow manually from the Actions tab or gh API 19 | workflow_dispatch: 20 | 21 | # run weekly on Sunday at 5:10 AM UTC (9:10 PM US western) 22 | schedule: 23 | - cron: '10 5 * * 0' 24 | 25 | jobs: 26 | zephyr_build_main: 27 | name: 'Zephyr build from latest on main' 28 | runs-on: ubuntu-latest 29 | steps: 30 | - name: Free Disk Space (Ubuntu) 31 | uses: jlumbroso/free-disk-space@main 32 | with: 33 | # this might remove tools that are actually needed, 34 | # if set to "true" but frees about 6 GB 35 | tool-cache: false 36 | android: true 37 | dotnet: true 38 | haskell: true 39 | large-packages: true 40 | docker-images: true 41 | swap-storage: true 42 | - name: Checkout open-amp 43 | uses: actions/checkout@v4 44 | with: 45 | path: open-amp 46 | - name: Checkout libmetal 47 | uses: actions/checkout@v4 48 | with: 49 | repository: OpenAMP/libmetal 50 | path: libmetal 51 | - name: Checkout openamp-system-reference 52 | uses: actions/checkout@v4 53 | with: 54 | repository: OpenAMP/openamp-system-reference 55 | path: openamp-system-reference 56 | - name: Zephyr Latest 57 | id: build_Zephyr_latest 58 | uses: ./open-amp/.github/actions/build_ci 59 | with: 60 | target: zephyr-latest 61 | -------------------------------------------------------------------------------- /.github/workflows/compliance.yml: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright (c) 2020 STMicroelectronics 3 | 4 | name: open-amp lib compliance checks 5 | 6 | on: 7 | pull_request: 8 | branches: [ main ] 9 | paths-ignore: 10 | - docs/** 11 | - cmake/** 12 | - scripts/** 13 | - .github/** 14 | 15 | jobs: 16 | checkpatch_review: 17 | name: checkpatch review 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Checkout the code 21 | uses: actions/checkout@v4 22 | with: 23 | ref: ${{ github.event.pull_request.head.sha }} 24 | fetch-depth: 0 25 | - name: Install python dependencies 26 | run: | 27 | pip3 install setuptools 28 | pip3 install python-magic junitparser gitlint codespell lxml 29 | - name: Run Compliance Tests 30 | continue-on-error: true 31 | id: compliance 32 | env: 33 | BASE_REF: ${{ github.base_ref }} 34 | run: | 35 | export PATH=$PATH:~/.local/bin 36 | export PROJECT_BASE=$PWD 37 | git config --global user.email "you@example.com" 38 | git config --global user.name "Your Name" 39 | git rebase origin/${BASE_REF} 40 | git log --pretty=oneline | head -n 10 41 | ./scripts/ci/check_compliance.py --annotate -c origin/${BASE_REF}.. 42 | 43 | - name: upload-results 44 | uses: actions/upload-artifact@main 45 | continue-on-error: True 46 | with: 47 | name: compliance.xml 48 | path: compliance.xml 49 | 50 | - name: check-warns 51 | run: | 52 | if [[ ! -s "compliance.xml" ]]; then 53 | exit 1; 54 | fi 55 | 56 | files=($(./scripts/ci/check_compliance.py -l)) 57 | for file in "${files[@]}"; do 58 | f="${file}.txt" 59 | if [[ -s $f ]]; then 60 | errors=$(cat $f) 61 | errors="${errors//'%'/'%25'}" 62 | errors="${errors//$'\n'/'%0A'}" 63 | errors="${errors//$'\r'/'%0D'}" 64 | echo "::error file=${f}::$errors" 65 | exit=1 66 | fi 67 | done 68 | 69 | if [ "${exit}" == "1" ]; then 70 | exit 1; 71 | fi 72 | -------------------------------------------------------------------------------- /lib/include/openamp/version.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, STMicroelectronics. 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | */ 6 | 7 | /* 8 | * @file version.h 9 | * @brief Library version information for OpenAMP. 10 | */ 11 | 12 | #ifndef __OPENAMP_VERSION__H__ 13 | #define __OPENAMP_VERSION__H__ 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | /** \defgroup versions Library Version Interfaces 20 | * @{ 21 | */ 22 | 23 | /** 24 | * @brief Library major version number. 25 | * 26 | * Return the major version number of the library linked into the application. 27 | * This is required to match the value of LIB_VERSION_MAJOR, which is the major 28 | * version of the library that the application was compiled against. 29 | * 30 | * @return Library major version number. 31 | * 32 | * @see PROJECT_VERSION_MAJOR 33 | */ 34 | extern int openamp_version_major(void); 35 | 36 | /** 37 | * @brief Library minor version number. 38 | * 39 | * Return the minor version number of the library linked into the application. 40 | * This could differ from the value of LIB_VERSION_MINOR, which is the minor 41 | * version of the library that the application was compiled against. 42 | * 43 | * @return Library minor version number. 44 | * 45 | * @see PROJECT_VERSION_MINOR 46 | */ 47 | extern int openamp_version_minor(void); 48 | 49 | /** 50 | * @brief Library patch level. 51 | * 52 | * Return the patch level of the library linked into the application. This 53 | * could differ from the value of LIB_VERSION_PATCH, which is the patch level of 54 | * the library that the application was compiled against. 55 | * 56 | * @return Library patch level. 57 | * 58 | * @see PROJECT_VERSION_PATCH 59 | */ 60 | extern int openamp_version_patch(void); 61 | 62 | /** 63 | * @brief Library version string. 64 | * 65 | * Return the version string of the library linked into the application. This 66 | * could differ from the value of LIB_VERSION, which is the version string of 67 | * the library that the application was compiled against. 68 | * 69 | * @return Library version string. 70 | * 71 | * @see PROJECT_VERSION 72 | */ 73 | extern const char *openamp_version(void); 74 | 75 | /** @} */ 76 | 77 | #ifdef __cplusplus 78 | } 79 | #endif 80 | 81 | #endif /* __OPENAMP_VERSION__H__ */ 82 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # The main readthedocs build is in openamp-docs and includes this repo as a 2 | # sub-module. 3 | 4 | # This config file supports doc preview for PRs in this repo. 5 | # This allows us to see how a PR in this repo will look in the docs before it 6 | # is promoted to main and before the openamp-docs repo picks up the new version. 7 | 8 | version: 2 9 | # only do html, this is the case for PRs anyway but make sure 10 | formats: [] 11 | sphinx: 12 | # See comments in the file for why this is required 13 | configuration: doc/readthedocs-conf.py 14 | build: 15 | os: "ubuntu-22.04" 16 | tools: 17 | python: "3.10" 18 | apt_packages: 19 | - cmake 20 | - libhugetlbfs-dev 21 | - libsysfs-dev 22 | jobs: 23 | post_checkout: 24 | - echo "post_checkout"; pwd; echo $PATH; env; ls -la . 25 | # we ignore the checkout they did and make a new one of the whole openamp-docs project 26 | - git log -n 1 --oneline 27 | - git rev-parse HEAD 28 | - git clone --recurse-submodules https://github.com/OpenAMP/openamp-docs.git 29 | # now adjust the focused submodule to the PR in progress 30 | - echo "URL=${READTHEDOCS_GIT_CLONE_URL} COMMIT=${READTHEDOCS_GIT_COMMIT_HASH}" 31 | - (cd openamp-docs/open-amp; git remote add this_pr ../../.git ) 32 | - (cd openamp-docs/open-amp; git fetch this_pr $(cd ../..; git rev-parse HEAD) ) 33 | - (cd openamp-docs/open-amp; git checkout $(cd ../..; git rev-parse HEAD) ) 34 | - (cd openamp-docs/open-amp; git log -n 1 --oneline) 35 | - (cd openamp-docs; git submodule status) 36 | post_install: 37 | - echo "post_install"; pwd; echo $PATH; env; ls -la . openamp-docs 38 | - python -m pip install --exists-action=w --no-cache-dir -r openamp-docs/requirements.txt 39 | pre_build: 40 | - echo "pre_build"; pwd; echo $PATH; env; ls -la . openamp-docs 41 | - echo "READTHEDOCS_OUTPUT=$READTHEDOCS_OUTPUT" 42 | - make -C openamp-docs BUILDDIR=$READTHEDOCS_OUTPUT doxygen 43 | build: 44 | html: 45 | - echo "build"; pwd; echo $PATH; env; ls -la . openamp-docs 46 | # This is the default build command as of 2025/01/12 but with 47 | # "." changed to "openamp-docs" 48 | - python -m sphinx -T -b html -d _build/doctrees -D language=en openamp-docs $READTHEDOCS_OUTPUT/html 49 | post_build: 50 | - echo "post_build"; pwd; echo $PATH; ls -la . openamp-docs 51 | - make -C openamp-docs BUILDDIR=$READTHEDOCS_OUTPUT doxygen_copy 52 | -------------------------------------------------------------------------------- /.github/workflows/continuous-integration.yml: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: BSD-3-Clause 2 | # Copyright (c) 2020 STMicroelectronics 3 | 4 | name: open-amp lib Continuous Integration 5 | 6 | on: 7 | push: 8 | branches: [ main ] 9 | paths-ignore: 10 | - docs/** 11 | - cmake/** 12 | - scripts/** 13 | pull_request: 14 | branches: [ main ] 15 | paths-ignore: 16 | - docs/** 17 | - cmake/** 18 | - scripts/** 19 | 20 | jobs: 21 | platform_builds: 22 | name: check builds on different platforms 23 | runs-on: ubuntu-latest 24 | steps: 25 | - name: Checkout open-amp 26 | uses: actions/checkout@v4 27 | with: 28 | path: open-amp 29 | - name: Checkout libmetal 30 | uses: actions/checkout@v4 31 | with: 32 | repository: OpenAMP/libmetal 33 | path: libmetal 34 | - name: Checkout openamp-system-reference 35 | uses: actions/checkout@v4 36 | with: 37 | repository: OpenAMP/openamp-system-reference 38 | path: openamp-system-reference 39 | - name: build for Linux 40 | id: build_linux 41 | uses: ./open-amp/.github/actions/build_ci 42 | with: 43 | target: linux 44 | - name: build for generic arm 45 | id: build_generic 46 | uses: ./open-amp/.github/actions/build_ci 47 | with: 48 | target: generic 49 | 50 | # Break the zephyr builds into their own job as the common runner was 51 | # running out of space when runs were together 52 | # Also, as the longest running jobs, this allows them to run in || 53 | zephyr_build_known_good_version: 54 | name: Zephyr build with a version that is known to work 55 | runs-on: ubuntu-latest 56 | steps: 57 | - name: Free Disk Space (Ubuntu) 58 | uses: jlumbroso/free-disk-space@main 59 | with: 60 | # this might remove tools that are actually needed, 61 | # if set to "true" but frees about 6 GB 62 | tool-cache: false 63 | android: true 64 | dotnet: true 65 | haskell: true 66 | large-packages: true 67 | docker-images: true 68 | swap-storage: true 69 | - name: Checkout open-amp 70 | uses: actions/checkout@v4 71 | with: 72 | path: open-amp 73 | - name: Checkout libmetal 74 | uses: actions/checkout@v4 75 | with: 76 | repository: OpenAMP/libmetal 77 | path: libmetal 78 | - name: Checkout openamp-system-reference 79 | uses: actions/checkout@v4 80 | with: 81 | repository: OpenAMP/openamp-system-reference 82 | path: openamp-system-reference 83 | - name: build for Zephyr (Known Good) 84 | id: build_Zephyr 85 | uses: ./open-amp/.github/actions/build_ci 86 | with: 87 | target: zephyr 88 | -------------------------------------------------------------------------------- /lib/service/rpmsg/rpc/rpmsg_rpc_server.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, L&T Technology Services Ltd. 3 | * All rights reserved. 4 | * 5 | * SPDX-License-Identifier: BSD-3-Clause 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | #define LPERROR(format, ...) metal_log(METAL_LOG_ERROR, format, ##__VA_ARGS__) 12 | 13 | static int rpmsg_endpoint_server_cb(struct rpmsg_endpoint *, void *, 14 | size_t, uint32_t, void *); 15 | 16 | int rpmsg_rpc_server_init(struct rpmsg_rpc_svr *rpcs, struct rpmsg_device *rdev, 17 | const struct rpmsg_rpc_services *services, int len, 18 | rpmsg_ns_unbind_cb rpmsg_service_server_unbind) 19 | { 20 | int ret; 21 | 22 | rpcs->services = services; 23 | rpcs->n_services = len; 24 | 25 | ret = rpmsg_create_ept(&rpcs->ept, rdev, RPMSG_RPC_SERVICE_NAME, 26 | RPMSG_ADDR_ANY, RPMSG_ADDR_ANY, 27 | rpmsg_endpoint_server_cb, 28 | rpmsg_service_server_unbind); 29 | if (ret) 30 | return ret; 31 | 32 | return ret; 33 | } 34 | 35 | static const struct rpmsg_rpc_services *find_service(struct rpmsg_rpc_svr *rpcs, 36 | unsigned int id) 37 | { 38 | const struct rpmsg_rpc_services *service; 39 | 40 | for (unsigned int i = 0; i < rpcs->n_services; i++) { 41 | service = &rpcs->services[i]; 42 | 43 | if (service->id == id) { 44 | return service; 45 | } 46 | } 47 | return NULL; 48 | } 49 | 50 | static int rpmsg_endpoint_server_cb(struct rpmsg_endpoint *ept, void *data, 51 | size_t len, 52 | uint32_t src, void *priv) 53 | { 54 | unsigned char buf[MAX_BUF_LEN]; 55 | unsigned int id; 56 | const struct rpmsg_rpc_services *service; 57 | struct rpmsg_rpc_svr *rpcs; 58 | (void)priv; 59 | (void)src; 60 | 61 | if (len > MAX_BUF_LEN) 62 | return -EINVAL; 63 | 64 | rpcs = metal_container_of(ept, struct rpmsg_rpc_svr, ept); 65 | 66 | memcpy(buf, data, len); 67 | id = *buf; 68 | service = find_service(rpcs, id); 69 | 70 | if (service) { 71 | if (service->cb_function(buf, rpcs)) { 72 | LPERROR("Service failed at rpc id: %ld\r\n", id); 73 | } 74 | } else { 75 | LPERROR("Handling remote procedure call errors: rpc id %ld\r\n", 76 | id); 77 | rpmsg_rpc_server_send(rpcs, id, RPMSG_RPC_INVALID_ID, NULL, 0); 78 | } 79 | return RPMSG_SUCCESS; 80 | } 81 | 82 | int rpmsg_rpc_server_send(struct rpmsg_rpc_svr *rpcs, uint32_t rpc_id, 83 | int status, void *request_param, size_t param_size) 84 | { 85 | struct rpmsg_endpoint *ept = &rpcs->ept; 86 | struct rpmsg_rpc_answer msg; 87 | 88 | if (!ept) 89 | return -EINVAL; 90 | if (param_size > (MAX_BUF_LEN - sizeof(msg.status))) 91 | return -EINVAL; 92 | 93 | msg.id = rpc_id; 94 | msg.status = status; 95 | memcpy(msg.params, request_param, param_size); 96 | 97 | return rpmsg_send(ept, &msg, MAX_FUNC_ID_LEN + param_size); 98 | } 99 | -------------------------------------------------------------------------------- /lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | set_property (GLOBAL PROPERTY "PROJECT_LIB_EXTRA_CFLAGS") 3 | 4 | collector_create (PROJECT_LIB_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}") 5 | collect (PROJECT_LIB_DIRS "${CMAKE_CURRENT_BINARY_DIR}") 6 | collect (PROJECT_INC_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/include") 7 | collect (PROJECT_LIB_SOURCES version.c) 8 | 9 | 10 | add_subdirectory (virtio) 11 | add_subdirectory (rpmsg) 12 | add_subdirectory (remoteproc) 13 | add_subdirectory (utils) 14 | if (WITH_VIRTIO_MMIO_DRV) 15 | add_subdirectory (virtio_mmio) 16 | endif (WITH_VIRTIO_MMIO_DRV) 17 | 18 | if (WITH_PROXY) 19 | add_subdirectory (proxy) 20 | add_subdirectory (service/rpmsg/rpc) 21 | endif (WITH_PROXY) 22 | 23 | set (OPENAMP_LIB open_amp) 24 | 25 | configure_file(version.h.in ${PROJECT_BINARY_DIR}/include/generated/openamp/version_def.h) 26 | collect (PROJECT_INC_DIRS " ${PROJECT_BINARY_DIR}/include/generated/openamp") 27 | collect (PROJECT_INC_DIRS " ${PROJECT_BINARY_DIR}/include/internal") 28 | 29 | if (NOT CMAKE_INSTALL_LIBDIR) 30 | set (CMAKE_INSTALL_LIBDIR "lib") 31 | endif (NOT CMAKE_INSTALL_LIBDIR) 32 | 33 | collector_list (_include PROJECT_INC_DIRS) 34 | include_directories (${_include}) 35 | 36 | collector_list (_deps PROJECT_LIB_DEPS) 37 | 38 | get_property (_ecflags GLOBAL PROPERTY "PROJECT_LIB_EXTRA_CFLAGS") 39 | 40 | collector_list (_sources PROJECT_LIB_SOURCES) 41 | set_property (SOURCE ${_sources} 42 | APPEND_STRING PROPERTY COMPILE_FLAGS " ${_ecflags}") 43 | 44 | # Build a shared library if so configured. 45 | if (WITH_ZEPHYR) 46 | zephyr_library_named(${OPENAMP_LIB}) 47 | add_dependencies(${ZEPHYR_CURRENT_LIBRARY} ${OFFSETS_H_TARGET}) 48 | zephyr_library_sources(${_sources}) 49 | zephyr_include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) 50 | else (WITH_ZEPHYR) 51 | if (WITH_SHARED_LIB) 52 | set (_lib ${OPENAMP_LIB}-shared) 53 | add_library (${_lib} SHARED ${_sources}) 54 | target_link_libraries (${_lib} ${_deps}) 55 | install (TARGETS ${_lib} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) 56 | set_target_properties (${_lib} PROPERTIES 57 | OUTPUT_NAME "${OPENAMP_LIB}" 58 | VERSION "${PROJECT_VERSION}" 59 | SOVERSION "${PROJECT_VERSION_MAJOR}" 60 | ) 61 | endif (WITH_SHARED_LIB) 62 | 63 | if (WITH_STATIC_LIB) 64 | set (_lib ${OPENAMP_LIB}-static) 65 | add_library (${_lib} STATIC ${_sources}) 66 | target_include_directories(${_lib} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) 67 | install (TARGETS ${_lib} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) 68 | set_target_properties (${_lib} PROPERTIES 69 | OUTPUT_NAME "${OPENAMP_LIB}" 70 | ) 71 | endif (WITH_STATIC_LIB) 72 | endif (WITH_ZEPHYR) 73 | 74 | install (DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/openamp" DESTINATION include) 75 | install (DIRECTORY "${PROJECT_BINARY_DIR}/include/generated/openamp" DESTINATION include) 76 | -------------------------------------------------------------------------------- /lib/virtio/virtio.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2011, Bryan Venteicher 3 | * All rights reserved. 4 | * 5 | * SPDX-License-Identifier: BSD-2-Clause 6 | */ 7 | 8 | #include 9 | 10 | /* 11 | * TODO : 12 | * This structure may change depending on the types of devices we support. 13 | */ 14 | static const struct virtio_ident { 15 | unsigned short devid; 16 | const char *name; 17 | } virtio_ident_table[] = { 18 | { 19 | VIRTIO_ID_NETWORK, "Network"}, { 20 | VIRTIO_ID_BLOCK, "Block"}, { 21 | VIRTIO_ID_CONSOLE, "Console"}, { 22 | VIRTIO_ID_ENTROPY, "Entropy"}, { 23 | VIRTIO_ID_BALLOON, "Balloon"}, { 24 | VIRTIO_ID_IOMEMORY, "IOMemory"}, { 25 | VIRTIO_ID_SCSI, "SCSI"}, { 26 | VIRTIO_ID_9P, "9P Transport"}, { 27 | VIRTIO_ID_MAC80211_WLAN, "MAC80211 WLAN"}, { 28 | VIRTIO_ID_RPROC_SERIAL, "Remoteproc Serial"}, { 29 | VIRTIO_ID_GPU, "GPU"}, { 30 | VIRTIO_ID_INPUT, "Input"}, { 31 | VIRTIO_ID_VSOCK, "Vsock Transport"}, { 32 | VIRTIO_ID_SOUND, "Sound"}, { 33 | VIRTIO_ID_FS, "File System"}, { 34 | VIRTIO_ID_MAC80211_HWSIM, "MAC80211 HWSIM"}, { 35 | VIRTIO_ID_I2C_ADAPTER, "I2C Adapter"}, { 36 | VIRTIO_ID_BT, "Bluetooth"}, { 37 | VIRTIO_ID_GPIO, "GPIO" }, { 38 | 0, NULL} 39 | }; 40 | 41 | const char *virtio_dev_name(unsigned short devid) 42 | { 43 | const struct virtio_ident *ident; 44 | 45 | for (ident = virtio_ident_table; ident->name; ident++) { 46 | if (ident->devid == devid) 47 | return ident->name; 48 | } 49 | 50 | return NULL; 51 | } 52 | 53 | int virtio_create_virtqueues(struct virtio_device *vdev, unsigned int flags, 54 | unsigned int nvqs, const char *names[], 55 | vq_callback callbacks[], void *callback_args[]) 56 | { 57 | struct virtio_vring_info *vring_info; 58 | struct vring_alloc_info *vring_alloc; 59 | unsigned int num_vrings, i; 60 | int ret; 61 | (void)flags; 62 | 63 | if (!vdev) 64 | return -EINVAL; 65 | 66 | if (vdev->func && vdev->func->create_virtqueues) { 67 | return vdev->func->create_virtqueues(vdev, flags, nvqs, 68 | names, callbacks, callback_args); 69 | } 70 | 71 | num_vrings = vdev->vrings_num; 72 | if (nvqs > num_vrings) 73 | return ERROR_VQUEUE_INVLD_PARAM; 74 | /* Initialize virtqueue for each vring */ 75 | for (i = 0; i < nvqs; i++) { 76 | vring_info = &vdev->vrings_info[i]; 77 | 78 | vring_alloc = &vring_info->info; 79 | if (VIRTIO_ROLE_IS_DRIVER(vdev)) { 80 | size_t offset; 81 | struct metal_io_region *io = vring_info->io; 82 | 83 | offset = metal_io_virt_to_offset(io, 84 | vring_alloc->vaddr); 85 | metal_io_block_set(io, offset, 0, 86 | vring_size(vring_alloc->num_descs, 87 | vring_alloc->align)); 88 | } 89 | ret = virtqueue_create(vdev, i, names[i], vring_alloc, 90 | callbacks[i], vdev->func->notify, 91 | vring_info->vq); 92 | if (ret) 93 | return ret; 94 | } 95 | return 0; 96 | } 97 | 98 | -------------------------------------------------------------------------------- /lib/service/rpmsg/rpc/rpmsg_rpc_client.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, L&T Technology Services Ltd. 3 | * All rights reserved. 4 | * 5 | * SPDX-License-Identifier: BSD-3-Clause 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | static int rpmsg_endpoint_client_cb(struct rpmsg_endpoint *, void *, size_t, 12 | uint32_t, void *); 13 | 14 | static void rpmsg_service_client_unbind(struct rpmsg_endpoint *ept) 15 | { 16 | struct rpmsg_rpc_clt *rpc; 17 | (void)ept; 18 | 19 | rpc = metal_container_of(ept, struct rpmsg_rpc_clt, ept); 20 | rpmsg_destroy_ept(&rpc->ept); 21 | if (rpc->shutdown_cb) 22 | rpc->shutdown_cb(rpc); 23 | } 24 | 25 | int rpmsg_rpc_client_init(struct rpmsg_rpc_clt *rpc, 26 | struct rpmsg_device *rdev, 27 | rpmsg_rpc_shutdown_cb shutdown_cb, 28 | const struct rpmsg_rpc_client_services *services, 29 | int len) 30 | { 31 | int ret; 32 | 33 | if (!rpc || !rdev) 34 | return -EINVAL; 35 | 36 | rpc->services = services; 37 | rpc->n_services = len; 38 | 39 | rpc->shutdown_cb = shutdown_cb; 40 | 41 | ret = rpmsg_create_ept(&rpc->ept, rdev, 42 | RPMSG_RPC_SERVICE_NAME, RPMSG_ADDR_ANY, 43 | RPMSG_ADDR_ANY, 44 | rpmsg_endpoint_client_cb, 45 | rpmsg_service_client_unbind); 46 | 47 | return ret; 48 | } 49 | 50 | int rpmsg_rpc_client_send(struct rpmsg_rpc_clt *rpc, 51 | uint32_t rpc_id, void *request_param, 52 | size_t req_param_size) 53 | { 54 | unsigned char tmpbuf[MAX_BUF_LEN]; 55 | 56 | if (!rpc) 57 | return -EINVAL; 58 | 59 | /* to optimize with the zero copy API */ 60 | memcpy(tmpbuf, &rpc_id, MAX_FUNC_ID_LEN); 61 | memcpy(&tmpbuf[MAX_FUNC_ID_LEN], request_param, req_param_size); 62 | return rpmsg_send(&rpc->ept, tmpbuf, MAX_FUNC_ID_LEN + req_param_size); 63 | } 64 | 65 | static const struct rpmsg_rpc_client_services *find_service(struct 66 | rpmsg_rpc_clt * rpc, 67 | uint32_t id) 68 | { 69 | const struct rpmsg_rpc_client_services *service; 70 | 71 | for (unsigned int i = 0; i < rpc->n_services; i++) { 72 | service = &rpc->services[i]; 73 | 74 | if (service->id == id) { 75 | return service; 76 | } 77 | } 78 | return NULL; 79 | } 80 | 81 | void rpmsg_rpc_client_release(struct rpmsg_rpc_clt *rpc) 82 | { 83 | if (!rpc) 84 | return; 85 | rpmsg_destroy_ept(&rpc->ept); 86 | 87 | } 88 | 89 | static int rpmsg_endpoint_client_cb(struct rpmsg_endpoint *ept, 90 | void *data, size_t len, 91 | uint32_t src, void *priv) 92 | { 93 | struct rpmsg_rpc_clt *rpc; 94 | const struct rpmsg_rpc_client_services *service; 95 | struct rpmsg_rpc_answer *msg; 96 | (void)priv; 97 | (void)src; 98 | 99 | if (!data || !ept) 100 | return -EINVAL; 101 | 102 | msg = (struct rpmsg_rpc_answer *)data; 103 | 104 | rpc = metal_container_of(ept, 105 | struct rpmsg_rpc_clt, 106 | ept); 107 | service = find_service(rpc, msg->id); 108 | if (!service) 109 | return -EINVAL; 110 | 111 | /* Invoke the callback function of the rpc */ 112 | service->cb(rpc, msg->status, msg->params, len); 113 | 114 | return RPMSG_SUCCESS; 115 | } 116 | -------------------------------------------------------------------------------- /lib/include/openamp/remoteproc_loader.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Mentor Graphics Corporation 3 | * All rights reserved. 4 | * 5 | * SPDX-License-Identifier: BSD-3-Clause 6 | */ 7 | 8 | /************************************************************************** 9 | * FILE NAME 10 | * 11 | * remoteproc_loader.h 12 | * 13 | * COMPONENT 14 | * 15 | * OpenAMP stack. 16 | * 17 | * DESCRIPTION 18 | * 19 | * This file provides definitions for remoteproc loader 20 | * 21 | * 22 | **************************************************************************/ 23 | #ifndef REMOTEPROC_LOADER_H_ 24 | #define REMOTEPROC_LOADER_H_ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #if defined __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | /* Loader feature macros */ 36 | #define SUPPORT_SEEK 1UL 37 | 38 | /* Remoteproc loader any address */ 39 | #define RPROC_LOAD_ANYADDR ((metal_phys_addr_t)-1) 40 | 41 | /* Remoteproc loader Executable Image Parsing States */ 42 | /* Remoteproc loader parser initial state */ 43 | #define RPROC_LOADER_NOT_READY 0x0L 44 | /* Remoteproc loader ready to load, even it can be not finish parsing */ 45 | #define RPROC_LOADER_READY_TO_LOAD 0x10000L 46 | /* Remoteproc loader post data load */ 47 | #define RPROC_LOADER_POST_DATA_LOAD 0x20000L 48 | /* Remoteproc loader finished loading */ 49 | #define RPROC_LOADER_LOAD_COMPLETE 0x40000L 50 | /* Remoteproc loader state mask */ 51 | #define RPROC_LOADER_MASK 0x00FF0000L 52 | /* Remoteproc loader private mask */ 53 | #define RPROC_LOADER_PRIVATE_MASK 0x0000FFFFL 54 | /* Remoteproc loader reserved mask */ 55 | #define RPROC_LOADER_RESERVED_MASK 0x0F000000L 56 | 57 | /** @brief User-defined image store operations */ 58 | struct image_store_ops { 59 | /** User-defined callback to open the "firmware" to prepare loading */ 60 | int (*open)(void *store, const char *path, const void **img_data); 61 | 62 | /** User-defined callback to close the "firmware" to clean up after loading */ 63 | void (*close)(void *store); 64 | 65 | /** User-defined callback to load the firmware contents to target memory or local memory */ 66 | int (*load)(void *store, size_t offset, size_t size, 67 | const void **data, 68 | metal_phys_addr_t pa, 69 | struct metal_io_region *io, char is_blocking); 70 | 71 | /** Loader supported features. e.g. seek */ 72 | unsigned int features; 73 | }; 74 | 75 | /** @brief Loader operations */ 76 | struct loader_ops { 77 | /** Define how to get the executable headers */ 78 | int (*load_header)(const void *img_data, size_t offset, size_t len, 79 | void **img_info, int last_state, 80 | size_t *noffset, size_t *nlen); 81 | 82 | /** Define how to load the target data */ 83 | int (*load_data)(struct remoteproc *rproc, 84 | const void *img_data, size_t offset, size_t len, 85 | void **img_info, int last_load_state, 86 | metal_phys_addr_t *da, 87 | size_t *noffset, size_t *nlen, 88 | unsigned char *padding, size_t *nmemsize); 89 | 90 | /** 91 | * Define how to get the resource table target address, offset to the ELF 92 | * image file and size of the resource table 93 | */ 94 | int (*locate_rsc_table)(void *img_info, metal_phys_addr_t *da, 95 | size_t *offset, size_t *size); 96 | 97 | /** Define how to release the loader */ 98 | void (*release)(void *img_info); 99 | 100 | /** Get entry address */ 101 | metal_phys_addr_t (*get_entry)(void *img_info); 102 | 103 | /** Get load state from the image information */ 104 | int (*get_load_state)(void *img_info); 105 | }; 106 | 107 | #if defined __cplusplus 108 | } 109 | #endif 110 | 111 | #endif /* REMOTEPROC_LOADER_H_ */ 112 | -------------------------------------------------------------------------------- /.gitlint: -------------------------------------------------------------------------------- 1 | # All these sections are optional, edit this file as you like. 2 | [general] 3 | # Ignore certain rules, you can reference them by their id or by their full name 4 | ignore=title-trailing-punctuation, T3, title-max-length, T1, body-hard-tab, B1, B3 5 | 6 | # verbosity should be a value between 1 and 3, the commandline -v flags take precedence over this 7 | verbosity = 3 8 | 9 | # By default gitlint will ignore merge commits. Set to 'false' to disable. 10 | ignore-merge-commits=true 11 | 12 | # By default gitlint will ignore fixup commits. Set to 'false' to disable. 13 | # ignore-fixup-commits=false 14 | 15 | # By default gitlint will ignore squash commits. Set to 'false' to disable. 16 | # ignore-squash-commits=true 17 | 18 | # Ignore any data send to gitlint via stdin 19 | # ignore-stdin=true 20 | 21 | # Enable debug mode (prints more output). Disabled by default. 22 | debug=true 23 | 24 | # Enable community contributed rules 25 | # See http://jorisroovers.github.io/gitlint/contrib_rules for details 26 | # contrib=contrib-title-conventional-commits,CC1 27 | 28 | # Set the extra-path where gitlint will search for user defined rules 29 | # See http://jorisroovers.github.io/gitlint/user_defined_rules for details 30 | extra-path=scripts/gitlint 31 | 32 | [title-max-length] 33 | line-length=75 34 | 35 | [body-min-line-count] 36 | min-line-count=1 37 | 38 | [body-max-line-count] 39 | max-line-count=200 40 | 41 | [title-must-not-contain-word] 42 | # Comma-separated list of words that should not occur in the title. Matching is case 43 | # insensitive. It's fine if the keyword occurs as part of a larger word (so "WIPING" 44 | # will not cause a violation, but "WIP: my title" will. 45 | words=wip 46 | 47 | # [title-match-regex] 48 | # python like regex (https://docs.python.org/2/library/re.html) that the 49 | # commit-msg title must be matched to. 50 | # Note that the regex can contradict with other rules if not used correctly 51 | # (e.g. title-must-not-contain-word). 52 | # regex=^US[0-9]* 53 | 54 | [body-max-line-length] 55 | # B1 = body-max-line-length 56 | line-length=80 57 | 58 | [body-min-length] 59 | min-length=3 60 | 61 | [body-is-missing] 62 | # Whether to ignore this rule on merge commits (which typically only have a title) 63 | # default = True 64 | ignore-merge-commits=false 65 | 66 | # [body-changed-file-mention] 67 | # List of files that need to be explicitly mentioned in the body when they are changed 68 | # This is useful for when developers often erroneously edit certain files or git submodules. 69 | # By specifying this rule, developers can only change the file when they explicitly reference 70 | # it in the commit message. 71 | # files=gitlint/rules.py,README.md 72 | 73 | # [author-valid-email] 74 | # python like regex (https://docs.python.org/2/library/re.html) that the 75 | # commit author email address should be matched to 76 | # For example, use the following regex if you only want to allow email addresses from foo.com 77 | # regex=[^@]+@foo.com 78 | 79 | # [ignore-by-title] 80 | # Ignore certain rules for commits of which the title matches a regex 81 | # E.g. Match commit titles that start with "Release" 82 | # regex=^Release(.*) 83 | # 84 | # Ignore certain rules, you can reference them by their id or by their full name 85 | # Use 'all' to ignore all rules 86 | # ignore=T1,body-min-length 87 | 88 | # [ignore-by-body] 89 | # Ignore certain rules for commits of which the body has a line that matches a regex 90 | # E.g. Match bodies that have a line that that contain "release" 91 | # regex=(.*)release(.*) 92 | # 93 | # Ignore certain rules, you can reference them by their id or by their full name 94 | # Use 'all' to ignore all rules 95 | # ignore=T1,body-min-length 96 | 97 | # [contrib-title-conventional-commits] 98 | # Specify allowed commit types. For details see: https://www.conventionalcommits.org/ 99 | # types = bugfix,user-story,epic -------------------------------------------------------------------------------- /lib/include/openamp/rpmsg_retarget.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Mentor Graphics Corporation 3 | * All rights reserved. 4 | * 5 | * SPDX-License-Identifier: BSD-3-Clause 6 | */ 7 | 8 | #ifndef RPMSG_RETARGET_H 9 | #define RPMSG_RETARGET_H 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #if defined __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | /* File Operations System call definitions */ 20 | #define OPEN_SYSCALL_ID 0x1UL 21 | #define CLOSE_SYSCALL_ID 0x2UL 22 | #define WRITE_SYSCALL_ID 0x3UL 23 | #define READ_SYSCALL_ID 0x4UL 24 | #define ACK_STATUS_ID 0x5UL 25 | 26 | #define TERM_SYSCALL_ID 0x6UL 27 | 28 | #define DEFAULT_PROXY_ENDPOINT 0xFFUL 29 | 30 | struct rpmsg_rpc_data; 31 | 32 | typedef int (*rpmsg_rpc_poll)(void *arg); 33 | typedef void (*rpmsg_rpc_shutdown_cb)(struct rpmsg_rpc_data *rpc); 34 | 35 | struct rpmsg_rpc_syscall_header { 36 | int32_t int_field1; 37 | int32_t int_field2; 38 | uint32_t data_len; 39 | }; 40 | 41 | struct rpmsg_rpc_syscall { 42 | uint32_t id; 43 | struct rpmsg_rpc_syscall_header args; 44 | }; 45 | 46 | struct rpmsg_rpc_data { 47 | struct rpmsg_endpoint ept; 48 | int ept_destroyed; 49 | atomic_flag nacked; 50 | void *respbuf; 51 | size_t respbuf_len; 52 | rpmsg_rpc_poll poll; 53 | void *poll_arg; 54 | rpmsg_rpc_shutdown_cb shutdown_cb; 55 | metal_mutex_t lock; 56 | struct metal_spinlock buflock; 57 | }; 58 | 59 | /** 60 | * @internal 61 | * 62 | * @brief Initialize RPMsg remote procedure call 63 | * 64 | * This function is to initialize the remote procedure call 65 | * global data. RPMsg RPC will send request to remote and 66 | * wait for callback. 67 | * 68 | * @param rpc Pointer to the global remote procedure call data 69 | * @param rdev Pointer to the rpmsg device 70 | * @param ept_name Name of the endpoint used by RPC 71 | * @param ept_addr Address of the endpoint used by RPC 72 | * @param ept_raddr Remote address of the endpoint used by RPC 73 | * @param poll_arg Pointer to poll function argument 74 | * @param poll Poll function 75 | * @param shutdown_cb Shutdown callback function 76 | * 77 | * @return 0 for success, and negative value for failure. 78 | */ 79 | int rpmsg_rpc_init(struct rpmsg_rpc_data *rpc, 80 | struct rpmsg_device *rdev, 81 | const char *ept_name, uint32_t ept_addr, 82 | uint32_t ept_raddr, 83 | void *poll_arg, rpmsg_rpc_poll poll, 84 | rpmsg_rpc_shutdown_cb shutdown_cb); 85 | 86 | /** 87 | * @internal 88 | * 89 | * @brief Release RPMsg remote procedure call 90 | * 91 | * This function is to release remoteproc procedure call 92 | * global data. 93 | * 94 | * @param rpc Pointer to the global remote procedure call 95 | */ 96 | void rpmsg_rpc_release(struct rpmsg_rpc_data *rpc); 97 | 98 | /** 99 | * @internal 100 | * 101 | * @brief Request RPMsg RPC call 102 | * 103 | * This function sends RPC request it will return with the length 104 | * of data and the response buffer. 105 | * 106 | * @param rpc Pointer to remoteproc procedure call data struct 107 | * @param req Pointer to request buffer 108 | * @param len Length of the request data 109 | * @param resp Pointer to where store the response buffer 110 | * @param resp_len Length of the response buffer 111 | * 112 | * @return Length of the received response, negative value for failure. 113 | */ 114 | int rpmsg_rpc_send(struct rpmsg_rpc_data *rpc, 115 | void *req, size_t len, 116 | void *resp, size_t resp_len); 117 | 118 | /** 119 | * @internal 120 | * 121 | * @brief Set default RPMsg RPC data 122 | * 123 | * The default RPC data is used to redirect standard C file operations 124 | * to RPMsg channels. 125 | * 126 | * @param rpc Pointer to remoteproc procedure call data struct 127 | */ 128 | void rpmsg_set_default_rpc(struct rpmsg_rpc_data *rpc); 129 | 130 | #if defined __cplusplus 131 | } 132 | #endif 133 | 134 | #endif /* RPMSG_RETARGET_H */ 135 | -------------------------------------------------------------------------------- /lib/include/openamp/remoteproc_virtio.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Remoteproc Virtio Framework 3 | * 4 | * Copyright(c) 2018 Xilinx Ltd. 5 | * Copyright(c) 2011 Texas Instruments, Inc. 6 | * Copyright(c) 2011 Google, Inc. 7 | * All rights reserved. 8 | * 9 | * SPDX-License-Identifier: BSD-3-Clause 10 | */ 11 | 12 | #ifndef REMOTEPROC_VIRTIO_H 13 | #define REMOTEPROC_VIRTIO_H 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #if defined __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | /* maximum number of vring descriptors for a vdev limited by 16-bit data type */ 25 | #define RPROC_MAX_VRING_DESC USHRT_MAX 26 | 27 | /* cache invalidation helpers for resource table */ 28 | #if defined(VIRTIO_USE_DCACHE) 29 | #define RSC_TABLE_FLUSH(x, s) metal_cache_flush(x, s) 30 | #define RSC_TABLE_INVALIDATE(x, s) metal_cache_invalidate(x, s) 31 | #else 32 | #define RSC_TABLE_FLUSH(x, s) do { } while (0) 33 | #define RSC_TABLE_INVALIDATE(x, s) do { } while (0) 34 | #endif /* VIRTIO_USE_DCACHE */ 35 | 36 | /* define vdev notification function user should implement */ 37 | typedef int (*rpvdev_notify_func)(void *priv, uint32_t id); 38 | 39 | /** @brief Virtio structure for remoteproc instance */ 40 | struct remoteproc_virtio { 41 | /** Pointer to private data */ 42 | void *priv; 43 | 44 | /** Address of vdev resource */ 45 | void *vdev_rsc; 46 | 47 | /** Metal I/O region of vdev_info, can be NULL */ 48 | struct metal_io_region *vdev_rsc_io; 49 | 50 | /** Notification function */ 51 | rpvdev_notify_func notify; 52 | 53 | /** Virtio device */ 54 | struct virtio_device vdev; 55 | 56 | /** List node */ 57 | struct metal_list node; 58 | }; 59 | 60 | /** 61 | * @brief Create rproc virtio vdev 62 | * 63 | * @param role VIRTIO_DEV_DRIVER or VIRTIO_DEV_DEVICE 64 | * @param notifyid Virtio device notification id 65 | * @param rsc Pointer to the virtio device resource 66 | * @param rsc_io Pointer to the virtio device resource I/O region 67 | * @param priv Pointer to the private data 68 | * @param notify vdev and virtqueue notification function 69 | * @param rst_cb Reset virtio device callback 70 | * 71 | * @return pointer to the created virtio device for success, 72 | * NULL for failure. 73 | */ 74 | struct virtio_device * 75 | rproc_virtio_create_vdev(unsigned int role, unsigned int notifyid, 76 | void *rsc, struct metal_io_region *rsc_io, 77 | void *priv, 78 | rpvdev_notify_func notify, 79 | virtio_dev_reset_cb rst_cb); 80 | 81 | /** 82 | * @brief Remove rproc virtio vdev 83 | * 84 | * @param vdev Pointer to the virtio device 85 | */ 86 | void rproc_virtio_remove_vdev(struct virtio_device *vdev); 87 | 88 | /** 89 | * @brief Initialize rproc virtio vring 90 | * 91 | * @param vdev Pointer to the virtio device 92 | * @param index vring index in the virtio device 93 | * @param notifyid remoteproc vring notification id 94 | * @param va vring virtual address 95 | * @param io Pointer to vring I/O region 96 | * @param num_descs Number of descriptors 97 | * @param align vring alignment 98 | * 99 | * @return 0 for success, negative value for failure. 100 | */ 101 | int rproc_virtio_init_vring(struct virtio_device *vdev, unsigned int index, 102 | unsigned int notifyid, void *va, 103 | struct metal_io_region *io, 104 | unsigned int num_descs, unsigned int align); 105 | 106 | /** 107 | * @brief remoteproc virtio is got notified 108 | * 109 | * @param vdev Pointer to the virtio device 110 | * @param notifyid Notify id 111 | * 112 | * @return 0 for successful, negative value for failure 113 | */ 114 | int rproc_virtio_notified(struct virtio_device *vdev, uint32_t notifyid); 115 | 116 | /** 117 | * @brief Blocking function, waiting for the remote core is ready to start 118 | * communications. 119 | * 120 | * @param vdev Pointer to the virtio device 121 | */ 122 | void rproc_virtio_wait_remote_ready(struct virtio_device *vdev); 123 | 124 | #if defined __cplusplus 125 | } 126 | #endif 127 | 128 | #endif /* REMOTEPROC_VIRTIO_H */ 129 | -------------------------------------------------------------------------------- /cmake/options.cmake: -------------------------------------------------------------------------------- 1 | file(READ ${OPENAMP_ROOT_DIR}/VERSION ver) 2 | 3 | string(REGEX MATCH "VERSION_MAJOR = ([0-9]*)" _ ${ver}) 4 | set(PROJECT_VERSION_MAJOR ${CMAKE_MATCH_1}) 5 | 6 | string(REGEX MATCH "VERSION_MINOR = ([0-9]*)" _ ${ver}) 7 | set(PROJECT_VERSION_MINOR ${CMAKE_MATCH_1}) 8 | 9 | string(REGEX MATCH "VERSION_PATCH = ([0-9]*)" _ ${ver}) 10 | set(PROJECT_VERSION_PATCH ${CMAKE_MATCH_1}) 11 | 12 | set(PROJECT_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}) 13 | 14 | message(STATUS "open-amp version: ${PROJECT_VERSION} (${OPENAMP_ROOT_DIR})") 15 | 16 | if (NOT DEFINED CMAKE_BUILD_TYPE) 17 | set (CMAKE_BUILD_TYPE Debug) 18 | endif (NOT DEFINED CMAKE_BUILD_TYPE) 19 | 20 | if (NOT CMAKE_INSTALL_LIBDIR) 21 | set (CMAKE_INSTALL_LIBDIR "lib") 22 | endif (NOT CMAKE_INSTALL_LIBDIR) 23 | 24 | if (NOT CMAKE_INSTALL_BINDIR) 25 | set (CMAKE_INSTALL_BINDIR "bin") 26 | endif (NOT CMAKE_INSTALL_BINDIR) 27 | 28 | set (_host "${CMAKE_HOST_SYSTEM_NAME}/${CMAKE_HOST_SYSTEM_PROCESSOR}") 29 | message ("-- Host: ${_host}") 30 | 31 | set (_target "${CMAKE_SYSTEM_NAME}/${CMAKE_SYSTEM_PROCESSOR}") 32 | message ("-- Target: ${_target}") 33 | 34 | if (NOT DEFINED MACHINE) 35 | set (MACHINE "Generic") 36 | endif (NOT DEFINED MACHINE) 37 | message ("-- Machine: ${MACHINE}") 38 | 39 | string (TOLOWER ${CMAKE_SYSTEM_NAME} PROJECT_SYSTEM) 40 | string (TOUPPER ${CMAKE_SYSTEM_NAME} PROJECT_SYSTEM_UPPER) 41 | string (TOLOWER ${CMAKE_SYSTEM_PROCESSOR} PROJECT_PROCESSOR) 42 | string (TOUPPER ${CMAKE_SYSTEM_PROCESSOR} PROJECT_PROCESSOR_UPPER) 43 | string (TOLOWER ${MACHINE} PROJECT_MACHINE) 44 | string (TOUPPER ${MACHINE} PROJECT_MACHINE_UPPER) 45 | 46 | # Select which components are in the openamp lib 47 | option (WITH_PROXY "Build with proxy(access device controlled by other processor)" ON) 48 | 49 | # LOAD_FW only allowed for R5, otherwise turn off 50 | if (NOT ${MACHINE} STREQUAL "zynqmp_r5") 51 | set (WITH_LOAD_FW OFF) 52 | endif(NOT ${MACHINE} STREQUAL "zynqmp_r5") 53 | 54 | option (WITH_VIRTIO_DRIVER "Build with virtio driver (front end) enabled" ON) 55 | option (WITH_VIRTIO_DEVICE "Build with virtio device (back end) enabled" ON) 56 | 57 | 58 | if (NOT WITH_VIRTIO_DRIVER) 59 | add_definitions(-DVIRTIO_DRIVER_SUPPORT=0) 60 | else (NOT WITH_VIRTIO_DRIVER) 61 | add_definitions(-DVIRTIO_DRIVER_SUPPORT=1) 62 | endif (NOT WITH_VIRTIO_DRIVER) 63 | 64 | if (NOT WITH_VIRTIO_DEVICE) 65 | add_definitions(-DVIRTIO_DEVICE_SUPPORT=0) 66 | else (NOT WITH_VIRTIO_DEVICE) 67 | add_definitions(-DVIRTIO_DEVICE_SUPPORT=1) 68 | endif (NOT WITH_VIRTIO_DEVICE) 69 | 70 | option (WITH_VIRTIO_MMIO_DRV "Build with virtio mmio driver support enabled" OFF) 71 | 72 | if (WITH_VIRTIO_MMIO_DRV) 73 | add_definitions(-DWITH_VIRTIO_MMIO_DRV) 74 | endif (WITH_VIRTIO_MMIO_DRV) 75 | 76 | option (WITH_VQ_RX_EMPTY_NOTIFY "Build with virtqueue rx empty notify enabled" OFF) 77 | 78 | if (NOT WITH_VQ_RX_EMPTY_NOTIFY) 79 | add_definitions(-DVQ_RX_EMPTY_NOTIFY=0) 80 | else (NOT WITH_VQ_RX_EMPTY_NOTIFY) 81 | add_definitions(-DVQ_RX_EMPTY_NOTIFY=1) 82 | endif (NOT WITH_VQ_RX_EMPTY_NOTIFY) 83 | 84 | option (WITH_DCACHE "Build with all cache operations enabled" OFF) 85 | 86 | if (WITH_DCACHE) 87 | add_definitions(-DVIRTIO_USE_DCACHE) 88 | endif (WITH_DCACHE) 89 | 90 | # Set the complication flags 91 | set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra") 92 | 93 | option (WITH_STATIC_LIB "Build with a static library" ON) 94 | 95 | if ("${PROJECT_SYSTEM}" STREQUAL "linux") 96 | option (WITH_SHARED_LIB "Build with a shared library" ON) 97 | endif ("${PROJECT_SYSTEM}" STREQUAL "linux") 98 | 99 | if (WITH_ZEPHYR) 100 | option (WITH_ZEPHYR_LIB "Build open-amp as a zephyr library" OFF) 101 | endif (WITH_ZEPHYR) 102 | 103 | option (WITH_LIBMETAL_FIND "Check Libmetal library can be found" ON) 104 | 105 | if (DEFINED RPMSG_BUFFER_SIZE) 106 | add_definitions( -DRPMSG_BUFFER_SIZE=${RPMSG_BUFFER_SIZE} ) 107 | endif (DEFINED RPMSG_BUFFER_SIZE) 108 | 109 | option (WITH_DOC "Build with documentation" OFF) 110 | 111 | message ("-- C_FLAGS : ${CMAKE_C_FLAGS}") 112 | -------------------------------------------------------------------------------- /lib/rpmsg/rpmsg_internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-3-Clause 3 | * 4 | * $FreeBSD$ 5 | */ 6 | 7 | #ifndef _RPMSG_INTERNAL_H_ 8 | #define _RPMSG_INTERNAL_H_ 9 | 10 | #include 11 | #include 12 | 13 | #if defined __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | #ifdef RPMSG_DEBUG 18 | #include 19 | 20 | #define RPMSG_ASSERT(_exp, _msg) do { \ 21 | if (!(_exp)) { \ 22 | metal_log(METAL_LOG_EMERGENCY, \ 23 | "FATAL: %s - "_msg, __func__); \ 24 | metal_assert(_exp); \ 25 | } \ 26 | } while (0) 27 | #else 28 | #define RPMSG_ASSERT(_exp, _msg) metal_assert(_exp) 29 | #endif 30 | 31 | /* Mask to get the rpmsg buffer held counter from rpmsg_hdr reserved field */ 32 | #define RPMSG_BUF_HELD_SHIFT 16 33 | #define RPMSG_BUF_HELD_MASK (0xFFFFU << RPMSG_BUF_HELD_SHIFT) 34 | 35 | #define RPMSG_LOCATE_HDR(p) \ 36 | ((struct rpmsg_hdr *)((unsigned char *)(p) - sizeof(struct rpmsg_hdr))) 37 | #define RPMSG_LOCATE_DATA(p) ((unsigned char *)(p) + sizeof(struct rpmsg_hdr)) 38 | 39 | /** 40 | * @brief dynamic name service announcement flags 41 | */ 42 | enum rpmsg_ns_flags { 43 | /** A new remote service was just created */ 44 | RPMSG_NS_CREATE = 0, 45 | /** A known remote service was just destroyed */ 46 | RPMSG_NS_DESTROY = 1, 47 | }; 48 | 49 | /** 50 | * @brief Common header for all RPMsg messages 51 | * 52 | * Every message sent(/received) on the RPMsg bus begins with this header. 53 | */ 54 | METAL_PACKED_BEGIN 55 | struct rpmsg_hdr { 56 | /** Source address */ 57 | uint32_t src; 58 | 59 | /** Destination address */ 60 | uint32_t dst; 61 | 62 | /** Reserved for future use */ 63 | uint32_t reserved; 64 | 65 | /** Length of payload (in bytes) */ 66 | uint16_t len; 67 | 68 | /** Message flags */ 69 | uint16_t flags; 70 | } METAL_PACKED_END; 71 | 72 | /** 73 | * @brief Dynamic name service announcement message 74 | * 75 | * This message is sent across to publish a new service, or announce 76 | * about its removal. When we receive these messages, an appropriate 77 | * RPMsg channel (i.e device) is created/destroyed. In turn, the ->probe() 78 | * or ->remove() handler of the appropriate RPMsg driver will be invoked 79 | * (if/as-soon-as one is registered). 80 | */ 81 | METAL_PACKED_BEGIN 82 | struct rpmsg_ns_msg { 83 | /** Name of the remote service that is being published */ 84 | char name[RPMSG_NAME_SIZE]; 85 | 86 | /** Endpoint address of the remote service that is being published */ 87 | uint32_t addr; 88 | 89 | /** Indicates whether service is created or destroyed */ 90 | uint32_t flags; 91 | } METAL_PACKED_END; 92 | 93 | int rpmsg_send_ns_message(struct rpmsg_endpoint *ept, unsigned long flags); 94 | 95 | struct rpmsg_endpoint *rpmsg_get_endpoint(struct rpmsg_device *rvdev, 96 | const char *name, uint32_t addr, 97 | uint32_t dest_addr); 98 | void rpmsg_register_endpoint(struct rpmsg_device *rdev, 99 | struct rpmsg_endpoint *ept, 100 | const char *name, 101 | uint32_t src, uint32_t dest, 102 | rpmsg_ept_cb cb, 103 | rpmsg_ns_unbind_cb ns_unbind_cb, void *priv); 104 | 105 | static inline struct rpmsg_endpoint * 106 | rpmsg_get_ept_from_addr(struct rpmsg_device *rdev, uint32_t addr) 107 | { 108 | return rpmsg_get_endpoint(rdev, NULL, addr, RPMSG_ADDR_ANY); 109 | } 110 | 111 | /** 112 | * @internal 113 | * 114 | * @brief Increase the endpoint reference count 115 | * 116 | * This function is used to avoid calling ept_cb after release lock causes race condition 117 | * it should be called under lock protection. 118 | * 119 | * @param ept pointer to rpmsg endpoint 120 | * 121 | */ 122 | void rpmsg_ept_incref(struct rpmsg_endpoint *ept); 123 | 124 | /** 125 | * @internal 126 | * 127 | * @brief Decrease the end point reference count 128 | * 129 | * This function is used to avoid calling ept_cb after release lock causes race condition 130 | * it should be called under lock protection. 131 | * 132 | * @param ept pointer to rpmsg endpoint 133 | */ 134 | void rpmsg_ept_decref(struct rpmsg_endpoint *ept); 135 | 136 | #if defined __cplusplus 137 | } 138 | #endif 139 | 140 | #endif /* _RPMSG_INTERNAL_H_ */ 141 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Software License Agreement (BSD 3-Clause License) 2 | ======================================== 3 | 4 | Copyright (c) 2014, Mentor Graphics Corporation. All rights reserved. 5 | Copyright (c) 2015 - 2016 Xilinx, Inc. All rights reserved. 6 | Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 14 | 2. Redistributions in binary form must reproduce the above copyright notice, 15 | this list of conditions and the following disclaimer in the documentation 16 | and/or other materials provided with the distribution. 17 | 18 | 3. Neither the name of `` nor the names of its contributors 19 | may be used to endorse or promote products derived from this software 20 | without specific prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 26 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 | POSSIBILITY OF SUCH DAMAGE. 33 | 34 | BSD 2-Clause License 35 | ------------------------- 36 | 37 | Copyright (c) ` `. All rights reserved. 38 | 39 | Redistribution and use in source and binary forms, with or without 40 | modification, are permitted provided that the following conditions are met: 41 | 42 | 1. Redistributions of source code must retain the above copyright notice, this 43 | list of conditions and the following disclaimer. 44 | 45 | 2. Redistributions in binary form must reproduce the above copyright notice, 46 | this list of conditions and the following disclaimer in the documentation 47 | and/or other materials provided with the distribution. 48 | 49 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 50 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 52 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 53 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 55 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 56 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 57 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 58 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 59 | 60 | Apache License :2.0 61 | ------------------------- 62 | 63 | Copyright [yyyy] [name of copyright owner] 64 | 65 | Licensed under the Apache License, Version 2.0 (the "License"); 66 | you may not use this file except in compliance with the License. 67 | You may obtain a copy of the License at 68 | 69 | http://www.apache.org/licenses/LICENSE-2.0 70 | 71 | Unless required by applicable law or agreed to in writing, software 72 | distributed under the License is distributed on an "AS IS" BASIS, 73 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 74 | See the License for the specific language governing permissions and 75 | limitations under the License. 76 | 77 | GPL 2.0 78 | ------------------------- 79 | 80 | Copyright (C) yyyy name of author 81 | 82 | This program is free software; you can redistribute it and/or 83 | modify it under the terms of the GNU General Public License 84 | as published by the Free Software Foundation; either version 2 85 | of the License, or (at your option) any later version. 86 | 87 | This program is distributed in the hope that it will be useful, 88 | but WITHOUT ANY WARRANTY; without even the implied warranty of 89 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 90 | GNU General Public License for more details. 91 | 92 | 93 | Notes 94 | ========================================= 95 | Use the following tag instead of the full license text in the individual files: 96 | 97 | SPDX-License-Identifier: BSD-3-Clause 98 | SPDX-License-Identifier: BSD-2-Clause 99 | SPDX-License-Identifier: Apache-2.0 100 | SPDX-License-Identifier: GPL-2.0 101 | 102 | This enables machine processing of license information based on the SPDX 103 | License Identifiers that are here available: http://spdx.org/licenses/ 104 | 105 | -------------------------------------------------------------------------------- /scripts/gitlint/commit_rules.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | """ 4 | The classes below are examples of user-defined CommitRules. Commit rules are gitlint rules that 5 | act on the entire commit at once. Once the rules are discovered, gitlint will automatically take care of applying them 6 | to the entire commit. This happens exactly once per commit. 7 | 8 | A CommitRule contrasts with a LineRule (see examples/my_line_rules.py) in that a commit rule is only applied once on 9 | an entire commit. This allows commit rules to implement more complex checks that span multiple lines and/or checks 10 | that should only be done once per gitlint run. 11 | 12 | While every LineRule can be implemented as a CommitRule, it's usually easier and more concise to go with a LineRule if 13 | that fits your needs. 14 | """ 15 | 16 | from gitlint.rules import CommitRule, RuleViolation, CommitMessageTitle, LineRule, CommitMessageBody 17 | from gitlint.options import IntOption, StrOption 18 | import re 19 | 20 | class BodyMinLineCount(CommitRule): 21 | # A rule MUST have a human friendly name 22 | name = "body-min-line-count" 23 | 24 | # A rule MUST have an *unique* id, we recommend starting with UC (for User-defined Commit-rule). 25 | id = "UC6" 26 | 27 | # A rule MAY have an option_spec if its behavior should be configurable. 28 | options_spec = [IntOption('min-line-count', 2, "Minimum body line count excluding Signed-off-by")] 29 | 30 | def validate(self, commit): 31 | filtered = [x for x in commit.message.body if not x.lower().startswith("signed-off-by") and x != ''] 32 | line_count = len(filtered) 33 | min_line_count = self.options['min-line-count'].value 34 | if line_count < min_line_count: 35 | message = "Body has no content, should at least have {} line.".format(min_line_count) 36 | return [RuleViolation(self.id, message, line_nr=1)] 37 | 38 | class BodyMaxLineCount(CommitRule): 39 | # A rule MUST have a human friendly name 40 | name = "body-max-line-count" 41 | 42 | # A rule MUST have an *unique* id, we recommend starting with UC (for User-defined Commit-rule). 43 | id = "UC1" 44 | 45 | # A rule MAY have an option_spec if its behavior should be configurable. 46 | options_spec = [IntOption('max-line-count', 3, "Maximum body line count")] 47 | 48 | def validate(self, commit): 49 | line_count = len(commit.message.body) 50 | max_line_count = self.options['max-line-count'].value 51 | if line_count > max_line_count: 52 | message = "Body contains too many lines ({0} > {1})".format(line_count, max_line_count) 53 | return [RuleViolation(self.id, message, line_nr=1)] 54 | 55 | class SignedOffBy(CommitRule): 56 | """ This rule will enforce that each commit contains a "Signed-off-by" line. 57 | We keep things simple here and just check whether the commit body contains a line that starts with "Signed-off-by". 58 | """ 59 | 60 | # A rule MUST have a human friendly name 61 | name = "body-requires-signed-off-by" 62 | 63 | # A rule MUST have an *unique* id, we recommend starting with UC (for User-defined Commit-rule). 64 | id = "UC2" 65 | 66 | def validate(self, commit): 67 | flags = re.UNICODE 68 | flags |= re.IGNORECASE 69 | for line in commit.message.body: 70 | if line.lower().startswith("signed-off-by"): 71 | if not re.search(r"(^)Signed-off-by: ([-'\w.]+) ([-'\w.]+) (.*)", line, flags=flags): 72 | return [RuleViolation(self.id, "Signed-off-by: must have a full name", line_nr=1)] 73 | else: 74 | return 75 | return [RuleViolation(self.id, "Body does not contain a 'Signed-off-by:' line", line_nr=1)] 76 | 77 | class TitleMaxLengthRevert(LineRule): 78 | name = "title-max-length-no-revert" 79 | id = "UC5" 80 | target = CommitMessageTitle 81 | options_spec = [IntOption('line-length', 72, "Max line length")] 82 | violation_message = "Title exceeds max length ({0}>{1})" 83 | 84 | def validate(self, line, _commit): 85 | max_length = self.options['line-length'].value 86 | if len(line) > max_length and not line.startswith("Revert"): 87 | return [RuleViolation(self.id, self.violation_message.format(len(line), max_length), line)] 88 | 89 | class TitleStartsWithSubsystem(LineRule): 90 | name = "title-starts-with-subsystem" 91 | id = "UC3" 92 | target = CommitMessageTitle 93 | options_spec = [StrOption('regex', ".*", "Regex the title should match")] 94 | 95 | def validate(self, title, _commit): 96 | regex = self.options['regex'].value 97 | pattern = re.compile(regex, re.UNICODE) 98 | violation_message = "Title does not follow [subsystem]: [subject] (and should not start with literal subsys:)" 99 | if not pattern.search(title): 100 | return [RuleViolation(self.id, violation_message, title)] 101 | 102 | class MaxLineLengthExceptions(LineRule): 103 | name = "max-line-length-with-exceptions" 104 | id = "UC4" 105 | target = CommitMessageBody 106 | options_spec = [IntOption('line-length', 80, "Max line length")] 107 | violation_message = "Line exceeds max length ({0}>{1})" 108 | 109 | def validate(self, line, _commit): 110 | max_length = self.options['line-length'].value 111 | urls = re.findall(r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', line) 112 | if line.startswith('Signed-off-by'): 113 | return 114 | 115 | if urls: 116 | return 117 | 118 | if len(line) > max_length: 119 | return [RuleViolation(self.id, self.violation_message.format(len(line), max_length), line)] 120 | -------------------------------------------------------------------------------- /lib/include/openamp/rpmsg_rpc_client_server.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, L&T Technology Services Ltd. 3 | * All rights reserved. 4 | * 5 | * SPDX-License-Identifier: BSD-3-Clause 6 | */ 7 | 8 | #ifndef RPMSG_RPC_CLIENT_SERVER_H 9 | #define RPMSG_RPC_CLIENT_SERVER_H 10 | 11 | #include 12 | #include 13 | 14 | #if defined __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | #define RPMSG_RPC_OK 0 19 | #define RPMSG_RPC_INVALID_ID (-1L) 20 | #define RPMSG_RPC_SERVICE_NAME "rpmsg-rpc" 21 | 22 | /* RPMSG_BUFFER_SIZE = 512 23 | * sizeof(struct rpmsg_hdr) = 16 24 | * RPMSG_BUFFER_SIZE - sizeof(struct rpmsg_hdr) - 1 = 495 25 | * Aligning to 64 bits -> 488UL 26 | */ 27 | #define MAX_BUF_LEN 488UL 28 | #define MAX_FUNC_ID_LEN sizeof(uint32_t) 29 | 30 | struct rpmsg_rpc_clt; 31 | struct rpmsg_rpc_svr; 32 | 33 | typedef void (*rpmsg_rpc_shutdown_cb)(struct rpmsg_rpc_clt *rpc); 34 | typedef void (*app_cb)(struct rpmsg_rpc_clt *rpc, int status, void *data, 35 | size_t len); 36 | typedef int (*rpmsg_rpc_syscall_cb)(void *data, struct rpmsg_rpc_svr *rpcs); 37 | 38 | /** 39 | * struct rpmsg_rpc_request - rpc request message 40 | * 41 | * @param id service id 42 | * @param params request params 43 | * 44 | */ 45 | struct rpmsg_rpc_request { 46 | uint32_t id; 47 | unsigned char params[MAX_BUF_LEN]; 48 | }; 49 | 50 | /** @brief RPC request message */ 51 | METAL_PACKED_BEGIN 52 | struct rpmsg_rpc_answer { 53 | /** Service ID */ 54 | uint32_t id; 55 | 56 | /** Status of RPC */ 57 | int32_t status; 58 | 59 | /** Answer params */ 60 | unsigned char params[MAX_BUF_LEN]; 61 | } METAL_PACKED_END; 62 | 63 | /** @brief Table for services */ 64 | struct rpmsg_rpc_services { 65 | /** Service ID */ 66 | uint32_t id; 67 | 68 | /** ID callback */ 69 | rpmsg_rpc_syscall_cb cb_function; 70 | }; 71 | 72 | /** @brief Table for client services */ 73 | struct rpmsg_rpc_client_services { 74 | /** Service ID */ 75 | uint32_t id; 76 | 77 | /** ID callback */ 78 | app_cb cb; 79 | }; 80 | 81 | /** 82 | * @brief Server remote procedure call data 83 | * 84 | * RPMsg RPC will send request to endpoint 85 | */ 86 | struct rpmsg_rpc_svr { 87 | /** RPMsg destination endpoint structure */ 88 | struct rpmsg_endpoint ept; 89 | 90 | /** Service table */ 91 | const struct rpmsg_rpc_services *services; 92 | 93 | /** Number of services */ 94 | unsigned int n_services; 95 | }; 96 | 97 | /** 98 | * @brief Client remote procedure call data 99 | * 100 | * RPMsg RPC will send request to remote and 101 | * wait for callback. 102 | */ 103 | struct rpmsg_rpc_clt { 104 | /** RPMsg endpoint associated with the call */ 105 | struct rpmsg_endpoint ept; 106 | 107 | /** Shutdown callback function */ 108 | rpmsg_rpc_shutdown_cb shutdown_cb; 109 | 110 | /** Service table */ 111 | const struct rpmsg_rpc_client_services *services; 112 | 113 | /** Number of services */ 114 | unsigned int n_services; 115 | }; 116 | 117 | /** 118 | * @internal 119 | * 120 | * @brief Release RPMsg remote procedure call 121 | * 122 | * This function is to release remoteproc procedure call service 123 | * 124 | * @param rpc Pointer to the client remote procedure call data 125 | */ 126 | void rpmsg_rpc_client_release(struct rpmsg_rpc_clt *rpc); 127 | 128 | /** 129 | * @internal 130 | * 131 | * @brief Initialize RPMsg remote procedure call 132 | * 133 | * This function is to initialize the remote procedure call 134 | * client data. RPMsg RPC will send request to remote and 135 | * wait for callback and load services to table 136 | * 137 | * @param rpc Pointer to the client remote procedure call data 138 | * @param rdev Pointer to the rpmsg device 139 | * @param shutdown_cb Shutdown callback function 140 | * @param services Pointer to service table 141 | * @param len Length of table 142 | * 143 | * @return 0 for success, and negative value for failure 144 | */ 145 | int rpmsg_rpc_client_init(struct rpmsg_rpc_clt *rpc, 146 | struct rpmsg_device *rdev, 147 | rpmsg_rpc_shutdown_cb shutdown_cb, 148 | const struct rpmsg_rpc_client_services *services, 149 | int len); 150 | 151 | /** 152 | * @internal 153 | * 154 | * @brief Initialize RPMsg rpc for server 155 | * 156 | * This function create endpoint and loads services into table 157 | * 158 | * @param rpcs Pointer to the server rpc 159 | * @param rdev Pointer to the rpmsg device 160 | * @param services Pointer to service table 161 | * @param len Length of table 162 | * @param rpmsg_service_server_unbind Unbind function callback 163 | * 164 | * @return 0 for success, and negative value for failure 165 | */ 166 | int rpmsg_rpc_server_init(struct rpmsg_rpc_svr *rpcs, struct rpmsg_device *rdev, 167 | const struct rpmsg_rpc_services *services, int len, 168 | rpmsg_ns_unbind_cb rpmsg_service_server_unbind); 169 | 170 | /** 171 | * @internal 172 | * 173 | * @brief Request RPMsg RPC call 174 | * 175 | * @param rpc Pointer to client remoteproc procedure call 176 | * data 177 | * @param rpc_id Function id 178 | * @param request_param Pointer to request buffer 179 | * @param req_param_size Length of the request data 180 | * 181 | * @return Length of the received response, negative value for failure. 182 | */ 183 | int rpmsg_rpc_client_send(struct rpmsg_rpc_clt *rpc, 184 | uint32_t rpc_id, void *request_param, 185 | size_t req_param_size); 186 | 187 | /** 188 | * @internal 189 | * 190 | * @brief Request RPMsg RPC call 191 | * 192 | * This function sends RPC request 193 | * 194 | * @param rpcs Pointer to server rpc data 195 | * @param rpc_id Function id 196 | * @param status Status of rpc 197 | * @param request_param Pointer to request buffer 198 | * @param param_size Length of the request data 199 | * 200 | * @return Length of the received response, negative value for failure. 201 | */ 202 | int rpmsg_rpc_server_send(struct rpmsg_rpc_svr *rpcs, uint32_t rpc_id, 203 | int status, void *request_param, 204 | size_t param_size); 205 | 206 | #if defined __cplusplus 207 | } 208 | #endif 209 | 210 | #endif /* RPMSG_RPC_CLIENT_SERVER_H */ 211 | -------------------------------------------------------------------------------- /.github/actions/build_ci/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | readonly TARGET="$1" 4 | 5 | # Known good version for PR testing 6 | ZEPHYR_VERSION=v4.3.0 7 | 8 | FREERTOS_ZIP_URL=https://cfhcable.dl.sourceforge.net/project/freertos/FreeRTOS/V10.0.1/FreeRTOSv10.0.1.zip 9 | 10 | pre_build(){ 11 | # fix issue related to tzdata install, not needed for 24.04 but kept for 22.04 and earlier 12 | echo 'Etc/UTC' > /etc/timezone || exit 1 13 | ln -fs /usr/share/zoneinfo/Etc/UTC /etc/localtime || exit 1 14 | 15 | #Create a new virtual environment 16 | python3 -m venv ./.venv 17 | source ./.venv/bin/activate 18 | 19 | # add make, curl, and cmake 20 | # cmake from packages will work for 22.04 and later but use pip3 to get the latest on any distro 21 | apt update -qq || exit 1 22 | apt-get install -qqy make curl || exit 1 23 | pip3 install cmake || exit 1 24 | } 25 | 26 | build_linux(){ 27 | echo " Build for linux" 28 | apt-get install -y libsysfs-dev libhugetlbfs-dev gcc || exit 1 29 | export PROJECT_ROOT=$PWD 30 | echo " -- Build libmetal --" 31 | cd $PROJECT_ROOT/libmetal && 32 | cmake . -Bbuild -DCMAKE_INSTALL_PREFIX=$PROJECT_ROOT/target \ 33 | -DCMAKE_C_FLAGS="-Werror -Wall -Wextra -Wshadow -Wunused-but-set-variable" || exit 1 34 | make -C build install || exit 1 35 | echo " -- Build open_amp --" 36 | cd $PROJECT_ROOT/open-amp 37 | cmake . -Bbuild -DCMAKE_INCLUDE_PATH=$PROJECT_ROOT/libmetal/build/lib/include/ \ 38 | -DCMAKE_LIBRARY_PATH=$PROJECT_ROOT/libmetal/build/lib/ \ 39 | -DCMAKE_INSTALL_PREFIX=$PROJECT_ROOT/target -DWITH_PROXY=on \ 40 | -DCMAKE_C_FLAGS="-Werror -Wall -Wextra -Wshadow -Wunused-but-set-variable" || exit 1 41 | make -C build install || exit 1 42 | pwd 43 | echo " -- Build legacy Apps --" 44 | cd $PROJECT_ROOT/openamp-system-reference/examples/legacy_apps 45 | cmake -Bbuild \ 46 | -DCMAKE_INCLUDE_PATH="$PROJECT_ROOT/libmetal/build/lib/include/;$PROJECT_ROOT/open-amp/build/lib/include/" \ 47 | -DCMAKE_LIBRARY_PATH="$PROJECT_ROOT/libmetal/build/lib/;$PROJECT_ROOT/open-amp/build/lib/" \ 48 | -DCMAKE_INSTALL_PREFIX=$PROJECT_ROOT/target \ 49 | -DCMAKE_C_FLAGS="-Werror -Wall -Wextra -Wshadow -Wunused-but-set-variable" || exit 1 50 | make -C build install || exit 1 51 | exit 0 52 | } 53 | 54 | build_generic(){ 55 | echo " Build for generic platform " 56 | apt-get install -y gcc-arm-none-eabi || exit 1 57 | export PROJECT_ROOT=$PWD 58 | cd $PROJECT_ROOT/libmetal || exit 1 59 | cmake . -Bbuild-generic -DCMAKE_TOOLCHAIN_FILE=template-generic \ 60 | -DCMAKE_C_FLAGS="-Werror -Wall -Wextra -Wshadow -Wunused-but-set-variable" || exit 1 61 | cd build-generic || exit 1 62 | make VERBOSE=1 || exit 1 63 | cd $PROJECT_ROOT/open-amp || exit 1 64 | cmake . -Bbuild-generic -DCMAKE_TRY_COMPILE_TARGET_TYPE="STATIC_LIBRARY" \ 65 | -DCMAKE_C_FLAGS="-Werror -Wall -Wextra -Wshadow -Wunused-but-set-variable" \ 66 | -DCMAKE_SYSTEM_PROCESSOR="arm" -DCMAKE_C_COMPILER=arm-none-eabi-gcc \ 67 | -DCMAKE_INCLUDE_PATH="$PROJECT_ROOT/libmetal/build-generic/lib/include" \ 68 | -DCMAKE_LIBRARY_PATH="$PROJECT_ROOT/libmetal/build-generic/lib" || exit 1 69 | cd build-generic || exit 1 70 | make VERBOSE=1 || exit 1 71 | exit 0 72 | } 73 | 74 | build_freertos(){ 75 | echo " Build for freertos OS " 76 | apt-get install -y gcc-arm-none-eabi unzip || exit 1 77 | wget $FREERTOS_ZIP_URL > /dev/null || exit 1 78 | unzip FreeRTOSv10.0.1.zip > /dev/null || exit 1 79 | mkdir -p build-freertos || exit 1 80 | cd build-freertos || exit 1 81 | cmake .. -DCMAKE_TOOLCHAIN_FILE=template-freertos -DCMAKE_C_FLAGS="-I$PWD/../FreeRTOSv10.0.1/FreeRTOS/Source/include/ -I$PWD/../FreeRTOSv10.0.1/FreeRTOS/Demo/CORTEX_STM32F107_GCC_Rowley -I$PWD/../FreeRTOSv10.0.1/FreeRTOS/Source/portable/GCC/ARM_CM3" || exit 1 82 | make VERBOSE=1 || exit 1 83 | exit 0 84 | } 85 | 86 | build_zephyr(){ 87 | echo " Build for Zephyr OS " 88 | echo " install Zephyr environment" 89 | sudo apt-get install -y git cmake ninja-build gperf pv || exit 1 90 | sudo apt-get install -y ccache dfu-util device-tree-compiler wget || exit 1 91 | sudo apt-get install -y python3-dev python3-setuptools python3-tk python3-wheel xz-utils file || exit 1 92 | sudo apt-get install -y make gcc gcc-multilib g++-multilib libsdl2-dev || exit 1 93 | sudo apt-get install -y libc6-dev-i386 gperf g++ python3-ply python3-yaml device-tree-compiler ncurses-dev uglifyjs -qq || exit 1 94 | pip3 install west || exit 1 95 | 96 | export PROJECT_ROOT=$PWD 97 | west init --mr $ZEPHYR_VERSION ./zephyrproject || exit 1 98 | cd ./zephyrproject || exit 1 99 | west update -n || exit 1 100 | west zephyr-export || exit 1 101 | west packages pip --install || exit 1 102 | 103 | echo "Update zephyr OpenAMP repos" 104 | #Update zephyr OpenAMP repos 105 | cp -r $PROJECT_ROOT/open-amp/lib modules/lib/open-amp/open-amp/ || exit 1 106 | cp $PROJECT_ROOT/open-amp/CMakeLists.txt modules/lib/open-amp/open-amp/ || exit 1 107 | cp $PROJECT_ROOT/open-amp/VERSION modules/lib/open-amp/open-amp/ || exit 1 108 | cp -r $PROJECT_ROOT/open-amp/cmake modules/lib/open-amp/open-amp/ || exit 1 109 | cp -r $PROJECT_ROOT/libmetal modules/hal/libmetal/ || exit 1 110 | 111 | # only arm target tested for now 112 | cd zephyr 113 | west -q sdk install -t arm-zephyr-eabi 114 | 115 | echo "build openamp sample" 116 | west build --sysbuild -b lpcxpresso54114/lpc54114/m4 samples/subsys/ipc/openamp/ || exit 1 117 | rm -r build 118 | echo "build openamp/remote sample" 119 | west build --sysbuild -b lpcxpresso54114/lpc54114/m0 samples/subsys/ipc/openamp/remote/ || exit 1 120 | rm -r build 121 | echo "build openamp_rsc_table sample" 122 | west build --sysbuild -b stm32mp157c_dk2 samples/subsys/ipc/openamp_rsc_table || exit 1 123 | exit 0 124 | } 125 | 126 | main(){ 127 | pre_build; 128 | 129 | if [[ "$TARGET" == "linux" ]]; then 130 | build_linux 131 | fi 132 | if [[ "$TARGET" == "generic" ]]; then 133 | build_generic 134 | fi 135 | if [[ "$TARGET" == "freertos" ]]; then 136 | build_freertos 137 | fi 138 | if [[ "$TARGET" == "zephyr" ]]; then 139 | build_zephyr 140 | fi 141 | if [[ "$TARGET" == "zephyr-latest" ]]; then 142 | ZEPHYR_SDK_VER_SELECT=latest 143 | ZEPHYR_VERSION=main 144 | build_zephyr 145 | fi 146 | } 147 | 148 | main 149 | -------------------------------------------------------------------------------- /lib/remoteproc/rsc_table_parser.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Mentor Graphics Corporation 3 | * Copyright (c) 2018, Xilinx Inc. 4 | * All rights reserved. 5 | * 6 | * SPDX-License-Identifier: BSD-3-Clause 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | #include "rsc_table_parser.h" 13 | 14 | #define RSC_TAB_SUPPORTED_VERSION 1 15 | 16 | /** 17 | * @internal 18 | * 19 | * @brief Carveout resource handler. 20 | * 21 | * @param rproc Pointer to remote remoteproc 22 | * @param rsc Pointer to carveout resource 23 | * 24 | * @return 0 for success, or negative value for failure 25 | */ 26 | static int handle_carve_out_rsc(struct remoteproc *rproc, void *rsc) 27 | { 28 | struct fw_rsc_carveout *carve_rsc = rsc; 29 | metal_phys_addr_t da; 30 | metal_phys_addr_t pa; 31 | size_t size; 32 | unsigned int attribute; 33 | 34 | /* Validate resource fields */ 35 | if (!carve_rsc) { 36 | return -RPROC_ERR_RSC_TAB_NP; 37 | } 38 | 39 | if (carve_rsc->reserved) { 40 | return -RPROC_ERR_RSC_TAB_RSVD; 41 | } 42 | pa = carve_rsc->pa; 43 | da = carve_rsc->da; 44 | size = carve_rsc->len; 45 | attribute = carve_rsc->flags; 46 | if (remoteproc_mmap(rproc, &pa, &da, size, attribute, NULL)) 47 | return 0; 48 | else 49 | return -RPROC_EINVAL; 50 | } 51 | 52 | /** 53 | * @internal 54 | * 55 | * @brief Trace resource handler. 56 | * 57 | * @param rproc Pointer to remote remoteproc 58 | * @param rsc Pointer to trace resource 59 | * 60 | * @return No service error 61 | */ 62 | static int handle_trace_rsc(struct remoteproc *rproc, void *rsc) 63 | { 64 | struct fw_rsc_trace *vdev_rsc = rsc; 65 | (void)rproc; 66 | 67 | if (vdev_rsc->da != FW_RSC_U32_ADDR_ANY && vdev_rsc->len != 0) 68 | return 0; 69 | /* FIXME: The host should allocated a memory used by remote */ 70 | 71 | return -RPROC_ERR_RSC_TAB_NS; 72 | } 73 | 74 | static int handle_vdev_rsc(struct remoteproc *rproc, void *rsc) 75 | { 76 | struct fw_rsc_vdev *vdev_rsc = rsc; 77 | int i, num_vrings; 78 | unsigned int notifyid; 79 | struct fw_rsc_vdev_vring *vring_rsc; 80 | 81 | /* only assign notification IDs but do not initialize vdev */ 82 | notifyid = vdev_rsc->notifyid; 83 | notifyid = remoteproc_allocate_id(rproc, 84 | notifyid, 85 | notifyid == RSC_NOTIFY_ID_ANY ? 86 | RSC_NOTIFY_ID_ANY : notifyid + 1); 87 | if (notifyid != RSC_NOTIFY_ID_ANY) 88 | vdev_rsc->notifyid = notifyid; 89 | else 90 | return -RPROC_ERR_RSC_TAB_NP; 91 | 92 | num_vrings = vdev_rsc->num_of_vrings; 93 | for (i = 0; i < num_vrings; i++) { 94 | vring_rsc = &vdev_rsc->vring[i]; 95 | notifyid = vring_rsc->notifyid; 96 | notifyid = remoteproc_allocate_id(rproc, 97 | notifyid, 98 | notifyid == RSC_NOTIFY_ID_ANY ? 99 | RSC_NOTIFY_ID_ANY : notifyid + 1); 100 | if (notifyid != RSC_NOTIFY_ID_ANY) 101 | vring_rsc->notifyid = notifyid; 102 | else 103 | goto err; 104 | } 105 | 106 | return 0; 107 | 108 | err: 109 | for (i--; i >= 0; i--) { 110 | vring_rsc = &vdev_rsc->vring[i]; 111 | metal_bitmap_clear_bit(&rproc->bitmap, vring_rsc->notifyid); 112 | } 113 | metal_bitmap_clear_bit(&rproc->bitmap, vdev_rsc->notifyid); 114 | 115 | return -RPROC_ERR_RSC_TAB_NP; 116 | } 117 | 118 | static int handle_vendor_rsc(struct remoteproc *rproc, void *rsc) 119 | { 120 | if (rproc && rproc->ops->handle_rsc) { 121 | struct fw_rsc_vendor *vend_rsc = rsc; 122 | size_t len = vend_rsc->len; 123 | 124 | return rproc->ops->handle_rsc(rproc, rsc, len); 125 | } 126 | return -RPROC_ERR_RSC_TAB_NS; 127 | } 128 | 129 | /** 130 | * @internal 131 | * 132 | * @brief Dummy resource handler. 133 | * 134 | * @param rproc Pointer to remote remoteproc 135 | * @param rsc Pointer to trace resource 136 | * 137 | * @return No service error 138 | */ 139 | static int handle_dummy_rsc(struct remoteproc *rproc, void *rsc) 140 | { 141 | (void)rproc; 142 | (void)rsc; 143 | 144 | return -RPROC_ERR_RSC_TAB_NS; 145 | } 146 | 147 | /* Standard control request handling. */ 148 | typedef int (*rsc_handler)(struct remoteproc *rproc, void *rsc); 149 | 150 | /* Resources handler */ 151 | static const rsc_handler rsc_handler_table[] = { 152 | handle_carve_out_rsc, /**< carved out resource */ 153 | handle_dummy_rsc, /**< IOMMU dev mem resource */ 154 | handle_trace_rsc, /**< trace buffer resource */ 155 | handle_vdev_rsc, /**< virtio resource */ 156 | }; 157 | 158 | int handle_rsc_table(struct remoteproc *rproc, 159 | struct resource_table *rsc_table, size_t size, 160 | struct metal_io_region *io) 161 | { 162 | struct fw_rsc_hdr *hdr; 163 | uint32_t rsc_type; 164 | unsigned int idx, offset; 165 | int status = 0; 166 | 167 | /* Validate rsc table header fields */ 168 | 169 | /* Minimum rsc table size */ 170 | if (sizeof(struct resource_table) > size) { 171 | return -RPROC_ERR_RSC_TAB_TRUNC; 172 | } 173 | 174 | /* Supported version */ 175 | if (rsc_table->ver != RSC_TAB_SUPPORTED_VERSION) { 176 | return -RPROC_ERR_RSC_TAB_VER; 177 | } 178 | 179 | /* Offset array */ 180 | offset = sizeof(struct resource_table) 181 | + rsc_table->num * sizeof(rsc_table->offset[0]); 182 | 183 | if (offset > size) { 184 | return -RPROC_ERR_RSC_TAB_TRUNC; 185 | } 186 | 187 | /* Reserved fields - must be zero */ 188 | if (rsc_table->reserved[0] != 0 || rsc_table->reserved[1] != 0) { 189 | return -RPROC_ERR_RSC_TAB_RSVD; 190 | } 191 | 192 | /* Loop through the offset array and parse each resource entry */ 193 | for (idx = 0; idx < rsc_table->num; idx++) { 194 | hdr = (void *)((char *)rsc_table + rsc_table->offset[idx]); 195 | if (io && metal_io_virt_to_offset(io, hdr) == METAL_BAD_OFFSET) 196 | return -RPROC_ERR_RSC_TAB_TRUNC; 197 | rsc_type = hdr->type; 198 | if (rsc_type < RSC_LAST) 199 | status = rsc_handler_table[rsc_type](rproc, hdr); 200 | else if (rsc_type >= RSC_VENDOR_START && 201 | rsc_type <= RSC_VENDOR_END) 202 | status = handle_vendor_rsc(rproc, hdr); 203 | if (status == -RPROC_ERR_RSC_TAB_NS) { 204 | status = 0; 205 | continue; 206 | } else if (status) { 207 | break; 208 | } 209 | } 210 | 211 | return status; 212 | } 213 | 214 | size_t find_rsc(void *rsc_table, unsigned int rsc_type, unsigned int index) 215 | { 216 | struct resource_table *r_table = rsc_table; 217 | struct fw_rsc_hdr *hdr; 218 | unsigned int i, rsc_index; 219 | unsigned int lrsc_type; 220 | 221 | metal_assert(r_table); 222 | if (!r_table) 223 | return 0; 224 | 225 | /* Loop through the offset array and parse each resource entry */ 226 | rsc_index = 0; 227 | for (i = 0; i < r_table->num; i++) { 228 | hdr = (void *)((char *)r_table + r_table->offset[i]); 229 | lrsc_type = hdr->type; 230 | if (lrsc_type == rsc_type) { 231 | if (rsc_index++ == index) 232 | return r_table->offset[i]; 233 | } 234 | } 235 | return 0; 236 | } 237 | -------------------------------------------------------------------------------- /lib/include/openamp/virtio_mmio.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Wind River Systems, Inc. 3 | * Based on Virtio PCI driver by Anthony Liguori, copyright IBM Corp. 2007 4 | * 5 | * SPDX-License-Identifier: BSD-3-Clause 6 | */ 7 | 8 | #ifndef OPENAMP_VIRTIO_MMIO_H 9 | #define OPENAMP_VIRTIO_MMIO_H 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | /* Enable support for legacy devices */ 20 | #define VIRTIO_MMIO_LEGACY 21 | 22 | /* Control registers */ 23 | 24 | /* Magic value ("virt" string) - Read Only */ 25 | #define VIRTIO_MMIO_MAGIC_VALUE 0x000 26 | 27 | #define VIRTIO_MMIO_MAGIC_VALUE_STRING ('v' | ('i' << 8) | ('r' << 16) | ('t' << 24)) 28 | 29 | /* Virtio device version - Read Only */ 30 | #define VIRTIO_MMIO_VERSION 0x004 31 | 32 | /* Virtio device ID - Read Only */ 33 | #define VIRTIO_MMIO_DEVICE_ID 0x008 34 | 35 | /* Virtio vendor ID - Read Only */ 36 | #define VIRTIO_MMIO_VENDOR_ID 0x00c 37 | 38 | /* 39 | * Bitmask of the features supported by the device (host) 40 | * (32 bits per set) - Read Only 41 | */ 42 | #define VIRTIO_MMIO_DEVICE_FEATURES 0x010 43 | 44 | /* Device (host) features set selector - Write Only */ 45 | #define VIRTIO_MMIO_DEVICE_FEATURES_SEL 0x014 46 | 47 | /* 48 | * Bitmask of features activated by the driver (guest) 49 | * (32 bits per set) - Write Only 50 | */ 51 | #define VIRTIO_MMIO_DRIVER_FEATURES 0x020 52 | 53 | /* Activated features set selector - Write Only */ 54 | #define VIRTIO_MMIO_DRIVER_FEATURES_SEL 0x024 55 | 56 | #ifndef VIRTIO_MMIO_NO_LEGACY /* LEGACY DEVICES ONLY! */ 57 | /* Guest's memory page size in bytes - Write Only */ 58 | #define VIRTIO_MMIO_GUEST_PAGE_SIZE 0x028 59 | #endif 60 | 61 | /* Queue selector - Write Only */ 62 | #define VIRTIO_MMIO_QUEUE_SEL 0x030 63 | 64 | /* Maximum size of the currently selected queue - Read Only */ 65 | #define VIRTIO_MMIO_QUEUE_NUM_MAX 0x034 66 | 67 | /* Queue size for the currently selected queue - Write Only */ 68 | #define VIRTIO_MMIO_QUEUE_NUM 0x038 69 | 70 | #ifdef VIRTIO_MMIO_LEGACY 71 | /* Used Ring alignment for the currently selected queue - Write Only */ 72 | #define VIRTIO_MMIO_QUEUE_ALIGN 0x03c 73 | /* Guest's PFN for the currently selected queue - Read Write */ 74 | #define VIRTIO_MMIO_QUEUE_PFN 0x040 75 | #endif 76 | 77 | /* Ready bit for the currently selected queue - Read Write */ 78 | #define VIRTIO_MMIO_QUEUE_READY 0x044 79 | 80 | /* Queue notifier - Write Only */ 81 | #define VIRTIO_MMIO_QUEUE_NOTIFY 0x050 82 | 83 | /* Interrupt status - Read Only */ 84 | #define VIRTIO_MMIO_INTERRUPT_STATUS 0x060 85 | 86 | /* Interrupt acknowledge - Write Only */ 87 | #define VIRTIO_MMIO_INTERRUPT_ACK 0x064 88 | 89 | /* Device status register - Read Write */ 90 | #define VIRTIO_MMIO_STATUS 0x070 91 | 92 | /* Selected queue's Descriptor Table address, 64 bits in two halves */ 93 | #define VIRTIO_MMIO_QUEUE_DESC_LOW 0x080 94 | #define VIRTIO_MMIO_QUEUE_DESC_HIGH 0x084 95 | 96 | /* Selected queue's Available Ring address, 64 bits in two halves */ 97 | #define VIRTIO_MMIO_QUEUE_AVAIL_LOW 0x090 98 | #define VIRTIO_MMIO_QUEUE_AVAIL_HIGH 0x094 99 | 100 | /* Selected queue's Used Ring address, 64 bits in two halves */ 101 | #define VIRTIO_MMIO_QUEUE_USED_LOW 0x0a0 102 | #define VIRTIO_MMIO_QUEUE_USED_HIGH 0x0a4 103 | 104 | /* Shared memory region id */ 105 | #define VIRTIO_MMIO_SHM_SEL 0x0ac 106 | 107 | /* Shared memory region length, 64 bits in two halves */ 108 | #define VIRTIO_MMIO_SHM_LEN_LOW 0x0b0 109 | #define VIRTIO_MMIO_SHM_LEN_HIGH 0x0b4 110 | 111 | /* Shared memory region base address, 64 bits in two halves */ 112 | #define VIRTIO_MMIO_SHM_BASE_LOW 0x0b8 113 | #define VIRTIO_MMIO_SHM_BASE_HIGH 0x0bc 114 | 115 | /* Configuration atomicity value */ 116 | #define VIRTIO_MMIO_CONFIG_GENERATION 0x0fc 117 | 118 | /* 119 | * The config space is defined by each driver as 120 | * the per-driver configuration space - Read Write 121 | */ 122 | #define VIRTIO_MMIO_CONFIG 0x100 123 | 124 | /* Interrupt flags (re: interrupt status & acknowledge registers) */ 125 | #define VIRTIO_MMIO_INT_VRING (1 << 0) 126 | #define VIRTIO_MMIO_INT_CONFIG (1 << 1) 127 | 128 | /* Data buffer size for preallocated buffers before vring */ 129 | #define VIRTIO_MMIO_MAX_DATA_SIZE 128 130 | 131 | /** @brief VIRTIO MMIO memory area */ 132 | struct virtio_mmio_dev_mem { 133 | /** Memory region physical address */ 134 | void *base; 135 | 136 | /** Memory region size */ 137 | size_t size; 138 | }; 139 | 140 | /** @brief A VIRTIO MMIO device */ 141 | struct virtio_mmio_device { 142 | /** Base virtio device structure */ 143 | struct virtio_device vdev; 144 | 145 | /** Device configuration space metal_io_region */ 146 | struct metal_io_region cfg_io; 147 | 148 | /** Pre-shared memory space metal_io_region */ 149 | struct metal_io_region shm_io; 150 | 151 | /** VIRTIO device configuration space */ 152 | struct virtio_mmio_dev_mem cfg_mem; 153 | 154 | /** VIRTIO device pre-shared memory */ 155 | struct virtio_mmio_dev_mem shm_mem; 156 | 157 | /** VIRTIO_DEV_DRIVER or VIRTIO_DEV_DEVICE */ 158 | unsigned int device_mode; 159 | 160 | /** Interrupt number */ 161 | unsigned int irq; 162 | 163 | /** Custom user data */ 164 | void *user_data; 165 | }; 166 | 167 | /** 168 | * @brief Register a VIRTIO device with the VIRTIO stack. 169 | * 170 | * @param vdev Pointer to device structure. 171 | * @param vq_num Number of virtqueues the device uses. 172 | * @param vqs Array of pointers to vthe virtqueues used by the device. 173 | */ 174 | void virtio_mmio_register_device(struct virtio_device *vdev, int vq_num, struct virtqueue **vqs); 175 | 176 | /** 177 | * @brief Setup a virtqueue structure. 178 | * 179 | * @param vdev Pointer to device structure. 180 | * @param idx Index of the virtqueue. 181 | * @param vq Pointer to virtqueue structure. 182 | * @param cb Pointer to virtqueue callback. Can be NULL. 183 | * @param cb_arg Argument for the virtqueue callback. 184 | * @param vq_name Name of the virtqueue. 185 | * 186 | * @return pointer to virtqueue structure. 187 | */ 188 | struct virtqueue *virtio_mmio_setup_virtqueue(struct virtio_device *vdev, 189 | unsigned int idx, 190 | struct virtqueue *vq, 191 | void (*cb)(void *), 192 | void *cb_arg, 193 | const char *vq_name); 194 | 195 | /** 196 | * @brief VIRTIO MMIO device initialization. 197 | * 198 | * @param vmdev Pointer to virtio_mmio_device structure. 199 | * @param virt_mem_ptr Guest virtio (shared) memory base address (virtual). 200 | * @param cfg_mem_ptr Virtio device configuration memory base address (virtual). 201 | * @param user_data Pointer to custom user data. 202 | * 203 | * @return int 0 for success. 204 | */ 205 | int virtio_mmio_device_init(struct virtio_mmio_device *vmdev, uintptr_t virt_mem_ptr, 206 | uintptr_t cfg_mem_ptr, void *user_data); 207 | 208 | /** 209 | * @brief VIRTIO MMIO interrupt service routine. 210 | * 211 | * @param vdev Pointer to virtio_device structure. 212 | */ 213 | void virtio_mmio_isr(struct virtio_device *vdev); 214 | 215 | #ifdef __cplusplus 216 | } 217 | #endif 218 | 219 | #endif /* OPENAMP_VIRTIO_MMIO_H */ 220 | -------------------------------------------------------------------------------- /lib/include/openamp/virtio_ring.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Rusty Russell IBM Corporation 2007. 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | * 6 | * $FreeBSD$ 7 | */ 8 | 9 | #ifndef VIRTIO_RING_H 10 | #define VIRTIO_RING_H 11 | 12 | #include 13 | 14 | #if defined __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | /* This marks a buffer as continuing via the next field. */ 19 | #define VRING_DESC_F_NEXT 1 20 | /* This marks a buffer as write-only (otherwise read-only). */ 21 | #define VRING_DESC_F_WRITE 2 22 | /* This means the buffer contains a list of buffer descriptors. */ 23 | #define VRING_DESC_F_INDIRECT 4 24 | 25 | /* The Host uses this in used->flags to advise the Guest: don't kick me 26 | * when you add a buffer. It's unreliable, so it's simply an 27 | * optimization. Guest will still kick if it's out of buffers. 28 | */ 29 | #define VRING_USED_F_NO_NOTIFY 1 30 | /* The Guest uses this in avail->flags to advise the Host: don't 31 | * interrupt me when you consume a buffer. It's unreliable, so it's 32 | * simply an optimization. 33 | */ 34 | #define VRING_AVAIL_F_NO_INTERRUPT 1 35 | 36 | /** 37 | * @brief VirtIO ring descriptors. 38 | * 39 | * The descriptor table refers to the buffers the driver is using for the 40 | * device. addr is a physical address, and the buffers can be chained via \ref next. 41 | * Each descriptor describes a buffer which is read-only for the device 42 | * (“device-readable”) or write-only for the device (“device-writable”), but a 43 | * chain of descriptors can contain both device-readable and device-writable 44 | * buffers. 45 | */ 46 | METAL_PACKED_BEGIN 47 | struct vring_desc { 48 | /** Address (guest-physical) */ 49 | uint64_t addr; 50 | 51 | /** Length */ 52 | uint32_t len; 53 | 54 | /** Flags relevant to the descriptors */ 55 | uint16_t flags; 56 | 57 | /** We chain unused descriptors via this, too */ 58 | uint16_t next; 59 | } METAL_PACKED_END; 60 | 61 | /** 62 | * @brief Used to offer buffers to the device. 63 | * 64 | * Each ring entry refers to the head of a descriptor chain. It is only 65 | * written by the driver and read by the device. 66 | */ 67 | METAL_PACKED_BEGIN 68 | struct vring_avail { 69 | /** Flag which determines whether device notifications are required */ 70 | uint16_t flags; 71 | 72 | /** 73 | * Indicates where the driver puts the next descriptor entry in the 74 | * ring (modulo the queue size) 75 | */ 76 | uint16_t idx; 77 | 78 | /** The ring of descriptors */ 79 | uint16_t ring[0]; 80 | } METAL_PACKED_END; 81 | 82 | /* uint32_t is used here for ids for padding reasons. */ 83 | METAL_PACKED_BEGIN 84 | struct vring_used_elem { 85 | union { 86 | uint16_t event; 87 | /* Index of start of used descriptor chain. */ 88 | uint32_t id; 89 | }; 90 | /* Total length of the descriptor chain which was written to. */ 91 | uint32_t len; 92 | } METAL_PACKED_END; 93 | 94 | /** 95 | * @brief The device returns buffers to this structure when done with them 96 | * 97 | * The structure is only written to by the device, and read by the driver. 98 | */ 99 | METAL_PACKED_BEGIN 100 | struct vring_used { 101 | /** Flag which determines whether device notifications are required */ 102 | uint16_t flags; 103 | 104 | /** 105 | * Indicates where the driver puts the next descriptor entry in the 106 | * ring (modulo the queue size) 107 | */ 108 | uint16_t idx; 109 | 110 | /** The ring of descriptors */ 111 | struct vring_used_elem ring[0]; 112 | } METAL_PACKED_END; 113 | 114 | /** 115 | * @brief The virtqueue layout structure 116 | * 117 | * Each virtqueue consists of; descriptor table, available ring, used ring, 118 | * where each part is physically contiguous in guest memory, referenced 119 | * by the pointers in this structure. 120 | * 121 | * When the driver wants to send a buffer to the device, it fills in a slot in 122 | * the descriptor table (or chains several together), and writes the descriptor 123 | * index into the available ring. It then notifies the device. When the device 124 | * has finished a buffer, it writes the descriptor index into the used ring, 125 | * and sends an interrupt. 126 | * 127 | * The standard layout for the ring, referenced by this structure, is a 128 | * continuous chunk of memory exemplified by this table. The maximum number 129 | * of buffer descriptors, num, is a power of 2. 130 | * 131 | * |vring| definition | description 132 | * |-----|-------------------------------- |------------ 133 | * | desc| struct vring_desc desc[num] | All num descriptors 134 | * |avail| uint16_t avail_flags | Device notification flags 135 | * | | uint16_t avail_idx | Driver's next descriptor location 136 | * | | uint16_t available[num] | The ring of descriptors 137 | * | | uint16_t used_event_idx | Free running index 138 | * | pad| char pad[] | Padding for memory alignment 139 | * | used| uint16_t used_flags | Device notification flags 140 | * | | uint16_t used_idx | Driver's next descriptor location 141 | * | | struct vring_used_elem used[num]| The ring of descriptors 142 | * | | uint16_t avail_event_idx | Free running index 143 | * 144 | * Padding for alignment requirements: 145 | * 146 | * Some architectures require strict alignment for atomic operations or DMA 147 | * transfer. The pad item should be inserted between avail and used memory 148 | * sections to ensure that the used ring is aligned, as the available ring 149 | * size is not necessarily a multiple of 4 or 8 bytes. 150 | * 151 | * The alignment may also be necessary for CPU cache line utilization, 152 | * as padding can avoid crossing cache lines or memory pages in the 153 | * shared memory. 154 | * 155 | * NOTE: for VirtIO PCI, align is 4096. 156 | */ 157 | struct vring { 158 | /** 159 | * The maximum number of buffer descriptors in the virtqueue. 160 | * The value is always a power of 2. 161 | */ 162 | unsigned int num; 163 | 164 | /** The actual buffer descriptors, 16 bytes each */ 165 | struct vring_desc *desc; 166 | 167 | /** A ring of available descriptor heads with free-running index */ 168 | struct vring_avail *avail; 169 | 170 | /** A ring of used descriptor heads with free-running index */ 171 | struct vring_used *used; 172 | }; 173 | 174 | /* 175 | * We publish the used event index at the end of the available ring, and vice 176 | * versa. They are at the end for backwards compatibility. 177 | */ 178 | #define vring_used_event(vr) ((vr)->avail->ring[(vr)->num]) 179 | #define vring_avail_event(vr) ((vr)->used->ring[(vr)->num].event) 180 | 181 | static inline int vring_size(unsigned int num, unsigned long align) 182 | { 183 | int size; 184 | 185 | size = num * sizeof(struct vring_desc); 186 | size += sizeof(struct vring_avail) + (num * sizeof(uint16_t)) + 187 | sizeof(uint16_t); 188 | size = (size + align - 1) & ~(align - 1); 189 | size += sizeof(struct vring_used) + 190 | (num * sizeof(struct vring_used_elem)) + sizeof(uint16_t); 191 | 192 | return size; 193 | } 194 | 195 | static inline void 196 | vring_init(struct vring *vr, unsigned int num, uint8_t *p, unsigned long align) 197 | { 198 | vr->num = num; 199 | vr->desc = (struct vring_desc *)p; 200 | vr->avail = (struct vring_avail *)(p + num * sizeof(struct vring_desc)); 201 | vr->used = (struct vring_used *) 202 | (((unsigned long)&vr->avail->ring[num] + sizeof(uint16_t) + 203 | align - 1) & ~(align - 1)); 204 | } 205 | 206 | /* 207 | * The following is used with VIRTIO_RING_F_EVENT_IDX. 208 | * 209 | * Assuming a given event_idx value from the other size, if we have 210 | * just incremented index from old to new_idx, should we trigger an 211 | * event? 212 | */ 213 | static inline int 214 | vring_need_event(uint16_t event_idx, uint16_t new_idx, uint16_t old) 215 | { 216 | return (uint16_t)(new_idx - event_idx - 1) < 217 | (uint16_t)(new_idx - old); 218 | } 219 | 220 | #if defined __cplusplus 221 | } 222 | #endif 223 | 224 | #endif /* VIRTIO_RING_H */ 225 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # open-amp 2 | This repository is the home for the Open Asymmetric Multi Processing (OpenAMP) 3 | framework project. The OpenAMP framework provides software components that 4 | enable development of software applications for Asymmetric Multiprocessing 5 | (AMP) systems. The framework provides the following key capabilities. 6 | 7 | 1. Provides Life Cycle Management, and Inter Processor Communication 8 | capabilities for management of remote compute resources and their associated 9 | software contexts. 10 | 2. Provides a stand alone library usable with RTOS and Baremetal software 11 | environments 12 | 3. Compatibility with upstream Linux remoteproc and rpmsg components 13 | 4. Following AMP configurations supported 14 | a. Linux host/Generic(Baremetal) remote 15 | b. Generic(Baremetal) host/Linux remote 16 | 5. Proxy infrastructure and supplied demos showcase ability of proxy on host 17 | to handle printf, scanf, open, close, read, write calls from Bare metal 18 | based remote contexts. 19 | 20 | ## OpenAMP Source Structure 21 | ``` 22 | |- lib/ 23 | | |- virtio/ # virtio implementation 24 | | |- rpmsg/ # rpmsg implementation 25 | | |- remoteproc/ # remoteproc implementation 26 | | |- proxy/ # implement one processor access device on the 27 | | | # other processor with file operations 28 | |- cmake # CMake files 29 | |- scripts # helper scripts (such as checkpatch) for contributors. 30 | ``` 31 | 32 | OpenAMP library libopen_amp is composed of the following directories in `lib/`: 33 | * `virtio/` 34 | * `rpmsg/` 35 | * `remoteproc/` 36 | * `proxy/` 37 | 38 | OpenAMP system/machine support has been moved to libmetal. 39 | 40 | ### libmetal APIs used in OpenAMP 41 | Here are the libmetal APIs used by OpenAMP, if you want to port OpenAMP for your 42 | system, you will need to implement the following libmetal APIs in the libmetal's 43 | `lib/system/` directory: 44 | * alloc, for memory allocation and memory free 45 | * cache, for flushing cache and invalidating cache 46 | * io, for memory mapping. OpenAMP required memory mapping in order to access 47 | vrings and carved out memory. 48 | * irq, for IRQ handler registration, IRQ disable/enable and global IRQ handling. 49 | * mutex 50 | * shmem (For RTOS, you can usually use the implementation from 51 | `lib/system/generic/`) 52 | * sleep, at the moment, OpenAMP only requires microseconds sleep as when OpenAMP 53 | fails to get a buffer to send messages, it will call this function to sleep and 54 | then try again. 55 | * time, for timestamp 56 | * init, for libmetal initialization. 57 | * atomic 58 | 59 | Please refer to `lib/system/generic` when you port libmetal for your system. 60 | 61 | If you a different compiler to GNU gcc, please refer to `lib/compiler/gcc/` to 62 | port libmetal for your compiler. At the moment, OpenAMP needs the atomic 63 | operations defined in `lib/compiler/gcc/atomic.h`. 64 | 65 | ## OpenAMP Compilation 66 | OpenAMP uses CMake for library and demonstration application compilation. 67 | OpenAMP requires libmetal library. For now, you will need to download and 68 | compile libmetal library separately before you compiling OpenAMP library. 69 | In future, we will try to make libmetal as a submodule to OpenAMP to make this 70 | flow easier. 71 | 72 | Some Cmake options are available to allow user to customize to the OpenAMP 73 | library for it project: 74 | * **WITH_PROXY** (default OFF): Include proxy support in the library. 75 | * **WITH_VIRTIO_DRIVER** (default ON): Build with virtio driver enabled. 76 | This option can be set to OFF if the only the remote mode is implemented. 77 | * **WITH_VIRTIO_DEVICE** (default ON): Build with virtio device enabled. 78 | This option can be set to OFF if the only the driver mode is implemented. 79 | * **WITH_VQ_RX_EMPTY_NOTIFY** (default OFF): Choose notify mode. When set to 80 | ON, only notify when there are no more Message in the RX queue. When set to 81 | OFF, notify for each RX buffer released. 82 | * **WITH_STATIC_LIB** (default ON): Build with a static library. 83 | * **WITH_SHARED_LIB** (default ON): Build with a shared library. 84 | * **WITH_ZEPHYR** (default OFF): Build open-amp as a zephyr library. This option 85 | is mandatory in a Zephyr environment. 86 | * **WITH_DCACHE_VRINGS** (default OFF): Build with data cache operations 87 | enabled on vrings. 88 | * **WITH_DCACHE_BUFFERS** (default OFF): Build with data cache operations 89 | enabled on buffers. 90 | * **WITH_DCACHE_RSC_TABLE** (default OFF): Build with data cache operations 91 | enabled on resource table. 92 | * **WITH_DCACHE** (default OFF): Build with all cache operations 93 | enabled. When set to ON, cache operations for vrings, buffers and resource 94 | table are enabled. 95 | * **RPMSG_BUFFER_SIZE** (default 512): adjust the size of the RPMsg buffers. 96 | The default value of the RPMsg size is compatible with the Linux Kernel hard 97 | coded value. If you AMP configuration is Linux kernel host/ OpenAMP remote, 98 | this option must not be used. 99 | 100 | ### Example to compile OpenAMP for Zephyr 101 | The [Zephyr open-amp repo](https://github.com/zephyrproject-rtos/open-amp) 102 | implements the open-amp library for the Zephyr project. It is mainly a fork of 103 | this repository, with some add-ons for integration in the Zephyr project. 104 | The standard way to compile OpenAMP for a Zephyr project is to use Zephyr build 105 | environment. Please refer to 106 | [Zephyr OpenAMP samples](https://github.com/zephyrproject-rtos/zephyr/tree/main/samples/subsys/ipc) 107 | for examples and [Zephyr documentation](https://docs.zephyrproject.org/latest/) for the build 108 | process. 109 | 110 | ### Example to compile OpenAMP for communication between Linux processes: 111 | * Install libsysfs devel and libhugetlbfs devel packages on your Linux host. 112 | * build libmetal library on your host as follows: 113 | ``` 114 | $ mkdir -p build-libmetal 115 | $ cd build-libmetal 116 | $ cmake 117 | $ make VERBOSE=1 DESTDIR= install 118 | ``` 119 | 120 | * build OpenAMP library on your host as follows: 121 | ``` 122 | $ mkdir -p build-openamp 123 | $ cd build-openamp 124 | $ cmake -DCMAKE_INCLUDE_PATH= \ 125 | -DCMAKE_LIBRARY_PATH= 126 | $ make VERBOSE=1 DESTDIR=$(pwd) install 127 | ``` 128 | The OpenAMP library will be generated to `build/usr/local/lib` directory, 129 | and the headers will be generated to `build/usr/local/include` directory. 130 | 131 | ## Example apps and tests 132 | * The openamp-system-reference is a new repository for the OpenAMP demos: 133 | https://github.com/OpenAMP/openamp-system-reference 134 | 135 | ## Documentation 136 | OpenAMP project documentation is available at: 137 | https://openamp.readthedocs.io/en/latest/ 138 | 139 | ## How to contribute: 140 | As an open-source project, we welcome and encourage the community to submit patches directly to the 141 | project. As a contributor you should be familiar with common developer tools such as Git and CMake, 142 | and platforms such as GitHub. 143 | Then following points should be rescpected to facilitate the review process. 144 | 145 | ### Licencing 146 | Code is contributed to the Linux kernel under a number of licenses, but all code must be compatible 147 | with version the [BSD License](https://github.com/OpenAMP/open-amp/blob/main/LICENSE.md), which is 148 | the license covering the OpenAMP distribution as a whole. In practice, use the following tag 149 | instead of the full license text in the individual files: 150 | ``` 151 | SPDX-License-Identifier: BSD-3-Clause 152 | SPDX-License-Identifier: BSD-2-Clause 153 | ``` 154 | ### Signed-off-by 155 | Commit message must contain Signed-off-by: line and your email must match the change authorship 156 | information. Make sure your .gitconfig is set up correctly: 157 | ``` 158 | git config --global user.name "first-name Last-Namer" 159 | git config --global user.email "yourmail@company.com" 160 | ``` 161 | ### gitlint 162 | Before you submit a pull request to the project, verify your commit messages meet the requirements. 163 | The check can be performed locally using the the gitlint command. 164 | 165 | Run gitlint locally in your tree and branch where your patches have been committed: 166 | ``` 167 | gitlint 168 | ``` 169 | Note, gitlint only checks HEAD (the most recent commit), so you should run it after each commit, or 170 | use the --commits option to specify a commit range covering all the development patches to be 171 | submitted. 172 | 173 | ### Code style 174 | In general, follow the Linux kernel coding style, with the following exceptions: 175 | 176 | * Use /** */ for doxygen comments that need to appear in the documentation. 177 | 178 | The Linux kernel GPL-licensed tool checkpatch is used to check coding style conformity.Checkpatch is 179 | available in the scripts directory. 180 | 181 | To check your \ commits in your git branch: 182 | ``` 183 | ./scripts/checkpatch.pl --strict -g HEAD- 184 | ``` 185 | ### Send a pull request 186 | We use standard github mechanism for pull request. Please refer to github documentation for help. 187 | 188 | ## Communication and Collaboration 189 | [Subscribe](https://lists.openampproject.org/mailman3/lists/openamp-rp.lists.openampproject.org/) to 190 | the OpenAMP mailing list(openamp-rp@lists.openampproject.org). 191 | 192 | For more details on the framework please refer to the 193 | [OpenAMP Docs](https://openamp.readthedocs.io/en/latest/). 194 | -------------------------------------------------------------------------------- /lib/proxy/rpmsg_retarget.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Mentor Graphics Corporation 3 | * All rights reserved. 4 | * 5 | * SPDX-License-Identifier: BSD-3-Clause 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | /************************************************************************* 19 | * Description 20 | * This files contains rpmsg based redefinitions for C RTL system calls 21 | * such as _open, _read, _write, _close. 22 | *************************************************************************/ 23 | static struct rpmsg_rpc_data *rpmsg_default_rpc; 24 | 25 | static int rpmsg_rpc_ept_cb(struct rpmsg_endpoint *ept, void *data, size_t len, 26 | uint32_t src, void *priv) 27 | { 28 | struct rpmsg_rpc_syscall *syscall; 29 | 30 | (void)priv; 31 | (void)src; 32 | 33 | if (data && ept) { 34 | syscall = data; 35 | if (syscall->id == TERM_SYSCALL_ID) { 36 | rpmsg_destroy_ept(ept); 37 | } else { 38 | struct rpmsg_rpc_data *rpc; 39 | 40 | rpc = metal_container_of(ept, 41 | struct rpmsg_rpc_data, 42 | ept); 43 | metal_spinlock_acquire(&rpc->buflock); 44 | if (rpc->respbuf && rpc->respbuf_len != 0) { 45 | if (len > rpc->respbuf_len) 46 | len = rpc->respbuf_len; 47 | memcpy(rpc->respbuf, data, len); 48 | } 49 | atomic_flag_clear(&rpc->nacked); 50 | metal_spinlock_release(&rpc->buflock); 51 | } 52 | } 53 | 54 | return RPMSG_SUCCESS; 55 | } 56 | 57 | static void rpmsg_service_unbind(struct rpmsg_endpoint *ept) 58 | { 59 | struct rpmsg_rpc_data *rpc; 60 | 61 | rpc = metal_container_of(ept, struct rpmsg_rpc_data, ept); 62 | rpc->ept_destroyed = 1; 63 | rpmsg_destroy_ept(ept); 64 | atomic_flag_clear(&rpc->nacked); 65 | if (rpc->shutdown_cb) 66 | rpc->shutdown_cb(rpc); 67 | } 68 | 69 | int rpmsg_rpc_init(struct rpmsg_rpc_data *rpc, 70 | struct rpmsg_device *rdev, 71 | const char *ept_name, uint32_t ept_addr, 72 | uint32_t ept_raddr, 73 | void *poll_arg, rpmsg_rpc_poll poll, 74 | rpmsg_rpc_shutdown_cb shutdown_cb) 75 | { 76 | int ret; 77 | 78 | if (!rpc || !rdev) 79 | return -EINVAL; 80 | metal_spinlock_init(&rpc->buflock); 81 | metal_mutex_init(&rpc->lock); 82 | rpc->shutdown_cb = shutdown_cb; 83 | rpc->poll_arg = poll_arg; 84 | rpc->poll = poll; 85 | rpc->ept_destroyed = 0; 86 | rpc->respbuf = NULL; 87 | rpc->respbuf_len = 0; 88 | rpc->nacked = (atomic_flag)ATOMIC_FLAG_INIT; 89 | atomic_flag_test_and_set(&rpc->nacked); 90 | ret = rpmsg_create_ept(&rpc->ept, rdev, 91 | ept_name, ept_addr, ept_raddr, 92 | rpmsg_rpc_ept_cb, rpmsg_service_unbind); 93 | if (ret != 0) { 94 | metal_mutex_release(&rpc->lock); 95 | return -EINVAL; 96 | } 97 | while (!is_rpmsg_ept_ready(&rpc->ept)) { 98 | if (rpc->poll) 99 | rpc->poll(rpc->poll_arg); 100 | } 101 | return 0; 102 | } 103 | 104 | void rpmsg_rpc_release(struct rpmsg_rpc_data *rpc) 105 | { 106 | if (!rpc) 107 | return; 108 | if (rpc->ept_destroyed == 0) 109 | rpmsg_destroy_ept(&rpc->ept); 110 | metal_mutex_acquire(&rpc->lock); 111 | metal_spinlock_acquire(&rpc->buflock); 112 | rpc->respbuf = NULL; 113 | rpc->respbuf_len = 0; 114 | metal_spinlock_release(&rpc->buflock); 115 | metal_mutex_release(&rpc->lock); 116 | metal_mutex_deinit(&rpc->lock); 117 | } 118 | 119 | int rpmsg_rpc_send(struct rpmsg_rpc_data *rpc, 120 | void *req, size_t len, 121 | void *resp, size_t resp_len) 122 | { 123 | int ret; 124 | 125 | if (!rpc) 126 | return -EINVAL; 127 | metal_spinlock_acquire(&rpc->buflock); 128 | rpc->respbuf = resp; 129 | rpc->respbuf_len = resp_len; 130 | metal_spinlock_release(&rpc->buflock); 131 | (void)atomic_flag_test_and_set(&rpc->nacked); 132 | ret = rpmsg_send(&rpc->ept, req, len); 133 | if (ret < 0) 134 | return -EINVAL; 135 | if (!resp) 136 | return ret; 137 | while ((atomic_flag_test_and_set(&rpc->nacked))) { 138 | if (rpc->poll) 139 | rpc->poll(rpc->poll_arg); 140 | } 141 | return ret; 142 | } 143 | 144 | void rpmsg_set_default_rpc(struct rpmsg_rpc_data *rpc) 145 | { 146 | if (!rpc) 147 | return; 148 | rpmsg_default_rpc = rpc; 149 | } 150 | 151 | /************************************************************************* 152 | * 153 | * FUNCTION 154 | * 155 | * _open 156 | * 157 | * DESCRIPTION 158 | * 159 | * Open a file. Minimal implementation 160 | * 161 | *************************************************************************/ 162 | #define MAX_BUF_LEN 496UL 163 | 164 | int _open(const char *filename, int flags, int mode) 165 | { 166 | struct rpmsg_rpc_data *rpc = rpmsg_default_rpc; 167 | struct rpmsg_rpc_syscall *syscall; 168 | struct rpmsg_rpc_syscall resp; 169 | int filename_len = strlen(filename) + 1; 170 | unsigned int payload_size = sizeof(*syscall) + filename_len; 171 | unsigned char tmpbuf[MAX_BUF_LEN]; 172 | int ret; 173 | 174 | if (!filename || payload_size > (int)MAX_BUF_LEN) { 175 | return -EINVAL; 176 | } 177 | 178 | if (!rpc) 179 | return -EINVAL; 180 | 181 | /* Construct rpc payload */ 182 | syscall = (void *)tmpbuf; 183 | syscall->id = OPEN_SYSCALL_ID; 184 | syscall->args.int_field1 = flags; 185 | syscall->args.int_field2 = mode; 186 | syscall->args.data_len = filename_len; 187 | memcpy(tmpbuf + sizeof(*syscall), filename, filename_len); 188 | 189 | resp.id = 0; 190 | ret = rpmsg_rpc_send(rpc, tmpbuf, payload_size, 191 | (void *)&resp, sizeof(resp)); 192 | if (ret >= 0) { 193 | /* Obtain return args and return to caller */ 194 | if (resp.id == OPEN_SYSCALL_ID) 195 | ret = resp.args.int_field1; 196 | else 197 | ret = -EINVAL; 198 | } 199 | 200 | return ret; 201 | } 202 | 203 | /************************************************************************* 204 | * 205 | * FUNCTION 206 | * 207 | * _read 208 | * 209 | * DESCRIPTION 210 | * 211 | * Low level function to redirect IO to serial. 212 | * 213 | *************************************************************************/ 214 | int _read(int fd, char *buffer, int buflen) 215 | { 216 | struct rpmsg_rpc_syscall syscall; 217 | struct rpmsg_rpc_syscall *resp; 218 | struct rpmsg_rpc_data *rpc = rpmsg_default_rpc; 219 | int payload_size = sizeof(syscall); 220 | unsigned char tmpbuf[MAX_BUF_LEN]; 221 | int ret; 222 | 223 | if (!rpc || !buffer || buflen == 0) 224 | return -EINVAL; 225 | 226 | /* Construct rpc payload */ 227 | syscall.id = READ_SYSCALL_ID; 228 | syscall.args.int_field1 = fd; 229 | syscall.args.int_field2 = buflen; 230 | syscall.args.data_len = 0; /*not used */ 231 | 232 | resp = (void *)tmpbuf; 233 | resp->id = 0; 234 | ret = rpmsg_rpc_send(rpc, (void *)&syscall, payload_size, 235 | tmpbuf, sizeof(tmpbuf)); 236 | 237 | /* Obtain return args and return to caller */ 238 | if (ret >= 0) { 239 | if (resp->id == READ_SYSCALL_ID) { 240 | if (resp->args.int_field1 > 0) { 241 | int tmplen = resp->args.data_len; 242 | unsigned char *tmpptr = tmpbuf; 243 | 244 | tmpptr += sizeof(*resp); 245 | if (tmplen > buflen) 246 | tmplen = buflen; 247 | memcpy(buffer, tmpptr, tmplen); 248 | } 249 | ret = resp->args.int_field1; 250 | } else { 251 | ret = -EINVAL; 252 | } 253 | } 254 | 255 | return ret; 256 | } 257 | 258 | /************************************************************************* 259 | * 260 | * FUNCTION 261 | * 262 | * _write 263 | * 264 | * DESCRIPTION 265 | * 266 | * Low level function to redirect IO to serial. 267 | * 268 | *************************************************************************/ 269 | int _write(int fd, const char *ptr, int len) 270 | { 271 | int ret; 272 | struct rpmsg_rpc_syscall *syscall; 273 | struct rpmsg_rpc_syscall resp; 274 | int payload_size = sizeof(*syscall) + len; 275 | struct rpmsg_rpc_data *rpc = rpmsg_default_rpc; 276 | unsigned char tmpbuf[MAX_BUF_LEN]; 277 | unsigned char *tmpptr; 278 | int null_term = 0; 279 | 280 | if (!rpc) 281 | return -EINVAL; 282 | if (fd == 1) 283 | null_term = 1; 284 | 285 | syscall = (void *)tmpbuf; 286 | syscall->id = WRITE_SYSCALL_ID; 287 | syscall->args.int_field1 = fd; 288 | syscall->args.int_field2 = len; 289 | syscall->args.data_len = len + null_term; 290 | tmpptr = tmpbuf + sizeof(*syscall); 291 | memcpy(tmpptr, ptr, len); 292 | if (null_term == 1) { 293 | *(char *)(tmpptr + len + null_term) = 0; 294 | payload_size += 1; 295 | } 296 | resp.id = 0; 297 | ret = rpmsg_rpc_send(rpc, tmpbuf, payload_size, 298 | (void *)&resp, sizeof(resp)); 299 | 300 | if (ret >= 0) { 301 | if (resp.id == WRITE_SYSCALL_ID) 302 | ret = resp.args.int_field1; 303 | else 304 | ret = -EINVAL; 305 | } 306 | 307 | return ret; 308 | 309 | } 310 | 311 | /************************************************************************* 312 | * 313 | * FUNCTION 314 | * 315 | * _close 316 | * 317 | * DESCRIPTION 318 | * 319 | * Close a file. Minimal implementation 320 | * 321 | *************************************************************************/ 322 | int _close(int fd) 323 | { 324 | int ret; 325 | struct rpmsg_rpc_syscall syscall; 326 | struct rpmsg_rpc_syscall resp; 327 | int payload_size = sizeof(syscall); 328 | struct rpmsg_rpc_data *rpc = rpmsg_default_rpc; 329 | 330 | if (!rpc) 331 | return -EINVAL; 332 | syscall.id = CLOSE_SYSCALL_ID; 333 | syscall.args.int_field1 = fd; 334 | syscall.args.int_field2 = 0; /*not used */ 335 | syscall.args.data_len = 0; /*not used */ 336 | 337 | resp.id = 0; 338 | ret = rpmsg_rpc_send(rpc, (void *)&syscall, payload_size, 339 | (void *)&resp, sizeof(resp)); 340 | 341 | if (ret >= 0) { 342 | if (resp.id == CLOSE_SYSCALL_ID) 343 | ret = resp.args.int_field1; 344 | else 345 | ret = -EINVAL; 346 | } 347 | 348 | return ret; 349 | } 350 | -------------------------------------------------------------------------------- /lib/rpmsg/rpmsg.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Mentor Graphics Corporation 3 | * All rights reserved. 4 | * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved. 5 | * Copyright (c) 2018 Linaro, Inc. All rights reserved. 6 | * 7 | * SPDX-License-Identifier: BSD-3-Clause 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include "rpmsg_internal.h" 15 | 16 | /** 17 | * @internal 18 | * 19 | * @brief rpmsg_get_address 20 | * 21 | * This function provides unique 32 bit address. 22 | * 23 | * @param bitmap Bit map for addresses 24 | * @param size Size of bitmap 25 | * 26 | * @return A unique address 27 | */ 28 | static uint32_t rpmsg_get_address(unsigned long *bitmap, unsigned int start, int size) 29 | { 30 | unsigned int addr = RPMSG_ADDR_ANY; 31 | unsigned int nextbit; 32 | 33 | nextbit = metal_bitmap_next_clear_bit(bitmap, start, size); 34 | if (nextbit < (uint32_t)size) { 35 | addr = RPMSG_RESERVED_ADDRESSES + nextbit; 36 | metal_bitmap_set_bit(bitmap, nextbit); 37 | } 38 | 39 | return addr; 40 | } 41 | 42 | /** 43 | * @internal 44 | * 45 | * @brief Frees the given address. 46 | * 47 | * @param bitmap Bit map for addresses 48 | * @param size Size of bitmap 49 | * @param addr Address to free 50 | */ 51 | static void rpmsg_release_address(unsigned long *bitmap, int size, 52 | int addr) 53 | { 54 | addr -= RPMSG_RESERVED_ADDRESSES; 55 | if (addr >= 0 && addr < size) 56 | metal_bitmap_clear_bit(bitmap, addr); 57 | } 58 | 59 | /** 60 | * @internal 61 | * 62 | * @brief Checks whether address is used or free. 63 | * 64 | * @param bitmap Bit map for addresses 65 | * @param size Size of bitmap 66 | * @param addr Address to free 67 | * 68 | * @return TRUE/FALSE 69 | */ 70 | static int rpmsg_is_address_set(unsigned long *bitmap, int size, int addr) 71 | { 72 | addr -= RPMSG_RESERVED_ADDRESSES; 73 | if (addr >= 0 && addr < size) 74 | return metal_bitmap_is_bit_set(bitmap, addr); 75 | else 76 | return RPMSG_ERR_PARAM; 77 | } 78 | 79 | /** 80 | * @internal 81 | * 82 | * @brief Marks the address as consumed. 83 | * 84 | * @param bitmap Bit map for addresses 85 | * @param size Size of bitmap 86 | * @param addr Address to free 87 | * 88 | * @return 0 on success, otherwise error code 89 | */ 90 | static int rpmsg_set_address(unsigned long *bitmap, int size, int addr) 91 | { 92 | addr -= RPMSG_RESERVED_ADDRESSES; 93 | if (addr >= 0 && addr < size) { 94 | metal_bitmap_set_bit(bitmap, addr); 95 | return RPMSG_SUCCESS; 96 | } else { 97 | return RPMSG_ERR_PARAM; 98 | } 99 | } 100 | 101 | void rpmsg_ept_incref(struct rpmsg_endpoint *ept) 102 | { 103 | if (ept) 104 | ept->refcnt++; 105 | } 106 | 107 | void rpmsg_ept_decref(struct rpmsg_endpoint *ept) 108 | { 109 | if (ept) { 110 | ept->refcnt--; 111 | if (!ept->refcnt) { 112 | if (ept->release_cb) 113 | ept->release_cb(ept); 114 | else 115 | ept->rdev = NULL; 116 | } 117 | } 118 | } 119 | 120 | int rpmsg_send_offchannel_raw(struct rpmsg_endpoint *ept, uint32_t src, 121 | uint32_t dst, const void *data, int len, 122 | int wait) 123 | { 124 | struct rpmsg_device *rdev; 125 | 126 | if (!ept || !ept->rdev || !data || dst == RPMSG_ADDR_ANY || len < 0) 127 | return RPMSG_ERR_PARAM; 128 | 129 | rdev = ept->rdev; 130 | 131 | if (rdev->ops.send_offchannel_raw) 132 | return rdev->ops.send_offchannel_raw(rdev, src, dst, data, 133 | len, wait); 134 | 135 | return RPMSG_ERR_PARAM; 136 | } 137 | 138 | int rpmsg_send_ns_message(struct rpmsg_endpoint *ept, unsigned long flags) 139 | { 140 | struct rpmsg_ns_msg ns_msg; 141 | int ret; 142 | 143 | ns_msg.flags = flags; 144 | ns_msg.addr = ept->addr; 145 | (void)safe_strcpy(ns_msg.name, sizeof(ns_msg.name), ept->name, sizeof(ept->name)); 146 | ret = rpmsg_send_offchannel_raw(ept, ept->addr, 147 | RPMSG_NS_EPT_ADDR, 148 | &ns_msg, sizeof(ns_msg), true); 149 | if (ret < 0) 150 | return ret; 151 | else 152 | return RPMSG_SUCCESS; 153 | } 154 | 155 | void rpmsg_hold_rx_buffer(struct rpmsg_endpoint *ept, void *rxbuf) 156 | { 157 | struct rpmsg_device *rdev; 158 | 159 | if (!ept || !ept->rdev || !rxbuf) 160 | return; 161 | 162 | rdev = ept->rdev; 163 | 164 | if (rdev->ops.hold_rx_buffer) 165 | rdev->ops.hold_rx_buffer(rdev, rxbuf); 166 | } 167 | 168 | void rpmsg_release_rx_buffer(struct rpmsg_endpoint *ept, void *rxbuf) 169 | { 170 | struct rpmsg_device *rdev; 171 | 172 | if (!ept || !ept->rdev || !rxbuf) 173 | return; 174 | 175 | rdev = ept->rdev; 176 | 177 | if (rdev->ops.release_rx_buffer) 178 | rdev->ops.release_rx_buffer(rdev, rxbuf); 179 | } 180 | 181 | int rpmsg_release_tx_buffer(struct rpmsg_endpoint *ept, void *buf) 182 | { 183 | struct rpmsg_device *rdev; 184 | 185 | if (!ept || !ept->rdev || !buf) 186 | return RPMSG_ERR_PARAM; 187 | 188 | rdev = ept->rdev; 189 | 190 | if (rdev->ops.release_tx_buffer) 191 | return rdev->ops.release_tx_buffer(rdev, buf); 192 | 193 | return RPMSG_ERR_PERM; 194 | } 195 | 196 | void *rpmsg_get_tx_payload_buffer(struct rpmsg_endpoint *ept, 197 | uint32_t *len, int wait) 198 | { 199 | struct rpmsg_device *rdev; 200 | 201 | if (!ept || !ept->rdev || !len) 202 | return NULL; 203 | 204 | rdev = ept->rdev; 205 | 206 | if (rdev->ops.get_tx_payload_buffer) 207 | return rdev->ops.get_tx_payload_buffer(rdev, len, wait); 208 | 209 | return NULL; 210 | } 211 | 212 | int rpmsg_get_tx_buffer_size(struct rpmsg_endpoint *ept) 213 | { 214 | struct rpmsg_device *rdev; 215 | 216 | if (!ept || !ept->rdev) 217 | return RPMSG_ERR_PARAM; 218 | 219 | rdev = ept->rdev; 220 | 221 | if (rdev->ops.get_tx_buffer_size) 222 | return rdev->ops.get_tx_buffer_size(rdev); 223 | 224 | return RPMSG_EOPNOTSUPP; 225 | } 226 | 227 | int rpmsg_get_rx_buffer_size(struct rpmsg_endpoint *ept) 228 | { 229 | struct rpmsg_device *rdev; 230 | 231 | if (!ept || !ept->rdev) 232 | return RPMSG_ERR_PARAM; 233 | 234 | rdev = ept->rdev; 235 | 236 | if (rdev->ops.get_rx_buffer_size) 237 | return rdev->ops.get_rx_buffer_size(rdev); 238 | 239 | return RPMSG_EOPNOTSUPP; 240 | } 241 | 242 | int rpmsg_send_offchannel_nocopy(struct rpmsg_endpoint *ept, uint32_t src, 243 | uint32_t dst, const void *data, int len) 244 | { 245 | struct rpmsg_device *rdev; 246 | 247 | if (!ept || !ept->rdev || !data || dst == RPMSG_ADDR_ANY || len < 0) 248 | return RPMSG_ERR_PARAM; 249 | 250 | rdev = ept->rdev; 251 | 252 | if (rdev->ops.send_offchannel_nocopy) 253 | return rdev->ops.send_offchannel_nocopy(rdev, src, dst, 254 | data, len); 255 | 256 | return RPMSG_ERR_PARAM; 257 | } 258 | 259 | struct rpmsg_endpoint *rpmsg_get_endpoint(struct rpmsg_device *rdev, 260 | const char *name, uint32_t addr, 261 | uint32_t dest_addr) 262 | { 263 | struct metal_list *node; 264 | struct rpmsg_endpoint *ept; 265 | 266 | metal_list_for_each(&rdev->endpoints, node) { 267 | int name_match = 0; 268 | 269 | ept = metal_container_of(node, struct rpmsg_endpoint, node); 270 | /* try to get by local address only */ 271 | if (addr != RPMSG_ADDR_ANY && ept->addr == addr) 272 | return ept; 273 | /* else use name service and destination address */ 274 | if (name) 275 | name_match = !strncmp(ept->name, name, 276 | sizeof(ept->name)); 277 | if (!name || !name_match) 278 | continue; 279 | /* destination address is known, equal to ept remote address */ 280 | if (dest_addr != RPMSG_ADDR_ANY && ept->dest_addr == dest_addr) 281 | return ept; 282 | /* ept is registered but not associated to remote ept */ 283 | if (addr == RPMSG_ADDR_ANY && ept->dest_addr == RPMSG_ADDR_ANY) 284 | return ept; 285 | } 286 | return NULL; 287 | } 288 | 289 | static void rpmsg_unregister_endpoint(struct rpmsg_endpoint *ept) 290 | { 291 | struct rpmsg_device *rdev = ept->rdev; 292 | 293 | metal_mutex_acquire(&rdev->lock); 294 | if (ept->addr != RPMSG_ADDR_ANY) 295 | rpmsg_release_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, 296 | ept->addr); 297 | metal_list_del(&ept->node); 298 | rpmsg_ept_decref(ept); 299 | metal_mutex_release(&rdev->lock); 300 | } 301 | 302 | void rpmsg_register_endpoint(struct rpmsg_device *rdev, 303 | struct rpmsg_endpoint *ept, 304 | const char *name, 305 | uint32_t src, uint32_t dest, 306 | rpmsg_ept_cb cb, 307 | rpmsg_ns_unbind_cb ns_unbind_cb, void *priv) 308 | { 309 | if (name) 310 | (void)safe_strcpy(ept->name, sizeof(ept->name), name, RPMSG_NAME_SIZE); 311 | else 312 | ept->name[0] = 0; 313 | 314 | ept->refcnt = 1; 315 | ept->addr = src; 316 | ept->dest_addr = dest; 317 | ept->cb = cb; 318 | ept->ns_unbind_cb = ns_unbind_cb; 319 | ept->priv = priv; 320 | ept->rdev = rdev; 321 | metal_list_add_tail(&rdev->endpoints, &ept->node); 322 | } 323 | 324 | int rpmsg_create_ept(struct rpmsg_endpoint *ept, struct rpmsg_device *rdev, 325 | const char *name, uint32_t src, uint32_t dest, 326 | rpmsg_ept_cb cb, rpmsg_ns_unbind_cb unbind_cb) 327 | { 328 | int status = RPMSG_SUCCESS; 329 | uint32_t addr = src; 330 | 331 | if (!ept || !rdev || !cb) 332 | return RPMSG_ERR_PARAM; 333 | 334 | metal_mutex_acquire(&rdev->lock); 335 | if (src == RPMSG_ADDR_ANY) { 336 | addr = rpmsg_get_address(rdev->bitmap, rdev->bitnext, RPMSG_ADDR_BMP_SIZE); 337 | if (addr == RPMSG_ADDR_ANY) { 338 | status = RPMSG_ERR_ADDR; 339 | goto ret_status; 340 | } 341 | rdev->bitnext = (addr + 1) % RPMSG_ADDR_BMP_SIZE; 342 | } else if (src >= RPMSG_RESERVED_ADDRESSES) { 343 | status = rpmsg_is_address_set(rdev->bitmap, 344 | RPMSG_ADDR_BMP_SIZE, src); 345 | if (!status) { 346 | /* Mark the address as used in the address bitmap. */ 347 | rpmsg_set_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, 348 | src); 349 | } else if (status > 0) { 350 | status = RPMSG_ERR_ADDR; 351 | goto ret_status; 352 | } else { 353 | goto ret_status; 354 | } 355 | } else { 356 | /* Skip check the address duplication in 0-1023: 357 | * 1.Trust the author of predefined service 358 | * 2.Simplify the tracking implementation 359 | */ 360 | } 361 | 362 | rpmsg_register_endpoint(rdev, ept, name, addr, dest, cb, unbind_cb, ept->priv); 363 | metal_mutex_release(&rdev->lock); 364 | 365 | /* Send NS announcement to remote processor */ 366 | if (ept->name[0] && rdev->support_ns && 367 | ept->dest_addr == RPMSG_ADDR_ANY) 368 | status = rpmsg_send_ns_message(ept, RPMSG_NS_CREATE); 369 | 370 | if (status) 371 | rpmsg_unregister_endpoint(ept); 372 | return status; 373 | 374 | ret_status: 375 | metal_mutex_release(&rdev->lock); 376 | return status; 377 | } 378 | 379 | void rpmsg_destroy_ept(struct rpmsg_endpoint *ept) 380 | { 381 | struct rpmsg_device *rdev; 382 | 383 | if (!ept || !ept->rdev) 384 | return; 385 | 386 | rdev = ept->rdev; 387 | 388 | if (ept->name[0] && rdev->support_ns && 389 | ept->addr >= RPMSG_RESERVED_ADDRESSES) 390 | (void)rpmsg_send_ns_message(ept, RPMSG_NS_DESTROY); 391 | rpmsg_unregister_endpoint(ept); 392 | } 393 | -------------------------------------------------------------------------------- /lib/virtio_mmio/virtio_mmio_drv.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Wind River Systems, Inc. 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | void virtio_mmio_isr(struct virtio_device *vdev); 15 | 16 | typedef void (*virtio_mmio_vq_callback)(void *); 17 | 18 | static int virtio_mmio_create_virtqueues(struct virtio_device *vdev, unsigned int flags, 19 | unsigned int nvqs, const char *names[], 20 | vq_callback callbacks[], void *callback_args[]); 21 | 22 | static inline void virtio_mmio_write32(struct virtio_device *vdev, int offset, uint32_t value) 23 | { 24 | struct virtio_mmio_device *vmdev = metal_container_of(vdev, 25 | struct virtio_mmio_device, vdev); 26 | 27 | metal_io_write32(&vmdev->cfg_io, offset, value); 28 | } 29 | 30 | static inline uint32_t virtio_mmio_read32(struct virtio_device *vdev, int offset) 31 | { 32 | struct virtio_mmio_device *vmdev = metal_container_of(vdev, 33 | struct virtio_mmio_device, vdev); 34 | 35 | return metal_io_read32(&vmdev->cfg_io, offset); 36 | } 37 | 38 | static inline uint8_t virtio_mmio_read8(struct virtio_device *vdev, int offset) 39 | { 40 | struct virtio_mmio_device *vmdev = metal_container_of(vdev, 41 | struct virtio_mmio_device, vdev); 42 | 43 | return metal_io_read8(&vmdev->cfg_io, offset); 44 | } 45 | 46 | static inline void virtio_mmio_set_status(struct virtio_device *vdev, uint8_t status) 47 | { 48 | virtio_mmio_write32(vdev, VIRTIO_MMIO_STATUS, status); 49 | } 50 | 51 | static uint8_t virtio_mmio_get_status(struct virtio_device *vdev) 52 | { 53 | return virtio_mmio_read32(vdev, VIRTIO_MMIO_STATUS); 54 | } 55 | 56 | static void virtio_mmio_write_config(struct virtio_device *vdev, 57 | uint32_t offset, void *dst, int length) 58 | { 59 | (void)(vdev); 60 | (void)(offset); 61 | (void)(dst); 62 | (void)length; 63 | 64 | metal_log(METAL_LOG_WARNING, "%s not supported\n", __func__); 65 | } 66 | 67 | static void virtio_mmio_read_config(struct virtio_device *vdev, 68 | uint32_t offset, void *dst, int length) 69 | { 70 | int i; 71 | uint8_t *d = dst; 72 | (void)(offset); 73 | 74 | for (i = 0; i < length; i++) 75 | d[i] = virtio_mmio_read8(vdev, VIRTIO_MMIO_CONFIG + i); 76 | } 77 | 78 | static uint32_t _virtio_mmio_get_features(struct virtio_device *vdev, int idx) 79 | { 80 | uint32_t hfeatures; 81 | 82 | /* Writing selection register VIRTIO_MMIO_DEVICE_FEATURES_SEL. In pure AMP 83 | * mode this needs to be followed by a synchronization w/ the device 84 | * before reading VIRTIO_MMIO_DEVICE_FEATURES 85 | */ 86 | virtio_mmio_write32(vdev, VIRTIO_MMIO_DEVICE_FEATURES_SEL, idx); 87 | hfeatures = virtio_mmio_read32(vdev, VIRTIO_MMIO_DEVICE_FEATURES); 88 | return hfeatures & vdev->features; 89 | } 90 | 91 | static uint32_t virtio_mmio_get_features(struct virtio_device *vdev) 92 | { 93 | return _virtio_mmio_get_features(vdev, 0); 94 | } 95 | 96 | /* This is more like negotiate_features */ 97 | static void _virtio_mmio_set_features(struct virtio_device *vdev, 98 | uint32_t features, int idx) 99 | { 100 | uint32_t hfeatures; 101 | 102 | /* Writing selection register VIRTIO_MMIO_DEVICE_FEATURES_SEL. In pure AMP 103 | * mode this needs to be followed by a synchronization w/ the device 104 | * before reading VIRTIO_MMIO_DEVICE_FEATURES 105 | */ 106 | virtio_mmio_write32(vdev, VIRTIO_MMIO_DEVICE_FEATURES_SEL, idx); 107 | hfeatures = virtio_mmio_read32(vdev, VIRTIO_MMIO_DEVICE_FEATURES); 108 | features &= hfeatures; 109 | virtio_mmio_write32(vdev, VIRTIO_MMIO_DRIVER_FEATURES, features); 110 | vdev->features = features; 111 | } 112 | 113 | static void virtio_mmio_set_features(struct virtio_device *vdev, uint32_t features) 114 | { 115 | _virtio_mmio_set_features(vdev, features, 0); 116 | } 117 | 118 | static void virtio_mmio_reset_device(struct virtio_device *vdev) 119 | { 120 | virtio_mmio_set_status(vdev, 0); 121 | } 122 | 123 | static void virtio_mmio_notify(struct virtqueue *vq) 124 | { 125 | /* VIRTIO_F_NOTIFICATION_DATA is not supported for now */ 126 | virtio_mmio_write32(vq->vq_dev, VIRTIO_MMIO_QUEUE_NOTIFY, vq->vq_queue_index); 127 | } 128 | 129 | const struct virtio_dispatch virtio_mmio_dispatch = { 130 | .create_virtqueues = virtio_mmio_create_virtqueues, 131 | .get_status = virtio_mmio_get_status, 132 | .set_status = virtio_mmio_set_status, 133 | .get_features = virtio_mmio_get_features, 134 | .set_features = virtio_mmio_set_features, 135 | .read_config = virtio_mmio_read_config, 136 | .write_config = virtio_mmio_write_config, 137 | .reset_device = virtio_mmio_reset_device, 138 | .notify = virtio_mmio_notify, 139 | }; 140 | 141 | static int virtio_mmio_get_metal_io(struct virtio_device *vdev, uintptr_t virt_mem_ptr, 142 | uintptr_t cfg_mem_ptr) 143 | { 144 | struct virtio_mmio_device *vmdev = metal_container_of(vdev, 145 | struct virtio_mmio_device, vdev); 146 | 147 | /* Setup shared memory region */ 148 | metal_io_init(&vmdev->shm_io, (void *)virt_mem_ptr, 149 | (metal_phys_addr_t *)&vmdev->shm_mem.base, 150 | vmdev->shm_mem.size, -1, 0, NULL); 151 | 152 | /* Setup configuration region */ 153 | metal_io_init(&vmdev->cfg_io, (void *)cfg_mem_ptr, 154 | (metal_phys_addr_t *)&vmdev->cfg_mem.base, 155 | vmdev->cfg_mem.size, -1, 0, NULL); 156 | 157 | return 0; 158 | } 159 | 160 | uint32_t virtio_mmio_get_max_elem(struct virtio_device *vdev, int idx) 161 | { 162 | /* Select the queue we're interested in by writing selection register 163 | * VIRTIO_MMIO_QUEUE_SEL. In pure AMP mode this needs to be followed by a 164 | * synchronization w/ the device before reading VIRTIO_MMIO_QUEUE_NUM_MAX 165 | */ 166 | virtio_mmio_write32(vdev, VIRTIO_MMIO_QUEUE_SEL, idx); 167 | return virtio_mmio_read32(vdev, VIRTIO_MMIO_QUEUE_NUM_MAX); 168 | } 169 | 170 | int virtio_mmio_device_init(struct virtio_mmio_device *vmdev, uintptr_t virt_mem_ptr, 171 | uintptr_t cfg_mem_ptr, void *user_data) 172 | { 173 | struct virtio_device *vdev = &vmdev->vdev; 174 | uint32_t magic, version, devid, vendor; 175 | 176 | vdev->role = vmdev->device_mode; 177 | vdev->priv = vmdev; 178 | vdev->func = &virtio_mmio_dispatch; 179 | vmdev->user_data = user_data; 180 | 181 | /* Set metal io mem ops */ 182 | virtio_mmio_get_metal_io(vdev, virt_mem_ptr, cfg_mem_ptr); 183 | 184 | magic = virtio_mmio_read32(vdev, VIRTIO_MMIO_MAGIC_VALUE); 185 | if (magic != VIRTIO_MMIO_MAGIC_VALUE_STRING) { 186 | metal_log(METAL_LOG_ERROR, "Bad magic value %08x\n", magic); 187 | return -1; 188 | } 189 | 190 | version = virtio_mmio_read32(vdev, VIRTIO_MMIO_VERSION); 191 | devid = virtio_mmio_read32(vdev, VIRTIO_MMIO_DEVICE_ID); 192 | if (devid == 0) { 193 | /* Placeholder */ 194 | return -1; 195 | } 196 | 197 | if (version != 1) { 198 | metal_log(METAL_LOG_ERROR, "Bad version %08x\n", version); 199 | return -1; 200 | } 201 | 202 | vendor = virtio_mmio_read32(vdev, VIRTIO_MMIO_VENDOR_ID); 203 | metal_log(METAL_LOG_DEBUG, "VIRTIO %08x:%08x\n", vendor, devid); 204 | 205 | vdev->id.version = version; 206 | vdev->id.device = devid; 207 | vdev->id.vendor = vendor; 208 | 209 | virtio_mmio_set_status(vdev, VIRTIO_CONFIG_STATUS_ACK); 210 | virtio_mmio_write32(vdev, VIRTIO_MMIO_GUEST_PAGE_SIZE, 4096); 211 | 212 | return 0; 213 | } 214 | 215 | /* Register preallocated virtqueues */ 216 | void virtio_mmio_register_device(struct virtio_device *vdev, int vq_num, struct virtqueue **vqs) 217 | { 218 | int i; 219 | 220 | vdev->vrings_info = metal_allocate_memory(sizeof(struct virtio_vring_info) * vq_num); 221 | /* TODO: handle error case */ 222 | for (i = 0; i < vq_num; i++) { 223 | vdev->vrings_info[i].vq = vqs[i]; 224 | } 225 | vdev->vrings_num = vq_num; 226 | } 227 | 228 | struct virtqueue *virtio_mmio_setup_virtqueue(struct virtio_device *vdev, 229 | unsigned int idx, 230 | struct virtqueue *vq, 231 | void (*cb)(void *), 232 | void *cb_arg, 233 | const char *vq_name) 234 | { 235 | uint32_t maxq; 236 | struct virtio_vring_info _vring_info = {0}; 237 | struct virtio_vring_info *vring_info = &_vring_info; 238 | struct vring_alloc_info *vring_alloc_info; 239 | struct virtio_mmio_device *vmdev = metal_container_of(vdev, 240 | struct virtio_mmio_device, vdev); 241 | 242 | if (vdev->role != (unsigned int)VIRTIO_DEV_DRIVER) { 243 | metal_log(METAL_LOG_ERROR, "Only VIRTIO_DEV_DRIVER is currently supported\n"); 244 | return NULL; 245 | } 246 | 247 | if (!vq) { 248 | metal_log(METAL_LOG_ERROR, 249 | "Only preallocated virtqueues are currently supported\n"); 250 | return NULL; 251 | } 252 | 253 | if (vdev->id.version != 0x1) { 254 | metal_log(METAL_LOG_ERROR, 255 | "Only VIRTIO MMIO version 1 is currently supported\n"); 256 | return NULL; 257 | } 258 | 259 | vring_info->io = &vmdev->shm_io; 260 | vring_info->info.num_descs = virtio_mmio_get_max_elem(vdev, idx); 261 | vring_info->info.align = VIRTIO_MMIO_VRING_ALIGNMENT; 262 | 263 | /* Check if vrings are already configured */ 264 | if (vq->vq_nentries != 0 && vq->vq_nentries == vq->vq_free_cnt && 265 | vq->vq_ring.desc) { 266 | vring_info->info.vaddr = vq->vq_ring.desc; 267 | vring_info->vq = vq; 268 | } 269 | vring_info->info.num_descs = vq->vq_nentries; 270 | 271 | vq->vq_dev = vdev; 272 | 273 | vring_alloc_info = &vring_info->info; 274 | 275 | unsigned int role_bk = vdev->role; 276 | /* Assign OA VIRTIO_DEV_DRIVER role to allow virtio guests to setup the vrings */ 277 | vdev->role = (unsigned int)VIRTIO_DEV_DRIVER; 278 | if (virtqueue_create(vdev, idx, vq_name, vring_alloc_info, (void (*)(struct virtqueue *))cb, 279 | vdev->func->notify, vring_info->vq)) { 280 | metal_log(METAL_LOG_ERROR, "virtqueue_create failed\n"); 281 | return NULL; 282 | } 283 | vdev->role = role_bk; 284 | vq->priv = cb_arg; 285 | virtqueue_set_shmem_io(vq, &vmdev->shm_io); 286 | 287 | /* Writing selection register VIRTIO_MMIO_QUEUE_SEL. In pure AMP 288 | * mode this needs to be followed by a synchronization w/ the device 289 | * before reading VIRTIO_MMIO_QUEUE_NUM_MAX 290 | */ 291 | virtio_mmio_write32(vdev, VIRTIO_MMIO_QUEUE_SEL, idx); 292 | maxq = virtio_mmio_read32(vdev, VIRTIO_MMIO_QUEUE_NUM_MAX); 293 | VIRTIO_ASSERT((maxq != 0), 294 | "VIRTIO_MMIO_QUEUE_NUM_MAX cannot be 0"); 295 | VIRTIO_ASSERT((maxq >= vq->vq_nentries), 296 | "VIRTIO_MMIO_QUEUE_NUM_MAX must be greater than vqueue->vq_nentries"); 297 | virtio_mmio_write32(vdev, VIRTIO_MMIO_QUEUE_NUM, vq->vq_nentries); 298 | virtio_mmio_write32(vdev, VIRTIO_MMIO_QUEUE_ALIGN, 4096); 299 | virtio_mmio_write32(vdev, VIRTIO_MMIO_QUEUE_PFN, 300 | ((uintptr_t)metal_io_virt_to_phys(&vmdev->shm_io, 301 | (char *)vq->vq_ring.desc)) / 4096); 302 | 303 | vdev->vrings_info[vdev->vrings_num].vq = vq; 304 | vdev->vrings_num++; 305 | virtqueue_enable_cb(vq); 306 | 307 | return vq; 308 | } 309 | 310 | void virtio_mmio_isr(struct virtio_device *vdev) 311 | { 312 | struct virtio_vring_info *vrings_info = vdev->vrings_info; 313 | 314 | uint32_t isr = virtio_mmio_read32(vdev, VIRTIO_MMIO_INTERRUPT_STATUS); 315 | struct virtqueue *vq; 316 | unsigned int i; 317 | 318 | if (isr & VIRTIO_MMIO_INT_VRING) { 319 | for (i = 0; i < vdev->vrings_num; i++) { 320 | vq = vrings_info[i].vq; 321 | if (vq->callback) 322 | vq->callback(vq->priv); 323 | } 324 | } 325 | 326 | if (isr & ~(VIRTIO_MMIO_INT_VRING)) 327 | metal_log(METAL_LOG_WARNING, "Unhandled interrupt type: 0x%x\n", isr); 328 | 329 | virtio_mmio_write32(vdev, VIRTIO_MMIO_INTERRUPT_ACK, isr); 330 | } 331 | 332 | static int virtio_mmio_create_virtqueues(struct virtio_device *vdev, unsigned int flags, 333 | unsigned int nvqs, const char *names[], 334 | vq_callback callbacks[], void *callback_args[]) 335 | { 336 | struct virtqueue *vq; 337 | struct virtqueue *vring_vq; 338 | void (*cb)(void *); 339 | void *cb_arg; 340 | unsigned int i; 341 | 342 | (void)flags; 343 | 344 | if (!vdev || !names || !vdev->vrings_info) 345 | return -EINVAL; 346 | 347 | for (i = 0; i < nvqs; i++) { 348 | vring_vq = NULL; 349 | cb = NULL; 350 | cb_arg = NULL; 351 | if (vdev->vrings_info[i].vq) 352 | vring_vq = vdev->vrings_info[i].vq; 353 | if (callbacks) 354 | cb = (virtio_mmio_vq_callback)callbacks[i]; 355 | if (callback_args) 356 | cb_arg = callback_args[i]; 357 | vq = virtio_mmio_setup_virtqueue(vdev, i, vring_vq, cb, cb_arg, names[i]); 358 | if (!vq) 359 | return -ENODEV; 360 | } 361 | 362 | return 0; 363 | } 364 | -------------------------------------------------------------------------------- /lib/remoteproc/remoteproc_virtio.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Remoteproc Virtio Framework Implementation 3 | * 4 | * Copyright(c) 2018 Xilinx Ltd. 5 | * Copyright(c) 2011 Texas Instruments, Inc. 6 | * Copyright(c) 2011 Google, Inc. 7 | * All rights reserved. 8 | * 9 | * SPDX-License-Identifier: BSD-3-Clause 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | static void rproc_virtio_delete_virtqueues(struct virtio_device *vdev) 21 | { 22 | struct virtio_vring_info *vring_info; 23 | unsigned int i; 24 | 25 | if (!vdev->vrings_info) 26 | return; 27 | 28 | for (i = 0; i < vdev->vrings_num; i++) { 29 | vring_info = &vdev->vrings_info[i]; 30 | if (vring_info->vq) 31 | virtqueue_free(vring_info->vq); 32 | } 33 | } 34 | 35 | static int rproc_virtio_create_virtqueue(struct virtio_device *vdev, 36 | unsigned int flags, 37 | unsigned int idx, 38 | const char *name, 39 | vq_callback callback) 40 | { 41 | struct virtio_vring_info *vring_info; 42 | struct vring_alloc_info *vring_alloc; 43 | int ret; 44 | (void)flags; 45 | 46 | /* Get the vring information */ 47 | vring_info = &vdev->vrings_info[idx]; 48 | vring_alloc = &vring_info->info; 49 | 50 | /* Fail if the virtqueue has already been created */ 51 | if (vring_info->vq) 52 | return ERROR_VQUEUE_INVLD_PARAM; 53 | 54 | /* Alloc the virtqueue and init it */ 55 | vring_info->vq = virtqueue_allocate(vring_alloc->num_descs); 56 | if (!vring_info->vq) 57 | return ERROR_NO_MEM; 58 | 59 | if (VIRTIO_ROLE_IS_DRIVER(vdev)) { 60 | size_t offset = metal_io_virt_to_offset(vring_info->io, vring_alloc->vaddr); 61 | size_t size = vring_size(vring_alloc->num_descs, vring_alloc->align); 62 | 63 | metal_io_block_set(vring_info->io, offset, 0, size); 64 | } 65 | 66 | ret = virtqueue_create(vdev, idx, name, vring_alloc, callback, 67 | vdev->func->notify, vring_info->vq); 68 | if (ret) 69 | return ret; 70 | 71 | return 0; 72 | } 73 | 74 | static int rproc_virtio_create_virtqueues(struct virtio_device *vdev, 75 | unsigned int flags, 76 | unsigned int nvqs, 77 | const char *names[], 78 | vq_callback callbacks[], 79 | void *callback_args[]) 80 | { 81 | unsigned int i; 82 | int ret; 83 | (void)callback_args; 84 | 85 | /* Check virtqueue numbers and the vrings_info */ 86 | if (nvqs > vdev->vrings_num || !vdev || !vdev->vrings_info) 87 | return ERROR_VQUEUE_INVLD_PARAM; 88 | 89 | /* set the notification id for vrings */ 90 | for (i = 0; i < nvqs; i++) { 91 | ret = rproc_virtio_create_virtqueue(vdev, flags, i, names[i], callbacks[i]); 92 | if (ret) 93 | goto err; 94 | } 95 | return 0; 96 | 97 | err: 98 | rproc_virtio_delete_virtqueues(vdev); 99 | return ret; 100 | } 101 | 102 | static void rproc_virtio_virtqueue_notify(struct virtqueue *vq) 103 | { 104 | struct remoteproc_virtio *rpvdev; 105 | struct virtio_vring_info *vring_info; 106 | struct virtio_device *vdev; 107 | unsigned int vq_id = vq->vq_queue_index; 108 | 109 | vdev = vq->vq_dev; 110 | rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); 111 | metal_assert(vq_id < vdev->vrings_num); 112 | vring_info = &vdev->vrings_info[vq_id]; 113 | rpvdev->notify(rpvdev->priv, vring_info->notifyid); 114 | } 115 | 116 | static unsigned char rproc_virtio_get_status(struct virtio_device *vdev) 117 | { 118 | struct remoteproc_virtio *rpvdev; 119 | struct fw_rsc_vdev *vdev_rsc; 120 | struct metal_io_region *io; 121 | char status; 122 | 123 | rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); 124 | vdev_rsc = rpvdev->vdev_rsc; 125 | io = rpvdev->vdev_rsc_io; 126 | RSC_TABLE_INVALIDATE(vdev_rsc, sizeof(struct fw_rsc_vdev)); 127 | status = metal_io_read8(io, 128 | metal_io_virt_to_offset(io, &vdev_rsc->status)); 129 | return status; 130 | } 131 | 132 | #if VIRTIO_ENABLED(VIRTIO_DRIVER_SUPPORT) 133 | static void rproc_virtio_set_status(struct virtio_device *vdev, 134 | unsigned char status) 135 | { 136 | struct remoteproc_virtio *rpvdev; 137 | struct fw_rsc_vdev *vdev_rsc; 138 | struct metal_io_region *io; 139 | 140 | rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); 141 | vdev_rsc = rpvdev->vdev_rsc; 142 | io = rpvdev->vdev_rsc_io; 143 | metal_io_write8(io, 144 | metal_io_virt_to_offset(io, &vdev_rsc->status), 145 | status); 146 | RSC_TABLE_FLUSH(vdev_rsc, sizeof(struct fw_rsc_vdev)); 147 | rpvdev->notify(rpvdev->priv, vdev->notifyid); 148 | } 149 | #endif 150 | 151 | static uint32_t rproc_virtio_get_dfeatures(struct virtio_device *vdev) 152 | { 153 | struct remoteproc_virtio *rpvdev; 154 | struct fw_rsc_vdev *vdev_rsc; 155 | struct metal_io_region *io; 156 | uint32_t features; 157 | 158 | rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); 159 | vdev_rsc = rpvdev->vdev_rsc; 160 | io = rpvdev->vdev_rsc_io; 161 | RSC_TABLE_INVALIDATE(vdev_rsc, sizeof(struct fw_rsc_vdev)); 162 | features = metal_io_read32(io, 163 | metal_io_virt_to_offset(io, &vdev_rsc->dfeatures)); 164 | 165 | return features; 166 | } 167 | 168 | static uint32_t rproc_virtio_get_features(struct virtio_device *vdev) 169 | { 170 | struct remoteproc_virtio *rpvdev; 171 | struct fw_rsc_vdev *vdev_rsc; 172 | struct metal_io_region *io; 173 | uint32_t gfeatures; 174 | uint32_t dfeatures; 175 | 176 | rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); 177 | vdev_rsc = rpvdev->vdev_rsc; 178 | io = rpvdev->vdev_rsc_io; 179 | RSC_TABLE_INVALIDATE(vdev_rsc, sizeof(struct fw_rsc_vdev)); 180 | gfeatures = metal_io_read32(io, 181 | metal_io_virt_to_offset(io, &vdev_rsc->gfeatures)); 182 | dfeatures = rproc_virtio_get_dfeatures(vdev); 183 | 184 | return dfeatures & gfeatures; 185 | } 186 | 187 | #if VIRTIO_ENABLED(VIRTIO_DRIVER_SUPPORT) 188 | static void rproc_virtio_set_features(struct virtio_device *vdev, 189 | uint32_t features) 190 | { 191 | struct remoteproc_virtio *rpvdev; 192 | struct fw_rsc_vdev *vdev_rsc; 193 | struct metal_io_region *io; 194 | 195 | rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); 196 | vdev_rsc = rpvdev->vdev_rsc; 197 | io = rpvdev->vdev_rsc_io; 198 | metal_io_write32(io, 199 | metal_io_virt_to_offset(io, &vdev_rsc->gfeatures), 200 | features); 201 | RSC_TABLE_FLUSH(vdev_rsc, sizeof(struct fw_rsc_vdev)); 202 | rpvdev->notify(rpvdev->priv, vdev->notifyid); 203 | } 204 | 205 | static uint32_t rproc_virtio_negotiate_features(struct virtio_device *vdev, 206 | uint32_t features) 207 | { 208 | features = features & rproc_virtio_get_dfeatures(vdev); 209 | rproc_virtio_set_features(vdev, features); 210 | 211 | /* return the mask of features successfully negotiated */ 212 | return features; 213 | } 214 | #endif 215 | 216 | static void rproc_virtio_read_config(struct virtio_device *vdev, 217 | uint32_t offset, void *dst, int length) 218 | { 219 | struct remoteproc_virtio *rpvdev; 220 | struct fw_rsc_vdev *vdev_rsc; 221 | struct metal_io_region *io; 222 | char *config; 223 | 224 | rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); 225 | vdev_rsc = rpvdev->vdev_rsc; 226 | config = (char *)(&vdev_rsc->vring[vdev->vrings_num]); 227 | io = rpvdev->vdev_rsc_io; 228 | 229 | if (offset + length <= vdev_rsc->config_len) { 230 | RSC_TABLE_INVALIDATE(config + offset, length); 231 | metal_io_block_read(io, 232 | metal_io_virt_to_offset(io, config + offset), 233 | dst, length); 234 | } 235 | } 236 | 237 | #if VIRTIO_ENABLED(VIRTIO_DRIVER_SUPPORT) 238 | static void rproc_virtio_write_config(struct virtio_device *vdev, 239 | uint32_t offset, void *src, int length) 240 | { 241 | struct remoteproc_virtio *rpvdev; 242 | struct fw_rsc_vdev *vdev_rsc; 243 | struct metal_io_region *io; 244 | char *config; 245 | 246 | rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); 247 | vdev_rsc = rpvdev->vdev_rsc; 248 | config = (char *)(&vdev_rsc->vring[vdev->vrings_num]); 249 | io = rpvdev->vdev_rsc_io; 250 | 251 | if (offset + length <= vdev_rsc->config_len) { 252 | metal_io_block_write(io, 253 | metal_io_virt_to_offset(io, config + offset), 254 | src, length); 255 | RSC_TABLE_FLUSH(config + offset, length); 256 | rpvdev->notify(rpvdev->priv, vdev->notifyid); 257 | } 258 | } 259 | 260 | static void rproc_virtio_reset_device(struct virtio_device *vdev) 261 | { 262 | if (vdev->role == VIRTIO_DEV_DRIVER) 263 | rproc_virtio_set_status(vdev, 264 | VIRTIO_CONFIG_STATUS_NEEDS_RESET); 265 | } 266 | #endif 267 | 268 | static const struct virtio_dispatch remoteproc_virtio_dispatch_funcs = { 269 | .create_virtqueues = rproc_virtio_create_virtqueues, 270 | .delete_virtqueues = rproc_virtio_delete_virtqueues, 271 | .get_status = rproc_virtio_get_status, 272 | .get_features = rproc_virtio_get_features, 273 | .read_config = rproc_virtio_read_config, 274 | .notify = rproc_virtio_virtqueue_notify, 275 | #if VIRTIO_ENABLED(VIRTIO_DRIVER_SUPPORT) 276 | /* 277 | * We suppose here that the vdev is in a shared memory so that can 278 | * be access only by one core: the host. In this case salve core has 279 | * only read access right. 280 | */ 281 | .set_status = rproc_virtio_set_status, 282 | .set_features = rproc_virtio_set_features, 283 | .negotiate_features = rproc_virtio_negotiate_features, 284 | .write_config = rproc_virtio_write_config, 285 | .reset_device = rproc_virtio_reset_device, 286 | #endif 287 | }; 288 | 289 | struct virtio_device * 290 | rproc_virtio_create_vdev(unsigned int role, unsigned int notifyid, 291 | void *rsc, struct metal_io_region *rsc_io, 292 | void *priv, 293 | rpvdev_notify_func notify, 294 | virtio_dev_reset_cb rst_cb) 295 | { 296 | struct remoteproc_virtio *rpvdev; 297 | struct virtio_vring_info *vrings_info; 298 | struct fw_rsc_vdev *vdev_rsc = rsc; 299 | struct virtio_device *vdev; 300 | unsigned int num_vrings = vdev_rsc->num_of_vrings; 301 | 302 | rpvdev = metal_allocate_memory(sizeof(*rpvdev)); 303 | if (!rpvdev) 304 | return NULL; 305 | vrings_info = metal_allocate_memory(sizeof(*vrings_info) * num_vrings); 306 | if (!vrings_info) 307 | goto err; 308 | memset(rpvdev, 0, sizeof(*rpvdev)); 309 | memset(vrings_info, 0, sizeof(*vrings_info) * num_vrings); 310 | 311 | /* Initialize the remoteproc virtio */ 312 | rpvdev->notify = notify; 313 | rpvdev->priv = priv; 314 | /* Assuming the shared memory has been mapped and registered if 315 | * necessary 316 | */ 317 | rpvdev->vdev_rsc = vdev_rsc; 318 | rpvdev->vdev_rsc_io = rsc_io; 319 | 320 | /* Initialize the virtio device */ 321 | vdev = &rpvdev->vdev; 322 | vdev->vrings_info = vrings_info; 323 | vdev->notifyid = notifyid; 324 | vdev->id.device = vdev_rsc->id; 325 | vdev->role = role; 326 | vdev->reset_cb = rst_cb; 327 | vdev->vrings_num = num_vrings; 328 | vdev->func = &remoteproc_virtio_dispatch_funcs; 329 | 330 | #if VIRTIO_ENABLED(VIRTIO_DRIVER_SUPPORT) 331 | if (role == VIRTIO_DEV_DRIVER) { 332 | uint32_t dfeatures = rproc_virtio_get_dfeatures(vdev); 333 | /* Assume the virtio driver support all remote features */ 334 | rproc_virtio_negotiate_features(vdev, dfeatures); 335 | } 336 | #endif 337 | 338 | return &rpvdev->vdev; 339 | err: 340 | metal_free_memory(rpvdev); 341 | return NULL; 342 | } 343 | 344 | void rproc_virtio_remove_vdev(struct virtio_device *vdev) 345 | { 346 | struct remoteproc_virtio *rpvdev; 347 | 348 | if (!vdev) 349 | return; 350 | rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); 351 | if (vdev->vrings_info) 352 | metal_free_memory(vdev->vrings_info); 353 | metal_free_memory(rpvdev); 354 | } 355 | 356 | int rproc_virtio_init_vring(struct virtio_device *vdev, unsigned int index, 357 | unsigned int notifyid, void *va, 358 | struct metal_io_region *io, 359 | unsigned int num_descs, unsigned int align) 360 | { 361 | struct virtio_vring_info *vring_info; 362 | unsigned int num_vrings; 363 | 364 | num_vrings = vdev->vrings_num; 365 | if ((index >= num_vrings) || (num_descs > RPROC_MAX_VRING_DESC)) 366 | return -RPROC_EINVAL; 367 | vring_info = &vdev->vrings_info[index]; 368 | vring_info->io = io; 369 | vring_info->notifyid = notifyid; 370 | vring_info->info.vaddr = va; 371 | vring_info->info.num_descs = num_descs; 372 | vring_info->info.align = align; 373 | 374 | return 0; 375 | } 376 | 377 | int rproc_virtio_notified(struct virtio_device *vdev, uint32_t notifyid) 378 | { 379 | unsigned int num_vrings, i; 380 | struct virtio_vring_info *vring_info; 381 | struct virtqueue *vq; 382 | 383 | if (!vdev) 384 | return -RPROC_EINVAL; 385 | /* We do nothing for vdev notification in this implementation */ 386 | if (vdev->notifyid == notifyid) 387 | return 0; 388 | num_vrings = vdev->vrings_num; 389 | for (i = 0; i < num_vrings; i++) { 390 | vring_info = &vdev->vrings_info[i]; 391 | if (vring_info->notifyid == notifyid || 392 | notifyid == RSC_NOTIFY_ID_ANY) { 393 | vq = vring_info->vq; 394 | virtqueue_notification(vq); 395 | } 396 | } 397 | return 0; 398 | } 399 | 400 | void rproc_virtio_wait_remote_ready(struct virtio_device *vdev) 401 | { 402 | uint8_t status; 403 | 404 | /* 405 | * No status available for remote. As virtio driver has not to wait 406 | * remote action, we can return. Behavior should be updated 407 | * in future if a remote status is added. 408 | */ 409 | if (VIRTIO_ROLE_IS_DRIVER(vdev)) 410 | return; 411 | 412 | while (1) { 413 | status = rproc_virtio_get_status(vdev); 414 | if (status & VIRTIO_CONFIG_STATUS_DRIVER_OK) 415 | return; 416 | metal_sleep_usec(1000); 417 | } 418 | } 419 | -------------------------------------------------------------------------------- /lib/include/openamp/virtqueue.h: -------------------------------------------------------------------------------- 1 | #ifndef VIRTQUEUE_H_ 2 | #define VIRTQUEUE_H_ 3 | 4 | /*- 5 | * Copyright (c) 2011, Bryan Venteicher 6 | * All rights reserved. 7 | * 8 | * SPDX-License-Identifier: BSD-2-Clause 9 | * 10 | * $FreeBSD$ 11 | */ 12 | 13 | #include 14 | #include 15 | 16 | #if defined __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | /* Error Codes */ 26 | #define VQ_ERROR_BASE -3000 27 | #define ERROR_VRING_FULL (VQ_ERROR_BASE - 1) 28 | #define ERROR_INVLD_DESC_IDX (VQ_ERROR_BASE - 2) 29 | #define ERROR_EMPTY_RING (VQ_ERROR_BASE - 3) 30 | #define ERROR_NO_MEM (VQ_ERROR_BASE - 4) 31 | #define ERROR_VRING_MAX_DESC (VQ_ERROR_BASE - 5) 32 | #define ERROR_VRING_ALIGN (VQ_ERROR_BASE - 6) 33 | #define ERROR_VRING_NO_BUFF (VQ_ERROR_BASE - 7) 34 | #define ERROR_VQUEUE_INVLD_PARAM (VQ_ERROR_BASE - 8) 35 | 36 | #define VQUEUE_SUCCESS 0 37 | 38 | /* The maximum virtqueue size is 2^15. Use that value as the end of 39 | * descriptor chain terminator since it will never be a valid index 40 | * in the descriptor table. This is used to verify we are correctly 41 | * handling vq_free_cnt. 42 | */ 43 | #define VQ_RING_DESC_CHAIN_END 32768 44 | 45 | /* Support for indirect buffer descriptors. */ 46 | #define VIRTIO_RING_F_INDIRECT_DESC (1 << 28) 47 | 48 | /* Support to suppress interrupt until specific index is reached. */ 49 | #define VIRTIO_RING_F_EVENT_IDX (1 << 29) 50 | 51 | #if defined(VIRTIO_USE_DCACHE) 52 | #define VRING_FLUSH(x, s) metal_cache_flush(x, s) 53 | #define VRING_INVALIDATE(x, s) metal_cache_invalidate(x, s) 54 | #else 55 | #define VRING_FLUSH(x, s) do { } while (0) 56 | #define VRING_INVALIDATE(x, s) do { } while (0) 57 | #endif /* VIRTIO_USE_DCACHE */ 58 | 59 | /** @brief Buffer descriptor. */ 60 | struct virtqueue_buf { 61 | /** Address of the buffer. */ 62 | void *buf; 63 | 64 | /** Size of the buffer. */ 65 | int len; 66 | }; 67 | 68 | /** @brief Vring descriptor extra information for buffer list management. */ 69 | struct vq_desc_extra { 70 | /** Pointer to first descriptor. */ 71 | void *cookie; 72 | 73 | /** Number of chained descriptors. */ 74 | uint16_t ndescs; 75 | }; 76 | 77 | /** @brief Local virtio queue to manage a virtio ring for sending or receiving. */ 78 | struct virtqueue { 79 | /** Associated virtio device. */ 80 | struct virtio_device *vq_dev; 81 | 82 | /** Name of the virtio queue. */ 83 | const char *vq_name; 84 | 85 | /** Index of the virtio queue. */ 86 | uint16_t vq_queue_index; 87 | 88 | /** Max number of buffers in the virtio queue. */ 89 | uint16_t vq_nentries; 90 | 91 | /** Function to invoke, when message is available on the virtio queue. */ 92 | void (*callback)(struct virtqueue *vq); 93 | 94 | /** Private data associated to the virtio queue. */ 95 | void *priv; 96 | 97 | /** Function to invoke, to inform the other side about an update in the virtio queue. */ 98 | void (*notify)(struct virtqueue *vq); 99 | 100 | /** Associated virtio ring. */ 101 | struct vring vq_ring; 102 | 103 | /** Number of free descriptor in the virtio ring. */ 104 | uint16_t vq_free_cnt; 105 | 106 | /** Number of queued buffer in the virtio ring. */ 107 | uint16_t vq_queued_cnt; 108 | 109 | /** 110 | * Metal I/O region of the buffers. 111 | * This structure is used for conversion between virtual and physical addresses. 112 | */ 113 | struct metal_io_region *shm_io; 114 | 115 | /** 116 | * Head of the free chain in the descriptor table. If there are no free descriptors, 117 | * this will be set to VQ_RING_DESC_CHAIN_END. 118 | */ 119 | uint16_t vq_desc_head_idx; 120 | 121 | /** Last consumed descriptor in the used table, trails vq_ring.used->idx. */ 122 | uint16_t vq_used_cons_idx; 123 | 124 | /** Last consumed descriptor in the available table, used by the consumer side. */ 125 | uint16_t vq_available_idx; 126 | 127 | #ifdef VQUEUE_DEBUG 128 | /** Debug counter for virtqueue reentrance check. */ 129 | bool vq_inuse; 130 | #endif 131 | 132 | /** 133 | * Used by the host side during callback. Cookie holds the address of buffer received from 134 | * other side. Other fields in this structure are not used currently. 135 | */ 136 | struct vq_desc_extra vq_descx[0]; 137 | }; 138 | 139 | /** @brief Virtio ring specific information. */ 140 | struct vring_alloc_info { 141 | /** Vring address. */ 142 | void *vaddr; 143 | 144 | /** Vring alignment. */ 145 | uint32_t align; 146 | 147 | /** Number of descriptors in the vring. */ 148 | uint16_t num_descs; 149 | 150 | /** Padding */ 151 | uint16_t pad; 152 | }; 153 | 154 | typedef void (*vq_callback)(struct virtqueue *); 155 | typedef void (*vq_notify)(struct virtqueue *); 156 | 157 | #ifdef VQUEUE_DEBUG 158 | #include 159 | #include 160 | 161 | #define VQASSERT(_vq, _exp, _msg) \ 162 | do { \ 163 | if (!(_exp)) { \ 164 | metal_log(METAL_LOG_EMERGENCY, \ 165 | "%s: %s - "_msg, __func__, (_vq)->vq_name); \ 166 | metal_assert(_exp); \ 167 | } \ 168 | } while (0) 169 | 170 | #define VQ_RING_ASSERT_VALID_IDX(_vq, _idx) \ 171 | VQASSERT((_vq), (_idx) < (_vq)->vq_nentries, "invalid ring index") 172 | 173 | #define VQ_RING_ASSERT_CHAIN_TERM(_vq) \ 174 | VQASSERT((_vq), (_vq)->vq_desc_head_idx == \ 175 | VQ_RING_DESC_CHAIN_END, \ 176 | "full ring terminated incorrectly: invalid head") 177 | 178 | #define VQ_PARAM_CHK(condition, status_var, status_err) \ 179 | do { \ 180 | if (((status_var) == 0) && (condition)) { \ 181 | status_var = status_err; \ 182 | } \ 183 | } while (0) 184 | 185 | #define VQUEUE_BUSY(vq) \ 186 | do { \ 187 | if (!(vq)->vq_inuse) \ 188 | (vq)->vq_inuse = true; \ 189 | else \ 190 | VQASSERT(vq, !(vq)->vq_inuse,\ 191 | "VirtQueue already in use"); \ 192 | } while (0) 193 | 194 | #define VQUEUE_IDLE(vq) ((vq)->vq_inuse = false) 195 | 196 | #else 197 | 198 | #define VQASSERT(_vq, _exp, _msg) 199 | #define VQ_RING_ASSERT_VALID_IDX(_vq, _idx) 200 | #define VQ_RING_ASSERT_CHAIN_TERM(_vq) 201 | #define VQ_PARAM_CHK(condition, status_var, status_err) 202 | #define VQUEUE_BUSY(vq) 203 | #define VQUEUE_IDLE(vq) 204 | 205 | #endif 206 | 207 | /** 208 | * @internal 209 | * 210 | * @brief Creates new VirtIO queue 211 | * 212 | * @param device Pointer to VirtIO device 213 | * @param id VirtIO queue ID , must be unique 214 | * @param name Name of VirtIO queue 215 | * @param ring Pointer to vring_alloc_info control block 216 | * @param callback Pointer to callback function, invoked 217 | * when message is available on VirtIO queue 218 | * @param notify Pointer to notify function, used to notify 219 | * other side that there is job available for it 220 | * @param vq Created VirtIO queue. 221 | * 222 | * @return Function status 223 | */ 224 | int virtqueue_create(struct virtio_device *device, unsigned short id, 225 | const char *name, struct vring_alloc_info *ring, 226 | void (*callback)(struct virtqueue *vq), 227 | void (*notify)(struct virtqueue *vq), 228 | struct virtqueue *vq); 229 | 230 | /* 231 | * virtqueue_set_shmem_io 232 | * 233 | * set virtqueue shared memory I/O region 234 | * 235 | * @vq - virt queue 236 | * @io - pointer to the shared memory I/O region 237 | */ 238 | static inline void virtqueue_set_shmem_io(struct virtqueue *vq, 239 | struct metal_io_region *io) 240 | { 241 | vq->shm_io = io; 242 | } 243 | 244 | /** 245 | * @internal 246 | * 247 | * @brief Enqueues new buffer in vring for consumption by other side. Readable 248 | * buffers are always inserted before writable buffers 249 | * 250 | * @param vq Pointer to VirtIO queue control block. 251 | * @param buf_list Pointer to a list of virtqueue buffers. 252 | * @param readable Number of readable buffers 253 | * @param writable Number of writable buffers 254 | * @param cookie Pointer to hold call back data 255 | * 256 | * @return Function status 257 | */ 258 | int virtqueue_add_buffer(struct virtqueue *vq, struct virtqueue_buf *buf_list, 259 | int readable, int writable, void *cookie); 260 | 261 | /** 262 | * @internal 263 | * 264 | * @brief Returns used buffers from VirtIO queue 265 | * 266 | * @param vq Pointer to VirtIO queue control block 267 | * @param len Length of conumed buffer 268 | * @param idx Index of the buffer 269 | * 270 | * @return Pointer to used buffer 271 | */ 272 | void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t *len, uint16_t *idx); 273 | 274 | /** 275 | * @internal 276 | * 277 | * @brief Returns buffer available for use in the VirtIO queue 278 | * 279 | * @param vq Pointer to VirtIO queue control block 280 | * @param avail_idx Pointer to index used in vring desc table 281 | * @param len Length of buffer 282 | * 283 | * @return Pointer to available buffer 284 | */ 285 | void *virtqueue_get_first_avail_buffer(struct virtqueue *vq, uint16_t *avail_idx, 286 | uint32_t *len); 287 | 288 | /** 289 | * @internal 290 | * 291 | * @brief Returns the next buffer available for use in the VirtIO queue 292 | * 293 | * This API retrieves the next available buffer pointer, descriptor table 294 | * index, and buffer length from the available buffer chain. The user must 295 | * provide the current descriptor table index of the active available 296 | * buffer (idx), next_len parameter is optional and not only if next_idx 297 | * parameter is not provided. 298 | * 299 | * Furthermore, the user can retrieve all available buffers in the buffer 300 | * chain one by one by repeatedly invoking this API. 301 | * 302 | * @param vq Pointer to VirtIO queue control block 303 | * @param idx Index used in vring desc table 304 | * @param next_idx Pointer to the index of the next buffer 305 | * @param next_len Pointer to the length of the next buffer 306 | * 307 | * @return Pointer to next available buffer of the desc[idx] described or 308 | * NULL on failure 309 | */ 310 | void *virtqueue_get_next_avail_buffer(struct virtqueue *vq, uint16_t idx, 311 | uint16_t *next_idx, uint32_t *next_len); 312 | 313 | /** 314 | * @internal 315 | * 316 | * @brief Returns consumed buffer back to VirtIO queue 317 | * 318 | * @param vq Pointer to VirtIO queue control block 319 | * @param head_idx Index of vring desc containing used buffer 320 | * @param len Length of buffer 321 | * 322 | * @return Function status 323 | */ 324 | int virtqueue_add_consumed_buffer(struct virtqueue *vq, uint16_t head_idx, 325 | uint32_t len); 326 | 327 | /** 328 | * @internal 329 | * 330 | * @brief Disables callback generation 331 | * 332 | * @param vq Pointer to VirtIO queue control block 333 | */ 334 | void virtqueue_disable_cb(struct virtqueue *vq); 335 | 336 | /** 337 | * @internal 338 | * 339 | * @brief Enables callback generation 340 | * 341 | * @param vq Pointer to VirtIO queue control block 342 | * 343 | * @return Function status 344 | */ 345 | int virtqueue_enable_cb(struct virtqueue *vq); 346 | 347 | /** 348 | * @internal 349 | * 350 | * @brief Notifies other side that there is buffer available for it. 351 | * 352 | * @param vq Pointer to VirtIO queue control block 353 | */ 354 | void virtqueue_kick(struct virtqueue *vq); 355 | 356 | static inline struct virtqueue *virtqueue_allocate(unsigned int num_desc_extra) 357 | { 358 | struct virtqueue *vqs; 359 | uint32_t vq_size = sizeof(struct virtqueue) + 360 | num_desc_extra * sizeof(struct vq_desc_extra); 361 | 362 | vqs = (struct virtqueue *)metal_allocate_memory(vq_size); 363 | if (vqs) { 364 | memset(vqs, 0x00, vq_size); 365 | } 366 | 367 | return vqs; 368 | } 369 | 370 | /** 371 | * @internal 372 | * 373 | * @brief Frees VirtIO queue resources 374 | * 375 | * @param vq Pointer to VirtIO queue control block 376 | */ 377 | void virtqueue_free(struct virtqueue *vq); 378 | 379 | /** 380 | * @internal 381 | * 382 | * @brief Dumps important virtqueue fields , use for debugging purposes 383 | * 384 | * @param vq Pointer to VirtIO queue control block 385 | */ 386 | void virtqueue_dump(struct virtqueue *vq); 387 | 388 | void virtqueue_notification(struct virtqueue *vq); 389 | 390 | /** 391 | * @internal 392 | * 393 | * @brief Returns vring descriptor size 394 | * 395 | * @param vq Pointer to VirtIO queue control block 396 | * 397 | * @return Descriptor length 398 | */ 399 | uint32_t virtqueue_get_desc_size(struct virtqueue *vq); 400 | 401 | uint32_t virtqueue_get_buffer_length(struct virtqueue *vq, uint16_t idx); 402 | void *virtqueue_get_buffer_addr(struct virtqueue *vq, uint16_t idx); 403 | 404 | /** 405 | * @brief Test if virtqueue is empty 406 | * 407 | * @param vq Pointer to VirtIO queue control block 408 | * 409 | * @return 1 if virtqueue is empty, 0 otherwise 410 | */ 411 | static inline int virtqueue_empty(struct virtqueue *vq) 412 | { 413 | return (vq->vq_nentries == vq->vq_free_cnt); 414 | } 415 | 416 | /** 417 | * @brief Test if virtqueue is full 418 | * 419 | * @param vq Pointer to VirtIO queue control block 420 | * 421 | * @return 1 if virtqueue is full, 0 otherwise 422 | */ 423 | static inline int virtqueue_full(struct virtqueue *vq) 424 | { 425 | return (vq->vq_free_cnt == 0); 426 | } 427 | 428 | #if defined __cplusplus 429 | } 430 | #endif 431 | 432 | #endif /* VIRTQUEUE_H_ */ 433 | -------------------------------------------------------------------------------- /lib/include/openamp/rpmsg_virtio.h: -------------------------------------------------------------------------------- 1 | /* 2 | * rpmsg based on virtio 3 | * 4 | * Copyright (C) 2018 Linaro, Inc. 5 | * 6 | * All rights reserved. 7 | * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved. 8 | * 9 | * SPDX-License-Identifier: BSD-3-Clause 10 | */ 11 | 12 | #ifndef _RPMSG_VIRTIO_H_ 13 | #define _RPMSG_VIRTIO_H_ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #if defined __cplusplus 22 | extern "C" { 23 | #endif 24 | 25 | /* Configurable parameters */ 26 | #ifndef RPMSG_BUFFER_SIZE 27 | #define RPMSG_BUFFER_SIZE (512) 28 | #endif 29 | 30 | /* The feature bitmap for virtio rpmsg */ 31 | #define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */ 32 | 33 | #if defined(VIRTIO_USE_DCACHE) 34 | #define BUFFER_FLUSH(x, s) metal_cache_flush(x, s) 35 | #define BUFFER_INVALIDATE(x, s) metal_cache_invalidate(x, s) 36 | #else 37 | #define BUFFER_FLUSH(x, s) do { } while (0) 38 | #define BUFFER_INVALIDATE(x, s) do { } while (0) 39 | #endif /* VIRTIO_USE_DCACHE */ 40 | 41 | /* Callback handler for rpmsg virtio service */ 42 | typedef int (*rpmsg_virtio_notify_wait_cb)(struct rpmsg_device *rdev, uint32_t id); 43 | 44 | /** @brief Shared memory pool used for RPMsg buffers */ 45 | struct rpmsg_virtio_shm_pool { 46 | /** Base address of the memory pool */ 47 | void *base; 48 | 49 | /** Available memory size */ 50 | size_t avail; 51 | 52 | /** Total pool size */ 53 | size_t size; 54 | }; 55 | 56 | /** 57 | * @brief Configuration of RPMsg device based on virtio 58 | * 59 | * This structure is used by the RPMsg virtio host to configure the virtiio 60 | * layer. 61 | */ 62 | struct rpmsg_virtio_config { 63 | /** The size of the buffer used to send data from host to remote */ 64 | uint32_t h2r_buf_size; 65 | 66 | /** The size of the buffer used to send data from remote to host */ 67 | uint32_t r2h_buf_size; 68 | 69 | /** The flag for splitting shared memory pool to TX and RX */ 70 | bool split_shpool; 71 | }; 72 | 73 | /** @brief Representation of a RPMsg device based on virtio */ 74 | struct rpmsg_virtio_device { 75 | /** RPMsg device */ 76 | struct rpmsg_device rdev; 77 | 78 | /** Structure containing virtio configuration */ 79 | struct rpmsg_virtio_config config; 80 | 81 | /** Pointer to the virtio device */ 82 | struct virtio_device *vdev; 83 | 84 | /** Pointer to receive virtqueue */ 85 | struct virtqueue *rvq; 86 | 87 | /** Pointer to send virtqueue */ 88 | struct virtqueue *svq; 89 | 90 | /** Pointer to the shared buffer I/O region */ 91 | struct metal_io_region *shbuf_io; 92 | 93 | /** Pointer to the shared buffers pool */ 94 | struct rpmsg_virtio_shm_pool *shpool; 95 | 96 | /** 97 | * RPMsg buffer reclaimer that contains buffers released by the 98 | * \ref rpmsg_virtio_release_tx_buffer function 99 | */ 100 | struct metal_list reclaimer; 101 | 102 | /** 103 | * Callback handler for rpmsg virtio service, called when service 104 | * can't get tx buffer 105 | */ 106 | rpmsg_virtio_notify_wait_cb notify_wait_cb; 107 | }; 108 | 109 | #define RPMSG_REMOTE VIRTIO_DEV_DEVICE 110 | #define RPMSG_HOST VIRTIO_DEV_DRIVER 111 | 112 | /** 113 | * @brief Set the virtio callback to manage the wait for TX buffer availability. 114 | * 115 | * @param rvdev Pointer to rpmsg virtio device. 116 | * @param notify_wait_cb Callback handler to wait buffer notification. 117 | */ 118 | static inline void rpmsg_virtio_set_wait_cb(struct rpmsg_virtio_device *rvdev, 119 | rpmsg_virtio_notify_wait_cb notify_wait_cb) 120 | { 121 | rvdev->notify_wait_cb = notify_wait_cb; 122 | } 123 | 124 | /** 125 | * @brief Get rpmsg virtio device role. 126 | * 127 | * @param rvdev Pointer to rpmsg virtio device. 128 | * 129 | * @return VIRTIO_DEV_DEVICE or VIRTIO_DEV_DRIVER 130 | */ 131 | static inline unsigned int 132 | rpmsg_virtio_get_role(struct rpmsg_virtio_device *rvdev) 133 | { 134 | return rvdev->vdev->role; 135 | } 136 | 137 | /** 138 | * @brief Set rpmsg virtio device status. 139 | * 140 | * Deprecated: Use virtio_set_status() instead 141 | * 142 | * @param rvdev Pointer to rpmsg virtio device. 143 | * @param status Value to be set as rpmsg virtio device status. 144 | */ 145 | __deprecated 146 | static inline void rpmsg_virtio_set_status(struct rpmsg_virtio_device *rvdev, 147 | uint8_t status) 148 | { 149 | rvdev->vdev->func->set_status(rvdev->vdev, status); 150 | } 151 | 152 | /** 153 | * @brief Retrieve rpmsg virtio device status. 154 | * 155 | * Deprecated: Use virtio_get_status() instead 156 | * 157 | * @param rvdev Pointer to rpmsg virtio device. 158 | * 159 | * @return The rpmsg virtio device status. 160 | */ 161 | __deprecated 162 | static inline uint8_t rpmsg_virtio_get_status(struct rpmsg_virtio_device *rvdev) 163 | { 164 | return rvdev->vdev->func->get_status(rvdev->vdev); 165 | } 166 | 167 | /** 168 | * @brief Get the rpmsg virtio device features. 169 | * 170 | * Deprecated: Use virtio_get_features() instead 171 | * 172 | * @param rvdev Pointer to the rpmsg virtio device. 173 | * 174 | * @return The features supported by both the rpmsg driver and rpmsg device. 175 | */ 176 | __deprecated 177 | static inline uint32_t 178 | rpmsg_virtio_get_features(struct rpmsg_virtio_device *rvdev) 179 | { 180 | return rvdev->vdev->func->get_features(rvdev->vdev); 181 | } 182 | 183 | /** 184 | * @brief Retrieve configuration data from the rpmsg virtio device. 185 | * 186 | * Deprecated: Use virtio_read_config() instead 187 | * 188 | * @param rvdev Pointer to the rpmsg virtio device. 189 | * @param offset Offset of the data within the configuration area. 190 | * @param dst Address of the buffer that will hold the data. 191 | * @param length Length of the data to be retrieved. 192 | */ 193 | __deprecated 194 | static inline void 195 | rpmsg_virtio_read_config(struct rpmsg_virtio_device *rvdev, 196 | uint32_t offset, void *dst, int length) 197 | { 198 | rvdev->vdev->func->read_config(rvdev->vdev, offset, dst, length); 199 | } 200 | 201 | /** 202 | * @brief Write configuration data to the rpmsg virtio device. 203 | * 204 | * Deprecated: Use virtio_write_config() instead 205 | * 206 | * @param rvdev Pointer to the rpmsg virtio device. 207 | * @param offset Offset of the data within the configuration area. 208 | * @param src Address of the buffer that holds the data to write. 209 | * @param length Length of the data to be written. 210 | * 211 | * @return 0 on success, otherwise error code. 212 | */ 213 | __deprecated 214 | static inline void 215 | rpmsg_virtio_write_config(struct rpmsg_virtio_device *rvdev, 216 | uint32_t offset, void *src, int length) 217 | { 218 | rvdev->vdev->func->write_config(rvdev->vdev, offset, src, length); 219 | } 220 | 221 | /** 222 | * @brief Create the rpmsg virtio device virtqueue. 223 | * 224 | * Deprecated: Use virtio_create_virtqueues() instead 225 | * 226 | * @param rvdev Pointer to the rpmsg virtio device. 227 | * @param flags Create flag. 228 | * @param nvqs The virtqueue number. 229 | * @param names Virtqueue names. 230 | * @param callbacks Virtqueue callback functions. 231 | * 232 | * @return 0 on success, otherwise error code. 233 | */ 234 | __deprecated 235 | static inline int 236 | rpmsg_virtio_create_virtqueues(struct rpmsg_virtio_device *rvdev, 237 | int flags, unsigned int nvqs, 238 | const char *names[], 239 | vq_callback *callbacks) 240 | { 241 | return virtio_create_virtqueues(rvdev->vdev, flags, nvqs, names, 242 | callbacks, NULL); 243 | } 244 | 245 | /** 246 | * @brief Delete the virtqueues created in rpmsg_virtio_create_virtqueues() 247 | * 248 | * Deprecated: Use virtio_delete_virtqueues() instead 249 | * 250 | * @param rvdev Pointer to the rpmsg virtio device 251 | */ 252 | __deprecated 253 | static inline void 254 | rpmsg_virtio_delete_virtqueues(struct rpmsg_virtio_device *rvdev) 255 | { 256 | virtio_delete_virtqueues(rvdev->vdev); 257 | } 258 | 259 | /** 260 | * @brief Get rpmsg virtio buffer size 261 | * 262 | * @param rdev Pointer to the rpmsg device 263 | * 264 | * @return Next available buffer size for text, negative value for failure 265 | */ 266 | int rpmsg_virtio_get_tx_buffer_size(struct rpmsg_device *rdev); 267 | 268 | /** 269 | * @brief Get rpmsg virtio Rx buffer size 270 | * 271 | * @param rdev Pointer to the rpmsg device 272 | * 273 | * @return Next available buffer size for text, negative value for failure 274 | */ 275 | int rpmsg_virtio_get_rx_buffer_size(struct rpmsg_device *rdev); 276 | 277 | /** 278 | * @brief Get rpmsg virtio Tx buffer size 279 | * 280 | * This function is same as rpmsg_virtio_get_tx_buffer_size(), keep it here 281 | * to maintain the forward compatibility. 282 | * 283 | * @param rdev Pointer to the rpmsg device. 284 | * 285 | * @return Next available buffer size for text, negative value for failure. 286 | */ 287 | static inline int rpmsg_virtio_get_buffer_size(struct rpmsg_device *rdev) 288 | { 289 | return rpmsg_virtio_get_tx_buffer_size(rdev); 290 | } 291 | 292 | /** 293 | * @brief Initialize rpmsg virtio device 294 | * 295 | * Host side: 296 | * Initialize RPMsg virtio queues and shared buffers, the address of shm can be 297 | * ANY. In this case, function will get shared memory from system shared memory 298 | * pools. If the vdev has the RPMsg name service feature, this API will create 299 | * a name service endpoint. 300 | * 301 | * Remote side: 302 | * This API will not return until the driver ready is set by the host side. 303 | * 304 | * @param rvdev Pointer to the rpmsg virtio device 305 | * @param vdev Pointer to the virtio device 306 | * @param ns_bind_cb Callback handler for name service announcement without 307 | * local endpoints waiting to bind. 308 | * @param shm_io Pointer to the share memory I/O region. 309 | * @param shpool Pointer to shared memory pool. 310 | * rpmsg_virtio_init_shm_pool has to be called first to 311 | * fill this structure. 312 | * 313 | * @return Status of function execution 314 | */ 315 | int rpmsg_init_vdev(struct rpmsg_virtio_device *rvdev, 316 | struct virtio_device *vdev, 317 | rpmsg_ns_bind_cb ns_bind_cb, 318 | struct metal_io_region *shm_io, 319 | struct rpmsg_virtio_shm_pool *shpool); 320 | 321 | /** 322 | * @brief Initialize rpmsg virtio device with config 323 | * 324 | * Host side: 325 | * Initialize RPMsg virtio queues and shared buffers, the address of shm can be 326 | * ANY. In this case, function will get shared memory from system shared memory 327 | * pools. If the vdev has the RPMsg name service feature, this API will create 328 | * a name service endpoint. 329 | * Sizes of virtio data buffers used by the initialized RPMsg instance are set 330 | * to values read from the passed configuration structure. 331 | * 332 | * Remote side: 333 | * This API will not return until the driver ready is set by the host side. 334 | * Sizes of virtio data buffers are set by the host side. Values passed in the 335 | * configuration structure have no effect. 336 | * 337 | * @param rvdev Pointer to the rpmsg virtio device 338 | * @param vdev Pointer to the virtio device 339 | * @param ns_bind_cb Callback handler for name service announcement without 340 | * local endpoints waiting to bind. 341 | * @param shm_io Pointer to the share memory I/O region. 342 | * @param shpool Pointer to shared memory pool array. 343 | * If the config->split_shpool is turn on, the array will 344 | * contain two elements, the shpool of txshpool and 345 | * rxshpool, Otherwise, the array has only one element, 346 | * and txshpool rxshpool shares a shpool. 347 | * And rpmsg_virtio_init_shm_pool has to be called first 348 | * to fill each shpool in this array. 349 | * @param config Pointer to configuration structure 350 | * 351 | * @return Status of function execution 352 | */ 353 | int rpmsg_init_vdev_with_config(struct rpmsg_virtio_device *rvdev, 354 | struct virtio_device *vdev, 355 | rpmsg_ns_bind_cb ns_bind_cb, 356 | struct metal_io_region *shm_io, 357 | struct rpmsg_virtio_shm_pool *shpool, 358 | const struct rpmsg_virtio_config *config); 359 | 360 | /** 361 | * @brief Deinitialize rpmsg virtio device 362 | * 363 | * @param rvdev Pointer to the rpmsg virtio device 364 | */ 365 | void rpmsg_deinit_vdev(struct rpmsg_virtio_device *rvdev); 366 | 367 | /** 368 | * @brief Initialize default shared buffers pool 369 | * 370 | * RPMsg virtio has default shared buffers pool implementation. 371 | * The memory assigned to this pool will be dedicated to the RPMsg 372 | * virtio. This function has to be called before calling rpmsg_init_vdev, 373 | * to initialize the rpmsg_virtio_shm_pool structure. 374 | * 375 | * @param shpool Pointer to the shared buffers pool structure 376 | * @param shbuf Pointer to the beginning of shared buffers 377 | * @param size Shared buffers total size 378 | */ 379 | void rpmsg_virtio_init_shm_pool(struct rpmsg_virtio_shm_pool *shpool, 380 | void *shbuf, size_t size); 381 | 382 | /** 383 | * @brief Get RPMsg device from RPMsg virtio device 384 | * 385 | * @param rvdev Pointer to RPMsg virtio device 386 | * 387 | * @return RPMsg device pointed by RPMsg virtio device 388 | */ 389 | static inline struct rpmsg_device * 390 | rpmsg_virtio_get_rpmsg_device(struct rpmsg_virtio_device *rvdev) 391 | { 392 | if (!rvdev) 393 | return NULL; 394 | 395 | return &rvdev->rdev; 396 | } 397 | 398 | /** 399 | * @brief Get buffer in the shared memory pool 400 | * 401 | * RPMsg virtio has default shared buffers pool implementation. 402 | * The memory assigned to this pool will be dedicated to the RPMsg 403 | * virtio. If you prefer to have other shared buffers allocation, 404 | * you can implement your rpmsg_virtio_shm_pool_get_buffer function. 405 | * 406 | * @param shpool Pointer to the shared buffers pool 407 | * @param size Shared buffers total size 408 | * 409 | * @return Buffer pointer if free buffer is available, NULL otherwise. 410 | */ 411 | metal_weak void * 412 | rpmsg_virtio_shm_pool_get_buffer(struct rpmsg_virtio_shm_pool *shpool, 413 | size_t size); 414 | 415 | #if defined __cplusplus 416 | } 417 | #endif 418 | 419 | #endif /* _RPMSG_VIRTIO_H_ */ 420 | -------------------------------------------------------------------------------- /lib/include/openamp/elf_loader.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Mentor Graphics Corporation 3 | * All rights reserved. 4 | * 5 | * SPDX-License-Identifier: BSD-3-Clause 6 | */ 7 | 8 | #ifndef ELF_LOADER_H_ 9 | #define ELF_LOADER_H_ 10 | 11 | #include 12 | #include 13 | 14 | #if defined __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | /* ELF32 base types - 32-bit. */ 19 | typedef uint32_t Elf32_Addr; 20 | typedef uint16_t Elf32_Half; 21 | typedef uint32_t Elf32_Off; 22 | typedef int32_t Elf32_Sword; 23 | typedef uint32_t Elf32_Word; 24 | 25 | /* ELF64 base types - 64-bit. */ 26 | typedef uint64_t Elf64_Addr; 27 | typedef uint16_t Elf64_Half; 28 | typedef uint64_t Elf64_Off; 29 | typedef int32_t Elf64_Sword; 30 | typedef uint32_t Elf64_Word; 31 | typedef uint64_t Elf64_Xword; 32 | typedef int64_t Elf64_Sxword; 33 | 34 | /* Size of ELF identifier field in the ELF file header. */ 35 | #define EI_NIDENT 16 36 | 37 | /* ELF32 file header */ 38 | typedef struct { 39 | unsigned char e_ident[EI_NIDENT]; 40 | Elf32_Half e_type; 41 | Elf32_Half e_machine; 42 | Elf32_Word e_version; 43 | Elf32_Addr e_entry; 44 | Elf32_Off e_phoff; 45 | Elf32_Off e_shoff; 46 | Elf32_Word e_flags; 47 | Elf32_Half e_ehsize; 48 | Elf32_Half e_phentsize; 49 | Elf32_Half e_phnum; 50 | Elf32_Half e_shentsize; 51 | Elf32_Half e_shnum; 52 | Elf32_Half e_shstrndx; 53 | } Elf32_Ehdr; 54 | 55 | /* ELF64 file header */ 56 | typedef struct { 57 | unsigned char e_ident[EI_NIDENT]; 58 | Elf64_Half e_type; 59 | Elf64_Half e_machine; 60 | Elf64_Word e_version; 61 | Elf64_Addr e_entry; 62 | Elf64_Off e_phoff; 63 | Elf64_Off e_shoff; 64 | Elf64_Word e_flags; 65 | Elf64_Half e_ehsize; 66 | Elf64_Half e_phentsize; 67 | Elf64_Half e_phnum; 68 | Elf64_Half e_shentsize; 69 | Elf64_Half e_shnum; 70 | Elf64_Half e_shstrndx; 71 | } Elf64_Ehdr; 72 | 73 | /* e_ident */ 74 | #define ET_NONE 0 75 | #define ET_REL 1 /* Re-locatable file */ 76 | #define ET_EXEC 2 /* Executable file */ 77 | #define ET_DYN 3 /* Shared object file */ 78 | #define ET_CORE 4 /* Core file */ 79 | #define ET_LOOS 0xfe00 /* Operating system-specific */ 80 | #define ET_HIOS 0xfeff /* Operating system-specific */ 81 | #define ET_LOPROC 0xff00 /* remote_proc-specific */ 82 | #define ET_HIPROC 0xffff /* remote_proc-specific */ 83 | 84 | /* e_machine */ 85 | #define EM_ARM 40 /* ARM/Thumb Architecture */ 86 | 87 | /* e_version */ 88 | #define EV_CURRENT 1 /* Current version */ 89 | 90 | /* e_ident[] Identification Indexes */ 91 | #define EI_MAG0 0 /* File identification */ 92 | #define EI_MAG1 1 /* File identification */ 93 | #define EI_MAG2 2 /* File identification */ 94 | #define EI_MAG3 3 /* File identification */ 95 | #define EI_CLASS 4 /* File class */ 96 | #define EI_DATA 5 /* Data encoding */ 97 | #define EI_VERSION 6 /* File version */ 98 | #define EI_OSABI 7 /* Operating system/ABI identification */ 99 | #define EI_ABIVERSION 8 /* ABI version */ 100 | #define EI_PAD 9 /* Start of padding bytes */ 101 | #define EI_NIDENT 16 /* Size of e_ident[] */ 102 | 103 | /* 104 | * EI_MAG0 to EI_MAG3 - A file's first 4 bytes hold amagic number, identifying 105 | * the file as an ELF object file 106 | */ 107 | #define ELFMAG0 0x7f /* e_ident[EI_MAG0] */ 108 | #define ELFMAG1 'E' /* e_ident[EI_MAG1] */ 109 | #define ELFMAG2 'L' /* e_ident[EI_MAG2] */ 110 | #define ELFMAG3 'F' /* e_ident[EI_MAG3] */ 111 | #define ELFMAG "\177ELF" 112 | #define SELFMAG 4 113 | 114 | /* 115 | * EI_CLASS - The next byte, e_ident[EI_CLASS], identifies the file's class, or 116 | * capacity. 117 | */ 118 | #define ELFCLASSNONE 0 /* Invalid class */ 119 | #define ELFCLASS32 1 /* 32-bit objects */ 120 | #define ELFCLASS64 2 /* 64-bit objects */ 121 | 122 | /* 123 | * EI_DATA - Byte e_ident[EI_DATA] specifies the data encoding of the 124 | * remote_proc-specific data in the object file. The following encodings are 125 | * currently defined. 126 | */ 127 | #define ELFDATANONE 0 /* Invalid data encoding */ 128 | #define ELFDATA2LSB 1 /* See Data encodings, below */ 129 | #define ELFDATA2MSB 2 /* See Data encodings, below */ 130 | 131 | /* EI_OSABI - We do not define an OS specific ABI */ 132 | #define ELFOSABI_NONE 0 133 | 134 | /* ELF32 program header */ 135 | typedef struct elf32_phdr { 136 | Elf32_Word p_type; 137 | Elf32_Off p_offset; 138 | Elf32_Addr p_vaddr; 139 | Elf32_Addr p_paddr; 140 | Elf32_Word p_filesz; 141 | Elf32_Word p_memsz; 142 | Elf32_Word p_flags; 143 | Elf32_Word p_align; 144 | } Elf32_Phdr; 145 | 146 | /* ELF64 program header */ 147 | typedef struct elf64_phdr { 148 | Elf64_Word p_type; 149 | Elf64_Word p_flags; 150 | Elf64_Off p_offset; 151 | Elf64_Addr p_vaddr; 152 | Elf64_Addr p_paddr; 153 | Elf64_Xword p_filesz; 154 | Elf64_Xword p_memsz; 155 | Elf64_Xword p_align; 156 | } Elf64_Phdr; 157 | 158 | /* segment types */ 159 | #define PT_NULL 0 160 | #define PT_LOAD 1 161 | #define PT_DYNAMIC 2 162 | #define PT_INTERP 3 163 | #define PT_NOTE 4 164 | #define PT_SHLIB 5 165 | #define PT_PHDR 6 166 | #define PT_TLS 7 /* Thread local storage segment */ 167 | #define PT_LOOS 0x60000000 /* OS-specific */ 168 | #define PT_HIOS 0x6fffffff /* OS-specific */ 169 | #define PT_LOPROC 0x70000000 170 | #define PT_HIPROC 0x7fffffff 171 | 172 | /* ELF32 section header. */ 173 | typedef struct { 174 | Elf32_Word sh_name; 175 | Elf32_Word sh_type; 176 | Elf32_Word sh_flags; 177 | Elf32_Addr sh_addr; 178 | Elf32_Off sh_offset; 179 | Elf32_Word sh_size; 180 | Elf32_Word sh_link; 181 | Elf32_Word sh_info; 182 | Elf32_Word sh_addralign; 183 | Elf32_Word sh_entsize; 184 | } Elf32_Shdr; 185 | 186 | /* ELF64 section header. */ 187 | typedef struct { 188 | Elf64_Word sh_name; 189 | Elf64_Word sh_type; 190 | Elf64_Xword sh_flags; 191 | Elf64_Addr sh_addr; 192 | Elf64_Off sh_offset; 193 | Elf64_Xword sh_size; 194 | Elf64_Word sh_link; 195 | Elf64_Word sh_info; 196 | Elf64_Xword sh_addralign; 197 | Elf64_Xword sh_entsize; 198 | } Elf64_Shdr; 199 | 200 | /* sh_type */ 201 | #define SHT_NULL 0 202 | #define SHT_PROGBITS 1 203 | #define SHT_SYMTAB 2 204 | #define SHT_STRTAB 3 205 | #define SHT_RELA 4 206 | #define SHT_HASH 5 207 | #define SHT_DYNAMIC 6 208 | #define SHT_NOTE 7 209 | #define SHT_NOBITS 8 210 | #define SHT_REL 9 211 | #define SHT_SHLIB 10 212 | #define SHT_DYNSYM 11 213 | #define SHT_INIT_ARRAY 14 214 | #define SHT_FINI_ARRAY 15 215 | #define SHT_PREINIT_ARRAY 16 216 | #define SHT_GROUP 17 217 | #define SHT_SYMTAB_SHNDX 18 218 | #define SHT_LOOS 0x60000000 219 | #define SHT_HIOS 0x6fffffff 220 | #define SHT_LOPROC 0x70000000 221 | #define SHT_HIPROC 0x7fffffff 222 | #define SHT_LOUSER 0x80000000 223 | #define SHT_HIUSER 0xffffffff 224 | 225 | /* sh_flags */ 226 | #define SHF_WRITE 0x1 227 | #define SHF_ALLOC 0x2 228 | #define SHF_EXECINSTR 0x4 229 | #define SHF_MASKPROC 0xf0000000 230 | 231 | /* Relocation entry (without addend) */ 232 | typedef struct { 233 | Elf32_Addr r_offset; 234 | Elf32_Word r_info; 235 | } Elf32_Rel; 236 | 237 | typedef struct { 238 | Elf64_Addr r_offset; 239 | Elf64_Xword r_info; 240 | } Elf64_Rel; 241 | 242 | /* Relocation entry with addend */ 243 | typedef struct { 244 | Elf32_Addr r_offset; 245 | Elf32_Word r_info; 246 | Elf32_Sword r_addend; 247 | } Elf32_Rela; 248 | 249 | typedef struct elf64_rela { 250 | Elf64_Addr r_offset; 251 | Elf64_Xword r_info; 252 | Elf64_Sxword r_addend; 253 | } Elf64_Rela; 254 | 255 | /* Macros to extract information from 'r_info' field of relocation entries */ 256 | #define ELF32_R_SYM(i) ((i) >> 8) 257 | #define ELF32_R_TYPE(i) ((unsigned char)(i)) 258 | #define ELF64_R_SYM(i) ((i) >> 32) 259 | #define ELF64_R_TYPE(i) ((i) & 0xffffffff) 260 | 261 | /* Symbol table entry */ 262 | typedef struct { 263 | Elf32_Word st_name; 264 | Elf32_Addr st_value; 265 | Elf32_Word st_size; 266 | unsigned char st_info; 267 | unsigned char st_other; 268 | Elf32_Half st_shndx; 269 | } Elf32_Sym; 270 | 271 | typedef struct elf64_sym { 272 | Elf64_Word st_name; 273 | unsigned char st_info; 274 | unsigned char st_other; 275 | Elf64_Half st_shndx; 276 | Elf64_Addr st_value; 277 | Elf64_Xword st_size; 278 | } Elf64_Sym; 279 | 280 | /* ARM specific dynamic relocation codes */ 281 | #define R_ARM_GLOB_DAT 21 /* 0x15 */ 282 | #define R_ARM_JUMP_SLOT 22 /* 0x16 */ 283 | #define R_ARM_RELATIVE 23 /* 0x17 */ 284 | #define R_ARM_ABS32 2 /* 0x02 */ 285 | 286 | /* ELF decoding information */ 287 | struct elf32_info { 288 | Elf32_Ehdr ehdr; 289 | int load_state; 290 | Elf32_Phdr *phdrs; 291 | Elf32_Shdr *shdrs; 292 | void *shstrtab; 293 | }; 294 | 295 | struct elf64_info { 296 | Elf64_Ehdr ehdr; 297 | int load_state; 298 | Elf64_Phdr *phdrs; 299 | Elf64_Shdr *shdrs; 300 | void *shstrtab; 301 | }; 302 | 303 | #define ELF_STATE_INIT 0x0L 304 | #define ELF_STATE_WAIT_FOR_PHDRS 0x100L 305 | #define ELF_STATE_WAIT_FOR_SHDRS 0x200L 306 | #define ELF_STATE_WAIT_FOR_SHSTRTAB 0x400L 307 | #define ELF_STATE_HDRS_COMPLETE 0x800L 308 | #define ELF_STATE_MASK 0xFF00L 309 | #define ELF_NEXT_SEGMENT_MASK 0x00FFL 310 | 311 | extern const struct loader_ops elf_ops; 312 | 313 | /** 314 | * @internal 315 | * 316 | * @brief Check if it is an ELF file 317 | * 318 | * It will check if the input image header is an ELF header. 319 | * 320 | * @param img_data Firmware private data which will be passed to user 321 | * defined loader operations 322 | * @param len Firmware header length 323 | * 324 | * @return 0 for success or negative value for failure. 325 | */ 326 | int elf_identify(const void *img_data, size_t len); 327 | 328 | /** 329 | * @internal 330 | * 331 | * @brief Load ELF headers 332 | * 333 | * It will get the ELF header, the program header, and the section header. 334 | * 335 | * @param img_data Image data 336 | * @param offset Input image data offset to the start of image 337 | * file 338 | * @param len Input image data length 339 | * @param img_info Pointer to store image information data 340 | * @param last_load_state Last state return by this function 341 | * @param noffset Pointer to next offset required by loading ELF 342 | * header 343 | * @param nlen Pointer to next data length required by loading 344 | * ELF header 345 | * 346 | * @return ELF loading header state, or negative value for failure 347 | */ 348 | int elf_load_header(const void *img_data, size_t offset, size_t len, 349 | void **img_info, int last_load_state, 350 | size_t *noffset, size_t *nlen); 351 | 352 | /** 353 | * @internal 354 | * 355 | * @brief Load ELF data 356 | * 357 | * It will parse the ELF image and return the target device address, 358 | * offset to the start of the ELF image of the data to load and the 359 | * length of the data to load. 360 | * 361 | * @param rproc Pointer to remoteproc instance 362 | * @param img_data Image data which will passed to the function. 363 | * it can be NULL, if image data doesn't need to 364 | * be handled by the load function. E.g. binary 365 | * data which was loaded to the target memory. 366 | * @param offset Last loaded image data offset to the start of 367 | * image file 368 | * @param len Last loaded image data length 369 | * @param img_info Pointer to store image information data 370 | * @param last_load_state The returned state of the last function call. 371 | * @param da Target device address, if the data to load is 372 | * not for target memory the da will be set to 373 | * ANY. 374 | * @param noffset Pointer to next offset required by loading ELF 375 | * header 376 | * @param nlen Pointer to next data length required by loading 377 | * ELF header 378 | * @param padding Value to pad it is possible that a size of a 379 | * segment in memory is larger than what it is in 380 | * the ELF image. e.g. a segment can have stack 381 | * section .bss. It doesn't need to copy image 382 | * file space, in this case, it will be packed 383 | * with 0. 384 | * @param nmemsize Pointer to next data target memory size. The 385 | * size of a segment in the target memory can be 386 | * larger than the its size in the image file. 387 | * 388 | * @return 0 for success, otherwise negative value for failure 389 | */ 390 | int elf_load(struct remoteproc *rproc, const void *img_data, 391 | size_t offset, size_t len, 392 | void **img_info, int last_load_state, 393 | metal_phys_addr_t *da, 394 | size_t *noffset, size_t *nlen, 395 | unsigned char *padding, size_t *nmemsize); 396 | 397 | /** 398 | * @internal 399 | * 400 | * @brief Release ELF image information 401 | * 402 | * It will release ELF image information data. 403 | * 404 | * @param img_info Pointer to ELF image information 405 | */ 406 | void elf_release(void *img_info); 407 | 408 | /** 409 | * @internal 410 | * 411 | * @brief Get entry point 412 | * 413 | * It will return entry point specified in the ELF file. 414 | * 415 | * @param img_info Pointer to ELF image information 416 | * 417 | * @return Entry address 418 | */ 419 | metal_phys_addr_t elf_get_entry(void *img_info); 420 | 421 | /** 422 | * @internal 423 | * 424 | * @brief Locate the resource table information 425 | * 426 | * It will return the length of the resource table, and the device address of 427 | * the resource table. 428 | * 429 | * @param img_info Pointer to ELF image information 430 | * @param da Pointer to the device address 431 | * @param offset Pointer to the offset to in the ELF image of the 432 | * resource table section. 433 | * @param size Pointer to the size of the resource table section. 434 | * 435 | * @return 0 if successfully locate the resource table, negative value for 436 | * failure. 437 | */ 438 | int elf_locate_rsc_table(void *img_info, metal_phys_addr_t *da, 439 | size_t *offset, size_t *size); 440 | 441 | #if defined __cplusplus 442 | } 443 | #endif 444 | 445 | #endif /* ELF_LOADER_H_ */ 446 | --------------------------------------------------------------------------------