1 /*
2  * Copyright (c) 2023 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef ZEPHYR_LLEXT_LOADER_H
8 #define ZEPHYR_LLEXT_LOADER_H
9 
10 #include <zephyr/llext/elf.h>
11 #include <stddef.h>
12 
13 #ifdef __cplusplus
14 extern "C" {
15 #endif
16 
17 /**
18  * @file
19  * @brief LLEXT ELF loader context types.
20  *
21  * The following types are used to define the context of the ELF loader
22  * used by the \ref llext subsystem.
23  *
24  * @defgroup llext_loader_apis ELF loader context
25  * @ingroup llext_apis
26  * @{
27  */
28 
29 #include <zephyr/llext/llext.h>
30 
31 /** @cond ignore */
32 struct llext_elf_sect_map; /* defined in llext_internal.h */
33 /** @endcond */
34 
35 /**
36  * @brief Storage type for the ELF data to be loaded.
37  *
38  * This enum defines the storage type of the ELF data that will be loaded. The
39  * storage type determines which memory optimizations can be tried by the LLEXT
40  * subsystem during the load process.
41  *
42  * @note Even with the most permissive option, LLEXT might still have to copy
43  * ELF data into a separate memory region to comply with other restrictions,
44  * such as hardware memory protection and/or alignment rules.
45  * Sections such as BSS that have no space in the file will also be allocated
46  * in the LLEXT heap.
47  */
48 enum llext_storage_type {
49 	/**
50 	 * ELF data is only available during llext_load(); even if the loader
51 	 * supports directly accessing the memory via llext_peek(), the buffer
52 	 * contents will be discarded afterwards.
53 	 * LLEXT will allocate copies of all required data into its heap.
54 	 */
55 	LLEXT_STORAGE_TEMPORARY,
56 	/**
57 	 * ELF data is stored in a *read-only* buffer that is guaranteed to be
58 	 * always accessible for as long as the extension is loaded. LLEXT may
59 	 * directly reuse constant data from the buffer, but may still allocate
60 	 * copies if relocations need to be applied.
61 	 */
62 	LLEXT_STORAGE_PERSISTENT,
63 	/**
64 	 * ELF data is stored in a *writable* memory buffer that is guaranteed
65 	 * to be always accessible for as long as the extension is loaded.
66 	 * LLEXT may freely modify and reuse data in the buffer; so, after the
67 	 * extension is unloaded, the contents should be re-initialized before
68 	 * a subsequent llext_load() call.
69 	 */
70 	LLEXT_STORAGE_WRITABLE,
71 };
72 
73 /**
74  * @brief Linkable loadable extension loader context
75  *
76  * This object is used to access the ELF file data and cache its contents
77  * while an extension is being loaded by the LLEXT subsystem. Once the
78  * extension is loaded, this object is no longer needed.
79  */
80 struct llext_loader {
81 	/**
82 	 * @brief Optional function to prepare the loader for loading extension.
83 	 *
84 	 * @param[in] ldr Loader
85 	 *
86 	 * @returns 0 on success, or a negative error.
87 	 */
88 	int (*prepare)(struct llext_loader *ldr);
89 
90 	/**
91 	 * @brief Function to read (copy) from the loader
92 	 *
93 	 * Copies len bytes into buf from the current position of the
94 	 * loader.
95 	 *
96 	 * @param[in] ldr Loader
97 	 * @param[in] out Output location
98 	 * @param[in] len Length to copy into the output location
99 	 *
100 	 * @returns 0 on success, or a negative error code.
101 	 */
102 	int (*read)(struct llext_loader *ldr, void *out, size_t len);
103 
104 	/**
105 	 * @brief Function to seek to a new absolute location in the stream.
106 	 *
107 	 * Changes the location of the loader position to a new absolute
108 	 * given position.
109 	 *
110 	 * @param[in] ldr Loader
111 	 * @param[in] pos Position in stream to move loader
112 	 *
113 	 * @returns 0 on success, or a negative error code.
114 	 */
115 	int (*seek)(struct llext_loader *ldr, size_t pos);
116 
117 	/**
118 	 * @brief Optional function to peek at an absolute location in the ELF.
119 	 *
120 	 * Return a pointer to the buffer at specified offset.
121 	 *
122 	 * @param[in] ldr Loader
123 	 * @param[in] pos Position to obtain a pointer to
124 	 *
125 	 * @returns a pointer into the buffer or `NULL` if not supported
126 	 */
127 	void *(*peek)(struct llext_loader *ldr, size_t pos);
128 
129 	/**
130 	 * @brief Optional function to clean after the extension has been loaded or error occurred.
131 	 *
132 	 * @param[in] ldr Loader
133 	 */
134 	void (*finalize)(struct llext_loader *ldr);
135 
136 	/**
137 	 * @brief Storage type of the underlying data accessed by this loader.
138 	 */
139 	enum llext_storage_type storage;
140 
141 	/** @cond ignore */
142 	elf_ehdr_t hdr;
143 	elf_shdr_t sects[LLEXT_MEM_COUNT];
144 	struct llext_elf_sect_map *sect_map;
145 	/** @endcond */
146 };
147 
148 /** @cond ignore */
llext_prepare(struct llext_loader * l)149 static inline int llext_prepare(struct llext_loader *l)
150 {
151 	if (l->prepare) {
152 		return l->prepare(l);
153 	}
154 
155 	return 0;
156 }
157 
llext_read(struct llext_loader * l,void * buf,size_t len)158 static inline int llext_read(struct llext_loader *l, void *buf, size_t len)
159 {
160 	return l->read(l, buf, len);
161 }
162 
llext_seek(struct llext_loader * l,size_t pos)163 static inline int llext_seek(struct llext_loader *l, size_t pos)
164 {
165 	return l->seek(l, pos);
166 }
167 
llext_peek(struct llext_loader * l,size_t pos)168 static inline void *llext_peek(struct llext_loader *l, size_t pos)
169 {
170 	if (l->peek) {
171 		return l->peek(l, pos);
172 	}
173 
174 	return NULL;
175 }
176 
llext_finalize(struct llext_loader * l)177 static inline void llext_finalize(struct llext_loader *l)
178 {
179 	if (l->finalize) {
180 		l->finalize(l);
181 	}
182 }
183 /* @endcond */
184 
185 /**
186  * @}
187  */
188 
189 #ifdef __cplusplus
190 }
191 #endif
192 
193 #endif /* ZEPHYR_LLEXT_LOADER_H */
194