summaryrefslogtreecommitdiff
path: root/common_modules/module_manager/src
diff options
context:
space:
mode:
Diffstat (limited to 'common_modules/module_manager/src')
-rw-r--r--common_modules/module_manager/src/txm_module_manager_absolute_load.c417
-rw-r--r--common_modules/module_manager/src/txm_module_manager_absolute_load_extended.c486
-rw-r--r--common_modules/module_manager/src/txm_module_manager_object_allocate.c27
-rw-r--r--common_modules/module_manager/src/txm_module_manager_object_deallocate.c108
-rw-r--r--common_modules/module_manager/src/txm_module_manager_object_pointer_get.c7
-rw-r--r--common_modules/module_manager/src/txm_module_manager_thread_create.c48
-rw-r--r--common_modules/module_manager/src/txm_module_manager_thread_reset.c16
-rw-r--r--common_modules/module_manager/src/txm_module_manager_util.c1023
8 files changed, 1737 insertions, 395 deletions
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..3fc06000 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
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -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
-
-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))
- )
- {
-
- /* 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
+UINT status;
- Start of callback thread stack
- ... [note: thread entry info is embedded near end of stack areas]
- End of callback thread stack
- Highest Address: */
+ /* 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);
- /* 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..874cd1d6
--- /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
+ **************************************************************************/
+
+// Portions of this file were generated with AI assistance.
+
+
+/**************************************************************************/
+/**************************************************************************/
+/** */
+/** 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/common_modules/module_manager/src/txm_module_manager_object_allocate.c b/common_modules/module_manager/src/txm_module_manager_object_allocate.c
index 92ae128c..8e452b44 100644
--- a/common_modules/module_manager/src/txm_module_manager_object_allocate.c
+++ b/common_modules/module_manager/src/txm_module_manager_object_allocate.c
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -23,6 +25,7 @@
#define TX_SOURCE_CODE
#include "txm_module.h"
+#include "txm_module_manager_util.h"
/**************************************************************************/
/* */
@@ -51,6 +54,11 @@
/* OUTPUT */
/* */
/* status Completion status */
+/* TXM_MODULE_MATH_OVERFLOW is */
+/* returned when object_size is so */
+/* large that adding the manager's */
+/* own object header to it would */
+/* not be representable */
/* */
/* CALLS */
/* */
@@ -67,6 +75,7 @@ UINT _txm_module_manager_object_allocate(VOID **object_ptr_ptr, ULONG object_siz
{
TXM_MODULE_ALLOCATED_OBJECT *object_ptr;
+ULONG allocation_size;
UINT return_value;
@@ -81,6 +90,18 @@ UINT return_value;
/* Initialize the return pointer to NULL. */
*((VOID **) object_ptr_ptr) = TX_NULL;
+ /* Work out how much memory the pool must supply: the size the caller asked for plus
+ the private header this function writes in front of it. The size is supplied by
+ the module, so the addition is checked. An unchecked one wraps for sizes near the
+ top of a ULONG and asks the pool for fewer bytes than the header alone occupies,
+ after which the header stores below run past the end of the allocation and into
+ the neighbouring pool block. Sizes that survive the addition but exceed the pool
+ are refused by _txe_byte_allocate, which bounds every request by the pool size.
+
+ This is done before the protection mutex is taken so that a refused request leaves
+ the object pool, the module's allocated object list and its count untouched. */
+ TXM_MODULE_MANAGER_UTIL_MATH_ADD_ULONG(object_size, (ULONG) sizeof(TXM_MODULE_ALLOCATED_OBJECT), allocation_size);
+
/* Get module manager protection mutex. */
_txe_mutex_get(&_txm_module_manager_mutex, TX_WAIT_FOREVER);
@@ -90,10 +111,10 @@ UINT return_value;
TXM_MODULE_ALLOCATED_OBJECT *next_object, *previous_object;
- /* Allocate the object requested by the module - adding an extra ULONG in order to
- store the module instance pointer. */
+ /* Allocate the object requested by the module, including the header checked above
+ that holds the owning module instance, the allocation list links and the size. */
return_value = (ULONG) _txe_byte_allocate(&_txm_module_manager_object_pool, (VOID **) &object_ptr,
- (ULONG) (object_size + sizeof(TXM_MODULE_ALLOCATED_OBJECT)), TX_NO_WAIT);
+ allocation_size, TX_NO_WAIT);
/* Determine if the request was successful. */
if (return_value == TX_SUCCESS)
diff --git a/common_modules/module_manager/src/txm_module_manager_object_deallocate.c b/common_modules/module_manager/src/txm_module_manager_object_deallocate.c
index 2efc465b..c9a9ed4f 100644
--- a/common_modules/module_manager/src/txm_module_manager_object_deallocate.c
+++ b/common_modules/module_manager/src/txm_module_manager_object_deallocate.c
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -25,6 +27,7 @@
#include "tx_api.h"
#include "tx_thread.h"
#include "txm_module.h"
+#include "txm_module_manager_util.h"
/**************************************************************************/
/* */
@@ -38,7 +41,29 @@
/* */
/* DESCRIPTION */
/* */
-/* This function deallocates a previously allocated object. */
+/* DEPRECATED. This function is called internally by the Module */
+/* Manager dispatch layer after a successful tx_*_delete() call from */
+/* a module. It must not be called directly by module or application */
+/* code. */
+/* */
+/* Module authors: remove any explicit call to */
+/* txm_module_object_deallocate(). Calling the appropriate */
+/* tx_*_delete() service is sufficient; pool deallocation is handled */
+/* automatically by the dispatch layer. */
+/* */
+/* Only memory the calling module allocated from the object pool is */
+/* released, and the allocation is identified by searching the */
+/* module's own allocation list rather than by reading a private */
+/* header from in front of the address the caller supplied. An */
+/* address that names none of this module's allocations returns */
+/* TX_PTR_ERROR and is not dereferenced. */
+/* Memory holding a live kernel object is not given back. Such a */
+/* request returns TX_DELETE_ERROR and changes nothing: the object */
+/* stays created, the allocation stays on the module's allocation */
+/* list, and the memory stays owned by the module. Storage that was */
+/* allocated but never made into an object is still released, so a */
+/* module can still clean up after a create that failed or was */
+/* abandoned. */
/* */
/* INPUT */
/* */
@@ -52,6 +77,9 @@
/* */
/* _txe_mutex_get Get module instance mutex */
/* _txe_mutex_put Release module instance mutex */
+/* _txm_module_manager_allocated_object_find */
+/* Find the module's allocation */
+/* _txm_module_manager_live_object_check Check for a live object */
/* _txe_byte_release Release object back to pool */
/* */
/* */
@@ -78,18 +106,65 @@ UINT return_value;
/* Pickup module instance pointer. */
module_instance = _tx_thread_current_ptr -> tx_thread_module_instance_ptr;
- /* Setup the memory pointer. */
- module_allocated_object_ptr = (TXM_MODULE_ALLOCATED_OBJECT *) object_ptr;
+ /* Find the allocation this address names.
+
+ The private header in front of an allocation is the manager's own
+ record of who the memory belongs to, but it is only a header when the
+ address is one the manager gave out. Reaching it by subtraction from
+ whatever address the caller supplied assumes the answer: for an object
+ the application allocated statically, or for any address outside the
+ object pool, the words in front of it are unrelated memory, and this
+ read them in privileged mode before deciding they were not a header.
+ Every delete dispatcher reaches this function with the address the
+ module named, so an object the module does not own arrived here as a
+ matter of course rather than exceptionally.
- /* Position the object pointer backwards to position back to the module manager information. */
- previous_object = module_allocated_object_ptr--;
+ Searching the module's own allocation list answers the same question
+ without that assumption. The address is compared against the
+ allocations the manager made for this module and is never
+ dereferenced, so an address that names none of them -- an object the
+ application owns, an object another module owns, or an address nowhere
+ near the object pool -- is refused without a privileged read. The
+ search also establishes what the header read could not: that the
+ address is the exact start of an allocation rather than somewhere
+ inside one. */
+ module_allocated_object_ptr = _txm_module_manager_allocated_object_find(module_instance, (ALIGN_TYPE) object_ptr, TX_NULL);
/* Make sure the object is valid. */
- if ((module_allocated_object_ptr == TX_NULL) || (module_allocated_object_ptr -> txm_module_allocated_object_module_instance != module_instance) || (module_instance -> txm_module_instance_object_list_count == 0))
+ if (module_allocated_object_ptr == TX_NULL)
{
/* Set return value to invalid pointer. */
return_value = TX_PTR_ERROR;
}
+
+ /* Determine if a live kernel object is in this memory.
+
+ Releasing the memory of a created object leaves the kernel holding the
+ only references to it. The object stays on the created list for its
+ type, a thread stays on the ready or suspension list it was on and stays
+ schedulable, and an active timer stays on the timer list. None of those
+ consult a control block ID, so nothing about the freed memory stops the
+ kernel using it: a created list walk reads a name pointer out of it, a
+ create or delete of another object of the same type writes through the
+ links in it, the scheduler restores a context from the stack pointer in
+ it, and timer expiration calls the function pointer in it. The byte pool
+ is meanwhile free to hand those bytes to the next allocation, so what the
+ kernel goes on reading as a control block is whatever the next owner of
+ the memory puts there.
+
+ This is asked before the allocation is unlinked, so a refusal leaves the
+ allocation list, the object and the memory exactly as they were. What is
+ refused is releasing the memory of an object that is still created; an
+ allocation that was never made into an object, or one whose object has
+ been deleted, is released as before, which is what keeps cleanup after a
+ failed or abandoned create working and what makes the release the delete
+ dispatchers perform after a successful delete go through. */
+ else if (_txm_module_manager_live_object_check((ALIGN_TYPE) object_ptr) == TX_TRUE)
+ {
+
+ /* Set return value to indicate the object must be deleted first. */
+ return_value = TX_DELETE_ERROR;
+ }
else
{
@@ -115,6 +190,27 @@ UINT return_value;
}
}
+ /* Clear the first word of the object being given back, which for every kernel
+ object is its control block ID.
+
+ Object authentication reads that ID to establish the type of an object and
+ that it is still created, having first established that the address is the
+ exact start of an allocation. The kernel clears the ID when it deletes an
+ object, so the ordinary sequence of delete and then deallocate has already
+ cleared it. What has not is a deallocation of an object that was never
+ deleted: the memory returns to the pool still carrying a valid ID, and the
+ next allocation to be placed there is a raw allocation that presents one.
+ Clearing it here means the manager stops vouching for a control block at
+ the moment it stops owning the memory, whatever order the module chose.
+
+ An allocation too small to hold an ID cannot be presenting one, and is
+ left alone rather than written past its end. */
+ if (module_allocated_object_ptr -> txm_module_object_size >= ((ULONG) sizeof(ULONG)))
+ {
+
+ *((ULONG *) object_ptr) = TX_CLEAR_ID;
+ }
+
/* Release the object memory. */
return_value = (ULONG) _txe_byte_release((VOID *) module_allocated_object_ptr);
}
diff --git a/common_modules/module_manager/src/txm_module_manager_object_pointer_get.c b/common_modules/module_manager/src/txm_module_manager_object_pointer_get.c
index 84cf6c96..8b24558b 100644
--- a/common_modules/module_manager/src/txm_module_manager_object_pointer_get.c
+++ b/common_modules/module_manager/src/txm_module_manager_object_pointer_get.c
@@ -37,9 +37,10 @@
/* */
/* DESCRIPTION */
/* */
-/* This function is deprecated and calls the secure version of this */
-/* function (_txm_module_manager_object_pointer_get_extended) with the */
-/* maximum possible name length since none was passed. */
+/* DEPRECATED. Use _txm_module_manager_object_pointer_get_extended() */
+/* instead, passing the actual name-buffer length. This wrapper */
+/* passes UINT_MAX as the length, which can cause the name-comparison */
+/* loop to read past the end of a short buffer (undefined behaviour). */
/* */
/* INPUT */
/* */
diff --git a/common_modules/module_manager/src/txm_module_manager_thread_create.c b/common_modules/module_manager/src/txm_module_manager_thread_create.c
index c14d8e4e..51b85e1b 100644
--- a/common_modules/module_manager/src/txm_module_manager_thread_create.c
+++ b/common_modules/module_manager/src/txm_module_manager_thread_create.c
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -82,7 +84,7 @@
/* _txm_module_manager_kernel_dispatch Kernel dispatch function */
/* */
/**************************************************************************/
-UINT _txm_module_manager_thread_create(TX_THREAD *thread_ptr, CHAR *name_ptr,
+UINT _txm_module_manager_thread_create(TX_THREAD *thread_ptr, TX_NAME_CONST CHAR *name_ptr,
VOID (*shell_function)(TX_THREAD *, TXM_MODULE_INSTANCE *),
VOID (*entry_function)(ULONG id), ULONG entry_input,
VOID *stack_start, ULONG stack_size, UINT priority, UINT preempt_threshold,
@@ -104,6 +106,9 @@ UCHAR *temp_ptr;
ALIGN_TYPE new_stack_start;
ALIGN_TYPE updated_stack_start;
#endif
+#if defined(TX_ENABLE_RANDOM_NUMBER_STACK_FILLING) && defined(TX_ENABLE_STACK_CHECKING) && !defined(TX_DISABLE_STACK_FILLING)
+ULONG stack_fill_value;
+#endif
TXM_MODULE_THREAD_ENTRY_INFO *thread_entry_info;
VOID *stack_end;
ULONG i;
@@ -261,13 +266,18 @@ ULONG i;
#if defined(TX_ENABLE_RANDOM_NUMBER_STACK_FILLING) && defined(TX_ENABLE_STACK_CHECKING)
/* Initialize the stack fill value to a 8-bit random value. */
- thread_ptr -> tx_thread_stack_fill_value = ((ULONG) TX_RAND()) & 0xFFUL;
+ stack_fill_value = ((ULONG) TX_RAND()) & 0xFFUL;
/* Duplicate the random value in each of the 4 bytes of the stack fill value. */
- thread_ptr -> tx_thread_stack_fill_value = thread_ptr -> tx_thread_stack_fill_value |
- (thread_ptr -> tx_thread_stack_fill_value << 8) |
- (thread_ptr -> tx_thread_stack_fill_value << 16) |
- (thread_ptr -> tx_thread_stack_fill_value << 24);
+ stack_fill_value = stack_fill_value |
+ (stack_fill_value << 8) |
+ (stack_fill_value << 16) |
+ (stack_fill_value << 24);
+
+ /* Store the fill value in the control block so that the stack fill below picks it up
+ through the TX_STACK_FILL macro. The control block is cleared further down in this
+ function, so the value is stored again once that has been done. */
+ thread_ptr -> tx_thread_stack_fill_value = stack_fill_value;
#endif
/* Set the thread stack to a pattern prior to creating the initial
@@ -284,7 +294,7 @@ ULONG i;
stack_size = ((stack_size/(sizeof(ULONG))) * (sizeof(ULONG))) - (sizeof(ULONG));
/* Ensure the starting stack address is evenly aligned. */
- new_stack_start = TX_POINTER_TO_ALIGN_TYPE_CONVERT(stack_start);
+ new_stack_start = (ALIGN_TYPE) ((VOID *) stack_start);
updated_stack_start = ((((ULONG) new_stack_start) + ((sizeof(ULONG)) - ((ULONG) 1)) ) & (~((sizeof(ULONG)) - ((ULONG) 1))));
/* Determine if the starting stack address is different. */
@@ -296,7 +306,7 @@ ULONG i;
}
/* Update the starting stack pointer. */
- stack_start = TX_ALIGN_TYPE_TO_POINTER_CONVERT(updated_stack_start);
+ stack_start = (VOID *) ((ALIGN_TYPE) updated_stack_start);
#endif
/* Allocate the thread entry information at the top of thread's stack - Leaving one
@@ -309,6 +319,21 @@ ULONG i;
/* Initialize thread control block to all zeros. */
TX_MEMSET(thread_ptr, 0, sizeof(TX_THREAD));
+#if defined(TX_ENABLE_RANDOM_NUMBER_STACK_FILLING) && defined(TX_ENABLE_STACK_CHECKING) && !defined(TX_DISABLE_STACK_FILLING)
+
+ /* Clearing the control block reset the stack fill value, so store the value that was
+ actually used to fill the stack again. Otherwise the stack checking and stack analyze
+ routines would look for a pattern that is not the one present in the stack. */
+ thread_ptr -> tx_thread_stack_fill_value = stack_fill_value;
+#endif
+
+ /* Note that TX_ENABLE_STACK_CHECKING is not supported for module threads. A user mode
+ module thread owns two stacks and the scheduler swaps tx_thread_stack_start,
+ tx_thread_stack_end and tx_thread_stack_size over to the kernel stack whenever the
+ thread enters the module manager. Neither tx_thread_stack_highest_ptr nor the guard
+ pattern beyond the end of the stack is maintained across that switch, so
+ TX_THREAD_STACK_CHECK may report spurious stack errors for module threads. */
+
/* If the thread runs on user mode, allocate the kernel stack for syscall. */
if((module_instance -> txm_module_instance_property_flags) & TXM_MODULE_USER_MODE)
{
@@ -331,8 +356,10 @@ ULONG i;
/* Align kernel stack pointer. */
thread_ptr -> tx_thread_module_kernel_stack_end = (VOID *) (((ALIGN_TYPE)(thread_ptr -> tx_thread_module_kernel_stack_start) + TXM_MODULE_KERNEL_STACK_SIZE) & ~0x07);
- /* Set kernel stack size. */
- thread_ptr -> tx_thread_module_kernel_stack_size = TXM_MODULE_KERNEL_STACK_SIZE;
+ /* Set kernel stack size. Aligning the end of the kernel stack downwards can consume
+ up to seven bytes of the block returned by the allocator, so the usable size must be
+ derived from the aligned range instead of from TXM_MODULE_KERNEL_STACK_SIZE. */
+ thread_ptr -> tx_thread_module_kernel_stack_size = (ULONG) ((ALIGN_TYPE) (thread_ptr -> tx_thread_module_kernel_stack_end) - (ALIGN_TYPE) (thread_ptr -> tx_thread_module_kernel_stack_start));
}
#if TXM_MODULE_MEMORY_PROTECTION
@@ -741,4 +768,3 @@ ULONG i;
/* Return success. */
return(TX_SUCCESS);
}
-
diff --git a/common_modules/module_manager/src/txm_module_manager_thread_reset.c b/common_modules/module_manager/src/txm_module_manager_thread_reset.c
index 75dd4a49..334070bf 100644
--- a/common_modules/module_manager/src/txm_module_manager_thread_reset.c
+++ b/common_modules/module_manager/src/txm_module_manager_thread_reset.c
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -106,6 +108,20 @@ TXM_MODULE_THREAD_ENTRY_INFO *thread_entry_info;
status = TX_NOT_DONE;
}
}
+
+ /* Resetting a thread means rebuilding its stack around a module's shell entry
+ function, so the thread has to be one a module manager created. A thread the
+ application created carries no module instance, and the fields this function
+ goes on to read from it -- the shell entry function it builds the new stack
+ frame around -- would be read through a null pointer in privileged mode. A
+ module can name such a thread: any thread the system created can be found by
+ name, and one that has run to completion satisfies the state test above. */
+ if (thread_ptr -> tx_thread_module_instance_ptr == TX_NULL)
+ {
+
+ /* Not a module thread, so there is nothing here to reset. */
+ status = TX_NOT_DONE;
+ }
}
/* Is the request valid? */
diff --git a/common_modules/module_manager/src/txm_module_manager_util.c b/common_modules/module_manager/src/txm_module_manager_util.c
index 78031b5f..f3c8beef 100644
--- a/common_modules/module_manager/src/txm_module_manager_util.c
+++ b/common_modules/module_manager/src/txm_module_manager_util.c
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -25,6 +27,15 @@
#define TX_SOURCE_CODE
+#include "tx_api.h"
+#include "tx_thread.h"
+#include "tx_timer.h"
+#include "tx_queue.h"
+#include "tx_event_flags.h"
+#include "tx_semaphore.h"
+#include "tx_mutex.h"
+#include "tx_block_pool.h"
+#include "tx_byte_pool.h"
#include "txm_module.h"
#include "txm_module_manager_util.h"
@@ -270,7 +281,7 @@ UINT return_value;
/* 09-30-2020 Scott Larson Initial Version 6.1 */
/* */
/**************************************************************************/
-UINT _txm_module_manager_object_name_compare(CHAR *search_name, UINT search_name_length, CHAR *object_name)
+UINT _txm_module_manager_object_name_compare(CHAR *search_name, UINT search_name_length, TX_NAME_CONST CHAR *object_name)
{
CHAR search_name_char;
@@ -461,11 +472,525 @@ UINT _txm_module_manager_param_check_object_for_use(TXM_MODULE_INSTANCE *modu
return(TX_FALSE);
}
- /* Determine if the object pointer is inside the module object pool. */
+ /* Determine if the object is outside the calling module. */
if (TXM_MODULE_MANAGER_ENSURE_OUTSIDE_MODULE(module_instance, object_ptr, object_size) == TX_FALSE)
{
- /* Object pointer is not inside the object pool, which is invalid. */
+ /* Object pointer is not outside the module, which is invalid. */
+ return(TX_FALSE);
+ }
+
+ /* Being outside the module does not make an address an object. The manager's
+ object pool is outside every module, so an address shifted into the interior of
+ one of this module's own privileged allocations satisfies the test above while
+ denoting no object at all, and the bytes the shifted address then presents as a
+ control block are bytes the module chose through ordinary create and set
+ services. An address in the object pool is therefore only usable if it is the
+ exact address the manager handed out for an allocation of this size.
+
+ This function is given a size rather than a type, so it can go no further than
+ that: it cannot establish which type of object it is, and it cannot authenticate
+ an application-owned object outside the pool. Dispatchers in this repository use
+ _txm_module_manager_param_check_typed_object_for_use, which does both. */
+ if ((_txm_module_manager_object_pool_created == TX_TRUE) &&
+ (object_ptr >= (ALIGN_TYPE) _txm_module_manager_object_pool.tx_byte_pool_start) &&
+ (object_ptr < (ALIGN_TYPE) (_txm_module_manager_object_pool.tx_byte_pool_start + _txm_module_manager_object_pool.tx_byte_pool_size)))
+ {
+
+ if (_txm_module_manager_allocated_object_check(module_instance, object_ptr, object_size) == TX_FALSE)
+ {
+
+ /* An address in the object pool that is not the exact start of one of this
+ module's allocations, which is invalid. */
+ return(TX_FALSE);
+ }
+ }
+
+ /* Define application-specific object memory check. */
+#ifdef TXM_MODULE_MANGER_APPLICATION_VALID_OBJECT_MEMORY_CHECK
+
+ /* Bring in the application-spefic objeft memory check, defined by the user. */
+ TXM_MODULE_MANGER_APPLICATION_VALID_OBJECT_MEMORY_CHECK
+#endif /* TXM_MODULE_MANGER_APPLICATION_VALID_OBJECT_MEMORY_ENABLE */
+
+ /* Everything is okay with the object, return TX_TRUE. */
+ return(TX_TRUE);
+}
+
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _txm_module_manager_object_type_size_get PORTABLE C */
+/* 6.4.3 */
+/* AUTHOR */
+/* */
+/* Eclipse ThreadX contributors */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function returns the size of the control block belonging to a */
+/* module object type. It is the size a service of that type is */
+/* entitled to dereference, and the size the manager recorded when it */
+/* allocated object memory for that type. */
+/* */
+/* INPUT */
+/* */
+/* object_type Module object type */
+/* object_size Destination for the control block */
+/* size of that type */
+/* */
+/* OUTPUT */
+/* */
+/* TX_TRUE Known object type */
+/* TX_FALSE Unknown object type */
+/* */
+/* CALLS */
+/* */
+/* None */
+/* */
+/* CALLED BY */
+/* */
+/* _txm_module_manager_param_check_typed_object_for_use */
+/* Module object authentication */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* xx-xx-2026 Eclipse ThreadX Initial Version 6.4.3 */
+/* contributors */
+/* */
+/**************************************************************************/
+UINT _txm_module_manager_object_type_size_get(UINT object_type, ULONG *object_size)
+{
+
+UINT status;
+
+
+ /* Assume the type is one this manager knows. */
+ status = TX_TRUE;
+
+ switch (object_type)
+ {
+
+ case TXM_BLOCK_POOL_OBJECT:
+
+ *object_size = (ULONG) sizeof(TX_BLOCK_POOL);
+ break;
+
+ case TXM_BYTE_POOL_OBJECT:
+
+ *object_size = (ULONG) sizeof(TX_BYTE_POOL);
+ break;
+
+ case TXM_EVENT_FLAGS_OBJECT:
+
+ *object_size = (ULONG) sizeof(TX_EVENT_FLAGS_GROUP);
+ break;
+
+ case TXM_MUTEX_OBJECT:
+
+ *object_size = (ULONG) sizeof(TX_MUTEX);
+ break;
+
+ case TXM_QUEUE_OBJECT:
+
+ *object_size = (ULONG) sizeof(TX_QUEUE);
+ break;
+
+ case TXM_SEMAPHORE_OBJECT:
+
+ *object_size = (ULONG) sizeof(TX_SEMAPHORE);
+ break;
+
+ case TXM_THREAD_OBJECT:
+
+ *object_size = (ULONG) sizeof(TX_THREAD);
+ break;
+
+ case TXM_TIMER_OBJECT:
+
+ *object_size = (ULONG) sizeof(TX_TIMER);
+ break;
+
+ default:
+
+ /* Not a type the manager authenticates. Report it rather than guessing a
+ size, so that a caller cannot be given a range to validate that has no
+ relationship to the object the service will dereference. */
+ *object_size = ((ULONG) 0);
+ status = TX_FALSE;
+ break;
+ }
+
+ return(status);
+}
+
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _txm_module_manager_allocated_object_find PORTABLE C */
+/* 6.4.3 */
+/* AUTHOR */
+/* */
+/* Eclipse ThreadX contributors */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function returns the manager's private header for the object */
+/* allocation an address names, or TX_NULL when the address names */
+/* none of the specified module's allocations. The size the */
+/* allocation was made for is reported to callers that ask for it. */
+/* */
+/* The allocation list is the manager's own record, built as it hands */
+/* object memory out, and it is searched rather than reached through */
+/* a header taken from in front of the caller's address. That order */
+/* is what makes the answer both correct and safe. */
+/* */
+/* Correct, because the address immediately after a header is the */
+/* only address in an allocation that the manager ever gave out, so */
+/* an address chosen inside an allocation is distinguishable from the */
+/* start of one. Reading a header cannot make that distinction: the */
+/* bytes in front of an interior address are part of the object, and */
+/* a module places values there through ordinary services. */
+/* */
+/* Safe, because the caller's address is only ever compared, never */
+/* dereferenced. An address that belongs to no allocation of this */
+/* module -- an object the application owns, an object another module */
+/* owns, or an address nowhere near the object pool -- is rejected */
+/* without a privileged read of the words in front of it. */
+/* */
+/* INPUT */
+/* */
+/* module_instance Requesting module instance pointer*/
+/* object_ptr Address of object memory area */
+/* object_size_ptr Address to return the size the */
+/* allocation was made for, or */
+/* TX_NULL to not return it */
+/* */
+/* OUTPUT */
+/* */
+/* allocation The allocation's private header, */
+/* or TX_NULL when the address */
+/* names none of this module's */
+/* */
+/* CALLS */
+/* */
+/* None */
+/* */
+/* CALLED BY */
+/* */
+/* _txm_module_manager_allocated_object_check */
+/* Module object ownership check */
+/* _txm_module_manager_object_deallocate Module object deallocation */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* xx-xx-2026 Eclipse ThreadX Initial Version 6.4.3 */
+/* contributors */
+/* */
+/**************************************************************************/
+TXM_MODULE_ALLOCATED_OBJECT *_txm_module_manager_allocated_object_find(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE object_ptr, ULONG *object_size_ptr)
+{
+
+TX_INTERRUPT_SAVE_AREA
+
+TXM_MODULE_ALLOCATED_OBJECT *allocated_object_ptr;
+TXM_MODULE_ALLOCATED_OBJECT *found_object_ptr;
+ULONG objects_examined;
+
+
+ /* Assume the address names none of this module's allocations. */
+ found_object_ptr = TX_NULL;
+
+ /* Determine if there is a module whose allocations can be searched. A request
+ that does not come from a module owns no allocation. */
+ if (module_instance == TX_NULL)
+ {
+
+ /* Nothing to search, and nothing to report. */
+ return(TX_NULL);
+ }
+
+ /* Disable interrupts. The allocation list is maintained by threads holding the
+ manager protection mutex, so a scan that runs to completion with interrupts
+ disabled cannot observe it being changed, and unlike taking the mutex it adds
+ no blocking point and no priority inversion to a kernel request. */
+ TX_DISABLE
+
+ allocated_object_ptr = module_instance -> txm_module_instance_object_list_head;
+ objects_examined = ((ULONG) 0);
+
+ /* Loop through the objects allocated to this module. The loop is bounded by the
+ count the manager maintains alongside the list, so the cost of one search is
+ bounded by the number of objects this module has allocated, and a list whose
+ links have been damaged cannot make the scan run on. */
+ while ((objects_examined < module_instance -> txm_module_instance_object_list_count) &&
+ (allocated_object_ptr != TX_NULL))
+ {
+
+ /* The address the module was given is the one immediately after the private
+ header, so that is the only address in this allocation that names it. */
+ if (((ALIGN_TYPE) (allocated_object_ptr + 1)) == object_ptr)
+ {
+
+ /* Found it. An address matches at most one allocation, so there is
+ nothing further to look at. */
+ found_object_ptr = allocated_object_ptr;
+
+ /* Report the size this allocation was made for, if the caller asked for
+ it. It is read here, inside the scan, so that the answer cannot be
+ taken from a header that stopped being one after the search. */
+ if (object_size_ptr != TX_NULL)
+ {
+
+ *object_size_ptr = allocated_object_ptr -> txm_module_object_size;
+ }
+
+ break;
+ }
+
+ /* Move to the next allocated object. */
+ objects_examined++;
+ allocated_object_ptr = allocated_object_ptr -> txm_module_allocated_object_next;
+ }
+
+ /* Restore interrupts. */
+ TX_RESTORE
+
+ return(found_object_ptr);
+}
+
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _txm_module_manager_allocated_object_check PORTABLE C */
+/* 6.4.3 */
+/* AUTHOR */
+/* */
+/* Eclipse ThreadX contributors */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function determines whether an address is the exact address */
+/* the manager handed the specified module for one of its object */
+/* allocations, and whether that allocation is the size the caller */
+/* expects. */
+/* */
+/* This is the question of ownership, and it is deliberately a */
+/* separate question from whether an object is there at all. A */
+/* module may hold, and legitimately use, a pointer to an object it */
+/* does not own: the manager hands application-owned objects to */
+/* modules by name through its object lookup service, and sharing an */
+/* object is what that service is for. Destroying one is not sharing */
+/* it, so the delete services ask this question in addition to the */
+/* ones that establish that the address denotes a usable object. */
+/* */
+/* INPUT */
+/* */
+/* module_instance Requesting module instance pointer*/
+/* object_ptr Address of object memory area */
+/* object_size Expected size of the allocation */
+/* */
+/* OUTPUT */
+/* */
+/* TX_TRUE An exact allocation of that size */
+/* TX_FALSE Anything else */
+/* */
+/* CALLS */
+/* */
+/* _txm_module_manager_allocated_object_find */
+/* Find the module's allocation */
+/* */
+/* CALLED BY */
+/* */
+/* txm_module_manager_* Module manager functions */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* xx-xx-2026 Eclipse ThreadX Initial Version 6.4.3 */
+/* contributors */
+/* */
+/**************************************************************************/
+UINT _txm_module_manager_allocated_object_check(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE object_ptr, ULONG object_size)
+{
+
+ULONG allocated_size;
+UINT status;
+
+
+ /* Assume the address is not one of this module's allocations. */
+ status = TX_FALSE;
+
+ /* Initialize the size, so that nothing is read if no allocation is found. */
+ allocated_size = ((ULONG) 0);
+
+ /* Determine if the address is the exact start of one of this module's
+ allocations. */
+ if (_txm_module_manager_allocated_object_find(module_instance, object_ptr, &allocated_size) != TX_NULL)
+ {
+
+ /* Is the allocation the size the caller expects? An allocation made for a
+ smaller object does not become a larger one because a service was asked
+ to treat it as one. */
+ if (allocated_size == object_size)
+ {
+
+ status = TX_TRUE;
+ }
+ }
+
+ return(status);
+}
+
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _txm_module_manager_param_check_typed_object_for_use */
+/* PORTABLE C */
+/* 6.4.3 */
+/* AUTHOR */
+/* */
+/* Eclipse ThreadX contributors */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function authenticates a kernel object a module has named, */
+/* before a privileged service is allowed to dereference it. It */
+/* establishes that the address is the exact address of a live kernel */
+/* object of the type the service expects. */
+/* */
+/* The address is accepted only if it is on the kernel's created list */
+/* for that type. That list is the record the create and delete */
+/* services maintain, so being on it establishes at once that the */
+/* address is an object start rather than an address inside an object, */
+/* that the object is of this type, and that it has not been deleted. */
+/* It is also how an object the application created and shared with a */
+/* module is authenticated, since the manager allocated no such object */
+/* and has no record of its own to consult. */
+/* */
+/* Nothing a module can influence is used to establish a type. In */
+/* particular the control block ID is not, on its own, evidence of */
+/* anything: a module can arrange for the value of an ID to appear */
+/* inside an object it legitimately owns, which is what lets a shifted */
+/* pointer pass an ID test, and distinct object types of equal size */
+/* exist, so an ID is not even a type at an address known to be an */
+/* object start. It is checked, after the created list has settled the */
+/* question, because it is the check the _txe_ services make and it is */
+/* compiled away with them under TX_DISABLE_ERROR_CHECKING. */
+/* */
+/* INPUT */
+/* */
+/* module_instance Requesting module instance pointer*/
+/* object_ptr Address of object memory area */
+/* object_type Module object type the service */
+/* expects */
+/* */
+/* OUTPUT */
+/* */
+/* TX_TRUE Authenticated object pointer */
+/* TX_FALSE Invalid object pointer */
+/* */
+/* CALLS */
+/* */
+/* _txm_module_manager_object_type_size_get */
+/* Get control block size */
+/* _txm_module_manager_created_object_type_check */
+/* Check kernel created list */
+/* _txm_module_manager_object_id_check Check control block ID */
+/* */
+/* CALLED BY */
+/* */
+/* txm_module_manager_* Module manager functions */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* xx-xx-2026 Eclipse ThreadX Initial Version 6.4.3 */
+/* contributors */
+/* */
+/**************************************************************************/
+UINT _txm_module_manager_param_check_typed_object_for_use(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE object_ptr, UINT object_type)
+{
+
+ULONG object_size;
+UINT exact_object;
+
+
+ /* Determine if the object pointer is NULL. */
+ if ((void *) object_ptr == TX_NULL)
+ {
+
+ /* Object pointer is NULL, which is invalid. */
+ return(TX_FALSE);
+ }
+
+ /* Pickup the size of the control block this type of service dereferences. */
+ if (_txm_module_manager_object_type_size_get(object_type, &object_size) == TX_FALSE)
+ {
+
+ /* Not an object type this manager authenticates, so it cannot be used. */
+ return(TX_FALSE);
+ }
+
+ /* Determine if the object is outside the calling module. A kernel object inside
+ the module's own memory is one the module can write behind the kernel's back,
+ so it is rejected here as it always has been. This also rejects a size that
+ wraps when added to the address. */
+ if (TXM_MODULE_MANAGER_ENSURE_OUTSIDE_MODULE(module_instance, object_ptr, object_size) == TX_FALSE)
+ {
+
+ /* Object pointer is not outside the module, which is invalid. */
+ return(TX_FALSE);
+ }
+
+ /* Establish that the address is the exact address of a live object of this type,
+ from the kernel's created list for the type. That list is the record the create
+ and delete services maintain, so being on it establishes at once that the
+ address is an object start, that the object is of this type, and that it has not
+ been deleted.
+
+ It is deliberately the only ground on which an address is accepted. The
+ manager's own allocation list would establish the address and the size of an
+ object a module allocated, and would do it by walking a shorter list, but it
+ records no type, and the type cannot then be taken from the control block
+ itself: distinct object types of equal size exist -- on a 32-bit target a byte
+ pool, a mutex and a timer are all the same size -- so a control block whose ID
+ has been made to read as one of them would be accepted as that type. Nothing a
+ module can influence is used to establish a type.
+
+ The address is not dereferenced to reach this decision. An address a module
+ named is not read until a kernel record says there is an object there. */
+ exact_object = _txm_module_manager_created_object_type_check(object_ptr, object_type);
+
+ if (exact_object == TX_FALSE)
+ {
+
+ /* The address is not the start of a live object of this type. */
+ return(TX_FALSE);
+ }
+
+ /* The address is a live object of the requested type. Confirm it against the
+ control block's own ID, which is the check the _txe_ services would make and
+ which is compiled away with them under TX_DISABLE_ERROR_CHECKING. */
+ if (_txm_module_manager_object_id_check(object_ptr, object_type) == TX_FALSE)
+ {
+
+ /* The created list and the control block disagree, so the object is not in a
+ state the manager is prepared to vouch for. */
return(TX_FALSE);
}
@@ -485,6 +1010,498 @@ UINT _txm_module_manager_param_check_object_for_use(TXM_MODULE_INSTANCE *modu
/* */
/* FUNCTION RELEASE */
/* */
+/* _txm_module_manager_created_object_type_check PORTABLE C */
+/* 6.4.3 */
+/* AUTHOR */
+/* */
+/* Eclipse ThreadX contributors */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function determines whether an address is the exact address */
+/* of an object on the kernel's created list for a module object type. */
+/* */
+/* The created list is the record the create and delete services */
+/* maintain, so being on it establishes at once that the address is an */
+/* object start rather than an address inside an object, that the */
+/* object is of this type, and that it has not been deleted. It is */
+/* also the only record of an object the application created and */
+/* shared with a module, since the manager allocated no such object. */
+/* */
+/* Nothing the module can influence is consulted. In particular the */
+/* control block ID is not: a module can arrange for the value of an */
+/* ID to appear inside memory it owns, and distinct object types of */
+/* equal size exist, so an ID is not evidence that an object is there */
+/* nor of what type it is. */
+/* */
+/* INPUT */
+/* */
+/* object_ptr Address of object memory area */
+/* object_type Module object type */
+/* */
+/* OUTPUT */
+/* */
+/* TX_TRUE A created object of that type */
+/* TX_FALSE Anything else */
+/* */
+/* CALLS */
+/* */
+/* None */
+/* */
+/* CALLED BY */
+/* */
+/* _txm_module_manager_live_object_check Module object liveness check */
+/* _txm_module_manager_param_check_typed_object_for_use */
+/* Module object authentication */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* xx-xx-2026 Eclipse ThreadX Initial Version 6.4.3 */
+/* contributors */
+/* */
+/**************************************************************************/
+UINT _txm_module_manager_created_object_type_check(ALIGN_TYPE object_ptr, UINT object_type)
+{
+
+TX_INTERRUPT_SAVE_AREA
+
+ULONG objects_examined;
+ULONG objects_created;
+ALIGN_TYPE candidate_ptr;
+UINT status;
+TX_BLOCK_POOL *block_pool_ptr;
+TX_BYTE_POOL *byte_pool_ptr;
+TX_EVENT_FLAGS_GROUP *event_flags_ptr;
+TX_MUTEX *mutex_ptr;
+TX_QUEUE *queue_ptr;
+TX_SEMAPHORE *semaphore_ptr;
+TX_THREAD *thread_ptr;
+TX_TIMER *timer_ptr;
+
+
+ /* Assume the address is not on the created list for this type. */
+ status = TX_FALSE;
+
+ /* Disable interrupts. The created lists are maintained with interrupts disabled,
+ so a scan that runs to completion this way sees a consistent list, and it adds
+ no blocking point to a kernel request. The cost of one check is bounded by the
+ number of objects of this type the system has created, which is the price of
+ authenticating an object the manager did not allocate; a module using its own
+ allocated objects does not reach this function. */
+ TX_DISABLE
+
+ /* Start each list from its head and pick up the count that bounds the walk, so a
+ list whose links have been damaged cannot make the scan run on. */
+ switch (object_type)
+ {
+
+ case TXM_BLOCK_POOL_OBJECT:
+
+ block_pool_ptr = _tx_block_pool_created_ptr;
+ objects_created = _tx_block_pool_created_count;
+ objects_examined = ((ULONG) 0);
+
+ while ((objects_examined < objects_created) && (block_pool_ptr != TX_NULL))
+ {
+ candidate_ptr = (ALIGN_TYPE) block_pool_ptr;
+ if (candidate_ptr == object_ptr)
+ {
+ status = TX_TRUE;
+ break;
+ }
+ objects_examined++;
+ block_pool_ptr = block_pool_ptr -> tx_block_pool_created_next;
+ }
+ break;
+
+ case TXM_BYTE_POOL_OBJECT:
+
+ byte_pool_ptr = _tx_byte_pool_created_ptr;
+ objects_created = _tx_byte_pool_created_count;
+ objects_examined = ((ULONG) 0);
+
+ while ((objects_examined < objects_created) && (byte_pool_ptr != TX_NULL))
+ {
+ candidate_ptr = (ALIGN_TYPE) byte_pool_ptr;
+ if (candidate_ptr == object_ptr)
+ {
+ status = TX_TRUE;
+ break;
+ }
+ objects_examined++;
+ byte_pool_ptr = byte_pool_ptr -> tx_byte_pool_created_next;
+ }
+ break;
+
+ case TXM_EVENT_FLAGS_OBJECT:
+
+ event_flags_ptr = _tx_event_flags_created_ptr;
+ objects_created = _tx_event_flags_created_count;
+ objects_examined = ((ULONG) 0);
+
+ while ((objects_examined < objects_created) && (event_flags_ptr != TX_NULL))
+ {
+ candidate_ptr = (ALIGN_TYPE) event_flags_ptr;
+ if (candidate_ptr == object_ptr)
+ {
+ status = TX_TRUE;
+ break;
+ }
+ objects_examined++;
+ event_flags_ptr = event_flags_ptr -> tx_event_flags_group_created_next;
+ }
+ break;
+
+ case TXM_MUTEX_OBJECT:
+
+ mutex_ptr = _tx_mutex_created_ptr;
+ objects_created = _tx_mutex_created_count;
+ objects_examined = ((ULONG) 0);
+
+ while ((objects_examined < objects_created) && (mutex_ptr != TX_NULL))
+ {
+ candidate_ptr = (ALIGN_TYPE) mutex_ptr;
+ if (candidate_ptr == object_ptr)
+ {
+ status = TX_TRUE;
+ break;
+ }
+ objects_examined++;
+ mutex_ptr = mutex_ptr -> tx_mutex_created_next;
+ }
+ break;
+
+ case TXM_QUEUE_OBJECT:
+
+ queue_ptr = _tx_queue_created_ptr;
+ objects_created = _tx_queue_created_count;
+ objects_examined = ((ULONG) 0);
+
+ while ((objects_examined < objects_created) && (queue_ptr != TX_NULL))
+ {
+ candidate_ptr = (ALIGN_TYPE) queue_ptr;
+ if (candidate_ptr == object_ptr)
+ {
+ status = TX_TRUE;
+ break;
+ }
+ objects_examined++;
+ queue_ptr = queue_ptr -> tx_queue_created_next;
+ }
+ break;
+
+ case TXM_SEMAPHORE_OBJECT:
+
+ semaphore_ptr = _tx_semaphore_created_ptr;
+ objects_created = _tx_semaphore_created_count;
+ objects_examined = ((ULONG) 0);
+
+ while ((objects_examined < objects_created) && (semaphore_ptr != TX_NULL))
+ {
+ candidate_ptr = (ALIGN_TYPE) semaphore_ptr;
+ if (candidate_ptr == object_ptr)
+ {
+ status = TX_TRUE;
+ break;
+ }
+ objects_examined++;
+ semaphore_ptr = semaphore_ptr -> tx_semaphore_created_next;
+ }
+ break;
+
+ case TXM_THREAD_OBJECT:
+
+ thread_ptr = _tx_thread_created_ptr;
+ objects_created = _tx_thread_created_count;
+ objects_examined = ((ULONG) 0);
+
+ while ((objects_examined < objects_created) && (thread_ptr != TX_NULL))
+ {
+ candidate_ptr = (ALIGN_TYPE) thread_ptr;
+ if (candidate_ptr == object_ptr)
+ {
+ status = TX_TRUE;
+ break;
+ }
+ objects_examined++;
+ thread_ptr = thread_ptr -> tx_thread_created_next;
+ }
+ break;
+
+ case TXM_TIMER_OBJECT:
+
+ timer_ptr = _tx_timer_created_ptr;
+ objects_created = _tx_timer_created_count;
+ objects_examined = ((ULONG) 0);
+
+ while ((objects_examined < objects_created) && (timer_ptr != TX_NULL))
+ {
+ candidate_ptr = (ALIGN_TYPE) timer_ptr;
+ if (candidate_ptr == object_ptr)
+ {
+ status = TX_TRUE;
+ break;
+ }
+ objects_examined++;
+ timer_ptr = timer_ptr -> tx_timer_created_next;
+ }
+ break;
+
+ default:
+
+ /* Not a type the manager authenticates. */
+ break;
+ }
+
+ /* Restore interrupts. */
+ TX_RESTORE
+
+ return(status);
+}
+
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _txm_module_manager_object_id_check PORTABLE C */
+/* 6.4.3 */
+/* AUTHOR */
+/* */
+/* Eclipse ThreadX contributors */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function determines whether the control block at an object */
+/* start carries the ID of a module object type. The kernel writes */
+/* that ID when it creates an object and clears it when it deletes */
+/* one, so at an address already established to be an object start the */
+/* ID reports both the type and whether the object is still created. */
+/* */
+/* This check must not be used on its own to decide that an address is */
+/* an object. A module can place the value of an ID inside an object */
+/* it legitimately owns, so an ID found at an address the manager has */
+/* not otherwise authenticated proves nothing. */
+/* */
+/* The check matters most where the error checking layer is absent: */
+/* with TX_DISABLE_ERROR_CHECKING the _txe_ services that would */
+/* otherwise test the ID are compiled away, and this is then the only */
+/* ID test between a module and a privileged dereference. */
+/* */
+/* INPUT */
+/* */
+/* object_ptr Address of an object start */
+/* object_type Module object type */
+/* */
+/* OUTPUT */
+/* */
+/* TX_TRUE A created object of that type */
+/* TX_FALSE Anything else */
+/* */
+/* CALLS */
+/* */
+/* None */
+/* */
+/* CALLED BY */
+/* */
+/* _txm_module_manager_param_check_typed_object_for_use */
+/* Module object authentication */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* xx-xx-2026 Eclipse ThreadX Initial Version 6.4.3 */
+/* contributors */
+/* */
+/**************************************************************************/
+UINT _txm_module_manager_object_id_check(ALIGN_TYPE object_ptr, UINT object_type)
+{
+
+TX_INTERRUPT_SAVE_AREA
+
+ULONG object_id;
+ULONG expected_id;
+UINT status;
+
+
+ /* Read the ID through a pointer to the type the caller named, so that the field
+ read is the one that type declares rather than an assumed offset. */
+ TX_DISABLE
+
+ switch (object_type)
+ {
+
+ case TXM_BLOCK_POOL_OBJECT:
+
+ object_id = ((TX_BLOCK_POOL *) object_ptr) -> tx_block_pool_id;
+ expected_id = TX_BLOCK_POOL_ID;
+ break;
+
+ case TXM_BYTE_POOL_OBJECT:
+
+ object_id = ((TX_BYTE_POOL *) object_ptr) -> tx_byte_pool_id;
+ expected_id = TX_BYTE_POOL_ID;
+ break;
+
+ case TXM_EVENT_FLAGS_OBJECT:
+
+ object_id = ((TX_EVENT_FLAGS_GROUP *) object_ptr) -> tx_event_flags_group_id;
+ expected_id = TX_EVENT_FLAGS_ID;
+ break;
+
+ case TXM_MUTEX_OBJECT:
+
+ object_id = ((TX_MUTEX *) object_ptr) -> tx_mutex_id;
+ expected_id = TX_MUTEX_ID;
+ break;
+
+ case TXM_QUEUE_OBJECT:
+
+ object_id = ((TX_QUEUE *) object_ptr) -> tx_queue_id;
+ expected_id = TX_QUEUE_ID;
+ break;
+
+ case TXM_SEMAPHORE_OBJECT:
+
+ object_id = ((TX_SEMAPHORE *) object_ptr) -> tx_semaphore_id;
+ expected_id = TX_SEMAPHORE_ID;
+ break;
+
+ case TXM_THREAD_OBJECT:
+
+ object_id = ((TX_THREAD *) object_ptr) -> tx_thread_id;
+ expected_id = TX_THREAD_ID;
+ break;
+
+ case TXM_TIMER_OBJECT:
+
+ object_id = ((TX_TIMER *) object_ptr) -> tx_timer_id;
+ expected_id = TX_TIMER_ID;
+ break;
+
+ default:
+
+ /* Not a type the manager authenticates. Choose values that cannot match. */
+ object_id = TX_CLEAR_ID;
+ expected_id = ~((ULONG) TX_CLEAR_ID);
+ break;
+ }
+
+ /* Restore interrupts. */
+ TX_RESTORE
+
+ if (object_id == expected_id)
+ {
+
+ status = TX_TRUE;
+ }
+ else
+ {
+
+ status = TX_FALSE;
+ }
+
+ return(status);
+}
+
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _txm_module_manager_live_object_check PORTABLE C */
+/* 6.4.3 */
+/* AUTHOR */
+/* */
+/* Eclipse ThreadX contributors */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function determines whether an address is the exact address */
+/* of a live kernel object of any type the Module Manager knows. */
+/* */
+/* It answers the question object deallocation has to ask before it */
+/* gives memory back: is the kernel still going to use these bytes as */
+/* a control block. Deallocation is told an address and nothing else, */
+/* so unlike the checks a typed service makes it cannot be given the */
+/* type to look for, and every type has to be looked for in turn. */
+/* */
+/* The eight created lists are searched whatever the size of the */
+/* allocation at the address. Skipping a type whose control block is */
+/* larger than the allocation would be sound only if every object had */
+/* been created through a size-checked path, and a module running */
+/* without memory protection creates objects without one. */
+/* */
+/* Each list is searched in its own interrupts-disabled window rather */
+/* than all of them in one, so the longest window is bounded by the */
+/* number of objects of a single type. The whole search costs one pass */
+/* over the objects the system has created, and is paid once per */
+/* object deallocation. */
+/* */
+/* INPUT */
+/* */
+/* object_ptr Address of object memory area */
+/* */
+/* OUTPUT */
+/* */
+/* TX_TRUE A live kernel object is there */
+/* TX_FALSE Anything else */
+/* */
+/* CALLS */
+/* */
+/* _txm_module_manager_created_object_type_check */
+/* Check one kernel created list */
+/* */
+/* CALLED BY */
+/* */
+/* _txm_module_manager_object_deallocate Deallocate object memory */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* xx-xx-2026 Eclipse ThreadX Initial Version 6.4.3 */
+/* contributors */
+/* */
+/**************************************************************************/
+UINT _txm_module_manager_live_object_check(ALIGN_TYPE object_ptr)
+{
+
+UINT object_type;
+UINT status;
+
+
+ /* Assume no live object is there. */
+ status = TX_FALSE;
+
+ /* The eight module object types that have a kernel created list occupy a
+ contiguous range, so each is asked in turn by walking the range. A value in
+ the range that the per-type check does not recognise answers TX_FALSE, so a
+ type the manager stops knowing does not silently pass this search. */
+ for (object_type = ((UINT) TXM_BLOCK_POOL_OBJECT); object_type <= ((UINT) TXM_TIMER_OBJECT); object_type++)
+ {
+
+ if (_txm_module_manager_created_object_type_check(object_ptr, object_type) == TX_TRUE)
+ {
+
+ /* An address is the start of at most one object, so there is nothing
+ further to look for. */
+ status = TX_TRUE;
+ break;
+ }
+ }
+
+ return(status);
+}
+
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
/* _txm_module_manager_util_code_allocation_size_and_alignment_get */
/* PORTABLE C */
/* 6.1 */