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