LCOV - code coverage report
Current view: top level - zephyr/llext - llext.h Coverage Total Hit
Test: new.info Lines: 95.3 % 43 41
Test Date: 2025-09-05 20:47:19

            Line data    Source code
       1            1 : /*
       2              :  * Copyright (c) 2023 Intel Corporation
       3              :  * Copyright (c) 2024 Schneider Electric
       4              :  *
       5              :  * SPDX-License-Identifier: Apache-2.0
       6              :  */
       7              : 
       8              : #ifndef ZEPHYR_LLEXT_H
       9              : #define ZEPHYR_LLEXT_H
      10              : 
      11              : #include <zephyr/sys/slist.h>
      12              : #include <zephyr/llext/elf.h>
      13              : #include <zephyr/llext/symbol.h>
      14              : #include <zephyr/kernel.h>
      15              : #include <sys/types.h>
      16              : #include <stdbool.h>
      17              : 
      18              : #ifdef __cplusplus
      19              : extern "C" {
      20              : #endif
      21              : 
      22              : /**
      23              :  * @file
      24              :  * @brief Support for linkable loadable extensions
      25              :  *
      26              :  * This file describes the APIs for loading and interacting with Linkable
      27              :  * Loadable Extensions (LLEXTs) in Zephyr.
      28              :  *
      29              :  * @defgroup llext_apis Linkable loadable extensions
      30              :  * @since 3.5
      31              :  * @version 0.1.0
      32              :  * @ingroup os_services
      33              :  * @{
      34              :  */
      35              : 
      36              : /**
      37              :  * @brief List of memory regions stored or referenced in the LLEXT subsystem
      38              :  *
      39              :  * This enum lists the different types of memory regions that are used by the
      40              :  * LLEXT subsystem. The names match common ELF file section names; but note
      41              :  * that at load time multiple ELF sections with similar flags may be merged
      42              :  * together into a single memory region.
      43              :  */
      44            1 : enum llext_mem {
      45              :         LLEXT_MEM_TEXT,         /**< Executable code */
      46              :         LLEXT_MEM_DATA,         /**< Initialized data */
      47              :         LLEXT_MEM_RODATA,       /**< Read-only data */
      48              :         LLEXT_MEM_BSS,          /**< Uninitialized data */
      49              :         LLEXT_MEM_EXPORT,       /**< Exported symbol table */
      50              :         LLEXT_MEM_SYMTAB,       /**< Symbol table */
      51              :         LLEXT_MEM_STRTAB,       /**< Symbol name strings */
      52              :         LLEXT_MEM_SHSTRTAB,     /**< Section name strings */
      53              :         LLEXT_MEM_PREINIT,      /**< Array of early setup functions */
      54              :         LLEXT_MEM_INIT,         /**< Array of setup functions */
      55              :         LLEXT_MEM_FINI,         /**< Array of cleanup functions */
      56              : 
      57              :         LLEXT_MEM_COUNT,        /**< Number of regions managed by LLEXT */
      58              : };
      59              : 
      60              : /** @cond ignore */
      61              : 
      62              : /* Number of memory partitions used by LLEXT */
      63              : #define LLEXT_MEM_PARTITIONS (LLEXT_MEM_BSS+1)
      64              : 
      65              : struct llext_loader;
      66              : /** @endcond */
      67              : 
      68              : /** Maximum length of an extension name */
      69            1 : #define LLEXT_MAX_NAME_LEN 15
      70              : 
      71              : /** Maximum number of dependency LLEXTs */
      72            1 : #define LLEXT_MAX_DEPENDENCIES 8
      73              : 
      74              : /**
      75              :  * @brief Structure describing a linkable loadable extension
      76              :  *
      77              :  * This structure holds the data for a loaded extension. It is created by the
      78              :  * @ref llext_load function and destroyed by the @ref llext_unload function.
      79              :  */
      80            1 : struct llext {
      81              :         /** @cond ignore */
      82              :         sys_snode_t llext_list;
      83              : 
      84              : #ifdef CONFIG_USERSPACE
      85              :         struct k_mem_partition mem_parts[LLEXT_MEM_PARTITIONS];
      86              : #endif
      87              : 
      88              :         /** @endcond */
      89              : 
      90              :         /** Name of the llext */
      91            1 :         char name[LLEXT_MAX_NAME_LEN + 1];
      92              : 
      93              :         /** Lookup table of memory regions */
      94            1 :         void *mem[LLEXT_MEM_COUNT];
      95              : 
      96              :         /** Is the memory for this region allocated on heap? */
      97            1 :         bool mem_on_heap[LLEXT_MEM_COUNT];
      98              : 
      99              :         /** Size of each stored region */
     100            1 :         size_t mem_size[LLEXT_MEM_COUNT];
     101              : 
     102              :         /** Total llext allocation size */
     103            1 :         size_t alloc_size;
     104              : 
     105              :         /**
     106              :          * Table of all global symbols in the extension; used internally as
     107              :          * part of the linking process. E.g. if the extension is built out of
     108              :          * several files, if any symbols are referenced between files, this
     109              :          * table will be used to link them.
     110              :          */
     111            1 :         struct llext_symtable sym_tab;
     112              : 
     113              :         /**
     114              :          * Table of symbols exported by the llext via @ref LL_EXTENSION_SYMBOL.
     115              :          * This can be used in the main Zephyr binary to find symbols in the
     116              :          * extension.
     117              :          */
     118            1 :         struct llext_symtable exp_tab;
     119              : 
     120              :         /** Extension use counter, prevents unloading while in use */
     121            1 :         unsigned int use_count;
     122              : 
     123              :         /** Array of extensions, whose symbols this extension accesses */
     124            1 :         struct llext *dependency[LLEXT_MAX_DEPENDENCIES];
     125              : 
     126              :         /** @cond ignore */
     127              :         unsigned int sect_cnt;
     128              :         elf_shdr_t *sect_hdrs;
     129              :         bool sect_hdrs_on_heap;
     130              :         bool mmu_permissions_set;
     131              :         /** @endcond */
     132              : };
     133              : 
     134            0 : static inline const elf_shdr_t *llext_section_headers(const struct llext *ext)
     135              : {
     136              :         return ext->sect_hdrs;
     137              : }
     138              : 
     139            0 : static inline unsigned int llext_section_count(const struct llext *ext)
     140              : {
     141              :         return ext->sect_cnt;
     142              : }
     143              : 
     144              : /**
     145              :  * @brief Advanced llext_load parameters
     146              :  *
     147              :  * This structure contains advanced parameters for @ref llext_load.
     148              :  */
     149            1 : struct llext_load_param {
     150              :         /** Perform local relocation */
     151            1 :         bool relocate_local;
     152              : 
     153              :         /**
     154              :          * Use the virtual symbol addresses from the ELF, not addresses within
     155              :          * the memory buffer, when calculating relocation targets. It also
     156              :          * means, that the application will take care to place the extension at
     157              :          * those pre-defined addresses, so the LLEXT core doesn't have to do any
     158              :          * allocation and copying internally. Any MMU permission adjustment will
     159              :          * be done by the application too.
     160              :          */
     161            1 :         bool pre_located;
     162              : 
     163              :         /**
     164              :          * Extensions can implement custom ELF sections to be loaded in specific
     165              :          * memory regions, detached from other sections of compatible types.
     166              :          * This optional callback checks whether a section should be detached.
     167              :          */
     168            1 :         bool (*section_detached)(const elf_shdr_t *shdr);
     169              : 
     170              :         /**
     171              :          * Keep the ELF section data in memory after loading the extension. This
     172              :          * is needed to use some of the functions in @ref llext_inspect_apis.
     173              :          *
     174              :          * @note Related memory must be freed by @ref llext_free_inspection_data
     175              :          *       before the extension can be unloaded via @ref llext_unload.
     176              :          */
     177            1 :         bool keep_section_info;
     178              : };
     179              : 
     180              : /** Default initializer for @ref llext_load_param */
     181            1 : #define LLEXT_LOAD_PARAM_DEFAULT { .relocate_local = true, }
     182              : 
     183              : /**
     184              :  * @brief Find an llext by name
     185              :  *
     186              :  * @param[in] name String name of the llext
     187              :  * @returns a pointer to the @ref llext, or `NULL` if not found
     188              :  */
     189            1 : struct llext *llext_by_name(const char *name);
     190              : 
     191              : /**
     192              :  * @brief Iterate over all loaded extensions
     193              :  *
     194              :  * Calls a provided callback function for each registered extension or until the
     195              :  * callback function returns a non-0 value.
     196              :  *
     197              :  * @param[in] fn callback function
     198              :  * @param[in] arg a private argument to be provided to the callback function
     199              :  * @returns the value returned by the last callback invocation
     200              :  * @retval 0 if no extensions are registered
     201              :  */
     202            1 : int llext_iterate(int (*fn)(struct llext *ext, void *arg), void *arg);
     203              : 
     204              : /**
     205              :  * @brief Load and link an extension
     206              :  *
     207              :  * Loads relevant ELF data into memory and provides a structure to work with it.
     208              :  *
     209              :  * @param[in] loader An extension loader that provides input data and context
     210              :  * @param[in] name A string identifier for the extension
     211              :  * @param[out] ext Pointer to the newly allocated @ref llext structure
     212              :  * @param[in] ldr_parm Optional advanced load parameters (may be `NULL`)
     213              :  *
     214              :  * @returns the previous extension use count on success, or a negative error code.
     215              :  * @retval -ENOMEM Not enough memory
     216              :  * @retval -ENOEXEC Invalid ELF stream
     217              :  * @retval -ENOTSUP Unsupported ELF features
     218              :  */
     219            1 : int llext_load(struct llext_loader *loader, const char *name, struct llext **ext,
     220              :                const struct llext_load_param *ldr_parm);
     221              : 
     222              : /**
     223              :  * @brief Unload an extension
     224              :  *
     225              :  * @param[in] ext Extension to unload
     226              :  */
     227            1 : int llext_unload(struct llext **ext);
     228              : 
     229              : /**
     230              :  * @brief Free any inspection-related memory for the specified loader and extension.
     231              :  *
     232              :  * This is only required if inspection data was requested at load time by
     233              :  * setting @ref llext_load_param.keep_section_info; otherwise, this call will
     234              :  * be a no-op.
     235              :  *
     236              :  * @param[in] ldr Extension loader
     237              :  * @param[in] ext Extension
     238              :  * @returns 0 on success, or a negative error code.
     239              :  */
     240            1 : int llext_free_inspection_data(struct llext_loader *ldr, struct llext *ext);
     241              : 
     242              : /** @brief Entry point function signature for an extension. */
     243            1 : typedef void (*llext_entry_fn_t)(void *user_data);
     244              : 
     245              : /**
     246              :  * @brief Calls bringup functions for an extension.
     247              :  *
     248              :  * Must be called before accessing any symbol in the extension. Will execute
     249              :  * the extension's own setup functions in the caller context.
     250              :  * @see llext_bootstrap
     251              :  *
     252              :  * @param[in] ext Extension to initialize.
     253              :  * @returns 0 on success, or a negative error code.
     254              :  * @retval -EFAULT A relocation issue was detected
     255              :  */
     256            1 : int llext_bringup(struct llext *ext);
     257              : 
     258              : /**
     259              :  * @brief Calls teardown functions for an extension.
     260              :  *
     261              :  * Will execute the extension's own cleanup functions in the caller context.
     262              :  * After this function completes, the extension is no longer usable and must be
     263              :  * fully unloaded with @ref llext_unload.
     264              :  * @see llext_bootstrap
     265              :  *
     266              :  * @param[in] ext Extension to de-initialize.
     267              :  * @returns 0 on success, or a negative error code.
     268              :  * @retval -EFAULT A relocation issue was detected
     269              :  */
     270            1 : int llext_teardown(struct llext *ext);
     271              : 
     272              : /**
     273              :  * @brief Bring up, execute, and teardown an extension.
     274              :  *
     275              :  * Calls the extension's own setup functions, an additional entry point and
     276              :  * the extension's cleanup functions in the current thread context.
     277              :  *
     278              :  * This is a convenient wrapper around @ref llext_bringup and @ref
     279              :  * llext_teardown that matches the @ref k_thread_entry_t signature, so it can
     280              :  * be directly started as a new user or kernel thread via @ref k_thread_create.
     281              :  *
     282              :  * @param[in] ext Extension to execute. Passed as `p1` in @ref k_thread_create.
     283              :  * @param[in] entry_fn Main entry point of the thread after performing
     284              :  *                     extension setup. Passed as `p2` in @ref k_thread_create.
     285              :  * @param[in] user_data Argument passed to @a entry_fn. Passed as `p3` in
     286              :  *                      @ref k_thread_create.
     287              :  */
     288            1 : void llext_bootstrap(struct llext *ext, llext_entry_fn_t entry_fn, void *user_data);
     289              : 
     290              : /**
     291              :  * @brief Get pointers to setup or cleanup functions for an extension.
     292              :  *
     293              :  * This syscall can be used to get the addresses of all the functions that
     294              :  * have to be called for full extension setup or cleanup.
     295              :  *
     296              :  * @see llext_bootstrap
     297              :  *
     298              :  * @param[in]    ext Extension to initialize.
     299              :  * @param[in]    is_init `true` to get functions to be called at setup time,
     300              :  *                       `false` to get the cleanup ones.
     301              :  * @param[inout] buf Buffer to store the function pointers in. Can be `NULL`
     302              :  *                   to only get the minimum required size.
     303              :  * @param[in]    size Allocated size of the buffer in bytes.
     304              :  * @returns the size used by the array in bytes, or a negative error code.
     305              :  * @retval -EFAULT A relocation issue was detected
     306              :  * @retval -ENOMEM Array does not fit in the allocated buffer
     307              :  */
     308            1 : __syscall ssize_t llext_get_fn_table(struct llext *ext, bool is_init, void *buf, size_t size);
     309              : 
     310              : /**
     311              :  * @brief Find the address for an arbitrary symbol.
     312              :  *
     313              :  * Searches for a symbol address, either in the list of symbols exported by
     314              :  * the main Zephyr binary or in an extension's symbol table.
     315              :  *
     316              :  * @param[in] sym_table Symbol table to lookup symbol in, or `NULL` to search
     317              :  *                      in the main Zephyr symbol table
     318              :  * @param[in] sym_name Symbol name to find
     319              :  *
     320              :  * @returns the address of symbol in memory, or `NULL` if not found
     321              :  */
     322            1 : const void *llext_find_sym(const struct llext_symtable *sym_table, const char *sym_name);
     323              : 
     324              : /**
     325              :  * @brief Call a function by name.
     326              :  *
     327              :  * Expects a symbol representing a `void fn(void)` style function exists
     328              :  * and may be called.
     329              :  *
     330              :  * @param[in] ext Extension to call function in
     331              :  * @param[in] sym_name Function name (exported symbol) in the extension
     332              :  *
     333              :  * @retval 0 Success
     334              :  * @retval -ENOENT Symbol name not found
     335              :  */
     336            1 : int llext_call_fn(struct llext *ext, const char *sym_name);
     337              : 
     338              : /**
     339              :  * @brief Add an extension to a memory domain.
     340              :  *
     341              :  * Allows an extension to be executed in user mode threads when memory
     342              :  * protection hardware is enabled by adding memory partitions covering the
     343              :  * extension's memory regions to a memory domain.
     344              :  *
     345              :  * @param[in] ext Extension to add to a domain
     346              :  * @param[in] domain Memory domain to add partitions to
     347              :  *
     348              :  * @returns 0 on success, or a negative error code.
     349              :  * @retval -ENOSYS Option @kconfig{CONFIG_USERSPACE} is not enabled or supported
     350              :  */
     351            1 : int llext_add_domain(struct llext *ext, struct k_mem_domain *domain);
     352              : 
     353              : /**
     354              :  * @brief Architecture specific opcode update function
     355              :  *
     356              :  * ELF files include sections describing a series of _relocations_, which are
     357              :  * instructions on how to rewrite opcodes given the actual placement of some
     358              :  * symbolic data such as a section, function, or object. These relocations
     359              :  * are architecture specific and each architecture supporting LLEXT must
     360              :  * implement this.
     361              :  * Arguments sym_base_addr, sym_name can be computed from the sym parameter,
     362              :  * but these parameters are provided redundantly to increase efficiency.
     363              :  *
     364              :  * @param[in] ldr Extension loader
     365              :  * @param[in] ext Extension being relocated refers to
     366              :  * @param[in] rel Relocation data provided by ELF
     367              :  * @param[in] shdr Header of the ELF section currently being located
     368              :  * @retval 0 Success
     369              :  * @retval -ENOTSUP Unsupported relocation
     370              :  * @retval -ENOEXEC Invalid relocation
     371              :  */
     372            1 : int arch_elf_relocate(struct llext_loader *ldr, struct llext *ext, elf_rela_t *rel,
     373              :                       const elf_shdr_t *shdr);
     374              : 
     375              : /**
     376              :  * @brief Locates an ELF section in the file.
     377              :  *
     378              :  * Searches for a section by name in the ELF file and returns its offset.
     379              :  *
     380              :  * @param[in] loader Extension loader data and context
     381              :  * @param[in] search_name Section name to search for
     382              :  * @returns the section offset or a negative error code
     383              :  */
     384            1 : ssize_t llext_find_section(struct llext_loader *loader, const char *search_name);
     385              : 
     386              : /**
     387              :  * @brief Extract ELF section header by name.
     388              :  *
     389              :  * Searches for a section by name in the ELF file and retrieves its full header.
     390              :  *
     391              :  * @param[in] loader Extension loader data and context
     392              :  * @param[in] ext Extension to be searched
     393              :  * @param[in] search_name Section name to search for
     394              :  * @param[out] shdr Buffer for the section header
     395              :  * @retval 0 Success
     396              :  * @retval -ENOTSUP "peek" method not supported
     397              :  * @retval -ENOENT section not found
     398              :  */
     399            1 : int llext_get_section_header(struct llext_loader *loader, struct llext *ext,
     400              :                              const char *search_name, elf_shdr_t *shdr);
     401              : 
     402              : /**
     403              :  * @brief Initialize LLEXT heap dynamically
     404              :  *
     405              :  * Use the provided memory block as the LLEXT heap at runtime.
     406              :  *
     407              :  * @param mem Pointer to memory.
     408              :  * @param bytes Size of memory region, in bytes
     409              :  *
     410              :  * @returns 0 on success, or a negative error code.
     411              :  * @retval -ENOSYS Option @kconfig{CONFIG_LLEXT_HEAP_DYNAMIC} is not enabled or supported,
     412              :  *         or it is and option @kconfig{CONFIG_HARVARD} is enabled
     413              :  */
     414            1 : int llext_heap_init(void *mem, size_t bytes);
     415              : 
     416              : /**
     417              :  * @brief Initialize LLEXT heap dynamically for Harvard architecture
     418              :  *
     419              :  * Use the provided memory blocks as the LLEXT heaps at runtime.
     420              :  *
     421              :  * @param instr_mem Pointer to instruction memory.
     422              :  * @param instr_bytes Size of instruction memory region, in bytes
     423              :  * @param data_mem Pointer to data memory.
     424              :  * @param data_bytes Size of data memory region, in bytes
     425              :  *
     426              :  * @returns 0 on success, or a negative error code.
     427              :  * @retval -ENOSYS Option @kconfig{CONFIG_LLEXT_HEAP_DYNAMIC} is not enabled or supported,
     428              :  *         or it is and option @kconfig{CONFIG_HARVARD} is not enabled
     429              :  */
     430            1 : int llext_heap_init_harvard(void *instr_mem, size_t instr_bytes, void *data_mem, size_t data_bytes);
     431              : 
     432              : /**
     433              :  * @brief Mark LLEXT heap as uninitialized.
     434              :  *
     435              :  * @returns 0 on success, or a negative error code.
     436              :  * @retval -ENOSYS Option @kconfig{CONFIG_LLEXT_HEAP_DYNAMIC} is not enabled or supported
     437              :  * @retval -EBUSY On heap not empty
     438              :  */
     439            1 : int llext_heap_uninit(void);
     440              : 
     441              : /**
     442              :  * @brief Relink dependencies to prepare for suspend
     443              :  *
     444              :  * For suspend-resume use-cases, when LLEXT context should be saved in a
     445              :  * non-volatile buffer, the user can save most LLEXT support data, but they have
     446              :  * to use @ref llext_restore() to re-allocate objects, which will also have to
     447              :  * restore dependency pointers. To make sure dependency saving and restoring is
     448              :  * done consistently, we provide a helper function for the former too.
     449              :  *
     450              :  * @warning this is a part of an experimental API, it WILL change in the future!
     451              :  * Its availability depends on CONFIG_LLEXT_EXPERIMENTAL, which is disabled by
     452              :  * default.
     453              :  *
     454              :  * @param[in] ext Extension array
     455              :  * @param[in] n_ext Number of extensions
     456              :  * @retval 0 Success
     457              :  * @retval -ENOENT Some dependencies not found
     458              :  */
     459            1 : int llext_relink_dependency(struct llext *ext, unsigned int n_ext);
     460              : 
     461              : /**
     462              :  * @brief Restore LLEXT context from saved data
     463              :  *
     464              :  * During suspend the user has saved all the extension and loader descriptors
     465              :  * and related objects and called @ref llext_relink_dependency() to prepare
     466              :  * dependency pointers.
     467              :  * When resuming llext_alloc_data() has to be used to re-allocate all the objects,
     468              :  * therefore the user needs support from LLEXT core to accomplish that.
     469              :  * This function takes arrays of pointers to saved copies of extensions and
     470              :  * loaders as arguments and re-allocates all the objects, while also adding them
     471              :  * to the global extension list. At the same time it relinks dependency pointers
     472              :  * to newly allocated extensions.
     473              :  *
     474              :  * @warning this is a part of an experimental API, it WILL change in the future!
     475              :  * Its availability depends on CONFIG_LLEXT_EXPERIMENTAL, which is disabled by
     476              :  * default.
     477              :  *
     478              :  * @param[in,out] ext Extension pointer array - replaced with re-allocated copies
     479              :  * @param[in,out] ldr Array of loader pointers to restore section maps
     480              :  * @param[in] n_ext Number of extensions
     481              :  * @retval 0 Success
     482              :  * @retval -ENOMEM No memory
     483              :  * @retval -EINVAL Stored dependency out of range
     484              :  * @retval -EFAULT Internal algorithmic error
     485              :  */
     486            1 : int llext_restore(struct llext **ext, struct llext_loader **ldr, unsigned int n_ext);
     487              : /**
     488              :  * @}
     489              :  */
     490              : 
     491              : #ifdef __cplusplus
     492              : }
     493              : #endif
     494              : 
     495              : #include <zephyr/syscalls/llext.h>
     496              : 
     497              : #endif /* ZEPHYR_LLEXT_H */
        

Generated by: LCOV version 2.0-1