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