1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** ThreadX Component */
17 /** */
18 /** Module Manager */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23 #define TX_SOURCE_CODE
24
25 #include "tx_api.h"
26 #include "tx_initialize.h"
27 #include "tx_mutex.h"
28 #include "tx_thread.h"
29 #include "tx_byte_pool.h"
30 #include "txm_module.h"
31 #include "txm_module_manager_util.h"
32
33
34 /**************************************************************************/
35 /* */
36 /* FUNCTION RELEASE */
37 /* */
38 /* _txm_module_manager_absolute_load PORTABLE C */
39 /* 6.1.3 */
40 /* AUTHOR */
41 /* */
42 /* Andres Mlinar, Microsoft Corporation */
43 /* */
44 /* DESCRIPTION */
45 /* */
46 /* This function ensures the code-related and data-related parts of */
47 /* the module preamble are valid and prepares the module for */
48 /* execution. */
49 /* */
50 /* INPUT */
51 /* */
52 /* module_instance Module instance pointer */
53 /* module_name Module name pointer */
54 /* module_location Module code location */
55 /* */
56 /* OUTPUT */
57 /* */
58 /* status Completion status */
59 /* */
60 /* CALLS */
61 /* */
62 /* _tx_byte_allocate Allocate data area */
63 /* _tx_mutex_get Get protection mutex */
64 /* _tx_mutex_put Release protection mutex */
65 /* */
66 /* CALLED BY */
67 /* */
68 /* Application code */
69 /* */
70 /* RELEASE HISTORY */
71 /* */
72 /* DATE NAME DESCRIPTION */
73 /* */
74 /* 12-31-2020 Andres Mlinar Initial Version 6.1.3 */
75 /* */
76 /**************************************************************************/
_txm_module_manager_absolute_load(TXM_MODULE_INSTANCE * module_instance,CHAR * module_name,VOID * module_location)77 UINT _txm_module_manager_absolute_load(TXM_MODULE_INSTANCE *module_instance, CHAR *module_name, VOID *module_location)
78 {
79
80 TX_INTERRUPT_SAVE_AREA
81
82 TXM_MODULE_PREAMBLE *module_preamble;
83 ULONG code_size;
84 ULONG code_alignment;
85 ULONG code_allocation_size_ignored;
86 UINT status;
87
88 TXM_MODULE_INSTANCE *next_module, *previous_module;
89 ULONG start_stop_stack_size;
90 ULONG callback_stack_size;
91 ULONG code_size_ignored;
92 ULONG code_alignment_ignored;
93 ALIGN_TYPE data_start;
94 ULONG data_size;
95 ULONG data_alignment;
96 ULONG data_allocation_size;
97 ULONG module_properties;
98 CHAR *memory_ptr;
99
100
101 /* Check for interrupt call. */
102 if (TX_THREAD_GET_SYSTEM_STATE() != 0)
103 {
104
105 /* Now, make sure the call is from an interrupt and not initialization. */
106 if (TX_THREAD_GET_SYSTEM_STATE() < TX_INITIALIZE_IN_PROGRESS)
107 {
108
109 /* Invalid caller of this function, return appropriate error code. */
110 return(TX_CALLER_ERROR);
111 }
112 }
113
114 /* Determine if the module manager has not been initialized yet. */
115 if (_txm_module_manager_ready != TX_TRUE)
116 {
117
118 /* Module manager has not been initialized. */
119 return(TX_NOT_AVAILABLE);
120 }
121
122 /* Determine if the module is valid. */
123 if (module_instance == TX_NULL)
124 {
125
126 /* Invalid module pointer. */
127 return(TX_PTR_ERROR);
128 }
129
130 /* Get module manager protection mutex. */
131 _tx_mutex_get(&_txm_module_manager_mutex, TX_WAIT_FOREVER);
132
133 /* Determine if the module is already valid. */
134 if (module_instance -> txm_module_instance_id == TXM_MODULE_ID)
135 {
136
137 /* Release the protection mutex. */
138 _tx_mutex_put(&_txm_module_manager_mutex);
139
140 /* Module already loaded. */
141 return(TXM_MODULE_ALREADY_LOADED);
142 }
143
144 /* Pickup the module's information. */
145 module_preamble = (TXM_MODULE_PREAMBLE *) module_location;
146
147 /* Check to make sure there is a valid module to load. */
148 if (module_preamble -> txm_module_preamble_id != TXM_MODULE_ID)
149 {
150
151 /* Release the protection mutex. */
152 _tx_mutex_put(&_txm_module_manager_mutex);
153
154 /* Invalid module preamble. */
155 return(TXM_MODULE_INVALID);
156 }
157
158 /* Check the properties of this module. */
159 module_properties = module_preamble -> txm_module_preamble_property_flags & TXM_MODULE_OPTIONS_MASK;
160 if (/* Ensure the requested properties are supported. */
161 ((module_properties & _txm_module_manager_properties_supported) != module_properties) ||
162 /* Ensure the required properties are there. */
163 ((_txm_module_manager_properties_required & module_properties) != _txm_module_manager_properties_required) ||
164 /* If memory protection is enabled, then so must user mode. */
165 ((module_properties & TXM_MODULE_MEMORY_PROTECTION) && !(module_properties & TXM_MODULE_USER_MODE))
166 )
167 {
168
169 /* Release the protection mutex. */
170 _tx_mutex_put(&_txm_module_manager_mutex);
171
172 /* Invalid properties. Return error. */
173 return(TXM_MODULE_INVALID_PROPERTIES);
174 }
175
176 /* Check for valid module entry offsets. */
177 if ((module_preamble -> txm_module_preamble_shell_entry_function == 0) ||
178 (module_preamble -> txm_module_preamble_start_function == 0))
179 {
180
181 /* Release the protection mutex. */
182 _tx_mutex_put(&_txm_module_manager_mutex);
183
184 /* Invalid module preamble. */
185 return(TXM_MODULE_INVALID);
186 }
187
188 /* Check for valid sizes. */
189 if ((module_preamble -> txm_module_preamble_code_size == 0) ||
190 /* (module_preamble -> txm_module_preamble_data_size == 0) || *** a zero data size is valid */
191 (module_preamble -> txm_module_preamble_start_stop_stack_size == 0) ||
192 (module_preamble -> txm_module_preamble_callback_stack_size == 0))
193 {
194
195 /* Release the protection mutex. */
196 _tx_mutex_put(&_txm_module_manager_mutex);
197
198 /* Invalid module preamble. */
199 return(TXM_MODULE_INVALID);
200 }
201
202 /* Get the amount of the bytes we need to allocate for the module's code
203 as well as the required alignment. Note that because this is an absolute
204 load, we only want the code alignment so we can check it. */
205 status = _txm_module_manager_util_code_allocation_size_and_alignment_get(module_preamble, &code_alignment, &code_allocation_size_ignored);
206 if (status != TX_SUCCESS)
207 {
208
209 /* Math overflow error occurred. */
210 return(status);
211 }
212
213 /* Since this is an absolute load, check the alignment of the module's instruction area (code). */
214 TXM_MODULE_MANAGER_CHECK_CODE_ALIGNMENT(module_location, code_alignment)
215
216 /* Initialize module control block to all zeros. */
217 TX_MEMSET(module_instance, 0, sizeof(TXM_MODULE_INSTANCE));
218
219 /* Pickup the basic module sizes. */
220 code_size = module_preamble -> txm_module_preamble_code_size;
221 data_size = module_preamble -> txm_module_preamble_data_size;
222 start_stop_stack_size = module_preamble -> txm_module_preamble_start_stop_stack_size;
223 callback_stack_size = module_preamble -> txm_module_preamble_callback_stack_size;
224
225 TXM_MODULE_MANAGER_UTIL_MATH_ADD_ULONG(data_size, TXM_MODULE_DATA_ALIGNMENT, data_size);
226 data_size = ((data_size - 1)/TXM_MODULE_DATA_ALIGNMENT) * TXM_MODULE_DATA_ALIGNMENT;
227
228 /* Adjust the size of the module elements to be aligned to the default alignment. We do this
229 so that when we partition the allocated memory, we can simply place these regions right beside
230 each other without having to align their pointers. Note this only works when they all have
231 the same alignment. */
232
233 TXM_MODULE_MANAGER_UTIL_MATH_ADD_ULONG(start_stop_stack_size, TXM_MODULE_DATA_ALIGNMENT, start_stop_stack_size);
234 start_stop_stack_size = ((start_stop_stack_size - 1)/TXM_MODULE_DATA_ALIGNMENT) * TXM_MODULE_DATA_ALIGNMENT;
235
236 TXM_MODULE_MANAGER_UTIL_MATH_ADD_ULONG(callback_stack_size, TXM_MODULE_DATA_ALIGNMENT, callback_stack_size);
237 callback_stack_size = ((callback_stack_size - 1)/TXM_MODULE_DATA_ALIGNMENT) * TXM_MODULE_DATA_ALIGNMENT;
238
239 /* Update the data size to account for the default thread stacks. */
240 data_allocation_size = 0;
241 TXM_MODULE_MANAGER_UTIL_MATH_ADD_ULONG(data_allocation_size, start_stop_stack_size, data_allocation_size);
242 TXM_MODULE_MANAGER_UTIL_MATH_ADD_ULONG(data_allocation_size, callback_stack_size, data_allocation_size);
243
244 /* Setup the default code and data alignments. */
245 data_alignment = (ULONG) TXM_MODULE_DATA_ALIGNMENT;
246
247 /* Get the port-specific alignment for the data size. Note we only want data
248 so we pass values of 1 for code (to avoid any possible div by 0 errors). */
249 code_size_ignored = 1;
250 code_alignment_ignored = 1;
251 TXM_MODULE_MANAGER_ALIGNMENT_ADJUST(module_preamble, code_size_ignored, code_alignment_ignored, data_allocation_size, data_alignment)
252
253 /* Calculate the module's total RAM memory requirement. This entire area is allocated from the module
254 manager's byte pool. The general layout is defined as follows:
255
256 Lowest Address: Start of start/stop thread stack
257 ... [note: thread entry info is embedded near end of stack areas]
258 End of start/stop thread stack
259
260 Start of callback thread stack
261 ... [note: thread entry info is embedded near end of stack areas]
262 End of callback thread stack
263
264 Highest Address: */
265
266 /* Add an extra alignment increment so we can align the pointer after allocation. */
267 TXM_MODULE_MANAGER_UTIL_MATH_ADD_ULONG(data_allocation_size, data_alignment, data_allocation_size);
268
269 /* Allocate memory for the module. */
270 status = _tx_byte_allocate(&_txm_module_manager_byte_pool, (VOID **) &memory_ptr, data_allocation_size, TX_NO_WAIT);
271
272 /* Determine if the module memory allocation was successful. */
273 if (status)
274 {
275
276 /* Release the protection mutex. */
277 _tx_mutex_put(&_txm_module_manager_mutex);
278
279 /* No memory, return an error. */
280 return(TX_NO_MEMORY);
281 }
282
283 /* Clear the allocated memory. */
284 TX_MEMSET(memory_ptr, ((UCHAR) 0), data_allocation_size);
285
286 /* Disable interrupts. */
287 TX_DISABLE
288
289 /* Setup the module instance structure. */
290 module_instance -> txm_module_instance_id = TXM_MODULE_ID;
291
292 /* Save the module name. */
293 module_instance -> txm_module_instance_name = module_name;
294
295 /* Save the module properties. */
296 module_instance -> txm_module_instance_property_flags = module_preamble -> txm_module_preamble_property_flags;
297
298 /* Set the module data memory allocation. This is the address released
299 when the module is unloaded. */
300 module_instance -> txm_module_instance_data_allocation_ptr = (VOID *) memory_ptr;
301
302 /* Save the data allocation size. */
303 module_instance -> txm_module_instance_data_allocation_size = data_allocation_size;
304
305 /* Calculate the actual start of the data area. This needs to be adjusted based on the alignment. */
306 data_start = (ALIGN_TYPE) memory_ptr;
307 data_start = (data_start + (((ALIGN_TYPE)data_alignment) - 1)) & ~(((ALIGN_TYPE)data_alignment) - 1);
308 memory_ptr = (CHAR *) data_start;
309
310 /* Compute the beginning and end of the data area. */
311 #ifdef ALIGN_TYPE_DEFINED
312 module_instance -> txm_module_instance_data_start = (VOID *) (((CHAR *) (ALIGN_TYPE) module_preamble->txm_module_preamble_code_size) + sizeof(TXM_MODULE_PREAMBLE));
313 module_instance -> txm_module_instance_data_end = (VOID *) (((CHAR *) (ALIGN_TYPE) module_instance -> txm_module_instance_data_start) + module_preamble->txm_module_preamble_data_size);
314 #else
315 module_instance -> txm_module_instance_data_start = (VOID *) (((CHAR *) module_preamble->txm_module_preamble_code_size) + sizeof(TXM_MODULE_PREAMBLE));
316 module_instance -> txm_module_instance_data_end = (VOID *) (((CHAR *) module_instance -> txm_module_instance_data_start) + module_preamble->txm_module_preamble_data_size);
317 #endif
318
319 /* Save the size of the data area. */
320 module_instance -> txm_module_instance_data_size = data_size;
321
322 /* Set the module code memory allocation. This is the address released
323 when the module is unloaded. */
324 module_instance -> txm_module_instance_code_allocation_ptr = (VOID *) NULL;
325
326 /* Save the code allocation size. */
327 module_instance -> txm_module_instance_code_allocation_size = 0;
328
329 /* Setup the code pointers. Since the code was loaded in-place, this is effectively just the values supplied in the API call. */
330 module_instance -> txm_module_instance_code_start = (VOID *) module_location;
331 module_instance -> txm_module_instance_code_end = (VOID *) (((CHAR *) module_location) + (code_size - 1));
332
333 /* Setup the code size. */
334 module_instance -> txm_module_instance_code_size = code_size;
335
336 /* Save the module's total memory usage. */
337 module_instance -> txm_module_instance_total_ram_usage = 0 /* Code is executed in place */ + data_allocation_size /* just the size of stacks */;
338
339 /* Set the module state to started. */
340 module_instance -> txm_module_instance_state = TXM_MODULE_LOADED;
341
342 /* Save the preamble pointer. */
343 module_instance -> txm_module_instance_preamble_ptr = module_preamble;
344
345 /* Save the module application ID in the module instance. */
346 module_instance -> txm_module_instance_application_module_id = module_preamble -> txm_module_preamble_application_module_id;
347
348 /* Setup the module's start/stop thread stack area. */
349 module_instance -> txm_module_instance_start_stop_stack_start_address = (VOID *) (memory_ptr);
350 module_instance -> txm_module_instance_start_stop_stack_size = start_stop_stack_size;
351 module_instance -> txm_module_instance_start_stop_stack_end_address = (VOID *) (memory_ptr + (start_stop_stack_size - 1));
352
353 /* Move the memory pointer forward. */
354 memory_ptr = memory_ptr + start_stop_stack_size;
355
356 /* Save the start/stop thread priority. */
357 module_instance -> txm_module_instance_start_stop_priority = module_preamble -> txm_module_preamble_start_stop_priority;
358
359 /* Setup the module's callback thread stack area. */
360 module_instance -> txm_module_instance_callback_stack_start_address = (VOID *) (memory_ptr);
361 module_instance -> txm_module_instance_callback_stack_size = callback_stack_size;
362 module_instance -> txm_module_instance_callback_stack_end_address = (VOID *) (memory_ptr + (callback_stack_size - 1));
363
364 /* Move the memory pointer forward. */
365 memory_ptr = memory_ptr + callback_stack_size;
366
367 /* Save the callback thread priority. */
368 module_instance -> txm_module_instance_callback_priority = module_preamble -> txm_module_preamble_callback_priority;
369
370 /* Setup the start of the module data section. */
371 module_instance -> txm_module_instance_module_data_base_address = (VOID *) (memory_ptr);
372
373 /* Build actual addresses based on load... Setup all the function pointers. Any adjustments needed to shell entry, start function, and callback function are defined in the
374 module preamble. */
375 #ifdef ALIGN_TYPE_DEFINED
376 module_instance -> txm_module_instance_shell_entry_function = (VOID (*)(TX_THREAD *, TXM_MODULE_INSTANCE *)) ((VOID *) (ALIGN_TYPE) module_preamble -> txm_module_preamble_shell_entry_function);
377 module_instance -> txm_module_instance_start_thread_entry = (VOID (*)(ULONG)) ((VOID *) (ALIGN_TYPE) module_preamble -> txm_module_preamble_start_function);
378 module_instance -> txm_module_instance_callback_request_thread_entry = (VOID (*)(ULONG)) ((VOID *) (ALIGN_TYPE) module_preamble -> txm_module_preamble_callback_function);
379 #else
380 module_instance -> txm_module_instance_shell_entry_function = (VOID (*)(TX_THREAD *, TXM_MODULE_INSTANCE *)) ((VOID *) module_preamble -> txm_module_preamble_shell_entry_function);
381 module_instance -> txm_module_instance_start_thread_entry = (VOID (*)(ULONG)) ((VOID *) module_preamble -> txm_module_preamble_start_function);
382 module_instance -> txm_module_instance_callback_request_thread_entry = (VOID (*)(ULONG)) ((VOID *) module_preamble -> txm_module_preamble_callback_function);
383 #endif
384
385 /* Determine if there is a stop function for this module. */
386 if (module_preamble -> txm_module_preamble_stop_function)
387 {
388
389 /* Yes, there is a stop function, build the address. */
390 #ifdef ALIGN_TYPE_DEFINED
391 module_instance -> txm_module_instance_stop_thread_entry = (VOID (*)(ULONG)) ((VOID *) (ALIGN_TYPE) module_preamble -> txm_module_preamble_stop_function);
392 #else
393 module_instance -> txm_module_instance_stop_thread_entry = (VOID (*)(ULONG)) ((VOID *) module_preamble -> txm_module_preamble_stop_function);
394 #endif
395 }
396 else
397 {
398
399 /* No, there is no stop function. Just set the pointer to NULL. */
400 module_instance -> txm_module_instance_stop_thread_entry = TX_NULL;
401 }
402
403 /* Load the module control block with port-specific information. */
404 TXM_MODULE_MANAGER_MODULE_SETUP(module_instance);
405
406 /* Now add the module to the linked list of created modules. */
407 if (_txm_module_manger_loaded_count++ == 0)
408 {
409
410 /* The loaded module list is empty. Add module to empty list. */
411 _txm_module_manager_loaded_list_ptr = module_instance;
412 module_instance -> txm_module_instance_loaded_next = module_instance;
413 module_instance -> txm_module_instance_loaded_previous = module_instance;
414 }
415 else
416 {
417
418 /* This list is not NULL, add to the end of the list. */
419 next_module = _txm_module_manager_loaded_list_ptr;
420 previous_module = next_module -> txm_module_instance_loaded_previous;
421
422 /* Place the new module in the list. */
423 next_module -> txm_module_instance_loaded_previous = module_instance;
424 previous_module -> txm_module_instance_loaded_next = module_instance;
425
426 /* Setup this module's created links. */
427 module_instance -> txm_module_instance_loaded_previous = previous_module;
428 module_instance -> txm_module_instance_loaded_next = next_module;
429 }
430
431 /* Restore interrupts. */
432 TX_RESTORE
433
434 /* Release the protection mutex. */
435 _tx_mutex_put(&_txm_module_manager_mutex);
436
437 /* Return success. */
438 return(TX_SUCCESS);
439 }
440