LCOV - code coverage report
Current view: top level - zephyr/llext - llext.h Hit Total Coverage
Test: new.info Lines: 34 37 91.9 %
Date: 2024-12-22 00:14:23

          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             : /* Maximim number of dependency LLEXTs */
      69           0 : #define LLEXT_MAX_DEPENDENCIES 8
      70             : 
      71             : /**
      72             :  * @brief Structure describing a linkable loadable extension
      73             :  *
      74             :  * This structure holds the data for a loaded extension. It is created by the
      75             :  * @ref llext_load function and destroyed by the @ref llext_unload function.
      76             :  */
      77           1 : struct llext {
      78             :         /** @cond ignore */
      79             :         sys_snode_t _llext_list;
      80             : 
      81             : #ifdef CONFIG_USERSPACE
      82             :         struct k_mem_partition mem_parts[LLEXT_MEM_PARTITIONS];
      83             :         struct k_mem_domain mem_domain;
      84             : #endif
      85             : 
      86             :         /** @endcond */
      87             : 
      88             :         /** Name of the llext */
      89           1 :         char name[16];
      90             : 
      91             :         /** Lookup table of memory regions */
      92           1 :         void *mem[LLEXT_MEM_COUNT];
      93             : 
      94             :         /** Is the memory for this region allocated on heap? */
      95           1 :         bool mem_on_heap[LLEXT_MEM_COUNT];
      96             : 
      97             :         /** Size of each stored region */
      98           1 :         size_t mem_size[LLEXT_MEM_COUNT];
      99             : 
     100             :         /** Total llext allocation size */
     101           1 :         size_t alloc_size;
     102             : 
     103             :         /**
     104             :          * Table of all global symbols in the extension; used internally as
     105             :          * part of the linking process. E.g. if the extension is built out of
     106             :          * several files, if any symbols are referenced between files, this
     107             :          * table will be used to link them.
     108             :          */
     109           1 :         struct llext_symtable sym_tab;
     110             : 
     111             :         /**
     112             :          * Table of symbols exported by the llext via @ref LL_EXTENSION_SYMBOL.
     113             :          * This can be used in the main Zephyr binary to find symbols in the
     114             :          * extension.
     115             :          */
     116           1 :         struct llext_symtable exp_tab;
     117             : 
     118             :         /** Extension use counter, prevents unloading while in use */
     119           1 :         unsigned int use_count;
     120             : 
     121             :         /** Array of extensions, whose symbols this extension accesses */
     122           1 :         struct llext *dependency[LLEXT_MAX_DEPENDENCIES];
     123             : 
     124             :         /** @cond ignore */
     125             :         unsigned int sect_cnt;
     126             :         elf_shdr_t *sect_hdrs;
     127             :         bool sect_hdrs_on_heap;
     128             :         /** @endcond */
     129             : };
     130             : 
     131           0 : static inline const elf_shdr_t *llext_section_headers(const struct llext *ext)
     132             : {
     133             :         return ext->sect_hdrs;
     134             : }
     135             : 
     136           0 : static inline unsigned int llext_section_count(const struct llext *ext)
     137             : {
     138             :         return ext->sect_cnt;
     139             : }
     140             : 
     141             : /**
     142             :  * @brief Advanced llext_load parameters
     143             :  *
     144             :  * This structure contains advanced parameters for @ref llext_load.
     145             :  */
     146           1 : struct llext_load_param {
     147             :         /** Perform local relocation */
     148           1 :         bool relocate_local;
     149             :         /**
     150             :          * Use the virtual symbol addresses from the ELF, not addresses within
     151             :          * the memory buffer, when calculating relocation targets. It also
     152             :          * means, that the application will take care to place the extension at
     153             :          * those pre-defined addresses, so the LLEXT core doesn't have to do any
     154             :          * allocation and copying internally.
     155             :          */
     156           1 :         bool pre_located;
     157             :         /**
     158             :          * Extensions can implement custom ELF sections to be loaded in specific
     159             :          * memory regions, detached from other sections of compatible types.
     160             :          * This optional callback checks whether a section should be detached.
     161             :          */
     162           1 :         bool (*section_detached)(const elf_shdr_t *shdr);
     163             : };
     164             : 
     165             : /** Default initializer for @ref llext_load_param */
     166           1 : #define LLEXT_LOAD_PARAM_DEFAULT { .relocate_local = true, }
     167             : 
     168             : /**
     169             :  * @brief Find an llext by name
     170             :  *
     171             :  * @param[in] name String name of the llext
     172             :  * @returns a pointer to the @ref llext, or `NULL` if not found
     173             :  */
     174           1 : struct llext *llext_by_name(const char *name);
     175             : 
     176             : /**
     177             :  * @brief Iterate over all loaded extensions
     178             :  *
     179             :  * Calls a provided callback function for each registered extension or until the
     180             :  * callback function returns a non-0 value.
     181             :  *
     182             :  * @param[in] fn callback function
     183             :  * @param[in] arg a private argument to be provided to the callback function
     184             :  * @returns the value returned by the last callback invocation
     185             :  * @retval 0 if no extensions are registered
     186             :  */
     187           1 : int llext_iterate(int (*fn)(struct llext *ext, void *arg), void *arg);
     188             : 
     189             : /**
     190             :  * @brief Load and link an extension
     191             :  *
     192             :  * Loads relevant ELF data into memory and provides a structure to work with it.
     193             :  *
     194             :  * @param[in] loader An extension loader that provides input data and context
     195             :  * @param[in] name A string identifier for the extension
     196             :  * @param[out] ext Pointer to the newly allocated @ref llext structure
     197             :  * @param[in] ldr_parm Optional advanced load parameters (may be `NULL`)
     198             :  *
     199             :  * @returns the previous extension use count on success, or a negative error code.
     200             :  * @retval -ENOMEM Not enough memory
     201             :  * @retval -ENOEXEC Invalid ELF stream
     202             :  * @retval -ENOTSUP Unsupported ELF features
     203             :  */
     204           1 : int llext_load(struct llext_loader *loader, const char *name, struct llext **ext,
     205             :                const struct llext_load_param *ldr_parm);
     206             : 
     207             : /**
     208             :  * @brief Unload an extension
     209             :  *
     210             :  * @param[in] ext Extension to unload
     211             :  */
     212           1 : int llext_unload(struct llext **ext);
     213             : 
     214             : /** @brief Entry point function signature for an extension. */
     215           1 : typedef void (*llext_entry_fn_t)(void *user_data);
     216             : 
     217             : /**
     218             :  * @brief Calls bringup functions for an extension.
     219             :  *
     220             :  * Must be called before accessing any symbol in the extension. Will execute
     221             :  * the extension's own setup functions in the caller context.
     222             :  * @see llext_bootstrap
     223             :  *
     224             :  * @param[in] ext Extension to initialize.
     225             :  * @returns 0 on success, or a negative error code.
     226             :  * @retval -EFAULT A relocation issue was detected
     227             :  */
     228           1 : int llext_bringup(struct llext *ext);
     229             : 
     230             : /**
     231             :  * @brief Calls teardown functions for an extension.
     232             :  *
     233             :  * Will execute the extension's own cleanup functions in the caller context.
     234             :  * After this function completes, the extension is no longer usable and must be
     235             :  * fully unloaded with @ref llext_unload.
     236             :  * @see llext_bootstrap
     237             :  *
     238             :  * @param[in] ext Extension to de-initialize.
     239             :  * @returns 0 on success, or a negative error code.
     240             :  * @retval -EFAULT A relocation issue was detected
     241             :  */
     242           1 : int llext_teardown(struct llext *ext);
     243             : 
     244             : /**
     245             :  * @brief Bring up, execute, and teardown an extension.
     246             :  *
     247             :  * Calls the extension's own setup functions, an additional entry point and
     248             :  * the extension's cleanup functions in the current thread context.
     249             :  *
     250             :  * This is a convenient wrapper around @ref llext_bringup and @ref
     251             :  * llext_teardown that matches the @ref k_thread_entry_t signature, so it can
     252             :  * be directly started as a new user or kernel thread via @ref k_thread_create.
     253             :  *
     254             :  * @param[in] ext Extension to execute. Passed as `p1` in @ref k_thread_create.
     255             :  * @param[in] entry_fn Main entry point of the thread after performing
     256             :  *                     extension setup. Passed as `p2` in @ref k_thread_create.
     257             :  * @param[in] user_data Argument passed to @a entry_fn. Passed as `p3` in
     258             :  *                      @ref k_thread_create.
     259             :  */
     260           1 : void llext_bootstrap(struct llext *ext, llext_entry_fn_t entry_fn, void *user_data);
     261             : 
     262             : /**
     263             :  * @brief Get pointers to setup or cleanup functions for an extension.
     264             :  *
     265             :  * This syscall can be used to get the addresses of all the functions that
     266             :  * have to be called for full extension setup or cleanup.
     267             :  *
     268             :  * @see llext_bootstrap
     269             :  *
     270             :  * @param[in]    ext Extension to initialize.
     271             :  * @param[in]    is_init `true` to get functions to be called at setup time,
     272             :  *                       `false` to get the cleanup ones.
     273             :  * @param[inout] buf Buffer to store the function pointers in. Can be `NULL`
     274             :  *                   to only get the minimum required size.
     275             :  * @param[in]    size Allocated size of the buffer in bytes.
     276             :  * @returns the size used by the array in bytes, or a negative error code.
     277             :  * @retval -EFAULT A relocation issue was detected
     278             :  * @retval -ENOMEM Array does not fit in the allocated buffer
     279             :  */
     280           1 : __syscall ssize_t llext_get_fn_table(struct llext *ext, bool is_init, void *buf, size_t size);
     281             : 
     282             : /**
     283             :  * @brief Find the address for an arbitrary symbol.
     284             :  *
     285             :  * Searches for a symbol address, either in the list of symbols exported by
     286             :  * the main Zephyr binary or in an extension's symbol table.
     287             :  *
     288             :  * @param[in] sym_table Symbol table to lookup symbol in, or `NULL` to search
     289             :  *                      in the main Zephyr symbol table
     290             :  * @param[in] sym_name Symbol name to find
     291             :  *
     292             :  * @returns the address of symbol in memory, or `NULL` if not found
     293             :  */
     294           1 : const void *llext_find_sym(const struct llext_symtable *sym_table, const char *sym_name);
     295             : 
     296             : /**
     297             :  * @brief Call a function by name.
     298             :  *
     299             :  * Expects a symbol representing a `void fn(void)` style function exists
     300             :  * and may be called.
     301             :  *
     302             :  * @param[in] ext Extension to call function in
     303             :  * @param[in] sym_name Function name (exported symbol) in the extension
     304             :  *
     305             :  * @retval 0 Success
     306             :  * @retval -ENOENT Symbol name not found
     307             :  */
     308           1 : int llext_call_fn(struct llext *ext, const char *sym_name);
     309             : 
     310             : /**
     311             :  * @brief Add an extension to a memory domain.
     312             :  *
     313             :  * Allows an extension to be executed in user mode threads when memory
     314             :  * protection hardware is enabled by adding memory partitions covering the
     315             :  * extension's memory regions to a memory domain.
     316             :  *
     317             :  * @param[in] ext Extension to add to a domain
     318             :  * @param[in] domain Memory domain to add partitions to
     319             :  *
     320             :  * @returns 0 on success, or a negative error code.
     321             :  * @retval -ENOSYS Option @kconfig{CONFIG_USERSPACE} is not enabled or supported
     322             :  */
     323           1 : int llext_add_domain(struct llext *ext, struct k_mem_domain *domain);
     324             : 
     325             : /**
     326             :  * @brief Architecture specific opcode update function
     327             :  *
     328             :  * ELF files include sections describing a series of _relocations_, which are
     329             :  * instructions on how to rewrite opcodes given the actual placement of some
     330             :  * symbolic data such as a section, function, or object. These relocations
     331             :  * are architecture specific and each architecture supporting LLEXT must
     332             :  * implement this.
     333             :  *
     334             :  * @param[in] rel Relocation data provided by ELF
     335             :  * @param[in] loc Address of opcode to rewrite
     336             :  * @param[in] sym_base_addr Address of symbol referenced by relocation
     337             :  * @param[in] sym_name Name of symbol referenced by relocation
     338             :  * @param[in] load_bias `.text` load address
     339             :  * @retval 0 Success
     340             :  * @retval -ENOTSUP Unsupported relocation
     341             :  * @retval -ENOEXEC Invalid relocation
     342             :  */
     343           1 : int arch_elf_relocate(elf_rela_t *rel, uintptr_t loc,
     344             :                              uintptr_t sym_base_addr, const char *sym_name, uintptr_t load_bias);
     345             : 
     346             : /**
     347             :  * @brief Locates an ELF section in the file.
     348             :  *
     349             :  * Searches for a section by name in the ELF file and returns its offset.
     350             :  *
     351             :  * @param[in] loader Extension loader data and context
     352             :  * @param[in] search_name Section name to search for
     353             :  * @returns the section offset or a negative error code
     354             :  */
     355           1 : ssize_t llext_find_section(struct llext_loader *loader, const char *search_name);
     356             : 
     357             : /**
     358             :  * @brief Extract ELF section header by name.
     359             :  *
     360             :  * Searches for a section by name in the ELF file and retrieves its full header.
     361             :  *
     362             :  * @param[in] loader Extension loader data and context
     363             :  * @param[in] ext Extension to be searched
     364             :  * @param[in] search_name Section name to search for
     365             :  * @param[out] shdr Buffer for the section header
     366             :  * @retval 0 Success
     367             :  * @retval -ENOTSUP "peek" method not supported
     368             :  * @retval -ENOENT section not found
     369             :  */
     370           1 : int llext_get_section_header(struct llext_loader *loader, struct llext *ext,
     371             :                              const char *search_name, elf_shdr_t *shdr);
     372             : 
     373             : /**
     374             :  * @brief Architecture specific function for local binding relocations
     375             :  *
     376             :  * @param[in] loader Extension loader data and context
     377             :  * @param[in] ext Extension to call function in
     378             :  * @param[in] rel Relocation data provided by elf
     379             :  * @param[in] sym Corresponding symbol table entry
     380             :  * @param[in] rel_addr Address where relocation should be performed
     381             :  * @param[in] ldr_parm Loader parameters
     382             :  */
     383           1 : void arch_elf_relocate_local(struct llext_loader *loader, struct llext *ext, const elf_rela_t *rel,
     384             :                              const elf_sym_t *sym, uint8_t *rel_addr,
     385             :                              const struct llext_load_param *ldr_parm);
     386             : 
     387             : /**
     388             :  * @brief Architecture specific function for global binding relocations
     389             :  *
     390             :  * @param[in] loader Extension loader data and context
     391             :  * @param[in] ext Extension to call function in
     392             :  * @param[in] rel Relocation data provided by elf
     393             :  * @param[in] sym Corresponding symbol table entry
     394             :  * @param[in] rel_addr Address where relocation should be performed
     395             :  * @param[in] link_addr target address for table-based relocations
     396             :  */
     397           1 : void arch_elf_relocate_global(struct llext_loader *loader, struct llext *ext, const elf_rela_t *rel,
     398             :                               const elf_sym_t *sym, uint8_t *rel_addr, const void *link_addr);
     399             : 
     400             : /**
     401             :  * @}
     402             :  */
     403             : 
     404             : #ifdef __cplusplus
     405             : }
     406             : #endif
     407             : 
     408             : #include <zephyr/syscalls/llext.h>
     409             : 
     410             : #endif /* ZEPHYR_LLEXT_H */

Generated by: LCOV version 1.14