diff --git a/developer_guides/firmware/index.rst b/developer_guides/firmware/index.rst index c0a0709a..ee2e75cd 100644 --- a/developer_guides/firmware/index.rst +++ b/developer_guides/firmware/index.rst @@ -12,3 +12,4 @@ Developer guides and information for firmware development. porting cmake async_messaging_best_practices + llext_modules diff --git a/developer_guides/firmware/llext_modules.rst b/developer_guides/firmware/llext_modules.rst new file mode 100644 index 00000000..4832495b --- /dev/null +++ b/developer_guides/firmware/llext_modules.rst @@ -0,0 +1,108 @@ +.. _llext_modules: + +LLEXT Modules +############# + +|SOF| support for loadable modules, using Zephyr LLEXT API. + +Zephyr LLEXT API +**************** + +Please refer to https://docs.zephyrproject.org/latest/services/llext/index.html +for detailed documentation. In short, the Zephyr Linkable Loadable Extensions +(LLEXT) API implements support for run-time loading and unloading of ELF-format +executable code and data. + +SOF use of the LLEXT API +************************ + +SOF has multiple ways to implement loadable modules. LLEXT is one of them. +With it modules are built as shared or relocatable ELF objects with an addition +of a cryptographic signature, using any user-supplied key, and a manifest. When +loaded and instantiated, Zephyr LLEXT functionality is used to dynamically +resolve module internal as well as SOF and Zephyr external code and data +references. In the future support for inter-module linking will be added. + +Accessing the base firmware from LLEXT modules +********************************************** + +LLEXT modules can access all code and data from the base firmware exported, +using the ``EXPORT_SYMBOL()`` macro. Therefore writing LLEXT modules isn't very +different from built-in ones. + +Implementing LLEXT modules +************************** + +At the moment only modules, implementing the Module Adapter API +:ref:`apps-comp-world` are supported. + +.. _multiple-adapter-modules: + +It is possible to implement multiple Module Adapter modules with a common code +base, i.e. sharing a set of source files and functions. Then a single LLEXT +object would be created, implementing multiple Module Adapter interfaces. In +that case an array of ``struct sof_module_api_build_info`` objects is needed and +the TOML file should contain those multiple module entries too. +src/audio/mixin_mixout/mixin_mixout.c is an example of such a case. + +As explained above, LLEXT modules in general look very similar to native SOF +code, with the only restriction of having no access to not-exported symbols. + +LLEXT modules should also contain a ``.buildinfo`` section, containing a +``struct sof_module_api_build_info`` object and a ``.module`` section, +containing a ``struct sof_man_module_manifest`` object. The latter should also +contain a pointer to a module entry point function, returning a pointer to the +module's ``struct module_interface`` instance. All these additions can be +performed, using ``SOF_LLEXT_MOD_ENTRY()``, ``SOF_LLEXT_MODULE_MANIFEST()`` and +``SOF_LLEXT_BUILDINFO`` helper macros. See src/audio/eq_iir/eq_iir.c for an +example. + +A TOML configuration file is needed for building of LLEXT modules too. It is +generated by the C preprocessor at build time from the same components, as would +be used for a monolithic build. For this preprocessor run a small header file is +added. It mostly just includes ``platform.toml`` and ``${module}.toml``, similar +to src/samples/audio/smart_amp_test_llext/llext.toml.h. + +Finally an additional CMakeLists.txt is needed similar to +src/samples/audio/smart_amp_test_llext/CMakeLists.txt. It contains a single call +to ``sof_llext_build()``, which is an SOF helper function, using Zephyr LLEXT +cmake support by calling ``add_llext_target()`` and ``add_llext_command()``. + +With that in place, it is also possible to switch between monolithic and modular +builds by specifying the module as "tristate" in its Kconfig and selecting "m" +for modular builds. Note, that it is possible to implement third party Module +Adapter drivers, that would be built exclusively as loadable modules. Such +modules don't have to use "tristate" in their Kconfig entries. + +Installation +************ + +As specified in +:ref:`Firmware look-up paths per Intel platform ` +the |SOF| Linux kernel driver loads SOF modules by their UUIDs, +specified in the topology. For SOF in-tree modules the process of creation and +installation of modules in a deployment tree is automated by the +xtensa-build-zephyr.py script. It copies modules to the deployment tree as +files with a "llext" extension and creates symbolic links to them named as +``${UUID}.bin``. E.g. + +.. code-block:: cfg + + B36EE4DA-006F-47F9-A06D-FECBE2D8B6CE.bin -> drc.llext + +Note, that as described :ref:`above ` multiple UUIDs +can be associated with a single module, in such cases multiple symbolic links +will be created, e.g. + +.. code-block:: cfg + + 39656EB2-3B71-4049-8D3F-F92CD5C43C09.bin -> mixin_mixout.llext + 3C56505A-24D7-418F-BDDC-C1F5A3AC2AE0.bin -> mixin_mixout.llext + +See :ref:`apps-component-overview` for more information on UUID use by SOF +component and module adapter drivers. + +It is also possible to avoid using the script by running ``west build`` to build +an SOF image and any modules, then using the cross-compiler to preprocess TOML +files and finally by running rimage to sign them. This would generate the same +result but figuring out all the command-line arguments would be rather difficult. diff --git a/getting_started/intel_debug/introduction.rst b/getting_started/intel_debug/introduction.rst index 45ae7e2f..2079812c 100755 --- a/getting_started/intel_debug/introduction.rst +++ b/getting_started/intel_debug/introduction.rst @@ -119,6 +119,7 @@ configuration issue. Linux SOF will look up firmware files at the following paths: +.. _intel_firmware_paths: .. list-table:: Firmware look-up paths per Intel platform :widths: 55 5 50 25 :header-rows: 1