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