Commit Graph

115 Commits

Author SHA1 Message Date
Eric Ackermann 5275d44409 llext: Add RISC-V arch-specific relocations
This commit introduces architecture-specific ELF relocations for RISC-V,
in accordance with the RISC-V PSABI specification:
https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc
Also, the necessary compiler configurations for compiling LLEXT
extensions on RISC-V are added, and the llext tests are executed on
RISC-V targets.
Calling llext extensions from user threads in RISC-V is still
unsupported as of this commit.

Signed-off-by: Eric Ackermann <eric.ackermann@cispa.de>
2024-10-03 21:59:42 +01:00
Guennadi Liakhovetski c6bf743df2 LLEXT: add support for detached sections
Some LLEXT objects can include sections, that should not be merged
with other sections of the same type. E.g. when such sections should
be placed into locations, other than the default. Add support for
such sections.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-09-29 21:21:24 +02:00
Guennadi Liakhovetski 0aa6b1c9de llext: pass the whole struct llext_load_param
To simplify LLEXT loader parameter extension pass the whole
struct llext_load_param to final consumers instead of extracting
individual fields from it in the caller function.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-09-29 21:21:24 +02:00
Guennadi Liakhovetski f04e646af0 llext: (cosmetic) use a more common name for a variable
It's more common in the LLEXT code base to call elf_sym_t instances
"sym" and not "sym_tbl." Convert llext_link_plt() to follow this
convention.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-09-29 21:21:24 +02:00
Guennadi Liakhovetski 43a69f868b llext: make llext_loaded_sect_ptr() available to all LLEXT code
Make llext_loaded_sect_ptr() a proper function to be able to call it
from platform LLEXT code.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-09-29 21:21:24 +02:00
Luca Burelli db451f2c46 llext: export DT devices to extensions
This change adds a new configuration option, LLEXT_EXPORT_DEVICES, which
enables exporting all devices defined in the device tree to llext
extensions. When enabled, all devices are made available to extensions
via the standard DT_ / DEVICE_* macros.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-09-25 12:59:13 +02:00
Keith Packard 88359d998c subsys/llext: Allow .exported_sym to be between other data sections
There's no reason for the .exported_sym data to always land at one end of a
data region; the order of sections depends on the whim of the compiler and
assembler.

Ignore overlaps between that region and other data regions.

Signed-off-by: Keith Packard <keithp@keithp.com>
2024-09-16 20:17:35 +02:00
Guennadi Liakhovetski 5332393066 llext: make loader parameters "const"
LLEXT loader parameters are input-only, make them "const."

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-09-12 13:02:59 -04:00
Adam Wojasinski 74b562569e llext: Add `RELA` sections processing for AARCH64
Allow to process `RELA` sections on aarch64 platform.

Signed-off-by: Adam Wojasinski <awojasinski@baylibre.com>
2024-09-12 14:48:55 +02:00
Adam Wojasinski eb51529ab3 llext: Introduce AARCH64 relocation support
Adds support for all relocation type produced by GCC
on AARCH64 platform using partial linking (-r flag) or
shared link (-fpic and -shared flag).

Signed-off-by: Adam Wojasinski <awojasinski@baylibre.com>
2024-09-12 14:48:55 +02:00
Adam Wojasinski 2ff71727f1 llext: Fix use of macro for relocation symbol index from r_info
Replace use of 32-bit architecture macro to macro arch agnostic that
is resolved in compilation.

Signed-off-by: Adam Wojasinski <awojasinski@baylibre.com>
2024-09-12 14:48:55 +02:00
Luca Burelli e6b32ab681 llext: hotfix: fix function pointer logging
Some function pointers were being passed via `%p` to LOG_DBG, and this
was causing the following issues in SOF CI with the `sparse` checker:

   subsys/llext/llext.c: error: arithmetics on pointers to functions
   subsys/llext/llext.c: error: incompatible types for operation (+)

This patch fixes the issue by casting the function pointers to void*.
Also fix a misleading error message in `llext_get_fn_table()`.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-09-11 13:59:02 -04:00
Pisit Sawangvonganan ead0dfc889 style: subsys: comply with MISRA C:2012 Rule 15.6
Add missing braces to comply with MISRA C:2012 Rule 15.6 and
also following Zephyr's style guideline.

Signed-off-by: Pisit Sawangvonganan <pisit@ndrsolution.com>
2024-09-11 07:40:35 -04:00
Luca Burelli af302cd5fe llext: add bringup, teardown, and bootstrap APIs
llext_bringup() and llext_teardown() are intended to be used to call the
extension's own initialization and cleanup functions, respectively. They
are meant to be called by the developer after loading an extension and
before unloading it. The list of function pointers to be called is
obtained via the new llext_get_fn_table() syscall, so that they are
compatible with user mode.

llext_bootstrap() is intended to be used as the entry point for a thread
created to run an extension, in either user or kernel contexts. It will
call the extension's own initialization functions and then an additional
entry point in the same context (if desired). The same function can also
be called directly in the main thread, if only initialization is
required.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-09-06 11:27:15 -04:00
Luca Burelli 04d7e4f490 llext: add support for ELF init/fini arrays
Load the .preinit_array, .init_array and .fini_array sections in ELF
files. These sections are arrays of function pointers that are filled by
the compiler with the addresses of functions that need to be called at
startup or termination by the loader, such as C++ constructors and
destructors.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-09-06 11:27:15 -04:00
Adam Wojasinski 420891cedb llext: Add shell command for loading LLEXT from a filesystem
This patch extends LLEXT shell commands with support for loading
LLEXT from a filesystem. Use of the command requires absolute path
to the llext file.

Example use:
`llext load_llext hello_world /lfs/hello_world.llext`

Signed-off-by: Adam Wojasinski <awojasinski@baylibre.com>
2024-09-06 11:26:09 -04:00
Adam Wojasinski fc114e85dd llext: Add filesystem based extension loader
Added loader allowing to load extensions stored in a filesystem.

Signed-off-by: Adam Wojasinski <awojasinski@baylibre.com>
2024-09-06 11:26:09 -04:00
Adam Wojasinski 93ffeced6a llext: Add new methods to loader API
Introducing `llext_prepare()` and `llext_finalize()` APIs
that are invoked and the beginning and the end of the `llext_load()`
function.

The purpose of these functions is to bring possibility of initializing
loader before it is used and uninitialize or clean up when
it is no longer needed. Both functions are optional.

The buffer loader has been aligned to methods introduced in the patch.

Signed-off-by: Adam Wojasinski <awojasinski@baylibre.com>
2024-09-06 11:26:09 -04:00
Nicolas Pitre b5addc808a llext: adjust memory permissions on MMU systems
By default, normal memory is set readable+writable and not executable.
Adjust those permissions according to each region:

	LLEXT_MEM_TEXT                  --> K_MEM_PERM_EXEC
	LLEXT_MEM_DATA, LLEXT_MEM_BSS   --> K_MEM_PERM_RW
	LLEXT_MEM_RODATA                --> K_MEM_PERM_RO aka 0

This must be done only at the end of an LLEXT load operation as memory
needs to remain RW for reloc processing, etc.

And while at it, flush/invalidate the cache accordingly.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2024-09-06 11:25:54 -04:00
Guennadi Liakhovetski dd50ff5585 llext: add dependencies
When an LLEXT object uses symbols of another such object, it depends
on it. Such dependencies have to be tracked to prevent their
accidental unloading. Ideally we should be able to track arbitrary
numbers of such dependencies, but this is a bit difficult. In this
first implementation we use a fixed-size array, currently consisting
of 8 entries.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-09-02 12:31:52 -04:00
Guennadi Liakhovetski c5e305fce6 llext: fix flag evaluation for section grouping
When deciding which sections to group together, only the low 3
section attribute bits are relevant, ignore the rest.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-09-02 12:31:52 -04:00
Guennadi Liakhovetski fe609dd8e8 llext: look for symbols in other LLEXT objects too
LLEXT objects can also export symbols for use by other such objects.
That means, that when linking an LLEXT object we have to look for
unresolved symbols in previously loaded objects too.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-09-02 12:31:52 -04:00
Guennadi Liakhovetski 92a7c772d9 llext: remove an unused variable
Remove a loop counter, that isn't actually used for anything.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-09-02 12:31:52 -04:00
Tom Burdick 9dffac0107 llext: flush logging before unloading extensions
Extensions could have used logging, when log processing is
deferred, the logging thread can run after the extension has
been unloaded and thereby access invalid memory addresses.
Make sure to flush all logs before unloading extensions.

Signed-off-by: Tom Burdick <thomas.burdick@intel.com>
Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-08-29 18:05:04 +02:00
Pisit Sawangvonganan 8f197c955d style: subsys: comply with MISRA C:2012 Rule 15.6
Add missing braces to comply with MISRA C:2012 Rule 15.6 and
also following Zephyr's style guideline.

Signed-off-by: Pisit Sawangvonganan <pisit@ndrsolution.com>
2024-08-20 10:33:51 +02:00
Luca Burelli f257c997b5 doc: llext: improve Doxygen comments
Review and improve comments in source code to better describe the API
and the functionality provided by the llext library.

No actual code changes are performed in this commit.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-07-11 16:17:52 +02:00
Luca Burelli 3cc452c92f llext: consistently use "regions" for memory areas
The term "section" has a very specific meaning in the ELF file format.
After 709b2e4 ("llext: automatically merge sections by type"), some of
the code that was originally dealing with ELF sections is now handling
"memory regions" made of multiple ELF sections of the same type.

Make sure to use the term "region" consistently in the code and
log messages to avoid confusion with the original ELF sections.

Notable exception to this is the "ldr->sect" array, which is actively
used outside Zephyr and will need to be phased out in the future.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-07-09 19:04:06 +02:00
Luca Burelli 2e085ba29a llext: harmonize error codes
This patch changes the error codes returned by the ELF subsystem to be
more consistent with the standard error descriptions. In particular:

- issues with the ELF file are now reported as -ENOEXEC;
- valid but unsupported edge cases are reported as -ENOTSUP;
- failures in searching for an entry are reported as -ENOENT.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-07-09 19:04:06 +02:00
Luca Burelli 9450240419 llext: fix table count check
llext_load() included a check to ensure that the ELF file contains all
the necessary tables, but it was not functional. Add the missing check
and rename the variable to avoid confusion with the total section count.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-07-09 19:04:06 +02:00
Luca Burelli 5ce6a750a5 llext: add explicit cast to fix Coverity CID: 392507
From https://mails.dpdk.org/archives/dev/2021-December/231212.html:

    Downcasting a void* to struct aesni_gcm_session* caused the session
    data to be treated as tainted. Removing the void* temporary variable
    and adding a cast avoids this issue.

Try the same approach here to prevent the ldr->sect_hdrs pointer from
being treated as tainted.

May fix #74817.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-07-09 11:51:29 +02:00
Luca Burelli d4ea1da10e llext: fix llext_find_section(), remove llext_section_by_name()
The function llext_section_by_name() is used only in one place, and it
expects the caller to have the section headers cache available. This
cache is freed after the ELF file is loaded, so the function is not
usable in the context where it is called.

Remove the function and replace the call with a direct search in the
ELF file section headers array, as was done before 08eb314c35.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-06-25 21:25:33 -04:00
Luca Burelli 95cab98110 llext: fix section addresses at link time by using sh_info
Currently, the code uses the section name to identify the target section
of a relocation. This is not reliable, as the section name is not
guaranteed to be in a specific format. Instead, use the sh_info field of
the relocation section header to identify the target section.

This is a tricky change, as it requires a workaround for the Xtensa
port, whose code path diverges here into the `link_plt` function and
ultimately different arch-specific code. Avoiding this divergence
will require additional refactorings.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-06-25 21:25:33 -04:00
Luca Burelli a1550c4db1 llext: fix llext_load() optimization
The optimization in llext_load() to avoid using the generic path for
sections that are cached in memory was broken for two reasons:
- it was comparing an ELF section index to LLEXT_MEM_BSS, which is a
  llext_mem enum, and
- it was using the wrong section address for the cached sections since
  the "merged sections" feature was introduced in 709b2e44bf.

This patch fixes both issues using the new llext_loaded_sect_ptr()
helper function.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-06-25 21:25:33 -04:00
Luca Burelli ee6074a35d llext: calculate offsets for ELF sections in memory areas
The recent changes to the loader code merged related sections together,
making sure the merged sections are self-coherent. This, however, did
not take into account that the original ELF sections are now a _subset_
of the merged section - and might not start from the beginning of the
merged section.

This patch converts the `sect_map` member of `struct llext_loader` to a
structure with two fields:
- mem_idx: the memory area index where the ELF section is mapped
- offset: the offset of the ELF section inside the memory area

The offset is calculated after all sections are merged and the final
groups are defined. This will allow the loader to correctly calculate
the address of symbols and relocations in the merged sections.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-06-25 21:25:33 -04:00
Luca Burelli 6c5983492b llext: set proper LLEXT_STORAGE default for Xtensa
This patch sets the default value for LLEXT_STORAGE_WRITABLE to 'y' on
the Xtensa architecture. This is necessary because it does not currently
support the read-only mode for the LLEXT storage.

Make sure the default reflects this instead of asking the user to
manually set it.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-06-25 21:25:33 -04:00
Luca Burelli 08eb314c35 llext: refactor: use cached section headers
The section headers are now available in the loader structure, so we can
use those directly instead of reading them from the ELF file every time.

This commit contains no logic changes; it removes all copies of the
header loading code and replaces them with direct access to the cached
section headers.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-06-14 11:13:44 +02:00
Luca Burelli 817bbda5cc llext: read all section headers at once
This change reads all section headers at once, instead of reading them
one by one. This is more efficient and allows to further simplify the
code downstream.

The section headers are directly accessed from the file buffer if the
llext_peek() function is supported by the loader. Otherwise, they are
read into a buffer allocated on the heap and used only during the
llext_load() function.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-06-14 11:13:44 +02:00
Luca Burelli a976a1a25c llext: llext_load: document memory management policy
The do_llext_load function is responsible for loading an extension from a
file, and for this purpose it calls a number of functions that a) allocate
memory, and b) can fail. This creates the opportunity for memory leaks if
the error paths are not handled correctly.

This commit adds a comment at the beginning of the function to document
the memory management policy that has to be followed in this file:
cleanup is not performed in the error paths, and all memory is freed at
the end of the do_llext_load() function, both in the case of error and of
successful loading.

As an improvement, the symbol table is not freed if the LLEXT log level
is set to debug, so that it can be used, for example, to inspect the
symbols of the loaded extension.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-06-14 11:13:44 +02:00
Luca Burelli 89e27b9312 llext: improve debug messages
The recent llext_map_sections() rework changed the way debug messages
are output so that the names of most skipped sections are not printed
at all. This makes debugging harder since the section names are useful
to identify the contents at a glance.

Also print a few additional fields from the section header, and use 0x
prefixes for hex numbers.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-06-14 11:13:44 +02:00
Luca Burelli 1a2f6ae381 llext: refact: move ELF loading and linking to separate files
This commit moves ELF loading and linking code to separate files. This
is done to make the code more manageable and to make it easier to add
new features in the future.

No functional changes are introduced by this commit, except for a few
static functions now made public to allow this file split to occur.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-06-07 18:07:53 +01:00
Luca Burelli 9c5412f79e llext: refact: move memory code to llext_mem.c
Move all memory management code to a separate file, llext_mem.c, to
allow for better separation of concerns and to make the code more
readable.

No functional changes are introduced by this commit.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-06-07 18:07:53 +01:00
Luca Burelli 35ef089cb1 llext: move basic ELF checks to llext_load_elf_data()
This patch moves the initial checks performed on the ELF file, that were
split between llext_load() and do_llext_load(), to the newly defined
llext_load_elf_data() function.

This way:

- only one function deals with ELF internal data checks;
- do_llext_load() is reduced to a list of tasks;
- llext_load() only focuses on the extension management.

One totally misplaced line initializing the number of symbols has been
moved to llext_count_export_syms().

No functional change except that the `struct llext` allocation may be
performed unnecessarily if the ELF file is not valid.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-06-07 18:07:53 +01:00
Luca Burelli cefeae0048 llext: add llext heap management functions
Add llext_alloc(), llext_aligned_alloc() and llext_free() wrapper
functions to manage memory allocation and deallocation from the llext
heap. Also add a helper to free all memory regions allocated by an
extension.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-06-07 18:07:53 +01:00
Luca Burelli 709b2e44bf llext: automatically merge sections by type
This patch changes the way sections are mapped to memories. Instead of
looking at the section name, each section in the ELF file is mapped to
the llext_mem enum by looking at the section type and flags.

This allows for a more generic mapping that works for both the ARM and
Xtensa cases, and also allows for sections to be merged if they are
contiguous and non-overlapping in the ELF file.

This patch also fixes a number of corner cases, such as in the logging
test where a section with read-only data was being ignored (not copied
and not relinked).

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-06-04 13:37:22 +02:00
Mathieu Choplain 8aa6ae43ce llext: add support for SLID-based linking
This commit introduces support for an alternate linking method in the
LLEXT subsystem, called "SLID" (short for Symbol Link Identifier),
enabled by the CONFIG_LLEXT_EXPORT_BUILTINS_BY_SLID Kconfig option.

SLID-based linking uses a unique identifier (integer) to identify
exported symbols, instead of using the symbol name as done currently.
This approach provides several benefits:
 * linking is faster because the comparison operation to determine
   whether we found the correct symbol in the export table is now an
   integer compare, instead of a string compare
 * binary size is reduced as symbol names can be dropped from the binary
 * confidentiality is improved as a side-effect, as symbol names are no
   longer present in the binary

Signed-off-by: Mathieu Choplain <mathieu.choplain@st.com>
2024-06-03 15:29:34 -04:00
Joel Guittet 05ad2565fa llext: add _POSIX_C_SOURCE definition to build shell
Fix implicit-function-declaration warning while building the llext shell.

Signed-off-by: Joel Guittet <joelguittet@gmail.com>
2024-06-03 15:28:33 -04:00
Mathieu Choplain a07d493c9d llext: relocate all symbols regardless of type
In the current implementation, the LLEXT linker will only apply
relocations targeting a given symbol if it has a specfic symbol type.
This is overzealous and causes issues on some platforms, as some symbols
that need to be relocated are skipped due to being of a "bad" type.

Ignore the symbol type when performing relocation to solve this problem,
but also add checks to ensure we don't attempt to relocate symbols with
an invalid section index. If such a relocation is found, return an error
instead of ignoring the relocation entry to ensure that it is impossible
to execute code from a (partially) unrelocated LLEXT.

Also remove all hacks added to circumvent this issue:
* qemu_cortex_r5 exclusion from test cases
* unnecessary exclusion of some flags when building with LLEXT EDK

Fixes #72832.

Signed-off-by: Mathieu Choplain <mathieu.choplain@st.com>
2024-05-31 16:38:09 -05:00
Guennadi Liakhovetski 518a712db0 llext: zero is a valid relocation offset
Zero offset in a relocation entry is valid, shouldn't ignore it.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-05-30 09:50:17 -05:00
Guennadi Liakhovetski 946fd3fda2 llext: (cosmetic) fix a misplaced space and re-use a variable
Use an existing variable instead of re-calculating and fix swapped
space and a paranthesis.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-05-30 09:50:17 -05:00
Guennadi Liakhovetski ebde53904d llext: fix handling of non-standard sections in relocatable case
When building partially linked / relocatable objects no ELF segments
are created and it becomes more difficult to predict which sections
the compiler will build and use. In this case a .data.rel.local
section is created by the compiler and it is needed to link .rodata
strings in a twister test. We can handle arbitrary sections at run-
time if .peek() is supported. If it isn't we need to allocate and
copy the section. For now we simply error out in such cases. Fixing
that would represent a larger change and can be done incrementally.

This also fixes the relocation calculation to point to the correct
symbol address instead of the memory location, where it's currently
residing, because that can be a temporary buffer as is the case with
SOF.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-05-30 09:50:17 -05:00