diff options
Diffstat (limited to 'common_modules/module_manager')
13 files changed, 2429 insertions, 583 deletions
diff --git a/common_modules/module_manager/inc/txm_module_manager_dispatch.h b/common_modules/module_manager/inc/txm_module_manager_dispatch.h index 03bd86eb..e8c0629b 100644 --- a/common_modules/module_manager/inc/txm_module_manager_dispatch.h +++ b/common_modules/module_manager/inc/txm_module_manager_dispatch.h @@ -1,6 +1,7 @@ /*************************************************************************** * Copyright (c) 2024 Microsoft Corporation * Copyright (c) 2025 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 @@ -8,6 +9,7 @@ * * SPDX-License-Identifier: MIT **************************************************************************/ +// Portions of this file were generated with AI assistance. /**************************************************************************/ @@ -33,7 +35,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_BLOCK_POOL))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_BLOCK_POOL_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); if (!TXM_MODULE_MANAGER_PARAM_CHECK_BUFFER_WRITE(module_instance, param_1, sizeof(VOID *))) @@ -52,7 +54,7 @@ ALIGN_TYPE return_value; #ifndef TXM_BLOCK_POOL_CREATE_CALL_NOT_USED /* UINT _txe_block_pool_create( TX_BLOCK_POOL *pool_ptr, -> param_0 - CHAR *name_ptr, -> param_1 + TX_NAME_CONST CHAR *name_ptr, -> param_1 ULONG block_size, -> extra_parameters[0] VOID *pool_start, -> extra_parameters[1] ULONG pool_size, -> extra_parameters[2] @@ -71,7 +73,7 @@ ALIGN_TYPE return_value; if (!TXM_MODULE_MANAGER_PARAM_CHECK_DEREFERENCE_STRING(module_instance, param_1)) return(TXM_MODULE_INVALID_MEMORY); - if (!TXM_MODULE_MANAGER_ENSURE_INSIDE_MODULE_DATA(module_instance, (ALIGN_TYPE)extra_parameters, sizeof(ALIGN_TYPE[2]))) + if (!TXM_MODULE_MANAGER_ENSURE_INSIDE_MODULE_DATA(module_instance, (ALIGN_TYPE)extra_parameters, sizeof(ALIGN_TYPE[4]))) return(TXM_MODULE_INVALID_MEMORY); if (!TXM_MODULE_MANAGER_PARAM_CHECK_BUFFER_WRITE(module_instance, extra_parameters[1], extra_parameters[2])) @@ -80,7 +82,7 @@ ALIGN_TYPE return_value; return_value = (ALIGN_TYPE) _txe_block_pool_create( (TX_BLOCK_POOL *) param_0, - (CHAR *) param_1, + (TX_NAME_CONST CHAR *) param_1, (ULONG) extra_parameters[0], (VOID *) extra_parameters[1], (ULONG) extra_parameters[2], @@ -101,7 +103,10 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_BLOCK_POOL))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_BLOCK_POOL_OBJECT)) + return(TXM_MODULE_INVALID_MEMORY); + + if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_DELETION(module_instance, param_0, sizeof(TX_BLOCK_POOL))) return(TXM_MODULE_INVALID_MEMORY); } @@ -121,7 +126,7 @@ ALIGN_TYPE return_value; #ifndef TXM_BLOCK_POOL_INFO_GET_CALL_NOT_USED /* UINT _txe_block_pool_info_get( TX_BLOCK_POOL *pool_ptr, -> param_0 - CHAR **name, -> param_1 + TX_NAME_CONST CHAR **name, -> param_1 ULONG *available_blocks, -> extra_parameters[0] ULONG *total_blocks, -> extra_parameters[1] TX_THREAD **first_suspended, -> extra_parameters[2] @@ -135,7 +140,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_BLOCK_POOL))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_BLOCK_POOL_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); if (!TXM_MODULE_MANAGER_PARAM_CHECK_BUFFER_WRITE(module_instance, param_1, sizeof(CHAR *))) @@ -162,7 +167,7 @@ ALIGN_TYPE return_value; return_value = (ALIGN_TYPE) _txe_block_pool_info_get( (TX_BLOCK_POOL *) param_0, - (CHAR **) param_1, + (TX_NAME_CONST CHAR **) param_1, (ULONG *) extra_parameters[0], (ULONG *) extra_parameters[1], (TX_THREAD **) extra_parameters[2], @@ -188,7 +193,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_BLOCK_POOL))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_BLOCK_POOL_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); if (!TXM_MODULE_MANAGER_PARAM_CHECK_BUFFER_WRITE(module_instance, param_1, sizeof(ULONG))) @@ -269,7 +274,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_BLOCK_POOL))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_BLOCK_POOL_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); } @@ -335,7 +340,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_BYTE_POOL))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_BYTE_POOL_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); if (!TXM_MODULE_MANAGER_PARAM_CHECK_BUFFER_WRITE(module_instance, param_1, sizeof(VOID *))) @@ -358,7 +363,7 @@ ALIGN_TYPE return_value; #ifndef TXM_BYTE_POOL_CREATE_CALL_NOT_USED /* UINT _txe_byte_pool_create( TX_BYTE_POOL *pool_ptr, -> param_0 - CHAR *name_ptr, -> param_1 + TX_NAME_CONST CHAR *name_ptr, -> param_1 VOID *pool_start, -> extra_parameters[0] ULONG pool_size, -> extra_parameters[1] UINT pool_control_block_size -> extra_parameters[2] @@ -385,7 +390,7 @@ ALIGN_TYPE return_value; return_value = (ALIGN_TYPE) _txe_byte_pool_create( (TX_BYTE_POOL *) param_0, - (CHAR *) param_1, + (TX_NAME_CONST CHAR *) param_1, (VOID *) extra_parameters[0], (ULONG) extra_parameters[1], (UINT) extra_parameters[2] @@ -405,7 +410,10 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_BYTE_POOL))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_BYTE_POOL_OBJECT)) + return(TXM_MODULE_INVALID_MEMORY); + + if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_DELETION(module_instance, param_0, sizeof(TX_BYTE_POOL))) return(TXM_MODULE_INVALID_MEMORY); } @@ -425,7 +433,7 @@ ALIGN_TYPE return_value; #ifndef TXM_BYTE_POOL_INFO_GET_CALL_NOT_USED /* UINT _txe_byte_pool_info_get( TX_BYTE_POOL *pool_ptr, -> param_0 - CHAR **name, -> param_1 + TX_NAME_CONST CHAR **name, -> param_1 ULONG *available_bytes, -> extra_parameters[0] ULONG *fragments, -> extra_parameters[1] TX_THREAD **first_suspended, -> extra_parameters[2] @@ -439,7 +447,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_BYTE_POOL))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_BYTE_POOL_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); if (!TXM_MODULE_MANAGER_PARAM_CHECK_BUFFER_WRITE(module_instance, param_1, sizeof(CHAR *))) @@ -466,7 +474,7 @@ ALIGN_TYPE return_value; return_value = (ALIGN_TYPE) _txe_byte_pool_info_get( (TX_BYTE_POOL *) param_0, - (CHAR **) param_1, + (TX_NAME_CONST CHAR **) param_1, (ULONG *) extra_parameters[0], (ULONG *) extra_parameters[1], (TX_THREAD **) extra_parameters[2], @@ -495,7 +503,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_BYTE_POOL))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_BYTE_POOL_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); if (!TXM_MODULE_MANAGER_PARAM_CHECK_BUFFER_WRITE(module_instance, param_1, sizeof(ULONG))) @@ -603,7 +611,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_BYTE_POOL))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_BYTE_POOL_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); } @@ -658,7 +666,7 @@ ALIGN_TYPE block_header_start; #ifndef TXM_EVENT_FLAGS_CREATE_CALL_NOT_USED /* UINT _txe_event_flags_create( TX_EVENT_FLAGS_GROUP *group_ptr, -> param_0 - CHAR *name_ptr, -> param_1 + TX_NAME_CONST CHAR *name_ptr, -> param_1 UINT event_control_block_size -> param_2 ); */ static ALIGN_TYPE _txm_module_manager_tx_event_flags_create_dispatch(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE param_0, ALIGN_TYPE param_1, ALIGN_TYPE param_2) @@ -677,7 +685,7 @@ ALIGN_TYPE return_value; return_value = (ALIGN_TYPE) _txe_event_flags_create( (TX_EVENT_FLAGS_GROUP *) param_0, - (CHAR *) param_1, + (TX_NAME_CONST CHAR *) param_1, (UINT) param_2 ); return(return_value); @@ -695,7 +703,10 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_EVENT_FLAGS_GROUP))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_EVENT_FLAGS_OBJECT)) + return(TXM_MODULE_INVALID_MEMORY); + + if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_DELETION(module_instance, param_0, sizeof(TX_EVENT_FLAGS_GROUP))) return(TXM_MODULE_INVALID_MEMORY); } @@ -727,7 +738,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_EVENT_FLAGS_GROUP))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_EVENT_FLAGS_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); if (!TXM_MODULE_MANAGER_PARAM_CHECK_BUFFER_WRITE(module_instance, extra_parameters[1], sizeof(ULONG))) @@ -751,7 +762,7 @@ ALIGN_TYPE return_value; #ifndef TXM_EVENT_FLAGS_INFO_GET_CALL_NOT_USED /* UINT _txe_event_flags_info_get( TX_EVENT_FLAGS_GROUP *group_ptr, -> param_0 - CHAR **name, -> param_1 + TX_NAME_CONST CHAR **name, -> param_1 ULONG *current_flags, -> extra_parameters[0] TX_THREAD **first_suspended, -> extra_parameters[1] ULONG *suspended_count, -> extra_parameters[2] @@ -764,7 +775,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_EVENT_FLAGS_GROUP))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_EVENT_FLAGS_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); if (!TXM_MODULE_MANAGER_PARAM_CHECK_BUFFER_WRITE(module_instance, param_1, sizeof(CHAR *))) @@ -788,7 +799,7 @@ ALIGN_TYPE return_value; return_value = (ALIGN_TYPE) _txe_event_flags_info_get( (TX_EVENT_FLAGS_GROUP *) param_0, - (CHAR **) param_1, + (TX_NAME_CONST CHAR **) param_1, (ULONG *) extra_parameters[0], (TX_THREAD **) extra_parameters[1], (ULONG *) extra_parameters[2], @@ -813,7 +824,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_EVENT_FLAGS_GROUP))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_EVENT_FLAGS_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); if (!TXM_MODULE_MANAGER_PARAM_CHECK_BUFFER_WRITE(module_instance, param_1, sizeof(ULONG))) @@ -896,7 +907,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_EVENT_FLAGS_GROUP))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_EVENT_FLAGS_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); } @@ -923,7 +934,7 @@ VOID (*events_set_notify)(TX_EVENT_FLAGS_GROUP *); if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_EVENT_FLAGS_GROUP))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_EVENT_FLAGS_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); /* Since we need to write to the object, ensure it's valid. */ @@ -958,7 +969,7 @@ VOID (*events_set_notify)(TX_EVENT_FLAGS_GROUP *); #ifndef TXM_MUTEX_CREATE_CALL_NOT_USED /* UINT _txe_mutex_create( TX_MUTEX *mutex_ptr, -> param_0 - CHAR *name_ptr, -> param_1 + TX_NAME_CONST CHAR *name_ptr, -> param_1 UINT inherit, -> extra_parameters[0] UINT mutex_control_block_size -> extra_parameters[1] ); */ @@ -981,7 +992,7 @@ ALIGN_TYPE return_value; return_value = (ALIGN_TYPE) _txe_mutex_create( (TX_MUTEX *) param_0, - (CHAR *) param_1, + (TX_NAME_CONST CHAR *) param_1, (UINT) extra_parameters[0], (UINT) extra_parameters[1] ); @@ -1000,7 +1011,10 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_MUTEX))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_MUTEX_OBJECT)) + return(TXM_MODULE_INVALID_MEMORY); + + if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_DELETION(module_instance, param_0, sizeof(TX_MUTEX))) return(TXM_MODULE_INVALID_MEMORY); } @@ -1029,7 +1043,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_MUTEX))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_MUTEX_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); } @@ -1044,7 +1058,7 @@ ALIGN_TYPE return_value; #ifndef TXM_MUTEX_INFO_GET_CALL_NOT_USED /* UINT _txe_mutex_info_get( TX_MUTEX *mutex_ptr, -> param_0 - CHAR **name, -> param_1 + TX_NAME_CONST CHAR **name, -> param_1 ULONG *count, -> extra_parameters[0] TX_THREAD **owner, -> extra_parameters[1] TX_THREAD **first_suspended, -> extra_parameters[2] @@ -1058,7 +1072,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_MUTEX))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_MUTEX_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); if (!TXM_MODULE_MANAGER_PARAM_CHECK_BUFFER_WRITE(module_instance, param_1, sizeof(CHAR *))) @@ -1085,7 +1099,7 @@ ALIGN_TYPE return_value; return_value = (ALIGN_TYPE) _txe_mutex_info_get( (TX_MUTEX *) param_0, - (CHAR **) param_1, + (TX_NAME_CONST CHAR **) param_1, (ULONG *) extra_parameters[0], (TX_THREAD **) extra_parameters[1], (TX_THREAD **) extra_parameters[2], @@ -1113,7 +1127,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_MUTEX))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_MUTEX_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); if (!TXM_MODULE_MANAGER_PARAM_CHECK_BUFFER_WRITE(module_instance, param_1, sizeof(ULONG))) @@ -1212,7 +1226,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_MUTEX))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_MUTEX_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); } @@ -1234,7 +1248,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_MUTEX))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_MUTEX_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); } @@ -1248,7 +1262,7 @@ ALIGN_TYPE return_value; #ifndef TXM_QUEUE_CREATE_CALL_NOT_USED /* UINT _txe_queue_create( TX_QUEUE *queue_ptr, -> param_0 - CHAR *name_ptr, -> param_1 + TX_NAME_CONST CHAR *name_ptr, -> param_1 UINT message_size, -> extra_parameters[0] VOID *queue_start, -> extra_parameters[1] ULONG queue_size, -> extra_parameters[2] @@ -1276,7 +1290,7 @@ ALIGN_TYPE return_value; return_value = (ALIGN_TYPE) _txe_queue_create( (TX_QUEUE *) param_0, - (CHAR *) param_1, + (TX_NAME_CONST CHAR *) param_1, (UINT) extra_parameters[0], (VOID *) extra_parameters[1], (ULONG) extra_parameters[2], @@ -1297,7 +1311,10 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_QUEUE))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_QUEUE_OBJECT)) + return(TXM_MODULE_INVALID_MEMORY); + + if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_DELETION(module_instance, param_0, sizeof(TX_QUEUE))) return(TXM_MODULE_INVALID_MEMORY); } @@ -1325,7 +1342,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_QUEUE))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_QUEUE_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); } @@ -1350,12 +1367,12 @@ TX_QUEUE *queue_ptr; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_QUEUE))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_QUEUE_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); /* We need to get the size of the message from the queue. */ queue_ptr = (TX_QUEUE *) param_0; - if (!TXM_MODULE_MANAGER_PARAM_CHECK_BUFFER_READ(module_instance, param_1, queue_ptr -> tx_queue_message_size)) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_BUFFER_READ(module_instance, param_1, sizeof(ULONG)*queue_ptr -> tx_queue_message_size)) return(TXM_MODULE_INVALID_MEMORY); } @@ -1371,7 +1388,7 @@ TX_QUEUE *queue_ptr; #ifndef TXM_QUEUE_INFO_GET_CALL_NOT_USED /* UINT _txe_queue_info_get( TX_QUEUE *queue_ptr, -> param_0 - CHAR **name, -> param_1 + TX_NAME_CONST CHAR **name, -> param_1 ULONG *enqueued, -> extra_parameters[0] ULONG *available_storage, -> extra_parameters[1] TX_THREAD **first_suspended, -> extra_parameters[2] @@ -1385,7 +1402,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_QUEUE))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_QUEUE_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); if (!TXM_MODULE_MANAGER_PARAM_CHECK_BUFFER_WRITE(module_instance, param_1, sizeof(CHAR *))) @@ -1412,7 +1429,7 @@ ALIGN_TYPE return_value; return_value = (ALIGN_TYPE) _txe_queue_info_get( (TX_QUEUE *) param_0, - (CHAR **) param_1, + (TX_NAME_CONST CHAR **) param_1, (ULONG *) extra_parameters[0], (ULONG *) extra_parameters[1], (TX_THREAD **) extra_parameters[2], @@ -1440,7 +1457,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_QUEUE))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_QUEUE_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); if (!TXM_MODULE_MANAGER_PARAM_CHECK_BUFFER_WRITE(module_instance, param_1, sizeof(ULONG))) @@ -1539,7 +1556,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_QUEUE))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_QUEUE_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); } @@ -1564,7 +1581,7 @@ TX_QUEUE *queue_ptr; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_QUEUE))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_QUEUE_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); /* We need to get the max size of the buffer from the queue. */ @@ -1596,7 +1613,7 @@ TX_QUEUE *queue_ptr; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_QUEUE))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_QUEUE_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); /* We need to get the size of the message from the queue. */ @@ -1628,7 +1645,7 @@ VOID (*queue_send_notify)(TX_QUEUE *); if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_QUEUE))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_QUEUE_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); /* Since we need to write to the object, ensure it's valid. */ @@ -1672,7 +1689,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_SEMAPHORE))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_SEMAPHORE_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); } @@ -1687,7 +1704,7 @@ ALIGN_TYPE return_value; #ifndef TXM_SEMAPHORE_CREATE_CALL_NOT_USED /* UINT _txe_semaphore_create( TX_SEMAPHORE *semaphore_ptr, -> param_0 - CHAR *name_ptr, -> param_1 + TX_NAME_CONST CHAR *name_ptr, -> param_1 ULONG initial_count, -> extra_parameters[0] UINT semaphore_control_block_size -> extra_parameters[1] ); */ @@ -1710,7 +1727,7 @@ ALIGN_TYPE return_value; return_value = (ALIGN_TYPE) _txe_semaphore_create( (TX_SEMAPHORE *) param_0, - (CHAR *) param_1, + (TX_NAME_CONST CHAR *) param_1, (ULONG) extra_parameters[0], (UINT) extra_parameters[1] ); @@ -1729,7 +1746,10 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_SEMAPHORE))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_SEMAPHORE_OBJECT)) + return(TXM_MODULE_INVALID_MEMORY); + + if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_DELETION(module_instance, param_0, sizeof(TX_SEMAPHORE))) return(TXM_MODULE_INVALID_MEMORY); } @@ -1758,7 +1778,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_SEMAPHORE))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_SEMAPHORE_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); } @@ -1773,7 +1793,7 @@ ALIGN_TYPE return_value; #ifndef TXM_SEMAPHORE_INFO_GET_CALL_NOT_USED /* UINT _txe_semaphore_info_get( TX_SEMAPHORE *semaphore_ptr, -> param_0 - CHAR **name, -> param_1 + TX_NAME_CONST CHAR **name, -> param_1 ULONG *current_value, -> extra_parameters[0] TX_THREAD **first_suspended, -> extra_parameters[1] ULONG *suspended_count, -> extra_parameters[2] @@ -1786,7 +1806,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_SEMAPHORE))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_SEMAPHORE_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); if (!TXM_MODULE_MANAGER_PARAM_CHECK_BUFFER_WRITE(module_instance, param_1, sizeof(CHAR *))) @@ -1810,7 +1830,7 @@ ALIGN_TYPE return_value; return_value = (ALIGN_TYPE) _txe_semaphore_info_get( (TX_SEMAPHORE *) param_0, - (CHAR **) param_1, + (TX_NAME_CONST CHAR **) param_1, (ULONG *) extra_parameters[0], (TX_THREAD **) extra_parameters[1], (ULONG *) extra_parameters[2], @@ -1835,7 +1855,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_SEMAPHORE))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_SEMAPHORE_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); if (!TXM_MODULE_MANAGER_PARAM_CHECK_BUFFER_WRITE(module_instance, param_1, sizeof(ULONG))) @@ -1916,7 +1936,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_SEMAPHORE))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_SEMAPHORE_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); } @@ -1938,7 +1958,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_SEMAPHORE))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_SEMAPHORE_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); } @@ -1963,7 +1983,7 @@ VOID (*semaphore_put_notify)(TX_SEMAPHORE *); if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_SEMAPHORE))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_SEMAPHORE_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); /* Since we need to write to the object, ensure it's valid. */ @@ -1998,7 +2018,7 @@ VOID (*semaphore_put_notify)(TX_SEMAPHORE *); #ifndef TXM_THREAD_CREATE_CALL_NOT_USED /* UINT _txe_thread_create( TX_THREAD *thread_ptr, -> param_0 - CHAR *name_ptr, -> param_1 + TX_NAME_CONST CHAR *name_ptr, -> param_1 VOID (*entry_function)(ULONG entry_input), -> extra_parameters[0] ULONG entry_input, -> extra_parameters[1] VOID *stack_start, -> extra_parameters[2] @@ -2037,7 +2057,7 @@ ALIGN_TYPE return_value; return_value = (ALIGN_TYPE) _txm_module_manager_thread_create( (TX_THREAD *) param_0, - (CHAR *) param_1, + (TX_NAME_CONST CHAR *) param_1, module_instance -> txm_module_instance_shell_entry_function, (VOID (*)(ULONG entry_input)) extra_parameters[0], (ULONG) extra_parameters[1], @@ -2061,22 +2081,48 @@ ALIGN_TYPE return_value; static ALIGN_TYPE _txm_module_manager_tx_thread_delete_dispatch(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE param_0) { -ALIGN_TYPE return_value; +TX_THREAD *thread_ptr; +ALIGN_TYPE return_value; +ALIGN_TYPE stack_status; + + thread_ptr = (TX_THREAD *) param_0; + stack_status = (ALIGN_TYPE) TX_SUCCESS; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_THREAD))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_THREAD_OBJECT)) + return(TXM_MODULE_INVALID_MEMORY); + + if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_DELETION(module_instance, param_0, sizeof(TX_THREAD))) return(TXM_MODULE_INVALID_MEMORY); } - return_value = (ALIGN_TYPE) _txe_thread_delete( - (TX_THREAD *) param_0 - ); + return_value = (ALIGN_TYPE) _txe_thread_delete(thread_ptr); - /* Deallocate object memory. */ + /* Deallocate the kernel stack for a user-mode thread. The pointer is tested + rather than the module's properties: both thread create paths clear the whole + control block before filling it in, so a thread that carries no kernel stack + the manager allocated holds TX_NULL here, and a user-mode module can be given + the address of such a thread. */ + if ((return_value == TX_SUCCESS) && + (module_instance -> txm_module_instance_property_flags & TXM_MODULE_USER_MODE) && + (thread_ptr -> tx_thread_module_kernel_stack_start != TX_NULL)) + { + stack_status = _txm_module_manager_object_deallocate(thread_ptr -> tx_thread_module_kernel_stack_start); + } + + /* Deallocate thread object memory. This must be attempted even when the kernel + stack could not be released, otherwise a successful thread delete would leave + the thread object allocated forever. */ if (return_value == TX_SUCCESS) { - return_value = _txm_module_manager_object_deallocate((VOID *) param_0); + return_value = _txm_module_manager_object_deallocate((VOID *) thread_ptr); + + /* Report the kernel stack failure if the thread object was released. */ + if ((return_value == TX_SUCCESS) && (stack_status != TX_SUCCESS)) + { + return_value = stack_status; + } } return(return_value); } @@ -2097,7 +2143,7 @@ VOID (*thread_entry_exit_notify)(TX_THREAD *, UINT); if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_THREAD))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_THREAD_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); /* Since we need to write to the object, ensure it's valid. */ @@ -2148,7 +2194,7 @@ ALIGN_TYPE return_value; #ifndef TXM_THREAD_INFO_GET_CALL_NOT_USED /* UINT _txe_thread_info_get( TX_THREAD *thread_ptr, -> param_0 - CHAR **name, -> param_1 + TX_NAME_CONST CHAR **name, -> param_1 UINT *state, -> extra_parameters[0] ULONG *run_count, -> extra_parameters[1] UINT *priority, -> extra_parameters[2] @@ -2164,7 +2210,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_THREAD))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_THREAD_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); if (!TXM_MODULE_MANAGER_PARAM_CHECK_BUFFER_WRITE(module_instance, param_1, sizeof(CHAR *))) @@ -2197,7 +2243,7 @@ ALIGN_TYPE return_value; return_value = (ALIGN_TYPE) _txe_thread_info_get( (TX_THREAD *) param_0, - (CHAR **) param_1, + (TX_NAME_CONST CHAR **) param_1, (UINT *) extra_parameters[0], (ULONG *) extra_parameters[1], (UINT *) extra_parameters[2], @@ -2250,7 +2296,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_THREAD))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_THREAD_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); if (!TXM_MODULE_MANAGER_PARAM_CHECK_BUFFER_WRITE(module_instance, param_1, sizeof(ULONG))) @@ -2397,7 +2443,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_THREAD))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_THREAD_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); if (!TXM_MODULE_MANAGER_PARAM_CHECK_BUFFER_WRITE(module_instance, param_2, sizeof(UINT))) @@ -2431,7 +2477,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_THREAD))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_THREAD_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); if (!TXM_MODULE_MANAGER_PARAM_CHECK_BUFFER_WRITE(module_instance, param_2, sizeof(UINT))) @@ -2468,7 +2514,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_THREAD))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_THREAD_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); } @@ -2490,7 +2536,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_THREAD))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_THREAD_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); } @@ -2547,7 +2593,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_THREAD))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_THREAD_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); } @@ -2576,7 +2622,7 @@ TX_THREAD *thread_ptr; { return(TXM_MODULE_INVALID_MEMORY); } - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_THREAD))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_THREAD_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); } @@ -2626,7 +2672,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_THREAD))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_THREAD_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); } @@ -2650,7 +2696,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_THREAD))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_THREAD_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); if (!TXM_MODULE_MANAGER_PARAM_CHECK_BUFFER_WRITE(module_instance, param_2, sizeof(ULONG))) @@ -2677,7 +2723,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_THREAD))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_THREAD_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); } @@ -2725,7 +2771,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_TIMER))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_TIMER_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); } @@ -2749,7 +2795,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_TIMER))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_TIMER_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); } @@ -2765,7 +2811,7 @@ ALIGN_TYPE return_value; #ifndef TXM_TIMER_CREATE_CALL_NOT_USED /* UINT _txe_timer_create( TX_TIMER *timer_ptr, -> param_0 - CHAR *name_ptr, -> param_1 + TX_NAME_CONST CHAR *name_ptr, -> param_1 VOID (*expiration_function)(ULONG), -> extra_parameters[0] ULONG expiration_input, -> extra_parameters[1] ULONG initial_ticks, -> extra_parameters[2] @@ -2808,7 +2854,7 @@ VOID (*expiration_function)(ULONG); return_value = (ALIGN_TYPE) _txe_timer_create( (TX_TIMER *) param_0, - (CHAR *) param_1, + (TX_NAME_CONST CHAR *) param_1, (VOID (*)(ULONG)) expiration_function, (ULONG) extra_parameters[1], (ULONG) extra_parameters[2], @@ -2846,7 +2892,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_TIMER))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_TIMER_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); } @@ -2868,7 +2914,10 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_TIMER))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_TIMER_OBJECT)) + return(TXM_MODULE_INVALID_MEMORY); + + if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_DELETION(module_instance, param_0, sizeof(TX_TIMER))) return(TXM_MODULE_INVALID_MEMORY); } @@ -2888,7 +2937,7 @@ ALIGN_TYPE return_value; #ifndef TXM_TIMER_INFO_GET_CALL_NOT_USED /* UINT _txe_timer_info_get( TX_TIMER *timer_ptr, -> param_0 - CHAR **name, -> param_1 + TX_NAME_CONST CHAR **name, -> param_1 UINT *active, -> extra_parameters[0] ULONG *remaining_ticks, -> extra_parameters[1] ULONG *reschedule_ticks, -> extra_parameters[2] @@ -2901,7 +2950,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_TIMER))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_TIMER_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); if (!TXM_MODULE_MANAGER_PARAM_CHECK_BUFFER_WRITE(module_instance, param_1, sizeof(CHAR *))) @@ -2925,7 +2974,7 @@ ALIGN_TYPE return_value; return_value = (ALIGN_TYPE) _txe_timer_info_get( (TX_TIMER *) param_0, - (CHAR **) param_1, + (TX_NAME_CONST CHAR **) param_1, (UINT *) extra_parameters[0], (ULONG *) extra_parameters[1], (ULONG *) extra_parameters[2], @@ -2951,7 +3000,7 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, param_0, sizeof(TX_TIMER))) + if (!TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, param_0, TXM_TIMER_OBJECT)) return(TXM_MODULE_INVALID_MEMORY); if (!TXM_MODULE_MANAGER_PARAM_CHECK_BUFFER_WRITE(module_instance, param_1, sizeof(ULONG))) @@ -3232,41 +3281,6 @@ static ALIGN_TYPE _txm_module_manager_txm_module_object_deallocate_dispatch(TXM_ { ALIGN_TYPE return_value; -TXM_MODULE_ALLOCATED_OBJECT *object_ptr; -ALIGN_TYPE object_end; -ALIGN_TYPE object_pool_end; - - if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) - { - /* Is the object pool created? */ - if (_txm_module_manager_object_pool_created == TX_TRUE) - { - - /* Get the module allocated object. */ - object_ptr = ((TXM_MODULE_ALLOCATED_OBJECT *) param_0) - 1; - - /* Get the end address of the object pool. */ - object_pool_end = (ALIGN_TYPE) (_txm_module_manager_object_pool.tx_byte_pool_start + _txm_module_manager_object_pool.tx_byte_pool_size); - - /* Check that the pointer is in the object pool. */ - if ((ALIGN_TYPE) object_ptr < (ALIGN_TYPE) _txm_module_manager_object_pool.tx_byte_pool_start || - (ALIGN_TYPE) object_ptr >= (ALIGN_TYPE) object_pool_end) - { - /* Pointer is outside of the object pool. */ - return(TXM_MODULE_INVALID_MEMORY); - } - - /* Get the end addresses of the object. */ - object_end = ((ALIGN_TYPE) object_ptr) + sizeof(TXM_MODULE_ALLOCATED_OBJECT) + object_ptr -> txm_module_object_size; - - /* Check that the object is in the object pool. */ - if (object_end >= object_pool_end) - { - /* Object is outside of the object pool. */ - return(TXM_MODULE_INVALID_MEMORY); - } - } - } return_value = (ALIGN_TYPE) _txm_module_manager_object_deallocate( (VOID *) param_0 @@ -3288,11 +3302,10 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_DEREFERENCE_STRING(module_instance, param_1)) - return(TXM_MODULE_INVALID_MEMORY); - - if (!TXM_MODULE_MANAGER_PARAM_CHECK_BUFFER_WRITE(module_instance, param_2, sizeof(VOID *))) - return(TXM_MODULE_INVALID_MEMORY); + /* This service carries no name length, so the manager searches with the largest + length a UINT can hold and no readable range can be proven for the name. A + memory-protected module must use the extended service, which declares one. */ + return(TXM_MODULE_INVALID_MEMORY); } return_value = (ALIGN_TYPE) _txm_module_manager_object_pointer_get( @@ -3318,10 +3331,13 @@ ALIGN_TYPE return_value; if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) { - if (!TXM_MODULE_MANAGER_PARAM_CHECK_DEREFERENCE_STRING(module_instance, param_1)) + if (!TXM_MODULE_MANAGER_ENSURE_INSIDE_MODULE_DATA(module_instance, (ALIGN_TYPE)extra_parameters, sizeof(ALIGN_TYPE[2]))) return(TXM_MODULE_INVALID_MEMORY); - if (!TXM_MODULE_MANAGER_ENSURE_INSIDE_MODULE_DATA(module_instance, (ALIGN_TYPE)extra_parameters, sizeof(ALIGN_TYPE[2]))) + /* The name length has to be checked before it is trusted, so the extra parameter + array is checked first. The comparison reads the declared length plus the + terminator that follows it, and all of that must be inside the module. */ + if (!TXM_MODULE_MANAGER_PARAM_CHECK_DEREFERENCE_STRING_RANGE(module_instance, param_1, (UINT) extra_parameters[0])) return(TXM_MODULE_INVALID_MEMORY); if (!TXM_MODULE_MANAGER_PARAM_CHECK_BUFFER_WRITE(module_instance, extra_parameters[1], sizeof(VOID *))) diff --git a/common_modules/module_manager/inc/txm_module_manager_util.h b/common_modules/module_manager/inc/txm_module_manager_util.h index 45c7f409..3583edcc 100644 --- a/common_modules/module_manager/inc/txm_module_manager_util.h +++ b/common_modules/module_manager/inc/txm_module_manager_util.h @@ -9,6 +9,8 @@ * SPDX-License-Identifier: MIT **************************************************************************/ +// Portions of this file were generated with AI assistance. + /**************************************************************************/ /**************************************************************************/ @@ -43,8 +45,32 @@ /* Define check macros for modules. */ +/* A port supplies TXM_MODULE_MANAGER_CHECK_INSIDE_DATA to decide whether a caller-supplied + range lies inside the module's writable data or shared memory. Ports whose check can tell + a read-only region from a writable one also supply the two intent-specific variants below. + Ports that cannot make the distinction inherit their single check for both intents, so + their behaviour is unchanged. */ + +#ifndef TXM_MODULE_MANAGER_CHECK_INSIDE_DATA_READ +#define TXM_MODULE_MANAGER_CHECK_INSIDE_DATA_READ(module_instance, obj_ptr, obj_size) \ + TXM_MODULE_MANAGER_CHECK_INSIDE_DATA(module_instance, obj_ptr, obj_size) +#endif + +#ifndef TXM_MODULE_MANAGER_CHECK_INSIDE_DATA_WRITE +#define TXM_MODULE_MANAGER_CHECK_INSIDE_DATA_WRITE(module_instance, obj_ptr, obj_size) \ + TXM_MODULE_MANAGER_CHECK_INSIDE_DATA(module_instance, obj_ptr, obj_size) +#endif + +/* A range is outside the module's data only when no part of it is reachable by the module. + The read intent is used here because it describes the widest set of reachable addresses. + A port whose inside check cannot prove the whole range at once must supply its own + definition, because negating a partial-range check would report a partly reachable range + as being outside the module. */ + +#ifndef TXM_MODULE_MANAGER_CHECK_OUTSIDE_DATA #define TXM_MODULE_MANAGER_CHECK_OUTSIDE_DATA(module_instance, obj_ptr, obj_size) \ - (!(TXM_MODULE_MANAGER_CHECK_INSIDE_DATA(module_instance, obj_ptr, obj_size))) + (!(TXM_MODULE_MANAGER_CHECK_INSIDE_DATA_READ(module_instance, obj_ptr, obj_size))) +#endif #define TXM_MODULE_MANAGER_CHECK_INSIDE_CODE(module_instance, obj_ptr, obj_size) \ (((obj_ptr) < ((obj_ptr) + (obj_size))) && \ @@ -63,12 +89,14 @@ /* Define macros for module. */ +/* The module reads from these ranges, so a read-only region is acceptable. */ #define TXM_MODULE_MANAGER_ENSURE_INSIDE_MODULE(module_instance, obj_ptr, obj_size) \ - (TXM_MODULE_MANAGER_CHECK_INSIDE_DATA(module_instance, obj_ptr, obj_size) || \ + (TXM_MODULE_MANAGER_CHECK_INSIDE_DATA_READ(module_instance, obj_ptr, obj_size) || \ TXM_MODULE_MANAGER_CHECK_INSIDE_CODE(module_instance, obj_ptr, obj_size)) +/* The kernel writes to these ranges, so the module must be able to write them too. */ #define TXM_MODULE_MANAGER_ENSURE_INSIDE_MODULE_DATA(module_instance, obj_ptr, obj_size) \ - TXM_MODULE_MANAGER_CHECK_INSIDE_DATA(module_instance, obj_ptr, obj_size) + TXM_MODULE_MANAGER_CHECK_INSIDE_DATA_WRITE(module_instance, obj_ptr, obj_size) #define TXM_MODULE_MANAGER_ENSURE_OUTSIDE_MODULE(module_instance, obj_ptr, obj_size) \ (TXM_MODULE_MANAGER_CHECK_OUTSIDE_DATA(module_instance, obj_ptr, obj_size) && \ @@ -89,19 +117,59 @@ ((TXM_MODULE_MANAGER_ENSURE_INSIDE_MODULE_DATA(module_instance, buffer_ptr, buffer_size)) || \ ((void *) (buffer_ptr) == TX_NULL)) -/* Kernel objects should be outside the module at the very least. */ +/* Kernel objects a module names must be authenticated before a privileged service is + allowed to dereference them. Being outside the module is necessary but nowhere near + sufficient: the manager's object pool is outside every module, so an address shifted + into the interior of one of the module's own privileged allocations satisfies that + test while denoting no object at all. Authentication answers the question the + location test cannot -- is this the exact address of a live kernel object of the type + this service expects -- and it answers it from manager and kernel bookkeeping rather + than from fields of the purported object, which a module can influence. + + TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE is the complete check and is what + the dispatch table uses. It is given the object type rather than a control block size + so that it can also establish the type, which a size cannot: distinct object types of + equal size exist. + + TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE is retained for dispatchers outside this + repository that pass a size. It authenticates addresses in the manager's object pool, + which is what the shifted-pointer attack needs, but without a type it can neither + establish the type nor authenticate an application-owned object, so in-repository code + should use the typed form. */ #define TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_USE(module_instance, obj_ptr, obj_size) \ (_txm_module_manager_param_check_object_for_use(module_instance, obj_ptr, obj_size)) +#define TXM_MODULE_MANAGER_PARAM_CHECK_TYPED_OBJECT_FOR_USE(module_instance, obj_ptr, obj_type) \ + (_txm_module_manager_param_check_typed_object_for_use(module_instance, obj_ptr, obj_type)) + /* When creating an object, the object must be inside the object pool. */ #define TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_CREATION(module_instance, obj_ptr, obj_size) \ (_txm_module_manager_param_check_object_for_creation(module_instance, obj_ptr, obj_size)) +/* When deleting an object, being allowed to use it is not enough. Deletion is the + inverse of creation, so it asks what creation asks: that the object is one this + module allocated from the manager's object pool, at the exact address the manager + gave it, for an object of this size. A module may hold a pointer to an object it + does not own -- the manager's object lookup service hands application-owned + objects to modules by name, and sharing an object is what that service is for -- + and this is what separates using such an object from destroying it. */ +#define TXM_MODULE_MANAGER_PARAM_CHECK_OBJECT_FOR_DELETION(module_instance, obj_ptr, obj_size) \ + (_txm_module_manager_allocated_object_check(module_instance, obj_ptr, obj_size)) + /* Strings we dereference can be in RW/RO/Shared areas. */ #define TXM_MODULE_MANAGER_PARAM_CHECK_DEREFERENCE_STRING(module_instance, string_ptr) \ ((TXM_MODULE_MANAGER_ENSURE_INSIDE_MODULE(module_instance, string_ptr, 1)) || \ ((void *) (string_ptr) == TX_NULL)) +/* Strings we walk are checked over the whole range the walk may reach: the declared + length plus the terminating character that follows it, since a length excludes the + terminator and the comparison reads it. A length whose range cannot be expressed + is refused rather than truncated. */ +#define TXM_MODULE_MANAGER_PARAM_CHECK_DEREFERENCE_STRING_RANGE(module_instance, string_ptr, string_length) \ + (((((ALIGN_TYPE) (string_length)) < (~((ALIGN_TYPE) 0))) && \ + (TXM_MODULE_MANAGER_ENSURE_INSIDE_MODULE(module_instance, string_ptr, ((ALIGN_TYPE) (string_length)) + ((ALIGN_TYPE) 1)))) || \ + ((void *) (string_ptr) == TX_NULL)) + #define TXM_MODULE_MANAGER_UTIL_MAX_VALUE_OF_TYPE_UNSIGNED(type) ((1ULL << (sizeof(type) * 8)) - 1) #define TXM_MODULE_MANAGER_UTIL_MATH_ADD_ULONG(augend, addend, result) \ @@ -118,10 +186,18 @@ UINT _txm_module_manager_object_memory_check(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE object_ptr, ULONG object_size); UINT _txm_module_manager_object_size_check(ALIGN_TYPE object_ptr, ULONG object_size); -UINT _txm_module_manager_object_name_compare(CHAR *object_name1, UINT object_name1_length, CHAR *object_name2); +UINT _txm_module_manager_object_name_compare(CHAR *object_name1, UINT object_name1_length, TX_NAME_CONST CHAR *object_name2); UCHAR _txm_module_manager_created_object_check(TXM_MODULE_INSTANCE *module_instance, void *object_ptr); UINT _txm_module_manager_param_check_object_for_creation(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE object_ptr, ULONG object_size); UINT _txm_module_manager_param_check_object_for_use(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE object_ptr, ULONG object_size); +UINT _txm_module_manager_param_check_typed_object_for_use(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE object_ptr, UINT object_type); +UINT _txm_module_manager_allocated_object_check(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE object_ptr, ULONG object_size); +TXM_MODULE_ALLOCATED_OBJECT + *_txm_module_manager_allocated_object_find(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE object_ptr, ULONG *object_size_ptr); +UINT _txm_module_manager_object_type_size_get(UINT object_type, ULONG *object_size); +UINT _txm_module_manager_created_object_type_check(ALIGN_TYPE object_ptr, UINT object_type); +UINT _txm_module_manager_object_id_check(ALIGN_TYPE object_ptr, UINT object_type); +UINT _txm_module_manager_live_object_check(ALIGN_TYPE object_ptr); UINT _txm_module_manager_util_code_allocation_size_and_alignment_get(TXM_MODULE_PREAMBLE *module_preamble, ULONG *code_alignment_dest, ULONG *code_allocation_size_dest); #endif 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 */ diff --git a/common_modules/module_manager/utilities/module_binary_to_c_array.c b/common_modules/module_manager/utilities/module_binary_to_c_array.c index da0cf97c..e418fbc1 100644 --- a/common_modules/module_manager/utilities/module_binary_to_c_array.c +++ b/common_modules/module_manager/utilities/module_binary_to_c_array.c @@ -1,3 +1,16 @@ +/***************************************************************************/ +/* Copyright (c) 2024 Microsoft Corporation */ +/* 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 */ +/* https://opensource.org/licenses/MIT. */ +/* */ +/* SPDX-License-Identifier: MIT */ +/***************************************************************************/ + +// Portions of this file were generated with AI assistance. + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -25,8 +38,11 @@ unsigned long column; { /* Print an error message out and wait for user key hit. */ - printf("module_binary_to_c_array.exe - Copyright (c) Microsoft Corporation v5.8\n"); - printf("**** Error: invalid input parameter for module_binary_to_c_array.exe **** \n"); + printf("module_binary_to_c_array\n"); + printf("(c) 2024 Microsoft Corp\n"); + printf("(c) 2026 Eclipse ThreadX contributors\n"); + printf("v6.5.2.202603\n"); + printf("**** Error: invalid input parameter for module_binary_to_c_array **** \n"); printf(" Command Line Should be:\n\n"); printf(" > module_binary_to_c_array source_binary_file c_array_file <cr> \n\n"); return(1); @@ -57,6 +73,10 @@ unsigned long column; /* Print an error message out and wait for user key hit. */ printf("**** Error: invalid format of binary input file **** \n"); printf(" File: %s ", argv[1]); + + /* Close the source file. */ + fclose(source_file); + return(3); } @@ -75,7 +95,9 @@ unsigned long column; fprintf(array_file, "/**************************** Module-Binary-to-C-array Utility **********************************/\n"); fprintf(array_file, "/* */\n"); - fprintf(array_file, "/* Copyright (c) Microsoft Corporation Version 5.4, build date: 03-01-2018 */\n"); + fprintf(array_file, "/* Copyright (c) 2024 Microsoft Corp */\n"); + fprintf(array_file, "/* Copyright (c) 2026 Eclipse ThreadX contributors */\n"); + fprintf(array_file, "/* v6.5.2.202603 */\n"); fprintf(array_file, "/* */\n"); fprintf(array_file, "/************************************************************************************************/\n\n"); fprintf(array_file, "/* \n"); @@ -109,7 +131,7 @@ unsigned long column; { if (address != 0) fprintf(array_file, ",\n"); - fprintf(array_file, "/* 0x%08X */ 0x%02X", address, (unsigned int) alpha); + fprintf(array_file, "/* 0x%08lX */ 0x%02X", address, (unsigned int) alpha); } else fprintf(array_file, ", 0x%02X", (unsigned int) alpha); diff --git a/common_modules/module_manager/utilities/module_to_binary.c b/common_modules/module_manager/utilities/module_to_binary.c index bb4f294d..0b159cd7 100644 --- a/common_modules/module_manager/utilities/module_to_binary.c +++ b/common_modules/module_manager/utilities/module_to_binary.c @@ -9,11 +9,25 @@ /* SPDX-License-Identifier: MIT */ /***************************************************************************/ +// Portions of this file were generated with AI assistance. + #include <stdio.h> #include <stdlib.h> #include <string.h> +/* MISRA C:2012 Rule 21.3 and Dir 4.12 deviation: dynamic memory is used in this + file. This is a host-side conversion utility executed on the development + machine, not ThreadX runtime code, and the ELF areas being read have sizes + that are only known at run time. Every allocation result is checked for NULL + and every buffer is released before its pointer is reused. */ + +/* MISRA C:2012 Rule 15.5 (advisory) deviation: main() returns from several + error paths instead of having a single point of exit. The project forbids + goto, so an early return is the only way to abandon the conversion, and this + matches the style already used by the parameter and file open checks. */ + + /* Define the file handles. */ FILE *source_file; @@ -137,13 +151,52 @@ unsigned char *buffer; } +/* Close the files and release the ELF areas allocated by main(). This is called + from every exit path taken after the files have been opened, so it must + tolerate being called with resources that were never acquired. The areas it + releases are the file scope pointers declared above. */ + +static void converter_cleanup(void) +{ + + /* Determine if the source file is open. */ + if (source_file != NULL) + { + + /* Close it. */ + fclose(source_file); + source_file = NULL; + } + + /* Determine if the binary output file is open. */ + if (binary_file != NULL) + { + + /* Close it. */ + fclose(binary_file); + binary_file = NULL; + } + + /* Release the ELF areas. Note that free() is defined to do nothing when it + is supplied a NULL pointer, so no test is required here. */ + free(program_header); + program_header = NULL; + free(section_header); + section_header = NULL; + free(section_string_table); + section_string_table = NULL; + free(code_section_array); + code_section_array = NULL; +} + + int main(int argc, char* argv[]) { unsigned long i, j; -unsigned long current_total; unsigned long address; unsigned long size; +unsigned long allocation_size; unsigned char *code_buffer; unsigned long code_section_index; CODE_SECTION_ENTRY code_section_temp; @@ -155,8 +208,11 @@ unsigned char zero_value; { /* Print an error message out and wait for user key hit. */ - printf("module_to_binary.exe - Copyright (c) Microsoft Corporation v5.8\n"); - printf("**** Error: invalid input parameter for module_to_binary.exe **** \n"); + printf("module_to_binary\n"); + printf("(c) 2024 Microsoft Corp\n"); + printf("(c) 2026 Eclipse ThreadX contributors\n"); + printf("v6.5.2.202603\n"); + printf("**** Error: invalid input parameter for module_to_binary **** \n"); printf(" Command Line Should be:\n\n"); printf(" > module_to_binary source_elf_file c_binary_file <cr> \n\n"); return(1); @@ -189,29 +245,140 @@ unsigned char zero_value; } /* Read the ELF header. */ - elf_object_read(0, &header, sizeof(header)); + if (elf_object_read(0, &header, sizeof(header)) != 0) + { + + /* Print an error message out. */ + printf("**** Error: read failed on the ELF header **** \n"); + + /* Close the files and release the ELF areas. */ + converter_cleanup(); + + return(6); + } /* Allocate memory for the program header(s). */ - program_header = malloc(sizeof(ELF_PROGRAM_HEADER)*header.elf_header_program_header_entries); + allocation_size = sizeof(ELF_PROGRAM_HEADER)*header.elf_header_program_header_entries; + program_header = malloc(allocation_size); + + /* Determine if the memory allocation was successful. Note that an empty area + is not an error, since malloc() is permitted to return NULL for it. */ + if ((program_header == NULL) && (allocation_size != 0)) + { + + /* Print an error message out. */ + printf("**** Error: memory allocation failed for the program header(s) **** \n"); + + /* Close the files and release the ELF areas. */ + converter_cleanup(); + + return(5); + } /* Read the program header(s). */ - elf_object_read(header.elf_header_program_header_offset, program_header, (sizeof(ELF_PROGRAM_HEADER)*header.elf_header_program_header_entries)); + if (elf_object_read(header.elf_header_program_header_offset, program_header, allocation_size) != 0) + { + + /* Print an error message out. */ + printf("**** Error: read failed on the program header(s) **** \n"); + + /* Close the files and release the ELF areas. */ + converter_cleanup(); + + return(6); + } /* Allocate memory for the section header(s). */ - section_header = malloc(sizeof(ELF_SECTION_HEADER)*header.elf_header_section_header_entries); + allocation_size = sizeof(ELF_SECTION_HEADER)*header.elf_header_section_header_entries; + section_header = malloc(allocation_size); + + /* Determine if the memory allocation was successful. */ + if ((section_header == NULL) && (allocation_size != 0)) + { + + /* Print an error message out. */ + printf("**** Error: memory allocation failed for the section header(s) **** \n"); + + /* Close the files and release the ELF areas. */ + converter_cleanup(); + + return(5); + } /* Read the section header(s). */ - elf_object_read(header.elf_header_section_header_offset, section_header, (sizeof(ELF_SECTION_HEADER)*header.elf_header_section_header_entries)); + if (elf_object_read(header.elf_header_section_header_offset, section_header, allocation_size) != 0) + { + /* Print an error message out. */ + printf("**** Error: read failed on the section header(s) **** \n"); + + /* Close the files and release the ELF areas. */ + converter_cleanup(); + + return(6); + } + + /* Determine if the section string table index supplied by the ELF header is + inside the section header area that was just read. */ + if (header.elf_header_section_string_index >= header.elf_header_section_header_entries) + { + + /* Print an error message out. */ + printf("**** Error: invalid section string table index in the ELF header **** \n"); + + /* Close the files and release the ELF areas. */ + converter_cleanup(); + + return(6); + } /* Alocate memory for the section string table. */ - section_string_table = malloc(section_header[header.elf_header_section_string_index].elf_section_header_size); + allocation_size = section_header[header.elf_header_section_string_index].elf_section_header_size; + section_string_table = malloc(allocation_size); + + /* Determine if the memory allocation was successful. */ + if ((section_string_table == NULL) && (allocation_size != 0)) + { + + /* Print an error message out. */ + printf("**** Error: memory allocation failed for the section string table **** \n"); + + /* Close the files and release the ELF areas. */ + converter_cleanup(); + + return(5); + } /* Read the section string table. */ - elf_object_read(section_header[header.elf_header_section_string_index].elf_section_header_offset, section_string_table, section_header[header.elf_header_section_string_index].elf_section_header_size); + if (elf_object_read(section_header[header.elf_header_section_string_index].elf_section_header_offset, section_string_table, allocation_size) != 0) + { + + /* Print an error message out. */ + printf("**** Error: read failed on the section string table **** \n"); + + /* Close the files and release the ELF areas. */ + converter_cleanup(); + + return(6); + } /* Allocate memory for the code section array. */ - code_section_array = malloc(sizeof(CODE_SECTION_ENTRY)*header.elf_header_section_header_entries); + allocation_size = sizeof(CODE_SECTION_ENTRY)*header.elf_header_section_header_entries; + code_section_array = malloc(allocation_size); + + /* Determine if the memory allocation was successful. */ + if ((code_section_array == NULL) && (allocation_size != 0)) + { + + /* Print an error message out. */ + printf("**** Error: memory allocation failed for the code section array **** \n"); + + /* Close the files and release the ELF areas. */ + converter_cleanup(); + + return(5); + } + code_section_index = 0; /* Print out the section header(s). */ @@ -258,9 +425,8 @@ unsigned char zero_value; if (code_section_index == 0) { - /* Close files. */ - fclose(source_file); - fclose(binary_file); + /* Close the files and release the ELF areas. */ + converter_cleanup(); return(4); } @@ -310,9 +476,34 @@ unsigned char zero_value; /* Now allocate memory for the code section. */ code_buffer = malloc(code_section_array[i].code_section_size); + /* Determine if the memory allocation was successful. */ + if (code_buffer == NULL) + { + + /* Print an error message out. */ + printf("**** Error: memory allocation failed for code section **** \n"); + + /* Close the files and release the ELF areas. */ + converter_cleanup(); + + return(5); + } + /* Read in the code area. */ j = code_section_array[i].code_section_index; - elf_object_read(section_header[j].elf_section_header_offset, code_buffer, code_section_array[i].code_section_size); + if (elf_object_read(section_header[j].elf_section_header_offset, code_buffer, code_section_array[i].code_section_size) != 0) + { + + /* Print an error message out. */ + printf("**** Error: read failed on a code section **** \n"); + + /* Release the code section buffer, then close the files and release + the ELF areas. */ + free(code_buffer); + converter_cleanup(); + + return(6); + } /* Write out the contents of this program area. */ size = code_section_array[i].code_section_size; @@ -333,11 +524,14 @@ unsigned char zero_value; /* Move index into buffer. */ j++; } + + /* Release the code section buffer before the next section is read. */ + free(code_buffer); + code_buffer = NULL; } - /* Close files. */ - fclose(source_file); - fclose(binary_file); + /* Close the files and release the ELF areas. */ + converter_cleanup(); return 0; } diff --git a/common_modules/module_manager/utilities/module_to_c_array.c b/common_modules/module_manager/utilities/module_to_c_array.c index d3472416..72e87de0 100644 --- a/common_modules/module_manager/utilities/module_to_c_array.c +++ b/common_modules/module_manager/utilities/module_to_c_array.c @@ -9,11 +9,25 @@ /* SPDX-License-Identifier: MIT */ /***************************************************************************/ +// Portions of this file were generated with AI assistance. + #include <stdio.h> #include <stdlib.h> #include <string.h> +/* MISRA C:2012 Rule 21.3 and Dir 4.12 deviation: dynamic memory is used in this + file. This is a host-side conversion utility executed on the development + machine, not ThreadX runtime code, and the ELF areas being read have sizes + that are only known at run time. Every allocation result is checked for NULL + and every buffer is released before its pointer is reused. */ + +/* MISRA C:2012 Rule 15.5 (advisory) deviation: main() returns from several + error paths instead of having a single point of exit. The project forbids + goto, so an early return is the only way to abandon the conversion, and this + matches the style already used by the parameter and file open checks. */ + + /* Define the file handles. */ FILE *source_file; @@ -137,13 +151,52 @@ unsigned char *buffer; } +/* Close the files and release the ELF areas allocated by main(). This is called + from every exit path taken after the files have been opened, so it must + tolerate being called with resources that were never acquired. The areas it + releases are the file scope pointers declared above. */ + +static void converter_cleanup(void) +{ + + /* Determine if the source file is open. */ + if (source_file != NULL) + { + + /* Close it. */ + fclose(source_file); + source_file = NULL; + } + + /* Determine if the C array output file is open. */ + if (array_file != NULL) + { + + /* Close it. */ + fclose(array_file); + array_file = NULL; + } + + /* Release the ELF areas. Note that free() is defined to do nothing when it + is supplied a NULL pointer, so no test is required here. */ + free(program_header); + program_header = NULL; + free(section_header); + section_header = NULL; + free(section_string_table); + section_string_table = NULL; + free(code_section_array); + code_section_array = NULL; +} + + int main(int argc, char* argv[]) { unsigned long i, j, k; -unsigned long current_total; unsigned long address; unsigned long size; +unsigned long allocation_size; unsigned long column; unsigned char *code_buffer; unsigned long code_section_index; @@ -155,8 +208,11 @@ CODE_SECTION_ENTRY code_section_temp; { /* Print an error message out and wait for user key hit. */ - printf("module_to_c_array.exe - Copyright (c) Microsoft Corporation v5.8\n"); - printf("**** Error: invalid input parameter for module_to_c_array.exe **** \n"); + printf("module_to_c_array\n"); + printf("(c) 2024 Microsoft Corp\n"); + printf("(c) 2026 Eclipse ThreadX contributors\n"); + printf("v6.5.2.202603\n"); + printf("**** Error: invalid input parameter for module_to_c_array **** \n"); printf(" Command Line Should be:\n\n"); printf(" > module_to_c_array source_elf_file c_array_file <cr> \n\n"); return(1); @@ -189,11 +245,23 @@ CODE_SECTION_ENTRY code_section_temp; } /* Read the ELF header. */ - elf_object_read(0, &header, sizeof(header)); + if (elf_object_read(0, &header, sizeof(header)) != 0) + { + + /* Print an error message out. */ + printf("**** Error: read failed on the ELF header **** \n"); + + /* Close the files and release the ELF areas. */ + converter_cleanup(); + + return(6); + } fprintf(array_file, "/**************************** Module-to-C-array Utility *****************************************/\n"); fprintf(array_file, "/* */\n"); - fprintf(array_file, "/* Copyright (c) Microsoft Corporation Version 5.8, build date: 03-01-2018 */\n"); + fprintf(array_file, "/* Copyright (c) 2024 Microsoft Corp */\n"); + fprintf(array_file, "/* Copyright (c) 2026 Eclipse ThreadX contributors */\n"); + fprintf(array_file, "/* v6.5.2.202603 */\n"); fprintf(array_file, "/* */\n"); fprintf(array_file, "/************************************************************************************************/\n\n"); fprintf(array_file, "/* \n"); @@ -202,26 +270,127 @@ CODE_SECTION_ENTRY code_section_temp; fprintf(array_file, "*/\n\n"); /* Allocate memory for the program header(s). */ - program_header = malloc(sizeof(ELF_PROGRAM_HEADER)*header.elf_header_program_header_entries); + allocation_size = sizeof(ELF_PROGRAM_HEADER)*header.elf_header_program_header_entries; + program_header = malloc(allocation_size); + + /* Determine if the memory allocation was successful. Note that an empty area + is not an error, since malloc() is permitted to return NULL for it. */ + if ((program_header == NULL) && (allocation_size != 0)) + { + + /* Print an error message out. */ + printf("**** Error: memory allocation failed for the program header(s) **** \n"); + + /* Close the files and release the ELF areas. */ + converter_cleanup(); + + return(5); + } /* Read the program header(s). */ - elf_object_read(header.elf_header_program_header_offset, program_header, (sizeof(ELF_PROGRAM_HEADER)*header.elf_header_program_header_entries)); + if (elf_object_read(header.elf_header_program_header_offset, program_header, allocation_size) != 0) + { + + /* Print an error message out. */ + printf("**** Error: read failed on the program header(s) **** \n"); + + /* Close the files and release the ELF areas. */ + converter_cleanup(); + + return(6); + } /* Allocate memory for the section header(s). */ - section_header = malloc(sizeof(ELF_SECTION_HEADER)*header.elf_header_section_header_entries); + allocation_size = sizeof(ELF_SECTION_HEADER)*header.elf_header_section_header_entries; + section_header = malloc(allocation_size); + + /* Determine if the memory allocation was successful. */ + if ((section_header == NULL) && (allocation_size != 0)) + { + + /* Print an error message out. */ + printf("**** Error: memory allocation failed for the section header(s) **** \n"); + + /* Close the files and release the ELF areas. */ + converter_cleanup(); + + return(5); + } /* Read the section header(s). */ - elf_object_read(header.elf_header_section_header_offset, section_header, (sizeof(ELF_SECTION_HEADER)*header.elf_header_section_header_entries)); + if (elf_object_read(header.elf_header_section_header_offset, section_header, allocation_size) != 0) + { + /* Print an error message out. */ + printf("**** Error: read failed on the section header(s) **** \n"); + + /* Close the files and release the ELF areas. */ + converter_cleanup(); + + return(6); + } + + /* Determine if the section string table index supplied by the ELF header is + inside the section header area that was just read. */ + if (header.elf_header_section_string_index >= header.elf_header_section_header_entries) + { + + /* Print an error message out. */ + printf("**** Error: invalid section string table index in the ELF header **** \n"); + + /* Close the files and release the ELF areas. */ + converter_cleanup(); + + return(6); + } /* Alocate memory for the section string table. */ - section_string_table = malloc(section_header[header.elf_header_section_string_index].elf_section_header_size); + allocation_size = section_header[header.elf_header_section_string_index].elf_section_header_size; + section_string_table = malloc(allocation_size); + + /* Determine if the memory allocation was successful. */ + if ((section_string_table == NULL) && (allocation_size != 0)) + { + + /* Print an error message out. */ + printf("**** Error: memory allocation failed for the section string table **** \n"); + + /* Close the files and release the ELF areas. */ + converter_cleanup(); + + return(5); + } /* Read the section string table. */ - elf_object_read(section_header[header.elf_header_section_string_index].elf_section_header_offset, section_string_table, section_header[header.elf_header_section_string_index].elf_section_header_size); + if (elf_object_read(section_header[header.elf_header_section_string_index].elf_section_header_offset, section_string_table, allocation_size) != 0) + { + + /* Print an error message out. */ + printf("**** Error: read failed on the section string table **** \n"); + + /* Close the files and release the ELF areas. */ + converter_cleanup(); + + return(6); + } /* Allocate memory for the code section array. */ - code_section_array = malloc(sizeof(CODE_SECTION_ENTRY)*header.elf_header_section_header_entries); + allocation_size = sizeof(CODE_SECTION_ENTRY)*header.elf_header_section_header_entries; + code_section_array = malloc(allocation_size); + + /* Determine if the memory allocation was successful. */ + if ((code_section_array == NULL) && (allocation_size != 0)) + { + + /* Print an error message out. */ + printf("**** Error: memory allocation failed for the code section array **** \n"); + + /* Close the files and release the ELF areas. */ + converter_cleanup(); + + return(5); + } + code_section_index = 0; /* Print out the section header(s). */ @@ -272,9 +441,8 @@ CODE_SECTION_ENTRY code_section_temp; fprintf(array_file, "unsigned char module_code[] = {0x00};\n\n"); - /* Close files. */ - fclose(source_file); - fclose(array_file); + /* Close the files and release the ELF areas. */ + converter_cleanup(); return(4); } @@ -321,7 +489,7 @@ CODE_SECTION_ENTRY code_section_temp; /* Print out a character with a leading comma, except on the first character. */ if (column == 0) - fprintf(array_file, "/* 0x%08X */ 0x00", address); + fprintf(array_file, "/* 0x%08lX */ 0x00", address); else fprintf(array_file, ", 0x00"); @@ -342,9 +510,34 @@ CODE_SECTION_ENTRY code_section_temp; /* Now allocate memory for the code section. */ code_buffer = malloc(code_section_array[i].code_section_size); + /* Determine if the memory allocation was successful. */ + if (code_buffer == NULL) + { + + /* Print an error message out. */ + printf("**** Error: memory allocation failed for code section **** \n"); + + /* Close the files and release the ELF areas. */ + converter_cleanup(); + + return(5); + } + /* Read in the code area. */ j = code_section_array[i].code_section_index; - elf_object_read(section_header[j].elf_section_header_offset, code_buffer, code_section_array[i].code_section_size); + if (elf_object_read(section_header[j].elf_section_header_offset, code_buffer, code_section_array[i].code_section_size) != 0) + { + + /* Print an error message out. */ + printf("**** Error: read failed on a code section **** \n"); + + /* Release the code section buffer, then close the files and release + the ELF areas. */ + free(code_buffer); + converter_cleanup(); + + return(6); + } /* Write out the contents of this program area. */ size = code_section_array[i].code_section_size; @@ -356,7 +549,7 @@ CODE_SECTION_ENTRY code_section_temp; /* Print out a character with a leading comma, except on the first character. */ if (column == 0) - fprintf(array_file, "/* 0x%08X */ 0x%02X", address, (unsigned int) code_buffer[j]); + fprintf(array_file, "/* 0x%08lX */ 0x%02X", address, (unsigned int) code_buffer[j]); else fprintf(array_file, ", 0x%02X", (unsigned int) code_buffer[j]); @@ -390,14 +583,17 @@ CODE_SECTION_ENTRY code_section_temp; /* Move index into buffer. */ j++; } + + /* Release the code section buffer before the next section is read. */ + free(code_buffer); + code_buffer = NULL; } /* Finally, finish the C array containing the module code. */ fprintf(array_file, "};\n\n"); - /* Close files. */ - fclose(source_file); - fclose(array_file); + /* Close the files and release the ELF areas. */ + converter_cleanup(); return 0; } |
