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