Add documentation for the new LLEXT APIs that allow to call the initialization and cleanup functions of an extension. Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
107 lines
4.5 KiB
ReStructuredText
107 lines
4.5 KiB
ReStructuredText
Loading extensions
|
|
##################
|
|
|
|
Once an extension is built and the ELF file is available, it can be loaded into
|
|
the Zephyr application using the LLEXT API, which provides a way to load the
|
|
extension into memory, access its symbols and call its functions.
|
|
|
|
Loading an extension
|
|
====================
|
|
|
|
An extension may be loaded using any implementation of a :c:struct:`llext_loader`
|
|
which has a set of function pointers that provide the necessary functionality
|
|
to read the ELF data. A loader also provides some minimal context (memory)
|
|
needed by the :c:func:`llext_load` function. An implementation over a buffer
|
|
containing an ELF in addressable memory in memory is available as
|
|
:c:struct:`llext_buf_loader`.
|
|
|
|
The extensions are loaded with a call to the :c:func:`llext_load` function,
|
|
passing in the extension name and the configured loader. Once that completes
|
|
successfully, the extension is loaded into memory and is ready to be used.
|
|
|
|
.. note::
|
|
When :ref:`User Mode <usermode_api>` is enabled, the extension will not be
|
|
included in any user memory domain. To allow access from user mode, the
|
|
:c:func:`llext_add_domain` function must be called.
|
|
|
|
Initializing and cleaning up the extension
|
|
==========================================
|
|
|
|
The extension may define a number of initialization functions that must be
|
|
called after loading but before any function in it can be used; this is typical
|
|
in languages such as C++ that provide the concept of object constructors. The
|
|
same is true for cleanup functions that must be called before unloading the
|
|
extension.
|
|
|
|
LLEXT supports calling the functions listed in the ``.preinit_array`` and
|
|
``.init_array`` sections of the ELF file with the :c:func:`llext_bringup`
|
|
function, and the functions listed in the ``.fini_array`` section with the
|
|
:c:func:`llext_teardown` function. These APIs are compatible with
|
|
:ref:`User Mode <usermode_api>`, and thus can be called from either kernel or
|
|
user context.
|
|
|
|
.. important::
|
|
The code run by these functions is fully determined by the contents of the
|
|
ELF file. This may have security implications if its origin is untrusted.
|
|
|
|
If the extension requires a dedicated thread, the :c:func:`llext_bootstrap`
|
|
function can be used to minimize boilerplate code. This function has a
|
|
signature that is compatible with the :c:func:`k_thread_create` API, and will
|
|
call :c:func:`llext_bringup`, then a user-specified function in the same
|
|
context, and finally :c:func:`llext_teardown` before returning.
|
|
|
|
Accessing code and data
|
|
=======================
|
|
|
|
To interact with the newly loaded extension, the host application must use the
|
|
:c:func:`llext_find_sym` function to get the address of the exported symbol.
|
|
The returned ``void *`` can then be cast to the appropriate type and used.
|
|
|
|
A wrapper for calling a function with no arguments is provided in
|
|
:c:func:`llext_call_fn`.
|
|
|
|
Cleaning up after use
|
|
=====================
|
|
|
|
The :c:func:`llext_unload` function must be called to free the memory used by
|
|
the extension once it is no longer required. After this call completes, all
|
|
pointers to symbols in the extension that were obtained will be invalid.
|
|
|
|
Troubleshooting
|
|
###############
|
|
|
|
This feature is being actively developed and as such it is possible that some
|
|
issues may arise. Since linking does modify the binary code, in case of errors
|
|
the results are difficult to predict. Some common issues may be:
|
|
|
|
* Results from :c:func:`llext_find_sym` point to an invalid address;
|
|
|
|
* Constants and variables defined in the extension do not have the expected
|
|
values;
|
|
|
|
* Calling a function defined in an extension results in a hard fault, or memory
|
|
in the main application is corrupted after returning from it.
|
|
|
|
If any of this happens, the following tips may help understand the issue:
|
|
|
|
* Make sure :kconfig:option:`CONFIG_LLEXT_LOG_LEVEL` is set to ``DEBUG``, then
|
|
obtain a log of the :c:func:`llext_load` invocation.
|
|
|
|
* If possible, disable memory protection (MMU/MPU) and see if this results in
|
|
different behavior.
|
|
|
|
* Try to simplify the extension to the minimum possible code that reproduces
|
|
the issue.
|
|
|
|
* Use a debugger to inspect the memory and registers to try to understand what
|
|
is happening.
|
|
|
|
.. note::
|
|
When using GDB, the ``add_symbol_file`` command may be used to load the
|
|
debugging information and symbols from the ELF file. Make sure to specify
|
|
the proper offset (usually the start of the ``.text`` section, reported
|
|
as ``region 0`` in the debug logs.)
|
|
|
|
If the issue persists, please open an issue in the GitHub repository, including
|
|
all the above information.
|