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 */
|