From b0ec8bfbb964a78e82c71b20bb6f79ef7597df32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= Date: Tue, 8 Sep 2026 10:03:45 -0400 Subject: [PATCH] Fixed the invalid module data pointers in the absolute module load (#699) An absolutely located module has its code and its data placed at two independent fixed addresses by the module's linker script. The module preamble carries the code and data sizes but not the data address, so _txm_module_manager_absolute_load() could not determine where the module's data area was. It computed txm_module_instance_data_start from the code size and the preamble size, which yields a size rather than an address, and it set txm_module_instance_module_data_base_address one past the end of the byte pool allocation. Added _txm_module_manager_absolute_load_extended(), which accepts the module's data area address from the caller. Deprecated _txm_module_manager_absolute_load(), which now forwards to the extended service with an unknown data area location and rejects modules that request memory protection, since the memory protection hardware cannot be programmed to cover an unknown data area. Fixes #450 Assisted-by: Copilot (Opus 5) --- common_modules/inc/txm_module.h | 4 + .../src/txm_module_manager_absolute_load.c | 417 ++------------- ...xm_module_manager_absolute_load_extended.c | 486 ++++++++++++++++++ .../sample_threadx_module_manager.c | 12 +- .../sample_threadx_module_manager.c | 12 +- .../sample_threadx_module_manager.c | 12 +- .../sample_threadx_module_manager.c | 12 +- 7 files changed, 578 insertions(+), 377 deletions(-) create mode 100644 common_modules/module_manager/src/txm_module_manager_absolute_load_extended.c diff --git a/common_modules/inc/txm_module.h b/common_modules/inc/txm_module.h index 88f79d9e..889f43ed 100644 --- a/common_modules/inc/txm_module.h +++ b/common_modules/inc/txm_module.h @@ -9,6 +9,8 @@ * SPDX-License-Identifier: MIT **************************************************************************/ +// Some portions generated by Copilot (Opus 5). + /**************************************************************************/ /**************************************************************************/ @@ -569,6 +571,7 @@ VOID _txm_module_usbx_duo_callback_request(TXM_MODULE_CALLBACK_MESSAGE *callbac #define txm_module_manager_initialize _txm_module_manager_initialize #define txm_module_manager_absolute_load _txm_module_manager_absolute_load +#define txm_module_manager_absolute_load_extended _txm_module_manager_absolute_load_extended #define txm_module_manager_in_place_load _txm_module_manager_in_place_load #define txm_module_manager_file_load _txm_module_manager_file_load #define txm_module_manager_memory_load _txm_module_manager_memory_load @@ -606,6 +609,7 @@ UINT _txm_module_manager_file_load(TXM_MODULE_INSTANCE *module_instance, CHAR * #endif UINT _txm_module_manager_initialize(VOID *module_memory_start, ULONG module_memory_size); UINT _txm_module_manager_absolute_load(TXM_MODULE_INSTANCE *module_instance, CHAR *name, VOID *module_location); +UINT _txm_module_manager_absolute_load_extended(TXM_MODULE_INSTANCE *module_instance, CHAR *name, VOID *module_location, VOID *module_data_location); UINT _txm_module_manager_in_place_load(TXM_MODULE_INSTANCE *module_instance, CHAR *name, VOID *module_location); UINT _txm_module_manager_internal_load(TXM_MODULE_INSTANCE *module_instance, CHAR *name, VOID *module_location, ULONG code_size, VOID *code_allocation_ptr, ULONG code_allocation_size); diff --git a/common_modules/module_manager/src/txm_module_manager_absolute_load.c b/common_modules/module_manager/src/txm_module_manager_absolute_load.c index dee6efd2..caa94719 100644 --- a/common_modules/module_manager/src/txm_module_manager_absolute_load.c +++ b/common_modules/module_manager/src/txm_module_manager_absolute_load.c @@ -1,6 +1,6 @@ /*************************************************************************** * Copyright (c) 2024 Microsoft Corporation - * Copyright (c) 2026-present Eclipse ThreadX contributors + * Copyright (c) 2026 Eclipse ThreadX contributors * * This program and the accompanying materials are made available under the * terms of the MIT License which is available at @@ -9,6 +9,8 @@ * SPDX-License-Identifier: MIT **************************************************************************/ +// Some portions generated by Copilot (Opus 5). + /**************************************************************************/ /**************************************************************************/ @@ -23,29 +25,57 @@ #define TX_SOURCE_CODE #include "tx_api.h" -#include "tx_initialize.h" -#include "tx_mutex.h" -#include "tx_thread.h" -#include "tx_byte_pool.h" #include "txm_module.h" -#include "txm_module_manager_util.h" +#ifndef TXM_MODULE_MANAGER_ABSOLUTE_LOAD_CALL_NOT_USED + +/* DEPRECATION NOTICE + * txm_module_manager_absolute_load() is deprecated. Do not use it in new code. + * + * WHY: an absolutely located module has its code and its data placed at two + * independent fixed addresses by the module's linker script. This service + * receives only the code address, and the module preamble carries the code and + * data sizes but not the data address. The module manager therefore has no way + * to determine where the module's data area is, and cannot describe it in the + * module instance. The affected fields are left empty by this wrapper. + * + * WHAT TO DO: replace calls with txm_module_manager_absolute_load_extended(), + * passing the module's data area address as the fourth argument. That address + * is the RAM segment start defined in the module's linker script. + * + * RISK: with the data area unknown, the module manager cannot tell whether an + * object, a thread control block, or the trace buffer resides in the module's + * data area, and a memory protection unit cannot be programmed to cover it. + * Modules that request memory protection are therefore rejected with + * TXM_MODULE_INVALID_PROPERTIES. + * + * Define TXM_MODULE_MANAGER_ABSOLUTE_LOAD_CALL_NOT_USED to remove this service + * and this message from the build. + */ +#pragma message("txm_module_manager_absolute_load() is deprecated. " \ + "Use txm_module_manager_absolute_load_extended() and pass " \ + "the module's data area address.") /**************************************************************************/ /* */ /* FUNCTION RELEASE */ /* */ /* _txm_module_manager_absolute_load PORTABLE C */ -/* 6.1.3 */ +/* 6.5.2 */ /* AUTHOR */ /* */ /* Andres Mlinar, Microsoft Corporation */ /* */ /* DESCRIPTION */ /* */ -/* This function ensures the code-related and data-related parts of */ -/* the module preamble are valid and prepares the module for */ -/* execution. */ +/* DEPRECATED. Use _txm_module_manager_absolute_load_extended() */ +/* instead, passing the module's data area address. This wrapper */ +/* passes TX_NULL, which leaves the module instance's data area */ +/* description empty because the module manager cannot derive the */ +/* data area address of an absolutely located module. Modules that */ +/* request memory protection are rejected with */ +/* TXM_MODULE_INVALID_PROPERTIES, because the memory protection */ +/* hardware cannot be programmed to cover an unknown data area. */ /* */ /* INPUT */ /* */ @@ -59,9 +89,8 @@ /* */ /* CALLS */ /* */ -/* _tx_byte_allocate Allocate data area */ -/* _tx_mutex_get Get protection mutex */ -/* _tx_mutex_put Release protection mutex */ +/* _txm_module_manager_absolute_load_extended */ +/* Load the module */ /* */ /* CALLED BY */ /* */ @@ -71,363 +100,13 @@ UINT _txm_module_manager_absolute_load(TXM_MODULE_INSTANCE *module_instance, CHAR *module_name, VOID *module_location) { -TX_INTERRUPT_SAVE_AREA +UINT status; -TXM_MODULE_PREAMBLE *module_preamble; -ULONG code_size; -ULONG code_alignment; -ULONG code_allocation_size_ignored; -UINT status; -TXM_MODULE_INSTANCE *next_module, *previous_module; -ULONG start_stop_stack_size; -ULONG callback_stack_size; -ULONG code_size_ignored; -ULONG code_alignment_ignored; -ALIGN_TYPE data_start; -ULONG data_size; -ULONG data_alignment; -ULONG data_allocation_size; -ULONG module_properties; -CHAR *memory_ptr; + /* Call the extended service with an unknown data area location. */ + status = _txm_module_manager_absolute_load_extended(module_instance, module_name, module_location, TX_NULL); - - /* Check for interrupt call. */ - if (TX_THREAD_GET_SYSTEM_STATE() != 0) - { - - /* Now, make sure the call is from an interrupt and not initialization. */ - if (TX_THREAD_GET_SYSTEM_STATE() < TX_INITIALIZE_IN_PROGRESS) - { - - /* Invalid caller of this function, return appropriate error code. */ - return(TX_CALLER_ERROR); - } - } - - /* Determine if the module manager has not been initialized yet. */ - if (_txm_module_manager_ready != TX_TRUE) - { - - /* Module manager has not been initialized. */ - return(TX_NOT_AVAILABLE); - } - - /* Determine if the module is valid. */ - if (module_instance == TX_NULL) - { - - /* Invalid module pointer. */ - return(TX_PTR_ERROR); - } - - /* Get module manager protection mutex. */ - _tx_mutex_get(&_txm_module_manager_mutex, TX_WAIT_FOREVER); - - /* Determine if the module is already valid. */ - if (module_instance -> txm_module_instance_id == TXM_MODULE_ID) - { - - /* Release the protection mutex. */ - _tx_mutex_put(&_txm_module_manager_mutex); - - /* Module already loaded. */ - return(TXM_MODULE_ALREADY_LOADED); - } - - /* Pickup the module's information. */ - module_preamble = (TXM_MODULE_PREAMBLE *) module_location; - - /* Check to make sure there is a valid module to load. */ - if (module_preamble -> txm_module_preamble_id != TXM_MODULE_ID) - { - - /* Release the protection mutex. */ - _tx_mutex_put(&_txm_module_manager_mutex); - - /* Invalid module preamble. */ - return(TXM_MODULE_INVALID); - } - - /* Check the properties of this module. */ - module_properties = module_preamble -> txm_module_preamble_property_flags & TXM_MODULE_OPTIONS_MASK; - if (/* Ensure the requested properties are supported. */ - ((module_properties & _txm_module_manager_properties_supported) != module_properties) || - /* Ensure the required properties are there. */ - ((_txm_module_manager_properties_required & module_properties) != _txm_module_manager_properties_required) || - /* If memory protection is enabled, then so must user mode. */ - ((module_properties & TXM_MODULE_MEMORY_PROTECTION) && !(module_properties & TXM_MODULE_USER_MODE)) - ) - { - - /* Release the protection mutex. */ - _tx_mutex_put(&_txm_module_manager_mutex); - - /* Invalid properties. Return error. */ - return(TXM_MODULE_INVALID_PROPERTIES); - } - - /* Check for valid module entry offsets. */ - if ((module_preamble -> txm_module_preamble_shell_entry_function == 0) || - (module_preamble -> txm_module_preamble_start_function == 0)) - { - - /* Release the protection mutex. */ - _tx_mutex_put(&_txm_module_manager_mutex); - - /* Invalid module preamble. */ - return(TXM_MODULE_INVALID); - } - - /* Check for valid sizes. */ - if ((module_preamble -> txm_module_preamble_code_size == 0) || - /* (module_preamble -> txm_module_preamble_data_size == 0) || *** a zero data size is valid */ - (module_preamble -> txm_module_preamble_start_stop_stack_size == 0) || - (module_preamble -> txm_module_preamble_callback_stack_size == 0)) - { - - /* Release the protection mutex. */ - _tx_mutex_put(&_txm_module_manager_mutex); - - /* Invalid module preamble. */ - return(TXM_MODULE_INVALID); - } - - /* Get the amount of the bytes we need to allocate for the module's code - as well as the required alignment. Note that because this is an absolute - load, we only want the code alignment so we can check it. */ - status = _txm_module_manager_util_code_allocation_size_and_alignment_get(module_preamble, &code_alignment, &code_allocation_size_ignored); - if (status != TX_SUCCESS) - { - - /* Math overflow error occurred. */ - return(status); - } - - /* Since this is an absolute load, check the alignment of the module's instruction area (code). */ - TXM_MODULE_MANAGER_CHECK_CODE_ALIGNMENT(module_location, code_alignment) - - /* Initialize module control block to all zeros. */ - TX_MEMSET(module_instance, 0, sizeof(TXM_MODULE_INSTANCE)); - - /* Pickup the basic module sizes. */ - code_size = module_preamble -> txm_module_preamble_code_size; - data_size = module_preamble -> txm_module_preamble_data_size; - start_stop_stack_size = module_preamble -> txm_module_preamble_start_stop_stack_size; - callback_stack_size = module_preamble -> txm_module_preamble_callback_stack_size; - - TXM_MODULE_MANAGER_UTIL_MATH_ADD_ULONG(data_size, TXM_MODULE_DATA_ALIGNMENT, data_size); - data_size = ((data_size - 1)/TXM_MODULE_DATA_ALIGNMENT) * TXM_MODULE_DATA_ALIGNMENT; - - /* Adjust the size of the module elements to be aligned to the default alignment. We do this - so that when we partition the allocated memory, we can simply place these regions right beside - each other without having to align their pointers. Note this only works when they all have - the same alignment. */ - - TXM_MODULE_MANAGER_UTIL_MATH_ADD_ULONG(start_stop_stack_size, TXM_MODULE_DATA_ALIGNMENT, start_stop_stack_size); - start_stop_stack_size = ((start_stop_stack_size - 1)/TXM_MODULE_DATA_ALIGNMENT) * TXM_MODULE_DATA_ALIGNMENT; - - TXM_MODULE_MANAGER_UTIL_MATH_ADD_ULONG(callback_stack_size, TXM_MODULE_DATA_ALIGNMENT, callback_stack_size); - callback_stack_size = ((callback_stack_size - 1)/TXM_MODULE_DATA_ALIGNMENT) * TXM_MODULE_DATA_ALIGNMENT; - - /* Update the data size to account for the default thread stacks. */ - data_allocation_size = 0; - TXM_MODULE_MANAGER_UTIL_MATH_ADD_ULONG(data_allocation_size, start_stop_stack_size, data_allocation_size); - TXM_MODULE_MANAGER_UTIL_MATH_ADD_ULONG(data_allocation_size, callback_stack_size, data_allocation_size); - - /* Setup the default code and data alignments. */ - data_alignment = (ULONG) TXM_MODULE_DATA_ALIGNMENT; - - /* Get the port-specific alignment for the data size. Note we only want data - so we pass values of 1 for code (to avoid any possible div by 0 errors). */ - code_size_ignored = 1; - code_alignment_ignored = 1; - TXM_MODULE_MANAGER_ALIGNMENT_ADJUST(module_preamble, code_size_ignored, code_alignment_ignored, data_allocation_size, data_alignment) - - /* Calculate the module's total RAM memory requirement. This entire area is allocated from the module - manager's byte pool. The general layout is defined as follows: - - Lowest Address: Start of start/stop thread stack - ... [note: thread entry info is embedded near end of stack areas] - End of start/stop thread stack - - Start of callback thread stack - ... [note: thread entry info is embedded near end of stack areas] - End of callback thread stack - - Highest Address: */ - - /* Add an extra alignment increment so we can align the pointer after allocation. */ - TXM_MODULE_MANAGER_UTIL_MATH_ADD_ULONG(data_allocation_size, data_alignment, data_allocation_size); - - /* Allocate memory for the module. */ - status = _tx_byte_allocate(&_txm_module_manager_byte_pool, (VOID **) &memory_ptr, data_allocation_size, TX_NO_WAIT); - - /* Determine if the module memory allocation was successful. */ - if (status) - { - - /* Release the protection mutex. */ - _tx_mutex_put(&_txm_module_manager_mutex); - - /* No memory, return an error. */ - return(TX_NO_MEMORY); - } - - /* Clear the allocated memory. */ - TX_MEMSET(memory_ptr, ((UCHAR) 0), data_allocation_size); - - /* Disable interrupts. */ - TX_DISABLE - - /* Setup the module instance structure. */ - module_instance -> txm_module_instance_id = TXM_MODULE_ID; - - /* Save the module name. */ - module_instance -> txm_module_instance_name = module_name; - - /* Save the module properties. */ - module_instance -> txm_module_instance_property_flags = module_preamble -> txm_module_preamble_property_flags; - - /* Set the module data memory allocation. This is the address released - when the module is unloaded. */ - module_instance -> txm_module_instance_data_allocation_ptr = (VOID *) memory_ptr; - - /* Save the data allocation size. */ - module_instance -> txm_module_instance_data_allocation_size = data_allocation_size; - - /* Calculate the actual start of the data area. This needs to be adjusted based on the alignment. */ - data_start = (ALIGN_TYPE) memory_ptr; - data_start = (data_start + (((ALIGN_TYPE)data_alignment) - 1)) & ~(((ALIGN_TYPE)data_alignment) - 1); - memory_ptr = (CHAR *) data_start; - - /* Compute the beginning and end of the data area. */ -#ifdef ALIGN_TYPE_DEFINED - module_instance -> txm_module_instance_data_start = (VOID *) (((CHAR *) (ALIGN_TYPE) module_preamble->txm_module_preamble_code_size) + sizeof(TXM_MODULE_PREAMBLE)); - 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); -#else - module_instance -> txm_module_instance_data_start = (VOID *) (((CHAR *) module_preamble->txm_module_preamble_code_size) + sizeof(TXM_MODULE_PREAMBLE)); - module_instance -> txm_module_instance_data_end = (VOID *) (((CHAR *) module_instance -> txm_module_instance_data_start) + module_preamble->txm_module_preamble_data_size); -#endif - - /* Save the size of the data area. */ - module_instance -> txm_module_instance_data_size = data_size; - - /* Set the module code memory allocation. This is the address released - when the module is unloaded. */ - module_instance -> txm_module_instance_code_allocation_ptr = (VOID *) NULL; - - /* Save the code allocation size. */ - module_instance -> txm_module_instance_code_allocation_size = 0; - - /* Setup the code pointers. Since the code was loaded in-place, this is effectively just the values supplied in the API call. */ - module_instance -> txm_module_instance_code_start = (VOID *) module_location; - module_instance -> txm_module_instance_code_end = (VOID *) (((CHAR *) module_location) + (code_size - 1)); - - /* Setup the code size. */ - module_instance -> txm_module_instance_code_size = code_size; - - /* Save the module's total memory usage. */ - module_instance -> txm_module_instance_total_ram_usage = 0 /* Code is executed in place */ + data_allocation_size /* just the size of stacks */; - - /* Set the module state to started. */ - module_instance -> txm_module_instance_state = TXM_MODULE_LOADED; - - /* Save the preamble pointer. */ - module_instance -> txm_module_instance_preamble_ptr = module_preamble; - - /* Save the module application ID in the module instance. */ - module_instance -> txm_module_instance_application_module_id = module_preamble -> txm_module_preamble_application_module_id; - - /* Setup the module's start/stop thread stack area. */ - module_instance -> txm_module_instance_start_stop_stack_start_address = (VOID *) (memory_ptr); - module_instance -> txm_module_instance_start_stop_stack_size = start_stop_stack_size; - module_instance -> txm_module_instance_start_stop_stack_end_address = (VOID *) (memory_ptr + (start_stop_stack_size - 1)); - - /* Move the memory pointer forward. */ - memory_ptr = memory_ptr + start_stop_stack_size; - - /* Save the start/stop thread priority. */ - module_instance -> txm_module_instance_start_stop_priority = module_preamble -> txm_module_preamble_start_stop_priority; - - /* Setup the module's callback thread stack area. */ - module_instance -> txm_module_instance_callback_stack_start_address = (VOID *) (memory_ptr); - module_instance -> txm_module_instance_callback_stack_size = callback_stack_size; - module_instance -> txm_module_instance_callback_stack_end_address = (VOID *) (memory_ptr + (callback_stack_size - 1)); - - /* Move the memory pointer forward. */ - memory_ptr = memory_ptr + callback_stack_size; - - /* Save the callback thread priority. */ - module_instance -> txm_module_instance_callback_priority = module_preamble -> txm_module_preamble_callback_priority; - - /* Setup the start of the module data section. */ - module_instance -> txm_module_instance_module_data_base_address = (VOID *) (memory_ptr); - - /* 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 - module preamble. */ -#ifdef ALIGN_TYPE_DEFINED - 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); - module_instance -> txm_module_instance_start_thread_entry = (VOID (*)(ULONG)) ((VOID *) (ALIGN_TYPE) module_preamble -> txm_module_preamble_start_function); - module_instance -> txm_module_instance_callback_request_thread_entry = (VOID (*)(ULONG)) ((VOID *) (ALIGN_TYPE) module_preamble -> txm_module_preamble_callback_function); -#else - module_instance -> txm_module_instance_shell_entry_function = (VOID (*)(TX_THREAD *, TXM_MODULE_INSTANCE *)) ((VOID *) module_preamble -> txm_module_preamble_shell_entry_function); - module_instance -> txm_module_instance_start_thread_entry = (VOID (*)(ULONG)) ((VOID *) module_preamble -> txm_module_preamble_start_function); - module_instance -> txm_module_instance_callback_request_thread_entry = (VOID (*)(ULONG)) ((VOID *) module_preamble -> txm_module_preamble_callback_function); -#endif - - /* Determine if there is a stop function for this module. */ - if (module_preamble -> txm_module_preamble_stop_function) - { - - /* Yes, there is a stop function, build the address. */ -#ifdef ALIGN_TYPE_DEFINED - module_instance -> txm_module_instance_stop_thread_entry = (VOID (*)(ULONG)) ((VOID *) (ALIGN_TYPE) module_preamble -> txm_module_preamble_stop_function); -#else - module_instance -> txm_module_instance_stop_thread_entry = (VOID (*)(ULONG)) ((VOID *) module_preamble -> txm_module_preamble_stop_function); -#endif - } - else - { - - /* No, there is no stop function. Just set the pointer to NULL. */ - module_instance -> txm_module_instance_stop_thread_entry = TX_NULL; - } - - /* Load the module control block with port-specific information. */ - TXM_MODULE_MANAGER_MODULE_SETUP(module_instance); - - /* Now add the module to the linked list of created modules. */ - if (_txm_module_manger_loaded_count++ == 0) - { - - /* The loaded module list is empty. Add module to empty list. */ - _txm_module_manager_loaded_list_ptr = module_instance; - module_instance -> txm_module_instance_loaded_next = module_instance; - module_instance -> txm_module_instance_loaded_previous = module_instance; - } - else - { - - /* This list is not NULL, add to the end of the list. */ - next_module = _txm_module_manager_loaded_list_ptr; - previous_module = next_module -> txm_module_instance_loaded_previous; - - /* Place the new module in the list. */ - next_module -> txm_module_instance_loaded_previous = module_instance; - previous_module -> txm_module_instance_loaded_next = module_instance; - - /* Setup this module's created links. */ - module_instance -> txm_module_instance_loaded_previous = previous_module; - module_instance -> txm_module_instance_loaded_next = next_module; - } - - /* Restore interrupts. */ - TX_RESTORE - - /* Release the protection mutex. */ - _tx_mutex_put(&_txm_module_manager_mutex); - - /* Return success. */ - return(TX_SUCCESS); + /* Return completion status. */ + return(status); } +#endif diff --git a/common_modules/module_manager/src/txm_module_manager_absolute_load_extended.c b/common_modules/module_manager/src/txm_module_manager_absolute_load_extended.c new file mode 100644 index 00000000..77b35678 --- /dev/null +++ b/common_modules/module_manager/src/txm_module_manager_absolute_load_extended.c @@ -0,0 +1,486 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * Copyright (c) 2026-present Eclipse ThreadX contributors + * + * This program and the accompanying materials are made available under the + * terms of the MIT License which is available at + * https://opensource.org/licenses/MIT. + * + * SPDX-License-Identifier: MIT + **************************************************************************/ + +// Some portions generated by Copilot (Opus 5). + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Module Manager */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + +#include "tx_api.h" +#include "tx_initialize.h" +#include "tx_mutex.h" +#include "tx_thread.h" +#include "tx_byte_pool.h" +#include "txm_module.h" +#include "txm_module_manager_util.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txm_module_manager_absolute_load_extended PORTABLE C */ +/* 6.5.2 */ +/* AUTHOR */ +/* */ +/* Andres Mlinar, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function ensures the code-related and data-related parts of */ +/* the module preamble are valid and prepares the module for */ +/* execution. */ +/* */ +/* An absolutely located module has its code and its data placed at */ +/* fixed addresses by the module's linker script. The module preamble */ +/* carries only the code and data sizes, so the module manager cannot */ +/* derive the module's data location on its own. This service accepts */ +/* that address from the caller, which allows the module instance's */ +/* data area to be described correctly. */ +/* */ +/* INPUT */ +/* */ +/* module_instance Module instance pointer */ +/* module_name Module name pointer */ +/* module_location Module code location */ +/* module_data_location Module data location, or TX_NULL */ +/* when the data location is not */ +/* known to the caller. Memory */ +/* protection cannot be used when */ +/* it is TX_NULL. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_byte_allocate Allocate data area */ +/* _tx_mutex_get Get protection mutex */ +/* _tx_mutex_put Release protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* _txm_module_manager_absolute_load Deprecated wrapper */ +/* */ +/**************************************************************************/ +UINT _txm_module_manager_absolute_load_extended(TXM_MODULE_INSTANCE *module_instance, CHAR *module_name, VOID *module_location, VOID *module_data_location) +{ + +TX_INTERRUPT_SAVE_AREA + +TXM_MODULE_PREAMBLE *module_preamble; +ULONG code_size; +ULONG code_alignment; +ULONG code_allocation_size_ignored; +UINT status; + +TXM_MODULE_INSTANCE *next_module, *previous_module; +ULONG start_stop_stack_size; +ULONG callback_stack_size; +ULONG code_size_ignored; +ULONG code_alignment_ignored; +ALIGN_TYPE data_start; +ULONG data_size; +ULONG data_alignment; +ULONG data_allocation_size; +ULONG module_properties; +CHAR *memory_ptr; + + + /* Check for interrupt call. */ + if (TX_THREAD_GET_SYSTEM_STATE() != 0) + { + + /* Now, make sure the call is from an interrupt and not initialization. */ + if (TX_THREAD_GET_SYSTEM_STATE() < TX_INITIALIZE_IN_PROGRESS) + { + + /* Invalid caller of this function, return appropriate error code. */ + return(TX_CALLER_ERROR); + } + } + + /* Determine if the module manager has not been initialized yet. */ + if (_txm_module_manager_ready != TX_TRUE) + { + + /* Module manager has not been initialized. */ + return(TX_NOT_AVAILABLE); + } + + /* Determine if the module is valid. */ + if (module_instance == TX_NULL) + { + + /* Invalid module pointer. */ + return(TX_PTR_ERROR); + } + + /* Get module manager protection mutex. */ + _tx_mutex_get(&_txm_module_manager_mutex, TX_WAIT_FOREVER); + + /* Determine if the module is already valid. */ + if (module_instance -> txm_module_instance_id == TXM_MODULE_ID) + { + + /* Release the protection mutex. */ + _tx_mutex_put(&_txm_module_manager_mutex); + + /* Module already loaded. */ + return(TXM_MODULE_ALREADY_LOADED); + } + + /* Pickup the module's information. */ + module_preamble = (TXM_MODULE_PREAMBLE *) module_location; + + /* Check to make sure there is a valid module to load. */ + if (module_preamble -> txm_module_preamble_id != TXM_MODULE_ID) + { + + /* Release the protection mutex. */ + _tx_mutex_put(&_txm_module_manager_mutex); + + /* Invalid module preamble. */ + return(TXM_MODULE_INVALID); + } + + /* Check the properties of this module. */ + module_properties = module_preamble -> txm_module_preamble_property_flags & TXM_MODULE_OPTIONS_MASK; + if (/* Ensure the requested properties are supported. */ + ((module_properties & _txm_module_manager_properties_supported) != module_properties) || + /* Ensure the required properties are there. */ + ((_txm_module_manager_properties_required & module_properties) != _txm_module_manager_properties_required) || + /* If memory protection is enabled, then so must user mode. */ + ((module_properties & TXM_MODULE_MEMORY_PROTECTION) && !(module_properties & TXM_MODULE_USER_MODE)) || + /* Memory protection requires a known data area, since the memory protection hardware must + be programmed to cover it. */ + ((module_properties & TXM_MODULE_MEMORY_PROTECTION) && (module_data_location == TX_NULL)) + ) + { + + /* Release the protection mutex. */ + _tx_mutex_put(&_txm_module_manager_mutex); + + /* Invalid properties. Return error. */ + return(TXM_MODULE_INVALID_PROPERTIES); + } + + /* Check for valid module entry offsets. */ + if ((module_preamble -> txm_module_preamble_shell_entry_function == 0) || + (module_preamble -> txm_module_preamble_start_function == 0)) + { + + /* Release the protection mutex. */ + _tx_mutex_put(&_txm_module_manager_mutex); + + /* Invalid module preamble. */ + return(TXM_MODULE_INVALID); + } + + /* Check for valid sizes. */ + if ((module_preamble -> txm_module_preamble_code_size == 0) || + /* (module_preamble -> txm_module_preamble_data_size == 0) || *** a zero data size is valid */ + (module_preamble -> txm_module_preamble_start_stop_stack_size == 0) || + (module_preamble -> txm_module_preamble_callback_stack_size == 0)) + { + + /* Release the protection mutex. */ + _tx_mutex_put(&_txm_module_manager_mutex); + + /* Invalid module preamble. */ + return(TXM_MODULE_INVALID); + } + + /* Get the amount of the bytes we need to allocate for the module's code + as well as the required alignment. Note that because this is an absolute + load, we only want the code alignment so we can check it. */ + status = _txm_module_manager_util_code_allocation_size_and_alignment_get(module_preamble, &code_alignment, &code_allocation_size_ignored); + if (status != TX_SUCCESS) + { + + /* Math overflow error occurred. */ + return(status); + } + + /* Since this is an absolute load, check the alignment of the module's instruction area (code). */ + TXM_MODULE_MANAGER_CHECK_CODE_ALIGNMENT(module_location, code_alignment) + + /* Initialize module control block to all zeros. */ + TX_MEMSET(module_instance, 0, sizeof(TXM_MODULE_INSTANCE)); + + /* Pickup the basic module sizes. */ + code_size = module_preamble -> txm_module_preamble_code_size; + data_size = module_preamble -> txm_module_preamble_data_size; + start_stop_stack_size = module_preamble -> txm_module_preamble_start_stop_stack_size; + callback_stack_size = module_preamble -> txm_module_preamble_callback_stack_size; + + TXM_MODULE_MANAGER_UTIL_MATH_ADD_ULONG(data_size, TXM_MODULE_DATA_ALIGNMENT, data_size); + data_size = ((data_size - 1)/TXM_MODULE_DATA_ALIGNMENT) * TXM_MODULE_DATA_ALIGNMENT; + + /* Adjust the size of the module elements to be aligned to the default alignment. We do this + so that when we partition the allocated memory, we can simply place these regions right beside + each other without having to align their pointers. Note this only works when they all have + the same alignment. */ + + TXM_MODULE_MANAGER_UTIL_MATH_ADD_ULONG(start_stop_stack_size, TXM_MODULE_DATA_ALIGNMENT, start_stop_stack_size); + start_stop_stack_size = ((start_stop_stack_size - 1)/TXM_MODULE_DATA_ALIGNMENT) * TXM_MODULE_DATA_ALIGNMENT; + + TXM_MODULE_MANAGER_UTIL_MATH_ADD_ULONG(callback_stack_size, TXM_MODULE_DATA_ALIGNMENT, callback_stack_size); + callback_stack_size = ((callback_stack_size - 1)/TXM_MODULE_DATA_ALIGNMENT) * TXM_MODULE_DATA_ALIGNMENT; + + /* Update the data size to account for the default thread stacks. */ + data_allocation_size = 0; + TXM_MODULE_MANAGER_UTIL_MATH_ADD_ULONG(data_allocation_size, start_stop_stack_size, data_allocation_size); + TXM_MODULE_MANAGER_UTIL_MATH_ADD_ULONG(data_allocation_size, callback_stack_size, data_allocation_size); + + /* Setup the default code and data alignments. */ + data_alignment = (ULONG) TXM_MODULE_DATA_ALIGNMENT; + + /* Get the port-specific alignment for the data size. Note we only want data + so we pass values of 1 for code (to avoid any possible div by 0 errors). */ + code_size_ignored = 1; + code_alignment_ignored = 1; + TXM_MODULE_MANAGER_ALIGNMENT_ADJUST(module_preamble, code_size_ignored, code_alignment_ignored, data_allocation_size, data_alignment) + + /* Since this is an absolute load, check the alignment of the module's data area when the caller + supplied its location. */ + if (module_data_location != TX_NULL) + { + if ((((ALIGN_TYPE) module_data_location) & (((ALIGN_TYPE) data_alignment) - ((ALIGN_TYPE) 1))) != ((ALIGN_TYPE) 0)) + { + + /* Release the protection mutex. */ + _tx_mutex_put(&_txm_module_manager_mutex); + + /* Invalid alignment, return error. */ + return(TXM_MODULE_ALIGNMENT_ERROR); + } + } + + /* Calculate the module's total RAM memory requirement. This entire area is allocated from the module + manager's byte pool. The general layout is defined as follows: + + Lowest Address: Start of start/stop thread stack + ... [note: thread entry info is embedded near end of stack areas] + End of start/stop thread stack + + Start of callback thread stack + ... [note: thread entry info is embedded near end of stack areas] + End of callback thread stack + + Highest Address: */ + + /* Add an extra alignment increment so we can align the pointer after allocation. */ + TXM_MODULE_MANAGER_UTIL_MATH_ADD_ULONG(data_allocation_size, data_alignment, data_allocation_size); + + /* Allocate memory for the module. */ + status = _tx_byte_allocate(&_txm_module_manager_byte_pool, (VOID **) &memory_ptr, data_allocation_size, TX_NO_WAIT); + + /* Determine if the module memory allocation was successful. */ + if (status) + { + + /* Release the protection mutex. */ + _tx_mutex_put(&_txm_module_manager_mutex); + + /* No memory, return an error. */ + return(TX_NO_MEMORY); + } + + /* Clear the allocated memory. */ + TX_MEMSET(memory_ptr, ((UCHAR) 0), data_allocation_size); + + /* Disable interrupts. */ + TX_DISABLE + + /* Setup the module instance structure. */ + module_instance -> txm_module_instance_id = TXM_MODULE_ID; + + /* Save the module name. */ + module_instance -> txm_module_instance_name = module_name; + + /* Save the module properties. */ + module_instance -> txm_module_instance_property_flags = module_preamble -> txm_module_preamble_property_flags; + + /* Set the module data memory allocation. This is the address released + when the module is unloaded. */ + module_instance -> txm_module_instance_data_allocation_ptr = (VOID *) memory_ptr; + + /* Save the data allocation size. */ + module_instance -> txm_module_instance_data_allocation_size = data_allocation_size; + + /* Calculate the actual start of the data area. This needs to be adjusted based on the alignment. */ + data_start = (ALIGN_TYPE) memory_ptr; + data_start = (data_start + (((ALIGN_TYPE)data_alignment) - 1)) & ~(((ALIGN_TYPE)data_alignment) - 1); + memory_ptr = (CHAR *) data_start; + + /* Compute the beginning and end of the data area. An absolutely located module has its data + placed at a fixed address by its linker script, and that address is not carried in the + module preamble. It must therefore be supplied by the caller. */ + if (module_data_location != TX_NULL) + { + + module_instance -> txm_module_instance_data_start = module_data_location; + + /* A zero data size is valid, so guard against wrapping when computing the end address. */ + if (data_size != 0) + { + module_instance -> txm_module_instance_data_end = (VOID *) (((CHAR *) module_data_location) + (data_size - 1)); + } + else + { + module_instance -> txm_module_instance_data_end = module_data_location; + } + + /* Save the size of the data area. */ + module_instance -> txm_module_instance_data_size = data_size; + } + else + { + + /* The caller does not know where the module's data area is, so the module instance cannot + describe it. Report an empty data area rather than an invalid one. */ + module_instance -> txm_module_instance_data_start = TX_NULL; + module_instance -> txm_module_instance_data_end = TX_NULL; + + /* Save the size of the data area. */ + module_instance -> txm_module_instance_data_size = 0; + } + + /* Set the module code memory allocation. This is the address released + when the module is unloaded. */ + module_instance -> txm_module_instance_code_allocation_ptr = (VOID *) NULL; + + /* Save the code allocation size. */ + module_instance -> txm_module_instance_code_allocation_size = 0; + + /* Setup the code pointers. Since the code was loaded in-place, this is effectively just the values supplied in the API call. */ + module_instance -> txm_module_instance_code_start = (VOID *) module_location; + module_instance -> txm_module_instance_code_end = (VOID *) (((CHAR *) module_location) + (code_size - 1)); + + /* Setup the code size. */ + module_instance -> txm_module_instance_code_size = code_size; + + /* Save the module's total memory usage. */ + module_instance -> txm_module_instance_total_ram_usage = 0 /* Code is executed in place */ + data_allocation_size /* just the size of stacks */; + + /* Set the module state to started. */ + module_instance -> txm_module_instance_state = TXM_MODULE_LOADED; + + /* Save the preamble pointer. */ + module_instance -> txm_module_instance_preamble_ptr = module_preamble; + + /* Save the module application ID in the module instance. */ + module_instance -> txm_module_instance_application_module_id = module_preamble -> txm_module_preamble_application_module_id; + + /* Setup the module's start/stop thread stack area. */ + module_instance -> txm_module_instance_start_stop_stack_start_address = (VOID *) (memory_ptr); + module_instance -> txm_module_instance_start_stop_stack_size = start_stop_stack_size; + module_instance -> txm_module_instance_start_stop_stack_end_address = (VOID *) (memory_ptr + (start_stop_stack_size - 1)); + + /* Move the memory pointer forward. */ + memory_ptr = memory_ptr + start_stop_stack_size; + + /* Save the start/stop thread priority. */ + module_instance -> txm_module_instance_start_stop_priority = module_preamble -> txm_module_preamble_start_stop_priority; + + /* Setup the module's callback thread stack area. */ + module_instance -> txm_module_instance_callback_stack_start_address = (VOID *) (memory_ptr); + module_instance -> txm_module_instance_callback_stack_size = callback_stack_size; + module_instance -> txm_module_instance_callback_stack_end_address = (VOID *) (memory_ptr + (callback_stack_size - 1)); + + /* Save the callback thread priority. */ + module_instance -> txm_module_instance_callback_priority = module_preamble -> txm_module_preamble_callback_priority; + + /* Setup the start of the module data section. For an absolute load, the byte pool allocation + holds only the two default thread stacks. The module's data section is the absolutely + located area supplied by the caller. */ + module_instance -> txm_module_instance_module_data_base_address = module_data_location; + + /* 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 + module preamble. */ +#ifdef ALIGN_TYPE_DEFINED + 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); + module_instance -> txm_module_instance_start_thread_entry = (VOID (*)(ULONG)) ((VOID *) (ALIGN_TYPE) module_preamble -> txm_module_preamble_start_function); + module_instance -> txm_module_instance_callback_request_thread_entry = (VOID (*)(ULONG)) ((VOID *) (ALIGN_TYPE) module_preamble -> txm_module_preamble_callback_function); +#else + module_instance -> txm_module_instance_shell_entry_function = (VOID (*)(TX_THREAD *, TXM_MODULE_INSTANCE *)) ((VOID *) module_preamble -> txm_module_preamble_shell_entry_function); + module_instance -> txm_module_instance_start_thread_entry = (VOID (*)(ULONG)) ((VOID *) module_preamble -> txm_module_preamble_start_function); + module_instance -> txm_module_instance_callback_request_thread_entry = (VOID (*)(ULONG)) ((VOID *) module_preamble -> txm_module_preamble_callback_function); +#endif + + /* Determine if there is a stop function for this module. */ + if (module_preamble -> txm_module_preamble_stop_function) + { + + /* Yes, there is a stop function, build the address. */ +#ifdef ALIGN_TYPE_DEFINED + module_instance -> txm_module_instance_stop_thread_entry = (VOID (*)(ULONG)) ((VOID *) (ALIGN_TYPE) module_preamble -> txm_module_preamble_stop_function); +#else + module_instance -> txm_module_instance_stop_thread_entry = (VOID (*)(ULONG)) ((VOID *) module_preamble -> txm_module_preamble_stop_function); +#endif + } + else + { + + /* No, there is no stop function. Just set the pointer to NULL. */ + module_instance -> txm_module_instance_stop_thread_entry = TX_NULL; + } + + /* Load the module control block with port-specific information. */ + TXM_MODULE_MANAGER_MODULE_SETUP(module_instance); + + /* Now add the module to the linked list of created modules. */ + if (_txm_module_manger_loaded_count++ == 0) + { + + /* The loaded module list is empty. Add module to empty list. */ + _txm_module_manager_loaded_list_ptr = module_instance; + module_instance -> txm_module_instance_loaded_next = module_instance; + module_instance -> txm_module_instance_loaded_previous = module_instance; + } + else + { + + /* This list is not NULL, add to the end of the list. */ + next_module = _txm_module_manager_loaded_list_ptr; + previous_module = next_module -> txm_module_instance_loaded_previous; + + /* Place the new module in the list. */ + next_module -> txm_module_instance_loaded_previous = module_instance; + previous_module -> txm_module_instance_loaded_next = module_instance; + + /* Setup this module's created links. */ + module_instance -> txm_module_instance_loaded_previous = previous_module; + module_instance -> txm_module_instance_loaded_next = next_module; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Release the protection mutex. */ + _tx_mutex_put(&_txm_module_manager_mutex); + + /* Return success. */ + return(TX_SUCCESS); +} diff --git a/ports_module/cortex_a35/ac6/example_build/sample_threadx_module_manager/sample_threadx_module_manager.c b/ports_module/cortex_a35/ac6/example_build/sample_threadx_module_manager/sample_threadx_module_manager.c index 475aabb3..c53fec02 100644 --- a/ports_module/cortex_a35/ac6/example_build/sample_threadx_module_manager/sample_threadx_module_manager.c +++ b/ports_module/cortex_a35/ac6/example_build/sample_threadx_module_manager/sample_threadx_module_manager.c @@ -9,6 +9,8 @@ /* SPDX-License-Identifier: MIT */ /***************************************************************************/ +// Some portions generated by Copilot (Opus 5). + /* Small demonstration of the ThreadX module manager. */ #include "tx_api.h" @@ -33,6 +35,12 @@ TXM_MODULE_INSTANCE my_module; #define MODULE_CODE (0x80180000) +/* The module data is located here. This must match the RAM segment start address + defined in the module's linker script. */ + +#define MODULE_DATA_LOCATION (0x801A0000) + + /* Define the object pool area. */ UCHAR object_memory[1024 * 16]; @@ -125,7 +133,7 @@ void module_manager_entry(ULONG thread_input) txm_module_manager_object_pool_create(object_memory, sizeof(object_memory)); /* Load the module with absolute address linkage, in this example it is placed there by the multiple image download. */ - txm_module_manager_absolute_load(&my_module, "my module", (void *) MODULE_CODE); + txm_module_manager_absolute_load_extended(&my_module, "my module", (void *) MODULE_CODE, (void *) MODULE_DATA_LOCATION); /* Start the module. */ txm_module_manager_start(&my_module); @@ -146,7 +154,7 @@ void module_manager_entry(ULONG thread_input) txm_module_manager_unload(&my_module); /* Load the module again. */ - txm_module_manager_absolute_load(&my_module, "my module", (void *) MODULE_CODE); + txm_module_manager_absolute_load_extended(&my_module, "my module", (void *) MODULE_CODE, (void *) MODULE_DATA_LOCATION); /* Start the module again. */ txm_module_manager_start(&my_module); diff --git a/ports_module/cortex_a35/gnu/example_build/sample_threadx_module_manager/sample_threadx_module_manager.c b/ports_module/cortex_a35/gnu/example_build/sample_threadx_module_manager/sample_threadx_module_manager.c index 475aabb3..c53fec02 100644 --- a/ports_module/cortex_a35/gnu/example_build/sample_threadx_module_manager/sample_threadx_module_manager.c +++ b/ports_module/cortex_a35/gnu/example_build/sample_threadx_module_manager/sample_threadx_module_manager.c @@ -9,6 +9,8 @@ /* SPDX-License-Identifier: MIT */ /***************************************************************************/ +// Some portions generated by Copilot (Opus 5). + /* Small demonstration of the ThreadX module manager. */ #include "tx_api.h" @@ -33,6 +35,12 @@ TXM_MODULE_INSTANCE my_module; #define MODULE_CODE (0x80180000) +/* The module data is located here. This must match the RAM segment start address + defined in the module's linker script. */ + +#define MODULE_DATA_LOCATION (0x801A0000) + + /* Define the object pool area. */ UCHAR object_memory[1024 * 16]; @@ -125,7 +133,7 @@ void module_manager_entry(ULONG thread_input) txm_module_manager_object_pool_create(object_memory, sizeof(object_memory)); /* Load the module with absolute address linkage, in this example it is placed there by the multiple image download. */ - txm_module_manager_absolute_load(&my_module, "my module", (void *) MODULE_CODE); + txm_module_manager_absolute_load_extended(&my_module, "my module", (void *) MODULE_CODE, (void *) MODULE_DATA_LOCATION); /* Start the module. */ txm_module_manager_start(&my_module); @@ -146,7 +154,7 @@ void module_manager_entry(ULONG thread_input) txm_module_manager_unload(&my_module); /* Load the module again. */ - txm_module_manager_absolute_load(&my_module, "my module", (void *) MODULE_CODE); + txm_module_manager_absolute_load_extended(&my_module, "my module", (void *) MODULE_CODE, (void *) MODULE_DATA_LOCATION); /* Start the module again. */ txm_module_manager_start(&my_module); diff --git a/ports_module/cortex_a35_smp/ac6/example_build/sample_threadx_module_manager/sample_threadx_module_manager.c b/ports_module/cortex_a35_smp/ac6/example_build/sample_threadx_module_manager/sample_threadx_module_manager.c index 475aabb3..c53fec02 100644 --- a/ports_module/cortex_a35_smp/ac6/example_build/sample_threadx_module_manager/sample_threadx_module_manager.c +++ b/ports_module/cortex_a35_smp/ac6/example_build/sample_threadx_module_manager/sample_threadx_module_manager.c @@ -9,6 +9,8 @@ /* SPDX-License-Identifier: MIT */ /***************************************************************************/ +// Some portions generated by Copilot (Opus 5). + /* Small demonstration of the ThreadX module manager. */ #include "tx_api.h" @@ -33,6 +35,12 @@ TXM_MODULE_INSTANCE my_module; #define MODULE_CODE (0x80180000) +/* The module data is located here. This must match the RAM segment start address + defined in the module's linker script. */ + +#define MODULE_DATA_LOCATION (0x801A0000) + + /* Define the object pool area. */ UCHAR object_memory[1024 * 16]; @@ -125,7 +133,7 @@ void module_manager_entry(ULONG thread_input) txm_module_manager_object_pool_create(object_memory, sizeof(object_memory)); /* Load the module with absolute address linkage, in this example it is placed there by the multiple image download. */ - txm_module_manager_absolute_load(&my_module, "my module", (void *) MODULE_CODE); + txm_module_manager_absolute_load_extended(&my_module, "my module", (void *) MODULE_CODE, (void *) MODULE_DATA_LOCATION); /* Start the module. */ txm_module_manager_start(&my_module); @@ -146,7 +154,7 @@ void module_manager_entry(ULONG thread_input) txm_module_manager_unload(&my_module); /* Load the module again. */ - txm_module_manager_absolute_load(&my_module, "my module", (void *) MODULE_CODE); + txm_module_manager_absolute_load_extended(&my_module, "my module", (void *) MODULE_CODE, (void *) MODULE_DATA_LOCATION); /* Start the module again. */ txm_module_manager_start(&my_module); diff --git a/ports_module/cortex_a35_smp/gnu/example_build/sample_threadx_module_manager/sample_threadx_module_manager.c b/ports_module/cortex_a35_smp/gnu/example_build/sample_threadx_module_manager/sample_threadx_module_manager.c index 475aabb3..c53fec02 100644 --- a/ports_module/cortex_a35_smp/gnu/example_build/sample_threadx_module_manager/sample_threadx_module_manager.c +++ b/ports_module/cortex_a35_smp/gnu/example_build/sample_threadx_module_manager/sample_threadx_module_manager.c @@ -9,6 +9,8 @@ /* SPDX-License-Identifier: MIT */ /***************************************************************************/ +// Some portions generated by Copilot (Opus 5). + /* Small demonstration of the ThreadX module manager. */ #include "tx_api.h" @@ -33,6 +35,12 @@ TXM_MODULE_INSTANCE my_module; #define MODULE_CODE (0x80180000) +/* The module data is located here. This must match the RAM segment start address + defined in the module's linker script. */ + +#define MODULE_DATA_LOCATION (0x801A0000) + + /* Define the object pool area. */ UCHAR object_memory[1024 * 16]; @@ -125,7 +133,7 @@ void module_manager_entry(ULONG thread_input) txm_module_manager_object_pool_create(object_memory, sizeof(object_memory)); /* Load the module with absolute address linkage, in this example it is placed there by the multiple image download. */ - txm_module_manager_absolute_load(&my_module, "my module", (void *) MODULE_CODE); + txm_module_manager_absolute_load_extended(&my_module, "my module", (void *) MODULE_CODE, (void *) MODULE_DATA_LOCATION); /* Start the module. */ txm_module_manager_start(&my_module); @@ -146,7 +154,7 @@ void module_manager_entry(ULONG thread_input) txm_module_manager_unload(&my_module); /* Load the module again. */ - txm_module_manager_absolute_load(&my_module, "my module", (void *) MODULE_CODE); + txm_module_manager_absolute_load_extended(&my_module, "my module", (void *) MODULE_CODE, (void *) MODULE_DATA_LOCATION); /* Start the module again. */ txm_module_manager_start(&my_module);