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