Skip to content

Commit

Permalink
developer-guide: add LLEXT module documentation
Browse files Browse the repository at this point in the history
Describe LLEXT loadable module support in SOF.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
  • Loading branch information
lyakh committed May 13, 2024
1 parent 97e7339 commit 78c2a05
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 0 deletions.
1 change: 1 addition & 0 deletions developer_guides/firmware/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ Developer guides and information for firmware development.
porting
cmake
async_messaging_best_practices
llext_modules
89 changes: 89 additions & 0 deletions developer_guides/firmware/llext_modules.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
.. _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.

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. If
any such symbols are needed to LLEXT modules, additionally exporting them can be
considered.

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,
that mostly just includes platform.toml and <module>.toml is added, 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, however, for modules, exclusively built as LLEXT objects,
this might not be necessary. Thus it is possible to implement third party Module
Adapter drivers, that would be built exclusively as loadable modules.

Installation
************

As specified in
:ref:`Firmware look-up paths per Intel platform <intel_firmware_paths>`
the |SOF| Linux kernel driver loads SOF modules, using their UUIDs. For SOF
internal modules the process of creation
and installation of modules in a deployment tree is automated by the
xtensa-build-zephyr.py script. 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 sing
them. This would generate the same result but figuring out all the command-line
arguments would be rather difficult.
1 change: 1 addition & 0 deletions getting_started/intel_debug/introduction.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 78c2a05

Please sign in to comment.