summaryrefslogtreecommitdiff
path: root/ports_module/cortex_a7
diff options
context:
space:
mode:
Diffstat (limited to 'ports_module/cortex_a7')
-rw-r--r--ports_module/cortex_a7/ac5/example_build/build_threadx.bat3
-rw-r--r--ports_module/cortex_a7/ac5/inc/tx_port.h2
-rw-r--r--ports_module/cortex_a7/ac5/inc/txm_module_port.h44
-rw-r--r--ports_module/cortex_a7/ac5/module_manager/src/txm_module_manager_inside_data_check.c538
-rw-r--r--ports_module/cortex_a7/ac5/module_manager/src/txm_module_manager_mm_register_setup.c115
-rw-r--r--ports_module/cortex_a7/gnu/example_build/build_threadx.bat3
-rw-r--r--ports_module/cortex_a7/gnu/example_build/tx_initialize_low_level.S (renamed from ports_module/cortex_a7/gnu/example_build/tx_initialize_low_level.s)0
-rw-r--r--ports_module/cortex_a7/gnu/inc/tx_port.h2
-rw-r--r--ports_module/cortex_a7/gnu/inc/txm_module_port.h44
-rw-r--r--ports_module/cortex_a7/gnu/module_manager/src/tx_thread_context_restore.S (renamed from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_context_restore.s)0
-rw-r--r--ports_module/cortex_a7/gnu/module_manager/src/tx_thread_context_save.S (renamed from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_context_save.s)0
-rw-r--r--ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_context_restore.S (renamed from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_context_restore.s)0
-rw-r--r--ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_context_save.S (renamed from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_context_save.s)0
-rw-r--r--ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_nesting_end.S (renamed from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_nesting_end.s)0
-rw-r--r--ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_nesting_start.S (renamed from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_nesting_start.s)0
-rw-r--r--ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_control.S (renamed from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_control.s)0
-rw-r--r--ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_disable.S (renamed from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_disable.s)0
-rw-r--r--ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_restore.S (renamed from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_restore.s)0
-rw-r--r--ports_module/cortex_a7/gnu/module_manager/src/tx_thread_irq_nesting_end.S (renamed from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_irq_nesting_end.s)0
-rw-r--r--ports_module/cortex_a7/gnu/module_manager/src/tx_thread_irq_nesting_start.S (renamed from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_irq_nesting_start.s)0
-rw-r--r--ports_module/cortex_a7/gnu/module_manager/src/tx_thread_schedule.S (renamed from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_schedule.s)0
-rw-r--r--ports_module/cortex_a7/gnu/module_manager/src/tx_thread_stack_build.S (renamed from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_stack_build.s)0
-rw-r--r--ports_module/cortex_a7/gnu/module_manager/src/tx_thread_system_return.S (renamed from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_system_return.s)5
-rw-r--r--ports_module/cortex_a7/gnu/module_manager/src/tx_thread_vectored_context_save.S (renamed from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_vectored_context_save.s)0
-rw-r--r--ports_module/cortex_a7/gnu/module_manager/src/tx_timer_interrupt.S (renamed from ports_module/cortex_a7/gnu/module_manager/src/tx_timer_interrupt.s)0
-rw-r--r--ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_inside_data_check.c538
-rw-r--r--ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_mm_register_setup.c115
-rw-r--r--ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_thread_stack_build.S (renamed from ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_thread_stack_build.s)0
-rw-r--r--ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_user_mode_entry.S (renamed from ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_user_mode_entry.s)0
-rw-r--r--ports_module/cortex_a7/iar/example_build/sample_threadx_module_manager.ewp2
-rw-r--r--ports_module/cortex_a7/iar/example_build/tx.ewp5
-rw-r--r--ports_module/cortex_a7/iar/example_build/txm.ewp2
-rw-r--r--ports_module/cortex_a7/iar/inc/tx_port.h2
-rw-r--r--ports_module/cortex_a7/iar/inc/txm_module_port.h44
-rw-r--r--ports_module/cortex_a7/iar/module_manager/src/tx_iar.c9
-rw-r--r--ports_module/cortex_a7/iar/module_manager/src/tx_thread_system_return.s6
-rw-r--r--ports_module/cortex_a7/iar/module_manager/src/txm_module_manager_inside_data_check.c538
-rw-r--r--ports_module/cortex_a7/iar/module_manager/src/txm_module_manager_mm_register_setup.c115
38 files changed, 2073 insertions, 59 deletions
diff --git a/ports_module/cortex_a7/ac5/example_build/build_threadx.bat b/ports_module/cortex_a7/ac5/example_build/build_threadx.bat
index ea349e37..764992f0 100644
--- a/ports_module/cortex_a7/ac5/example_build/build_threadx.bat
+++ b/ports_module/cortex_a7/ac5/example_build/build_threadx.bat
@@ -223,6 +223,7 @@ armcc -g -O0 --cpu=cortex-a7.no_neon --fpu=softvfp -c -I../inc -I../../../../com
armcc -g -O0 --cpu=cortex-a7.no_neon --fpu=softvfp -c -I../inc -I../../../../common/inc -I../../../../common_modules/inc -I../../../../common_modules/module_manager/inc ../../../../common_modules/module_manager/src/txm_module_manager_properties_get.c
armcc -g -O0 --cpu=cortex-a7.no_neon --fpu=softvfp -c -I../inc -I../../../../common/inc -I../../../../common_modules/inc -I../../../../common_modules/module_manager/inc ../../../../common_modules/module_manager/src/txm_module_manager_queue_notify_trampoline.c
armcc -g -O0 --cpu=cortex-a7.no_neon --fpu=softvfp -c -I../inc -I../../../../common/inc -I../../../../common_modules/inc -I../../../../common_modules/module_manager/inc ../../../../common_modules/module_manager/src/txm_module_manager_semaphore_notify_trampoline.c
+armcc -g -O0 --cpu=cortex-a7.no_neon --fpu=softvfp -c -I../inc -I../../../../common/inc -I../../../../common_modules/inc -I../../../../common_modules/module_manager/inc ../module_manager/src/txm_module_manager_inside_data_check.c
armcc -g -O0 --cpu=cortex-a7.no_neon --fpu=softvfp -c -I../inc -I../../../../common/inc -I../../../../common_modules/inc -I../../../../common_modules/module_manager/inc ../module_manager/src/txm_module_manager_mm_register_setup.c
armcc -g -O0 --cpu=cortex-a7.no_neon --fpu=softvfp -c -I../inc -I../../../../common/inc -I../../../../common_modules/inc -I../../../../common_modules/module_manager/inc ../../../../common_modules/module_manager/src/txm_module_manager_start.c
armcc -g -O0 --cpu=cortex-a7.no_neon --fpu=softvfp -c -I../inc -I../../../../common/inc -I../../../../common_modules/inc -I../../../../common_modules/module_manager/inc ../../../../common_modules/module_manager/src/txm_module_manager_stop.c
@@ -278,7 +279,7 @@ armar -r tx.a txm_module_manager_in_place_load.o txm_module_manager_initialize.o
armar -r tx.a txm_module_manager_kernel_dispatch.o txm_module_manager_maximum_module_priority_set.o txm_module_manager_memory_fault_handler.o
armar -r tx.a txm_module_manager_memory_fault_notify.o txm_module_manager_memory_load.o txm_module_manager_object_pointer_get.o
armar -r tx.a txm_module_manager_object_pool_create.o txm_module_manager_queue_notify_trampoline.o txm_module_manager_semaphore_notify_trampoline.o
-armar -r tx.a txm_module_manager_mm_register_setup.o txm_module_manager_start.o txm_module_manager_stop.o
+armar -r tx.a txm_module_manager_inside_data_check.o txm_module_manager_mm_register_setup.o txm_module_manager_start.o txm_module_manager_stop.o
armar -r tx.a txm_module_manager_thread_create.o txm_module_manager_thread_notify_trampoline.o txm_module_manager_thread_reset.o
armar -r tx.a txm_module_manager_timer_notify_trampoline.o txm_module_manager_unload.o txm_module_manager_thread_stack_build.o
armar -r tx.a txm_module_manager_user_mode_entry.o
diff --git a/ports_module/cortex_a7/ac5/inc/tx_port.h b/ports_module/cortex_a7/ac5/inc/tx_port.h
index 21d8878b..42bea41b 100644
--- a/ports_module/cortex_a7/ac5/inc/tx_port.h
+++ b/ports_module/cortex_a7/ac5/inc/tx_port.h
@@ -336,7 +336,7 @@ void tx_thread_vfp_disable(void);
#ifdef TX_THREAD_INIT
CHAR _tx_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * ThreadX Cortex-A7/AC5 Version 6.5.1.202602a *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * ThreadX Cortex-A7/AC5 Version 6.5.2.202603 *";
#else
extern CHAR _tx_version_id[];
#endif
diff --git a/ports_module/cortex_a7/ac5/inc/txm_module_port.h b/ports_module/cortex_a7/ac5/inc/txm_module_port.h
index 1102a377..8953710f 100644
--- a/ports_module/cortex_a7/ac5/inc/txm_module_port.h
+++ b/ports_module/cortex_a7/ac5/inc/txm_module_port.h
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -240,6 +242,22 @@ The following extensions must also be defined in tx_port.h:
#define TXM_ADDRESS_TRANSLATION_FAULT_BIT 1
+/* Mask selecting the ASID field of CONTEXTIDR in the short-descriptor format. */
+#define TXM_CONTEXTIDR_ASID_MASK 0x000000FF
+
+/* Access intents understood by the module data range check. */
+#define TXM_MODULE_MANAGER_ACCESS_READ 0
+#define TXM_MODULE_MANAGER_ACCESS_WRITE 1
+
+/* Define the largest number of MMU pages a single caller-supplied range may span before
+ the data range check rejects it. This bounds the worst-case, module-controlled cost of
+ validating one kernel request, which keeps the check deterministic. The default permits
+ a 4 MB range. Applications that hand larger shared-memory ranges to kernel services can
+ define a larger value. */
+#ifndef TXM_MODULE_MANAGER_DATA_CHECK_MAX_PAGES
+#define TXM_MODULE_MANAGER_DATA_CHECK_MAX_PAGES 1024
+#endif
+
#define TXM_ASID_RESERVED 0xFFFFFFFF
#define TXM_MODULE_ASID_ERROR 0xF6
@@ -375,9 +393,26 @@ typedef struct TXM_MODULE_MANAGER_MEMORY_FAULT_INFO_STRUCT
/* Define the macros to perform port-specific checks when passing pointers to the kernel. */
-/* Define macro to make sure object is inside the module's data or shared memory. */
+/* Define macros to make sure a whole object is inside the module's data or shared memory.
+ The MMU is the authority for shared and external memory, so the check translates every
+ page the range touches with the requested unprivileged access. Passing the size and the
+ access intent through is what keeps the check honest: translating only the first address,
+ and only for reading, would accept a range that leaves the module's mapping partway
+ through, or a read-only range used as a kernel write destination. */
+#define TXM_MODULE_MANAGER_CHECK_INSIDE_DATA_READ(module_instance, obj_ptr, obj_size) \
+ _txm_module_manager_inside_data_check(module_instance, (ALIGN_TYPE) (obj_ptr), (ULONG) (obj_size), TXM_MODULE_MANAGER_ACCESS_READ)
+
+#define TXM_MODULE_MANAGER_CHECK_INSIDE_DATA_WRITE(module_instance, obj_ptr, obj_size) \
+ _txm_module_manager_inside_data_check(module_instance, (ALIGN_TYPE) (obj_ptr), (ULONG) (obj_size), TXM_MODULE_MANAGER_ACCESS_WRITE)
+
+/* The unqualified check keeps its historical name and takes the stricter write intent. */
#define TXM_MODULE_MANAGER_CHECK_INSIDE_DATA(module_instance, obj_ptr, obj_size) \
- _txm_module_manager_inside_data_check((ULONG) obj_ptr)
+ TXM_MODULE_MANAGER_CHECK_INSIDE_DATA_WRITE(module_instance, obj_ptr, obj_size)
+
+/* Negating the inside check would report a range that only partly reaches into the module
+ as being outside it, so the outside direction gets its own check. */
+#define TXM_MODULE_MANAGER_CHECK_OUTSIDE_DATA(module_instance, obj_ptr, obj_size) \
+ _txm_module_manager_outside_data_check(module_instance, (ALIGN_TYPE) (obj_ptr), (ULONG) (obj_size))
/* Define some internal prototypes to this module port. */
@@ -397,7 +432,10 @@ UINT _txm_module_manager_mm_initialize(VOID);
VOID _txm_module_manager_mm_register_setup(TXM_MODULE_INSTANCE *module_instance); \
VOID _txm_level2_page_clear(TXM_MODULE_INSTANCE *module_instance); \
VOID _txm_module_manager_remove_asid(TXM_MODULE_INSTANCE *module_instance); \
-UINT _txm_module_manager_inside_data_check(ULONG pointer);
+UINT _txm_module_manager_inside_data_check(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE obj_ptr, ULONG obj_size, UINT write_request); \
+UINT _txm_module_manager_outside_data_check(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE obj_ptr, ULONG obj_size); \
+UINT _txm_module_manager_address_probe(ULONG address, UINT write_request); \
+ULONG _txm_module_manager_current_asid_get(VOID);
#define TXM_MODULE_MANAGER_VERSION_ID \
CHAR _txm_module_manager_version_id[] = \
diff --git a/ports_module/cortex_a7/ac5/module_manager/src/txm_module_manager_inside_data_check.c b/ports_module/cortex_a7/ac5/module_manager/src/txm_module_manager_inside_data_check.c
new file mode 100644
index 00000000..e7ebf262
--- /dev/null
+++ b/ports_module/cortex_a7/ac5/module_manager/src/txm_module_manager_inside_data_check.c
@@ -0,0 +1,538 @@
+/***************************************************************************
+ * 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.
+ *
+ * AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
+ * The AI-generated portions may be considered public domain (CC0-1.0)
+ * and not subject to the project's licence. The human contributor has
+ * reviewed and verified that the code is correct.
+ *
+ * SPDX-License-Identifier: MIT and CC0-1.0
+ **************************************************************************/
+
+
+/**************************************************************************/
+/**************************************************************************/
+/** */
+/** ThreadX Component */
+/** */
+/** Module Manager */
+/** */
+/**************************************************************************/
+/**************************************************************************/
+
+#define TX_SOURCE_CODE
+
+#include "tx_api.h"
+#include "txm_module.h"
+
+
+/* Define the ways a caller-supplied range can sit relative to the module's data region. */
+
+#define TXM_MODULE_DATA_WINDOW_OUTSIDE 0 /* No byte touches the data mapping. */
+#define TXM_MODULE_DATA_WINDOW_CONTAINED 1 /* Every byte is recorded module data. */
+#define TXM_MODULE_DATA_WINDOW_PARTIAL 2 /* Some, but not all, bytes are. */
+
+
+/* Define the page mask derived from the smallest MMU page this port maps. */
+
+#define TXM_MODULE_PAGE_OFFSET_MASK ((ALIGN_TYPE) (TXM_MODULE_MEMORY_ALIGNMENT - 1))
+#define TXM_MODULE_PAGE_BASE_MASK (~TXM_MODULE_PAGE_OFFSET_MASK)
+
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _txm_module_manager_range_end_get Cortex-A7/MMU/AC5 */
+/* 6.5.0 */
+/* AUTHOR */
+/* */
+/* Eclipse ThreadX contributors */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function derives the inclusive address of the last byte of a */
+/* caller-supplied range. An empty range is rejected, matching the */
+/* portable check macros, and so is a range whose last byte is not */
+/* representable, so that no caller ever works from a wrapped address. */
+/* */
+/* INPUT */
+/* */
+/* obj_ptr Address of the first byte */
+/* obj_size Size of the range in bytes */
+/* last_byte Destination for the last address */
+/* */
+/* OUTPUT */
+/* */
+/* TX_TRUE if the range is non-empty and does not wrap */
+/* */
+/* CALLS */
+/* */
+/* None */
+/* */
+/* CALLED BY */
+/* */
+/* _txm_module_manager_inside_data_check */
+/* _txm_module_manager_outside_data_check */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* 08-24-2026 Eclipse ThreadX Initial Version 6.5.0 */
+/* contributors */
+/* */
+/**************************************************************************/
+static UINT _txm_module_manager_range_end_get(ALIGN_TYPE obj_ptr, ULONG obj_size, ALIGN_TYPE *last_byte)
+{
+
+ALIGN_TYPE span;
+ALIGN_TYPE highest;
+UINT status;
+
+
+ /* Assume the range cannot be used until proven otherwise. */
+ status = TX_FALSE;
+
+ /* An empty range has no last byte and is rejected, just as the portable macros do. */
+ if (obj_size != ((ULONG) 0))
+ {
+
+ /* Work with the inclusive span so that a range reaching the top of the address
+ space stays representable. */
+ span = ((ALIGN_TYPE) obj_size) - ((ALIGN_TYPE) 1);
+
+ /* Determine the highest first byte this span can start from. */
+ highest = (~((ALIGN_TYPE) 0)) - span;
+
+ /* Determine if the range would run past the end of the address space. */
+ if (obj_ptr <= highest)
+ {
+
+ /* Record the last byte of the range. */
+ *last_byte = obj_ptr + span;
+
+ /* The range is usable. */
+ status = TX_TRUE;
+ }
+ }
+
+ /* Return the completion status. */
+ return(status);
+}
+
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _txm_module_manager_data_window_classify Cortex-A7/MMU/AC5 */
+/* 6.5.0 */
+/* AUTHOR */
+/* */
+/* Eclipse ThreadX contributors */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function reports how a range sits relative to the module's own */
+/* data region. The module manager records that region exactly, while */
+/* the MMU can only map it a page at a time, so the mapping may reach */
+/* past the recorded end. The recorded region therefore stays the */
+/* authority for the whole mapped window: a range that leaves the */
+/* recorded region but still lands in the window is reported as */
+/* partial, and its caller rejects it rather than asking the MMU, */
+/* which would accept the rounding slack. */
+/* */
+/* INPUT */
+/* */
+/* module_instance Pointer to module instance */
+/* first_byte Address of the first byte */
+/* last_byte Address of the last byte */
+/* */
+/* OUTPUT */
+/* */
+/* One of the TXM_MODULE_DATA_WINDOW_* classifications */
+/* */
+/* CALLS */
+/* */
+/* None */
+/* */
+/* CALLED BY */
+/* */
+/* _txm_module_manager_inside_data_check */
+/* _txm_module_manager_outside_data_check */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* 08-24-2026 Eclipse ThreadX Initial Version 6.5.0 */
+/* contributors */
+/* */
+/**************************************************************************/
+static UINT _txm_module_manager_data_window_classify(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE first_byte, ALIGN_TYPE last_byte)
+{
+
+ALIGN_TYPE data_start;
+ALIGN_TYPE data_end;
+ALIGN_TYPE window_start;
+ALIGN_TYPE window_end;
+UINT window;
+
+
+ /* Pick up the recorded data region. The end address is inclusive. */
+ data_start = (ALIGN_TYPE) module_instance -> txm_module_instance_data_start;
+ data_end = (ALIGN_TYPE) module_instance -> txm_module_instance_data_end;
+
+ /* Determine if the module has a usable data region at all. */
+ if (data_start > data_end)
+ {
+
+ /* An unset or inverted region owns nothing. */
+ window = TXM_MODULE_DATA_WINDOW_OUTSIDE;
+ }
+ else
+ {
+
+ /* Widen the region to the pages the MMU actually maps for it. */
+ window_start = data_start & TXM_MODULE_PAGE_BASE_MASK;
+ window_end = data_end | TXM_MODULE_PAGE_OFFSET_MASK;
+
+ /* Determine if every byte is recorded module data. */
+ if ((first_byte >= data_start) && (last_byte <= data_end))
+ {
+
+ /* The whole range belongs to the module. */
+ window = TXM_MODULE_DATA_WINDOW_CONTAINED;
+ }
+ else if ((first_byte <= window_end) && (last_byte >= window_start))
+ {
+
+ /* The range overlaps the mapped window without being contained by the
+ recorded region, so it leaves the module's data partway through. */
+ window = TXM_MODULE_DATA_WINDOW_PARTIAL;
+ }
+ else
+ {
+
+ /* The range lies elsewhere, so only the MMU can speak for it. */
+ window = TXM_MODULE_DATA_WINDOW_OUTSIDE;
+ }
+ }
+
+ /* Return the classification. */
+ return(window);
+}
+
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _txm_module_manager_page_walk Cortex-A7/MMU/AC5 */
+/* 6.5.0 */
+/* AUTHOR */
+/* */
+/* Eclipse ThreadX contributors */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function translates every page a range touches and reports */
+/* whether all of them answered as expected. The walk stops at the */
+/* first page that disagrees, and a range spanning more pages than */
+/* the configured maximum is refused so that one kernel request can */
+/* never impose unbounded work. */
+/* */
+/* INPUT */
+/* */
+/* first_byte Address of the first byte */
+/* last_byte Address of the last byte */
+/* write_request Access intent to translate for */
+/* expected Result every page must return */
+/* */
+/* OUTPUT */
+/* */
+/* TX_TRUE if every page answered as expected */
+/* */
+/* CALLS */
+/* */
+/* _txm_module_manager_address_probe */
+/* */
+/* CALLED BY */
+/* */
+/* _txm_module_manager_inside_data_check */
+/* _txm_module_manager_outside_data_check */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* 08-24-2026 Eclipse ThreadX Initial Version 6.5.0 */
+/* contributors */
+/* */
+/**************************************************************************/
+static UINT _txm_module_manager_page_walk(ALIGN_TYPE first_byte, ALIGN_TYPE last_byte, UINT write_request, UINT expected)
+{
+
+ALIGN_TYPE first_page;
+ALIGN_TYPE last_page;
+ALIGN_TYPE page;
+ULONG pages;
+ULONG index;
+UINT matched;
+
+
+ /* Reduce the range to the pages it touches. */
+ first_page = first_byte & TXM_MODULE_PAGE_BASE_MASK;
+ last_page = last_byte & TXM_MODULE_PAGE_BASE_MASK;
+
+ /* Count them. Both addresses are page-aligned, so the division is exact. */
+ pages = ((ULONG) ((last_page - first_page) / ((ALIGN_TYPE) TXM_MODULE_MEMORY_ALIGNMENT))) + ((ULONG) 1);
+
+ /* Determine if the range is longer than this port is willing to translate. */
+ if (pages > ((ULONG) TXM_MODULE_MANAGER_DATA_CHECK_MAX_PAGES))
+ {
+
+ /* Refuse rather than spend unbounded time in a kernel request. Refusing is safe
+ for both callers: neither can then claim the range is inside or outside. */
+ matched = TX_FALSE;
+ }
+ else
+ {
+
+ /* Assume every page agrees until one does not. */
+ matched = TX_TRUE;
+ index = (ULONG) 0;
+
+ /* Translate each page in turn, stopping as soon as the answer is settled. The
+ address is rebuilt from the index so that the walk cannot wrap past the top
+ page of the address space. */
+ while ((index < pages) && (matched == TX_TRUE))
+ {
+
+ /* Build the address of this page. */
+ page = first_page + (((ALIGN_TYPE) index) * ((ALIGN_TYPE) TXM_MODULE_MEMORY_ALIGNMENT));
+
+ /* Ask the MMU whether the module may reach this page with the requested access. */
+ if (_txm_module_manager_address_probe((ULONG) page, write_request) != expected)
+ {
+
+ /* This page disagrees, so the range as a whole does. */
+ matched = TX_FALSE;
+ }
+
+ /* Move to the next page. */
+ index++;
+ }
+ }
+
+ /* Return whether the whole range answered as expected. */
+ return(matched);
+}
+
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _txm_module_manager_inside_data_check Cortex-A7/MMU/AC5 */
+/* 6.5.0 */
+/* AUTHOR */
+/* */
+/* Eclipse ThreadX contributors */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function determines whether every byte of a caller-supplied */
+/* range lies inside the module's data or shared memory and is */
+/* reachable by the module with the requested access. The module's own */
+/* data region is answered from the manager's own records, which are */
+/* exact. Anything else is answered by translating every page the */
+/* range touches, because this port keeps no record of the shared and */
+/* external regions the application maps into the module. */
+/* */
+/* INPUT */
+/* */
+/* module_instance Pointer to module instance */
+/* obj_ptr Address of the first byte */
+/* obj_size Size of the range in bytes */
+/* write_request TXM_MODULE_MANAGER_ACCESS_READ or */
+/* TXM_MODULE_MANAGER_ACCESS_WRITE */
+/* */
+/* OUTPUT */
+/* */
+/* TX_TRUE if the whole range is reachable with that access */
+/* */
+/* CALLS */
+/* */
+/* _txm_module_manager_range_end_get */
+/* _txm_module_manager_current_asid_get */
+/* _txm_module_manager_data_window_classify */
+/* _txm_module_manager_page_walk */
+/* */
+/* CALLED BY */
+/* */
+/* TXM_MODULE_MANAGER_CHECK_INSIDE_DATA_READ */
+/* TXM_MODULE_MANAGER_CHECK_INSIDE_DATA_WRITE */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* 08-24-2026 Eclipse ThreadX Initial Version 6.5.0 */
+/* contributors */
+/* */
+/**************************************************************************/
+UINT _txm_module_manager_inside_data_check(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE obj_ptr, ULONG obj_size, UINT write_request)
+{
+
+ALIGN_TYPE last_byte;
+UINT window;
+UINT status;
+
+
+ /* Assume the range is not usable until every condition is met. */
+ status = TX_FALSE;
+
+ /* A range can only belong to a module that exists. */
+ if (module_instance != TX_NULL)
+ {
+
+ /* Determine the last byte, rejecting empty and wrapping ranges. */
+ if (_txm_module_manager_range_end_get(obj_ptr, obj_size, &last_byte) == TX_TRUE)
+ {
+
+ /* Address translation answers for whichever context is loaded, so it can only
+ be trusted while the requesting module's context is the loaded one. */
+ if (_txm_module_manager_current_asid_get() == (module_instance -> txm_module_instance_asid))
+ {
+
+ /* Place the range relative to the module's own data region. */
+ window = _txm_module_manager_data_window_classify(module_instance, obj_ptr, last_byte);
+
+ if (window == ((UINT) TXM_MODULE_DATA_WINDOW_CONTAINED))
+ {
+
+ /* The module's data region is mapped for unprivileged reading and
+ writing, so both intents are satisfied without translating. */
+ status = TX_TRUE;
+ }
+ else if (window == ((UINT) TXM_MODULE_DATA_WINDOW_OUTSIDE))
+ {
+
+ /* Shared or external memory: every page must grant the access. */
+ status = _txm_module_manager_page_walk(obj_ptr, last_byte, write_request, TX_TRUE);
+ }
+ else
+ {
+
+ /* The range leaves the module's data partway through. */
+ status = TX_FALSE;
+ }
+ }
+ }
+ }
+
+ /* Return the completion status. */
+ return(status);
+}
+
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _txm_module_manager_outside_data_check Cortex-A7/MMU/AC5 */
+/* 6.5.0 */
+/* AUTHOR */
+/* */
+/* Eclipse ThreadX contributors */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function determines whether no byte of a caller-supplied range */
+/* is reachable by the module. It is deliberately not the negation of */
+/* the inside check: a range that reaches into the module's memory */
+/* only partway is inside neither answer, and reporting it as outside */
+/* would let it pass as a kernel object. */
+/* */
+/* INPUT */
+/* */
+/* module_instance Pointer to module instance */
+/* obj_ptr Address of the first byte */
+/* obj_size Size of the range in bytes */
+/* */
+/* OUTPUT */
+/* */
+/* TX_TRUE if no byte of the range is reachable by the module */
+/* */
+/* CALLS */
+/* */
+/* _txm_module_manager_range_end_get */
+/* _txm_module_manager_current_asid_get */
+/* _txm_module_manager_data_window_classify */
+/* _txm_module_manager_page_walk */
+/* */
+/* CALLED BY */
+/* */
+/* TXM_MODULE_MANAGER_CHECK_OUTSIDE_DATA */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* 08-24-2026 Eclipse ThreadX Initial Version 6.5.0 */
+/* contributors */
+/* */
+/**************************************************************************/
+UINT _txm_module_manager_outside_data_check(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE obj_ptr, ULONG obj_size)
+{
+
+ALIGN_TYPE last_byte;
+UINT window;
+UINT status;
+
+
+ /* Assume the range is not provably outside the module. */
+ status = TX_FALSE;
+
+ /* A range can only be placed against a module that exists. */
+ if (module_instance != TX_NULL)
+ {
+
+ /* Determine the last byte, rejecting empty and wrapping ranges. */
+ if (_txm_module_manager_range_end_get(obj_ptr, obj_size, &last_byte) == TX_TRUE)
+ {
+
+ /* Address translation answers for whichever context is loaded, so it can only
+ be trusted while the requesting module's context is the loaded one. */
+ if (_txm_module_manager_current_asid_get() == (module_instance -> txm_module_instance_asid))
+ {
+
+ /* Place the range relative to the module's own data region. */
+ window = _txm_module_manager_data_window_classify(module_instance, obj_ptr, last_byte);
+
+ if (window == ((UINT) TXM_MODULE_DATA_WINDOW_OUTSIDE))
+ {
+
+ /* Clear of the module's data region, so the remaining question is
+ whether any page of it is shared or external memory. */
+ status = _txm_module_manager_page_walk(obj_ptr, last_byte, TXM_MODULE_MANAGER_ACCESS_READ, TX_FALSE);
+ }
+ else
+ {
+
+ /* The range touches the module's data region. */
+ status = TX_FALSE;
+ }
+ }
+ }
+ }
+
+ /* Return the completion status. */
+ return(status);
+}
diff --git a/ports_module/cortex_a7/ac5/module_manager/src/txm_module_manager_mm_register_setup.c b/ports_module/cortex_a7/ac5/module_manager/src/txm_module_manager_mm_register_setup.c
index bdaa548d..b5166df3 100644
--- a/ports_module/cortex_a7/ac5/module_manager/src/txm_module_manager_mm_register_setup.c
+++ b/ports_module/cortex_a7/ac5/module_manager/src/txm_module_manager_mm_register_setup.c
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -35,24 +37,34 @@ extern ULONG _txm_ttbr1_page_table[TXM_MAXIMUM_MODULES][TXM_MASTER_PAGE_TABLE_EN
/* */
/* FUNCTION RELEASE */
/* */
-/* _txm_module_manager_inside_data_check Cortex-A7/MMU/AC5 */
-/* 6.1 */
+/* _txm_module_manager_address_probe Cortex-A7/MMU/AC5 */
+/* 6.5.0 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
+/* Eclipse ThreadX contributors */
/* */
/* DESCRIPTION */
/* */
-/* This function determines if pointer is within the module's data or */
-/* shared memory. */
+/* This function asks the MMU whether unprivileged code running in the */
+/* currently loaded translation context may reach one address with the */
+/* requested access. Reading and writing are asked separately, because */
+/* a module's code and its read-only shared memory translate for */
+/* reading while a kernel service writing to them would fault or, */
+/* worse, succeed from privileged mode. */
+/* */
+/* This answers for one address only. Callers that hold a range must */
+/* ask about every page the range touches. */
/* */
/* INPUT */
/* */
-/* pointer Data pointer */
+/* address Address to translate */
+/* write_request TXM_MODULE_MANAGER_ACCESS_READ or */
+/* TXM_MODULE_MANAGER_ACCESS_WRITE */
/* */
/* OUTPUT */
/* */
-/* Completion Status */
+/* TX_TRUE if the translation granted the requested access */
/* */
/* CALLS */
/* */
@@ -60,17 +72,40 @@ extern ULONG _txm_ttbr1_page_table[TXM_MAXIMUM_MODULES][TXM_MASTER_PAGE_TABLE_EN
/* */
/* CALLED BY */
/* */
-/* TXM_MODULE_MANAGER_DATA_POINTER_CHECK */
+/* _txm_module_manager_page_walk */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* 03-08-2023 Scott Larson Initial Version 6.2.1 */
+/* 08-24-2026 Eclipse ThreadX Added the write intent and */
+/* contributors moved range handling to */
+/* the caller, resulting in */
+/* version 6.5.0 */
/* */
/**************************************************************************/
-UINT _txm_module_manager_inside_data_check(ULONG pointer)
+UINT _txm_module_manager_address_probe(ULONG address, UINT write_request)
{
-ULONG translation;
+ULONG translation;
+
+
+ /* Determine which unprivileged access the caller needs. */
+ if (write_request == ((UINT) TXM_MODULE_MANAGER_ACCESS_WRITE))
+ {
+
+ /* ATS1CUW operation on address supplied in address, Stage 1 unprivileged write. */
+ __asm("MCR p15, 0, address, c7, c8, 3");
+ }
+ else
+ {
+
+ /* ATS1CUR operation on address supplied in address, Stage 1 unprivileged read. */
+ __asm("MCR p15, 0, address, c7, c8, 2");
+ }
- /* ATS1CUR operation on address supplied in pointer, Stage 1 unprivileged read. */
- __asm("MCR p15, 0, pointer, c7, c8, 2");
- __asm("ISB"); /* Ensure completion of the MCR write to CP15. */
+ __asm("ISB"); /* Ensure completion of the MCR write to CP15. */
__asm("MRC p15, 0, translation, c7, c4, 0"); /* Read result from 32-bit PAR into translation. */
if (translation & TXM_ADDRESS_TRANSLATION_FAULT_BIT)
@@ -86,6 +121,62 @@ ULONG translation;
/* */
/* FUNCTION RELEASE */
/* */
+/* _txm_module_manager_current_asid_get Cortex-A7/MMU/AC5 */
+/* 6.5.0 */
+/* AUTHOR */
+/* */
+/* Eclipse ThreadX contributors */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function returns the ASID of the translation context that is */
+/* currently loaded. Address translation always answers for that */
+/* context, so a caller validating a pointer on behalf of a module */
+/* must confirm that the loaded context is that module's before it */
+/* believes the answer. */
+/* */
+/* INPUT */
+/* */
+/* None */
+/* */
+/* OUTPUT */
+/* */
+/* ASID of the currently loaded translation context */
+/* */
+/* CALLS */
+/* */
+/* None */
+/* */
+/* CALLED BY */
+/* */
+/* _txm_module_manager_inside_data_check */
+/* _txm_module_manager_outside_data_check */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* 08-24-2026 Eclipse ThreadX Initial Version 6.5.0 */
+/* contributors */
+/* */
+/**************************************************************************/
+ULONG _txm_module_manager_current_asid_get(VOID)
+{
+
+ULONG contextidr;
+
+
+ /* Read CONTEXTIDR, whose low byte holds the ASID in the short-descriptor format. */
+ __asm("MRC p15, 0, contextidr, c13, c0, 1");
+
+ return(contextidr & TXM_CONTEXTIDR_ASID_MASK);
+}
+
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
/* _txm_module_manager_assign_asid Cortex-A7/MMU/AC5 */
/* 6.1 */
/* AUTHOR */
diff --git a/ports_module/cortex_a7/gnu/example_build/build_threadx.bat b/ports_module/cortex_a7/gnu/example_build/build_threadx.bat
index 0e094b38..3e687587 100644
--- a/ports_module/cortex_a7/gnu/example_build/build_threadx.bat
+++ b/ports_module/cortex_a7/gnu/example_build/build_threadx.bat
@@ -223,6 +223,7 @@ arm-none-eabi-gcc -c -g -O0 -mcpu=cortex-a7 -mfloat-abi=hard -mfpu=neon-vfpv4 -m
arm-none-eabi-gcc -c -g -O0 -mcpu=cortex-a7 -mfloat-abi=hard -mfpu=neon-vfpv4 -marm -mthumb-interwork -DTX_ENABLE_VFP_SUPPORT -I../inc -I../../../../common/inc -I../../../../common_modules/inc -I../../../../common_modules/module_manager/inc ../../../../common_modules/module_manager/src/txm_module_manager_properties_get.c
arm-none-eabi-gcc -c -g -O0 -mcpu=cortex-a7 -mfloat-abi=hard -mfpu=neon-vfpv4 -marm -mthumb-interwork -DTX_ENABLE_VFP_SUPPORT -I../inc -I../../../../common/inc -I../../../../common_modules/inc -I../../../../common_modules/module_manager/inc ../../../../common_modules/module_manager/src/txm_module_manager_queue_notify_trampoline.c
arm-none-eabi-gcc -c -g -O0 -mcpu=cortex-a7 -mfloat-abi=hard -mfpu=neon-vfpv4 -marm -mthumb-interwork -DTX_ENABLE_VFP_SUPPORT -I../inc -I../../../../common/inc -I../../../../common_modules/inc -I../../../../common_modules/module_manager/inc ../../../../common_modules/module_manager/src/txm_module_manager_semaphore_notify_trampoline.c
+arm-none-eabi-gcc -c -g -O0 -mcpu=cortex-a7 -mfloat-abi=hard -mfpu=neon-vfpv4 -marm -mthumb-interwork -DTX_ENABLE_VFP_SUPPORT -I../inc -I../../../../common/inc -I../../../../common_modules/inc -I../../../../common_modules/module_manager/inc ../module_manager/src/txm_module_manager_inside_data_check.c
arm-none-eabi-gcc -c -g -O0 -mcpu=cortex-a7 -mfloat-abi=hard -mfpu=neon-vfpv4 -marm -mthumb-interwork -DTX_ENABLE_VFP_SUPPORT -I../inc -I../../../../common/inc -I../../../../common_modules/inc -I../../../../common_modules/module_manager/inc ../module_manager/src/txm_module_manager_mm_register_setup.c
arm-none-eabi-gcc -c -g -O0 -mcpu=cortex-a7 -mfloat-abi=hard -mfpu=neon-vfpv4 -marm -mthumb-interwork -DTX_ENABLE_VFP_SUPPORT -I../inc -I../../../../common/inc -I../../../../common_modules/inc -I../../../../common_modules/module_manager/inc ../../../../common_modules/module_manager/src/txm_module_manager_start.c
arm-none-eabi-gcc -c -g -O0 -mcpu=cortex-a7 -mfloat-abi=hard -mfpu=neon-vfpv4 -marm -mthumb-interwork -DTX_ENABLE_VFP_SUPPORT -I../inc -I../../../../common/inc -I../../../../common_modules/inc -I../../../../common_modules/module_manager/inc ../../../../common_modules/module_manager/src/txm_module_manager_stop.c
@@ -278,7 +279,7 @@ arm-none-eabi-ar -r tx.a txm_module_manager_in_place_load.o txm_module_manager_i
arm-none-eabi-ar -r tx.a txm_module_manager_kernel_dispatch.o txm_module_manager_maximum_module_priority_set.o txm_module_manager_memory_fault_handler.o
arm-none-eabi-ar -r tx.a txm_module_manager_memory_fault_notify.o txm_module_manager_memory_load.o txm_module_manager_object_pointer_get.o
arm-none-eabi-ar -r tx.a txm_module_manager_object_pool_create.o txm_module_manager_queue_notify_trampoline.o txm_module_manager_semaphore_notify_trampoline.o
-arm-none-eabi-ar -r tx.a txm_module_manager_mm_register_setup.o txm_module_manager_start.o txm_module_manager_stop.o
+arm-none-eabi-ar -r tx.a txm_module_manager_inside_data_check.o txm_module_manager_mm_register_setup.o txm_module_manager_start.o txm_module_manager_stop.o
arm-none-eabi-ar -r tx.a txm_module_manager_thread_create.o txm_module_manager_thread_notify_trampoline.o txm_module_manager_thread_reset.o
arm-none-eabi-ar -r tx.a txm_module_manager_timer_notify_trampoline.o txm_module_manager_unload.o txm_module_manager_thread_stack_build.o
arm-none-eabi-ar -r tx.a txm_module_manager_user_mode_entry.o
diff --git a/ports_module/cortex_a7/gnu/example_build/tx_initialize_low_level.s b/ports_module/cortex_a7/gnu/example_build/tx_initialize_low_level.S
index 0c267ac6..0c267ac6 100644
--- a/ports_module/cortex_a7/gnu/example_build/tx_initialize_low_level.s
+++ b/ports_module/cortex_a7/gnu/example_build/tx_initialize_low_level.S
diff --git a/ports_module/cortex_a7/gnu/inc/tx_port.h b/ports_module/cortex_a7/gnu/inc/tx_port.h
index 5475ab4a..8d3b88eb 100644
--- a/ports_module/cortex_a7/gnu/inc/tx_port.h
+++ b/ports_module/cortex_a7/gnu/inc/tx_port.h
@@ -321,7 +321,7 @@ void tx_thread_vfp_disable(void);
#ifdef TX_THREAD_INIT
CHAR _tx_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * ThreadX ARMv7-A Version 6.5.1.202602a *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * ThreadX ARMv7-A Version 6.5.2.202603 *";
#else
extern CHAR _tx_version_id[];
#endif
diff --git a/ports_module/cortex_a7/gnu/inc/txm_module_port.h b/ports_module/cortex_a7/gnu/inc/txm_module_port.h
index 9cd5a280..bfb04475 100644
--- a/ports_module/cortex_a7/gnu/inc/txm_module_port.h
+++ b/ports_module/cortex_a7/gnu/inc/txm_module_port.h
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -240,6 +242,22 @@ The following extensions must also be defined in tx_port.h:
#define TXM_ADDRESS_TRANSLATION_FAULT_BIT 1
+/* Mask selecting the ASID field of CONTEXTIDR in the short-descriptor format. */
+#define TXM_CONTEXTIDR_ASID_MASK 0x000000FF
+
+/* Access intents understood by the module data range check. */
+#define TXM_MODULE_MANAGER_ACCESS_READ 0
+#define TXM_MODULE_MANAGER_ACCESS_WRITE 1
+
+/* Define the largest number of MMU pages a single caller-supplied range may span before
+ the data range check rejects it. This bounds the worst-case, module-controlled cost of
+ validating one kernel request, which keeps the check deterministic. The default permits
+ a 4 MB range. Applications that hand larger shared-memory ranges to kernel services can
+ define a larger value. */
+#ifndef TXM_MODULE_MANAGER_DATA_CHECK_MAX_PAGES
+#define TXM_MODULE_MANAGER_DATA_CHECK_MAX_PAGES 1024
+#endif
+
#define TXM_ASID_RESERVED 0xFFFFFFFF
#define TXM_MODULE_ASID_ERROR 0xF6
@@ -375,9 +393,26 @@ typedef struct TXM_MODULE_MANAGER_MEMORY_FAULT_INFO_STRUCT
/* Define the macros to perform port-specific checks when passing pointers to the kernel. */
-/* Define macro to make sure object is inside the module's data or shared memory. */
+/* Define macros to make sure a whole object is inside the module's data or shared memory.
+ The MMU is the authority for shared and external memory, so the check translates every
+ page the range touches with the requested unprivileged access. Passing the size and the
+ access intent through is what keeps the check honest: translating only the first address,
+ and only for reading, would accept a range that leaves the module's mapping partway
+ through, or a read-only range used as a kernel write destination. */
+#define TXM_MODULE_MANAGER_CHECK_INSIDE_DATA_READ(module_instance, obj_ptr, obj_size) \
+ _txm_module_manager_inside_data_check(module_instance, (ALIGN_TYPE) (obj_ptr), (ULONG) (obj_size), TXM_MODULE_MANAGER_ACCESS_READ)
+
+#define TXM_MODULE_MANAGER_CHECK_INSIDE_DATA_WRITE(module_instance, obj_ptr, obj_size) \
+ _txm_module_manager_inside_data_check(module_instance, (ALIGN_TYPE) (obj_ptr), (ULONG) (obj_size), TXM_MODULE_MANAGER_ACCESS_WRITE)
+
+/* The unqualified check keeps its historical name and takes the stricter write intent. */
#define TXM_MODULE_MANAGER_CHECK_INSIDE_DATA(module_instance, obj_ptr, obj_size) \
- _txm_module_manager_inside_data_check((ULONG) obj_ptr)
+ TXM_MODULE_MANAGER_CHECK_INSIDE_DATA_WRITE(module_instance, obj_ptr, obj_size)
+
+/* Negating the inside check would report a range that only partly reaches into the module
+ as being outside it, so the outside direction gets its own check. */
+#define TXM_MODULE_MANAGER_CHECK_OUTSIDE_DATA(module_instance, obj_ptr, obj_size) \
+ _txm_module_manager_outside_data_check(module_instance, (ALIGN_TYPE) (obj_ptr), (ULONG) (obj_size))
/* Define some internal prototypes to this module port. */
@@ -397,7 +432,10 @@ UINT _txm_module_manager_mm_initialize(VOID);
VOID _txm_module_manager_mm_register_setup(TXM_MODULE_INSTANCE *module_instance); \
VOID _txm_level2_page_clear(TXM_MODULE_INSTANCE *module_instance); \
VOID _txm_module_manager_remove_asid(TXM_MODULE_INSTANCE *module_instance); \
-UINT _txm_module_manager_inside_data_check(ULONG pointer);
+UINT _txm_module_manager_inside_data_check(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE obj_ptr, ULONG obj_size, UINT write_request); \
+UINT _txm_module_manager_outside_data_check(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE obj_ptr, ULONG obj_size); \
+UINT _txm_module_manager_address_probe(ULONG address, UINT write_request); \
+ULONG _txm_module_manager_current_asid_get(VOID);
#define TXM_MODULE_MANAGER_VERSION_ID \
CHAR _txm_module_manager_version_id[] = \
diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_context_restore.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_context_restore.S
index 62b36534..62b36534 100644
--- a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_context_restore.s
+++ b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_context_restore.S
diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_context_save.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_context_save.S
index e124db7a..e124db7a 100644
--- a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_context_save.s
+++ b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_context_save.S
diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_context_restore.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_context_restore.S
index a6f5cbeb..a6f5cbeb 100644
--- a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_context_restore.s
+++ b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_context_restore.S
diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_context_save.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_context_save.S
index 2ce315f9..2ce315f9 100644
--- a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_context_save.s
+++ b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_context_save.S
diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_nesting_end.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_nesting_end.S
index 9938b4e6..9938b4e6 100644
--- a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_nesting_end.s
+++ b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_nesting_end.S
diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_nesting_start.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_nesting_start.S
index 2be8b631..2be8b631 100644
--- a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_nesting_start.s
+++ b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_nesting_start.S
diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_control.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_control.S
index 15e244f1..15e244f1 100644
--- a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_control.s
+++ b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_control.S
diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_disable.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_disable.S
index 7b6d8647..7b6d8647 100644
--- a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_disable.s
+++ b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_disable.S
diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_restore.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_restore.S
index ba5fe5b6..ba5fe5b6 100644
--- a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_restore.s
+++ b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_restore.S
diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_irq_nesting_end.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_irq_nesting_end.S
index dfd8b554..dfd8b554 100644
--- a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_irq_nesting_end.s
+++ b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_irq_nesting_end.S
diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_irq_nesting_start.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_irq_nesting_start.S
index c87978e7..c87978e7 100644
--- a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_irq_nesting_start.s
+++ b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_irq_nesting_start.S
diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_schedule.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_schedule.S
index 54e2c768..54e2c768 100644
--- a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_schedule.s
+++ b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_schedule.S
diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_stack_build.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_stack_build.S
index f4f0717b..f4f0717b 100644
--- a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_stack_build.s
+++ b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_stack_build.S
diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_system_return.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_system_return.S
index fd8de227..b9d17168 100644
--- a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_system_return.s
+++ b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_system_return.S
@@ -9,6 +9,7 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
/**************************************************************************/
/**************************************************************************/
@@ -117,7 +118,9 @@ _tx_skip_solicited_vfp_save:
LDR r2, =_tx_timer_time_slice // Pickup address of time slice
LDR r1, [r2] // Pickup current time slice
- /* Save current stack and switch to system stack. */
+ /* Save the current stack pointer in the thread control block. The
+ scheduler runs on the banked SVC mode stack that the startup code
+ set up, so there is no stack switch to perform. */
STR sp, [r0, #8] // Save thread stack pointer
diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_vectored_context_save.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_vectored_context_save.S
index ce0202d4..ce0202d4 100644
--- a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_vectored_context_save.s
+++ b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_vectored_context_save.S
diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_timer_interrupt.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_timer_interrupt.S
index 8c9b5186..8c9b5186 100644
--- a/ports_module/cortex_a7/gnu/module_manager/src/tx_timer_interrupt.s
+++ b/ports_module/cortex_a7/gnu/module_manager/src/tx_timer_interrupt.S
diff --git a/ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_inside_data_check.c b/ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_inside_data_check.c
new file mode 100644
index 00000000..942fd9f6
--- /dev/null
+++ b/ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_inside_data_check.c
@@ -0,0 +1,538 @@
+/***************************************************************************
+ * 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.
+ *
+ * AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
+ * The AI-generated portions may be considered public domain (CC0-1.0)
+ * and not subject to the project's licence. The human contributor has
+ * reviewed and verified that the code is correct.
+ *
+ * SPDX-License-Identifier: MIT and CC0-1.0
+ **************************************************************************/
+
+
+/**************************************************************************/
+/**************************************************************************/
+/** */
+/** ThreadX Component */
+/** */
+/** Module Manager */
+/** */
+/**************************************************************************/
+/**************************************************************************/
+
+#define TX_SOURCE_CODE
+
+#include "tx_api.h"
+#include "txm_module.h"
+
+
+/* Define the ways a caller-supplied range can sit relative to the module's data region. */
+
+#define TXM_MODULE_DATA_WINDOW_OUTSIDE 0 /* No byte touches the data mapping. */
+#define TXM_MODULE_DATA_WINDOW_CONTAINED 1 /* Every byte is recorded module data. */
+#define TXM_MODULE_DATA_WINDOW_PARTIAL 2 /* Some, but not all, bytes are. */
+
+
+/* Define the page mask derived from the smallest MMU page this port maps. */
+
+#define TXM_MODULE_PAGE_OFFSET_MASK ((ALIGN_TYPE) (TXM_MODULE_MEMORY_ALIGNMENT - 1))
+#define TXM_MODULE_PAGE_BASE_MASK (~TXM_MODULE_PAGE_OFFSET_MASK)
+
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _txm_module_manager_range_end_get Cortex-A7/MMU/GNU */
+/* 6.5.0 */
+/* AUTHOR */
+/* */
+/* Eclipse ThreadX contributors */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function derives the inclusive address of the last byte of a */
+/* caller-supplied range. An empty range is rejected, matching the */
+/* portable check macros, and so is a range whose last byte is not */
+/* representable, so that no caller ever works from a wrapped address. */
+/* */
+/* INPUT */
+/* */
+/* obj_ptr Address of the first byte */
+/* obj_size Size of the range in bytes */
+/* last_byte Destination for the last address */
+/* */
+/* OUTPUT */
+/* */
+/* TX_TRUE if the range is non-empty and does not wrap */
+/* */
+/* CALLS */
+/* */
+/* None */
+/* */
+/* CALLED BY */
+/* */
+/* _txm_module_manager_inside_data_check */
+/* _txm_module_manager_outside_data_check */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* 08-24-2026 Eclipse ThreadX Initial Version 6.5.0 */
+/* contributors */
+/* */
+/**************************************************************************/
+static UINT _txm_module_manager_range_end_get(ALIGN_TYPE obj_ptr, ULONG obj_size, ALIGN_TYPE *last_byte)
+{
+
+ALIGN_TYPE span;
+ALIGN_TYPE highest;
+UINT status;
+
+
+ /* Assume the range cannot be used until proven otherwise. */
+ status = TX_FALSE;
+
+ /* An empty range has no last byte and is rejected, just as the portable macros do. */
+ if (obj_size != ((ULONG) 0))
+ {
+
+ /* Work with the inclusive span so that a range reaching the top of the address
+ space stays representable. */
+ span = ((ALIGN_TYPE) obj_size) - ((ALIGN_TYPE) 1);
+
+ /* Determine the highest first byte this span can start from. */
+ highest = (~((ALIGN_TYPE) 0)) - span;
+
+ /* Determine if the range would run past the end of the address space. */
+ if (obj_ptr <= highest)
+ {
+
+ /* Record the last byte of the range. */
+ *last_byte = obj_ptr + span;
+
+ /* The range is usable. */
+ status = TX_TRUE;
+ }
+ }
+
+ /* Return the completion status. */
+ return(status);
+}
+
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _txm_module_manager_data_window_classify Cortex-A7/MMU/GNU */
+/* 6.5.0 */
+/* AUTHOR */
+/* */
+/* Eclipse ThreadX contributors */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function reports how a range sits relative to the module's own */
+/* data region. The module manager records that region exactly, while */
+/* the MMU can only map it a page at a time, so the mapping may reach */
+/* past the recorded end. The recorded region therefore stays the */
+/* authority for the whole mapped window: a range that leaves the */
+/* recorded region but still lands in the window is reported as */
+/* partial, and its caller rejects it rather than asking the MMU, */
+/* which would accept the rounding slack. */
+/* */
+/* INPUT */
+/* */
+/* module_instance Pointer to module instance */
+/* first_byte Address of the first byte */
+/* last_byte Address of the last byte */
+/* */
+/* OUTPUT */
+/* */
+/* One of the TXM_MODULE_DATA_WINDOW_* classifications */
+/* */
+/* CALLS */
+/* */
+/* None */
+/* */
+/* CALLED BY */
+/* */
+/* _txm_module_manager_inside_data_check */
+/* _txm_module_manager_outside_data_check */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* 08-24-2026 Eclipse ThreadX Initial Version 6.5.0 */
+/* contributors */
+/* */
+/**************************************************************************/
+static UINT _txm_module_manager_data_window_classify(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE first_byte, ALIGN_TYPE last_byte)
+{
+
+ALIGN_TYPE data_start;
+ALIGN_TYPE data_end;
+ALIGN_TYPE window_start;
+ALIGN_TYPE window_end;
+UINT window;
+
+
+ /* Pick up the recorded data region. The end address is inclusive. */
+ data_start = (ALIGN_TYPE) module_instance -> txm_module_instance_data_start;
+ data_end = (ALIGN_TYPE) module_instance -> txm_module_instance_data_end;
+
+ /* Determine if the module has a usable data region at all. */
+ if (data_start > data_end)
+ {
+
+ /* An unset or inverted region owns nothing. */
+ window = TXM_MODULE_DATA_WINDOW_OUTSIDE;
+ }
+ else
+ {
+
+ /* Widen the region to the pages the MMU actually maps for it. */
+ window_start = data_start & TXM_MODULE_PAGE_BASE_MASK;
+ window_end = data_end | TXM_MODULE_PAGE_OFFSET_MASK;
+
+ /* Determine if every byte is recorded module data. */
+ if ((first_byte >= data_start) && (last_byte <= data_end))
+ {
+
+ /* The whole range belongs to the module. */
+ window = TXM_MODULE_DATA_WINDOW_CONTAINED;
+ }
+ else if ((first_byte <= window_end) && (last_byte >= window_start))
+ {
+
+ /* The range overlaps the mapped window without being contained by the
+ recorded region, so it leaves the module's data partway through. */
+ window = TXM_MODULE_DATA_WINDOW_PARTIAL;
+ }
+ else
+ {
+
+ /* The range lies elsewhere, so only the MMU can speak for it. */
+ window = TXM_MODULE_DATA_WINDOW_OUTSIDE;
+ }
+ }
+
+ /* Return the classification. */
+ return(window);
+}
+
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _txm_module_manager_page_walk Cortex-A7/MMU/GNU */
+/* 6.5.0 */
+/* AUTHOR */
+/* */
+/* Eclipse ThreadX contributors */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function translates every page a range touches and reports */
+/* whether all of them answered as expected. The walk stops at the */
+/* first page that disagrees, and a range spanning more pages than */
+/* the configured maximum is refused so that one kernel request can */
+/* never impose unbounded work. */
+/* */
+/* INPUT */
+/* */
+/* first_byte Address of the first byte */
+/* last_byte Address of the last byte */
+/* write_request Access intent to translate for */
+/* expected Result every page must return */
+/* */
+/* OUTPUT */
+/* */
+/* TX_TRUE if every page answered as expected */
+/* */
+/* CALLS */
+/* */
+/* _txm_module_manager_address_probe */
+/* */
+/* CALLED BY */
+/* */
+/* _txm_module_manager_inside_data_check */
+/* _txm_module_manager_outside_data_check */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* 08-24-2026 Eclipse ThreadX Initial Version 6.5.0 */
+/* contributors */
+/* */
+/**************************************************************************/
+static UINT _txm_module_manager_page_walk(ALIGN_TYPE first_byte, ALIGN_TYPE last_byte, UINT write_request, UINT expected)
+{
+
+ALIGN_TYPE first_page;
+ALIGN_TYPE last_page;
+ALIGN_TYPE page;
+ULONG pages;
+ULONG index;
+UINT matched;
+
+
+ /* Reduce the range to the pages it touches. */
+ first_page = first_byte & TXM_MODULE_PAGE_BASE_MASK;
+ last_page = last_byte & TXM_MODULE_PAGE_BASE_MASK;
+
+ /* Count them. Both addresses are page-aligned, so the division is exact. */
+ pages = ((ULONG) ((last_page - first_page) / ((ALIGN_TYPE) TXM_MODULE_MEMORY_ALIGNMENT))) + ((ULONG) 1);
+
+ /* Determine if the range is longer than this port is willing to translate. */
+ if (pages > ((ULONG) TXM_MODULE_MANAGER_DATA_CHECK_MAX_PAGES))
+ {
+
+ /* Refuse rather than spend unbounded time in a kernel request. Refusing is safe
+ for both callers: neither can then claim the range is inside or outside. */
+ matched = TX_FALSE;
+ }
+ else
+ {
+
+ /* Assume every page agrees until one does not. */
+ matched = TX_TRUE;
+ index = (ULONG) 0;
+
+ /* Translate each page in turn, stopping as soon as the answer is settled. The
+ address is rebuilt from the index so that the walk cannot wrap past the top
+ page of the address space. */
+ while ((index < pages) && (matched == TX_TRUE))
+ {
+
+ /* Build the address of this page. */
+ page = first_page + (((ALIGN_TYPE) index) * ((ALIGN_TYPE) TXM_MODULE_MEMORY_ALIGNMENT));
+
+ /* Ask the MMU whether the module may reach this page with the requested access. */
+ if (_txm_module_manager_address_probe((ULONG) page, write_request) != expected)
+ {
+
+ /* This page disagrees, so the range as a whole does. */
+ matched = TX_FALSE;
+ }
+
+ /* Move to the next page. */
+ index++;
+ }
+ }
+
+ /* Return whether the whole range answered as expected. */
+ return(matched);
+}
+
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _txm_module_manager_inside_data_check Cortex-A7/MMU/GNU */
+/* 6.5.0 */
+/* AUTHOR */
+/* */
+/* Eclipse ThreadX contributors */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function determines whether every byte of a caller-supplied */
+/* range lies inside the module's data or shared memory and is */
+/* reachable by the module with the requested access. The module's own */
+/* data region is answered from the manager's own records, which are */
+/* exact. Anything else is answered by translating every page the */
+/* range touches, because this port keeps no record of the shared and */
+/* external regions the application maps into the module. */
+/* */
+/* INPUT */
+/* */
+/* module_instance Pointer to module instance */
+/* obj_ptr Address of the first byte */
+/* obj_size Size of the range in bytes */
+/* write_request TXM_MODULE_MANAGER_ACCESS_READ or */
+/* TXM_MODULE_MANAGER_ACCESS_WRITE */
+/* */
+/* OUTPUT */
+/* */
+/* TX_TRUE if the whole range is reachable with that access */
+/* */
+/* CALLS */
+/* */
+/* _txm_module_manager_range_end_get */
+/* _txm_module_manager_current_asid_get */
+/* _txm_module_manager_data_window_classify */
+/* _txm_module_manager_page_walk */
+/* */
+/* CALLED BY */
+/* */
+/* TXM_MODULE_MANAGER_CHECK_INSIDE_DATA_READ */
+/* TXM_MODULE_MANAGER_CHECK_INSIDE_DATA_WRITE */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* 08-24-2026 Eclipse ThreadX Initial Version 6.5.0 */
+/* contributors */
+/* */
+/**************************************************************************/
+UINT _txm_module_manager_inside_data_check(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE obj_ptr, ULONG obj_size, UINT write_request)
+{
+
+ALIGN_TYPE last_byte;
+UINT window;
+UINT status;
+
+
+ /* Assume the range is not usable until every condition is met. */
+ status = TX_FALSE;
+
+ /* A range can only belong to a module that exists. */
+ if (module_instance != TX_NULL)
+ {
+
+ /* Determine the last byte, rejecting empty and wrapping ranges. */
+ if (_txm_module_manager_range_end_get(obj_ptr, obj_size, &last_byte) == TX_TRUE)
+ {
+
+ /* Address translation answers for whichever context is loaded, so it can only
+ be trusted while the requesting module's context is the loaded one. */
+ if (_txm_module_manager_current_asid_get() == (module_instance -> txm_module_instance_asid))
+ {
+
+ /* Place the range relative to the module's own data region. */
+ window = _txm_module_manager_data_window_classify(module_instance, obj_ptr, last_byte);
+
+ if (window == ((UINT) TXM_MODULE_DATA_WINDOW_CONTAINED))
+ {
+
+ /* The module's data region is mapped for unprivileged reading and
+ writing, so both intents are satisfied without translating. */
+ status = TX_TRUE;
+ }
+ else if (window == ((UINT) TXM_MODULE_DATA_WINDOW_OUTSIDE))
+ {
+
+ /* Shared or external memory: every page must grant the access. */
+ status = _txm_module_manager_page_walk(obj_ptr, last_byte, write_request, TX_TRUE);
+ }
+ else
+ {
+
+ /* The range leaves the module's data partway through. */
+ status = TX_FALSE;
+ }
+ }
+ }
+ }
+
+ /* Return the completion status. */
+ return(status);
+}
+
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _txm_module_manager_outside_data_check Cortex-A7/MMU/GNU */
+/* 6.5.0 */
+/* AUTHOR */
+/* */
+/* Eclipse ThreadX contributors */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function determines whether no byte of a caller-supplied range */
+/* is reachable by the module. It is deliberately not the negation of */
+/* the inside check: a range that reaches into the module's memory */
+/* only partway is inside neither answer, and reporting it as outside */
+/* would let it pass as a kernel object. */
+/* */
+/* INPUT */
+/* */
+/* module_instance Pointer to module instance */
+/* obj_ptr Address of the first byte */
+/* obj_size Size of the range in bytes */
+/* */
+/* OUTPUT */
+/* */
+/* TX_TRUE if no byte of the range is reachable by the module */
+/* */
+/* CALLS */
+/* */
+/* _txm_module_manager_range_end_get */
+/* _txm_module_manager_current_asid_get */
+/* _txm_module_manager_data_window_classify */
+/* _txm_module_manager_page_walk */
+/* */
+/* CALLED BY */
+/* */
+/* TXM_MODULE_MANAGER_CHECK_OUTSIDE_DATA */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* 08-24-2026 Eclipse ThreadX Initial Version 6.5.0 */
+/* contributors */
+/* */
+/**************************************************************************/
+UINT _txm_module_manager_outside_data_check(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE obj_ptr, ULONG obj_size)
+{
+
+ALIGN_TYPE last_byte;
+UINT window;
+UINT status;
+
+
+ /* Assume the range is not provably outside the module. */
+ status = TX_FALSE;
+
+ /* A range can only be placed against a module that exists. */
+ if (module_instance != TX_NULL)
+ {
+
+ /* Determine the last byte, rejecting empty and wrapping ranges. */
+ if (_txm_module_manager_range_end_get(obj_ptr, obj_size, &last_byte) == TX_TRUE)
+ {
+
+ /* Address translation answers for whichever context is loaded, so it can only
+ be trusted while the requesting module's context is the loaded one. */
+ if (_txm_module_manager_current_asid_get() == (module_instance -> txm_module_instance_asid))
+ {
+
+ /* Place the range relative to the module's own data region. */
+ window = _txm_module_manager_data_window_classify(module_instance, obj_ptr, last_byte);
+
+ if (window == ((UINT) TXM_MODULE_DATA_WINDOW_OUTSIDE))
+ {
+
+ /* Clear of the module's data region, so the remaining question is
+ whether any page of it is shared or external memory. */
+ status = _txm_module_manager_page_walk(obj_ptr, last_byte, TXM_MODULE_MANAGER_ACCESS_READ, TX_FALSE);
+ }
+ else
+ {
+
+ /* The range touches the module's data region. */
+ status = TX_FALSE;
+ }
+ }
+ }
+ }
+
+ /* Return the completion status. */
+ return(status);
+}
diff --git a/ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_mm_register_setup.c b/ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_mm_register_setup.c
index 60202970..5be18136 100644
--- a/ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_mm_register_setup.c
+++ b/ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_mm_register_setup.c
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -35,24 +37,34 @@ extern ULONG _txm_ttbr1_page_table[TXM_MAXIMUM_MODULES][TXM_MASTER_PAGE_TABLE_EN
/* */
/* FUNCTION RELEASE */
/* */
-/* _txm_module_manager_inside_data_check Cortex-A7/MMU/GNU */
-/* 6.2.1 */
+/* _txm_module_manager_address_probe Cortex-A7/MMU/GNU */
+/* 6.5.0 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
+/* Eclipse ThreadX contributors */
/* */
/* DESCRIPTION */
/* */
-/* This function determines if pointer is within the module's data or */
-/* shared memory. */
+/* This function asks the MMU whether unprivileged code running in the */
+/* currently loaded translation context may reach one address with the */
+/* requested access. Reading and writing are asked separately, because */
+/* a module's code and its read-only shared memory translate for */
+/* reading while a kernel service writing to them would fault or, */
+/* worse, succeed from privileged mode. */
+/* */
+/* This answers for one address only. Callers that hold a range must */
+/* ask about every page the range touches. */
/* */
/* INPUT */
/* */
-/* pointer Data pointer */
+/* address Address to translate */
+/* write_request TXM_MODULE_MANAGER_ACCESS_READ or */
+/* TXM_MODULE_MANAGER_ACCESS_WRITE */
/* */
/* OUTPUT */
/* */
-/* Completion Status */
+/* TX_TRUE if the translation granted the requested access */
/* */
/* CALLS */
/* */
@@ -60,18 +72,41 @@ extern ULONG _txm_ttbr1_page_table[TXM_MAXIMUM_MODULES][TXM_MASTER_PAGE_TABLE_EN
/* */
/* CALLED BY */
/* */
-/* TXM_MODULE_MANAGER_DATA_POINTER_CHECK */
+/* _txm_module_manager_page_walk */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* 03-08-2023 Scott Larson Initial Version 6.2.1 */
+/* 08-24-2026 Eclipse ThreadX Added the write intent and */
+/* contributors moved range handling to */
+/* the caller, resulting in */
+/* version 6.5.0 */
/* */
/**************************************************************************/
-UINT _txm_module_manager_inside_data_check(ULONG pointer)
+UINT _txm_module_manager_address_probe(ULONG address, UINT write_request)
{
-ULONG translation;
+ULONG translation;
+
+
+ /* Determine which unprivileged access the caller needs. */
+ if (write_request == ((UINT) TXM_MODULE_MANAGER_ACCESS_WRITE))
+ {
+
+ /* ATS1CUW operation on address supplied in address, Stage 1 unprivileged write. */
+ __asm volatile ("MCR p15, 0, %0, c7, c8, 3" : : "r"(address) : );
+ }
+ else
+ {
+
+ /* ATS1CUR operation on address supplied in address, Stage 1 unprivileged read. */
+ __asm volatile ("MCR p15, 0, %0, c7, c8, 2" : : "r"(address) : );
+ }
- /* ATS1CUR operation on address supplied in pointer, Stage 1 unprivileged read. */
- __asm volatile ("MCR p15, 0, %0, c7, c8, 2" : : "r"(pointer) : );
__asm volatile ("ISB"); /* Ensure completion of the MCR write to CP15. */
- __asm volatile ("MRC p15, 0, %0, c7, c4, 0" : "=r"(translation) : : ); /* Read result from 32-bit PAR into translation. */
+ __asm volatile ("MRC p15, 0, %0, c7, c4, 0" : "=r"(translation) : : ); /* Read result from 32-bit PAR into translation. */
if (translation & TXM_ADDRESS_TRANSLATION_FAULT_BIT)
{
@@ -86,6 +121,62 @@ ULONG translation;
/* */
/* FUNCTION RELEASE */
/* */
+/* _txm_module_manager_current_asid_get Cortex-A7/MMU/GNU */
+/* 6.5.0 */
+/* AUTHOR */
+/* */
+/* Eclipse ThreadX contributors */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function returns the ASID of the translation context that is */
+/* currently loaded. Address translation always answers for that */
+/* context, so a caller validating a pointer on behalf of a module */
+/* must confirm that the loaded context is that module's before it */
+/* believes the answer. */
+/* */
+/* INPUT */
+/* */
+/* None */
+/* */
+/* OUTPUT */
+/* */
+/* ASID of the currently loaded translation context */
+/* */
+/* CALLS */
+/* */
+/* None */
+/* */
+/* CALLED BY */
+/* */
+/* _txm_module_manager_inside_data_check */
+/* _txm_module_manager_outside_data_check */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* 08-24-2026 Eclipse ThreadX Initial Version 6.5.0 */
+/* contributors */
+/* */
+/**************************************************************************/
+ULONG _txm_module_manager_current_asid_get(VOID)
+{
+
+ULONG contextidr;
+
+
+ /* Read CONTEXTIDR, whose low byte holds the ASID in the short-descriptor format. */
+ __asm volatile ("MRC p15, 0, %0, c13, c0, 1" : "=r"(contextidr) : : );
+
+ return(contextidr & TXM_CONTEXTIDR_ASID_MASK);
+}
+
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
/* _txm_module_manager_assign_asid Cortex-A7/MMU/GNU */
/* 6.2.1 */
/* AUTHOR */
diff --git a/ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_thread_stack_build.s b/ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_thread_stack_build.S
index e701846a..e701846a 100644
--- a/ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_thread_stack_build.s
+++ b/ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_thread_stack_build.S
diff --git a/ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_user_mode_entry.s b/ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_user_mode_entry.S
index b9c59109..b9c59109 100644
--- a/ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_user_mode_entry.s
+++ b/ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_user_mode_entry.S
diff --git a/ports_module/cortex_a7/iar/example_build/sample_threadx_module_manager.ewp b/ports_module/cortex_a7/iar/example_build/sample_threadx_module_manager.ewp
index 524b30f0..e77458be 100644
--- a/ports_module/cortex_a7/iar/example_build/sample_threadx_module_manager.ewp
+++ b/ports_module/cortex_a7/iar/example_build/sample_threadx_module_manager.ewp
@@ -1811,7 +1811,7 @@
</option>
<option>
<name>IlinkIcfFile</name>
- <state>C:\Users\cindydeng\AzureRTOS\threadx\modules\cortex-a-port\threadx\ports_module\cortex_a7\iar\example_build\sample_threadx_module_manager.icf</state>
+ <state>$PROJ_DIR$\sample_threadx_module_manager.icf</state>
</option>
<option>
<name>IlinkIcfFileSlave</name>
diff --git a/ports_module/cortex_a7/iar/example_build/tx.ewp b/ports_module/cortex_a7/iar/example_build/tx.ewp
index 079f4bd7..97f9ffe7 100644
--- a/ports_module/cortex_a7/iar/example_build/tx.ewp
+++ b/ports_module/cortex_a7/iar/example_build/tx.ewp
@@ -1053,7 +1053,7 @@
</option>
<option>
<name>IarchiveOutput</name>
- <state>C:\tmp\threadx\ports_module\cortex_a7\iar\example_build\Debug\Exe\tx.a</state>
+ <state>###Unitialized###</state>
</option>
</data>
</settings>
@@ -2833,6 +2833,9 @@
<name>$PROJ_DIR$\..\module_manager\src\txm_module_manager_mm_initialize.c</name>
</file>
<file>
+ <name>$PROJ_DIR$\..\module_manager\src\txm_module_manager_inside_data_check.c</name>
+ </file>
+ <file>
<name>$PROJ_DIR$\..\module_manager\src\txm_module_manager_mm_register_setup.c</name>
</file>
<file>
diff --git a/ports_module/cortex_a7/iar/example_build/txm.ewp b/ports_module/cortex_a7/iar/example_build/txm.ewp
index b8b34b1f..ad997463 100644
--- a/ports_module/cortex_a7/iar/example_build/txm.ewp
+++ b/ports_module/cortex_a7/iar/example_build/txm.ewp
@@ -1052,7 +1052,7 @@
</option>
<option>
<name>IarchiveOutput</name>
- <state>C:\tmp\threadx\ports_module\cortex_a7\iar\example_build\Debug\Exe\txm.a</state>
+ <state>###Unitialized###</state>
</option>
</data>
</settings>
diff --git a/ports_module/cortex_a7/iar/inc/tx_port.h b/ports_module/cortex_a7/iar/inc/tx_port.h
index 6fe0c274..b20563b9 100644
--- a/ports_module/cortex_a7/iar/inc/tx_port.h
+++ b/ports_module/cortex_a7/iar/inc/tx_port.h
@@ -399,7 +399,7 @@ void tx_thread_vfp_disable(void);
#ifdef TX_THREAD_INIT
CHAR _tx_version_id[] =
- "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * ThreadX Cortex-A7/IAR Version 6.5.1.202602a *";
+ "(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * ThreadX Cortex-A7/IAR Version 6.5.2.202603 *";
#else
#ifdef TX_MISRA_ENABLE
extern CHAR _tx_version_id[100];
diff --git a/ports_module/cortex_a7/iar/inc/txm_module_port.h b/ports_module/cortex_a7/iar/inc/txm_module_port.h
index 247868ea..aafa8d43 100644
--- a/ports_module/cortex_a7/iar/inc/txm_module_port.h
+++ b/ports_module/cortex_a7/iar/inc/txm_module_port.h
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -251,6 +253,22 @@ The following extensions must also be defined in tx_port.h:
#define TXM_ADDRESS_TRANSLATION_FAULT_BIT 1
+/* Mask selecting the ASID field of CONTEXTIDR in the short-descriptor format. */
+#define TXM_CONTEXTIDR_ASID_MASK 0x000000FF
+
+/* Access intents understood by the module data range check. */
+#define TXM_MODULE_MANAGER_ACCESS_READ 0
+#define TXM_MODULE_MANAGER_ACCESS_WRITE 1
+
+/* Define the largest number of MMU pages a single caller-supplied range may span before
+ the data range check rejects it. This bounds the worst-case, module-controlled cost of
+ validating one kernel request, which keeps the check deterministic. The default permits
+ a 4 MB range. Applications that hand larger shared-memory ranges to kernel services can
+ define a larger value. */
+#ifndef TXM_MODULE_MANAGER_DATA_CHECK_MAX_PAGES
+#define TXM_MODULE_MANAGER_DATA_CHECK_MAX_PAGES 1024
+#endif
+
#define TXM_ASID_RESERVED 0xFFFFFFFF
#define TXM_MODULE_ASID_ERROR 0xF6
@@ -386,9 +404,26 @@ typedef struct TXM_MODULE_MANAGER_MEMORY_FAULT_INFO_STRUCT
/* Define the macros to perform port-specific checks when passing pointers to the kernel. */
-/* Define macro to make sure object is inside the module's data or shared memory. */
+/* Define macros to make sure a whole object is inside the module's data or shared memory.
+ The MMU is the authority for shared and external memory, so the check translates every
+ page the range touches with the requested unprivileged access. Passing the size and the
+ access intent through is what keeps the check honest: translating only the first address,
+ and only for reading, would accept a range that leaves the module's mapping partway
+ through, or a read-only range used as a kernel write destination. */
+#define TXM_MODULE_MANAGER_CHECK_INSIDE_DATA_READ(module_instance, obj_ptr, obj_size) \
+ _txm_module_manager_inside_data_check(module_instance, (ALIGN_TYPE) (obj_ptr), (ULONG) (obj_size), TXM_MODULE_MANAGER_ACCESS_READ)
+
+#define TXM_MODULE_MANAGER_CHECK_INSIDE_DATA_WRITE(module_instance, obj_ptr, obj_size) \
+ _txm_module_manager_inside_data_check(module_instance, (ALIGN_TYPE) (obj_ptr), (ULONG) (obj_size), TXM_MODULE_MANAGER_ACCESS_WRITE)
+
+/* The unqualified check keeps its historical name and takes the stricter write intent. */
#define TXM_MODULE_MANAGER_CHECK_INSIDE_DATA(module_instance, obj_ptr, obj_size) \
- _txm_module_manager_inside_data_check((ULONG) obj_ptr)
+ TXM_MODULE_MANAGER_CHECK_INSIDE_DATA_WRITE(module_instance, obj_ptr, obj_size)
+
+/* Negating the inside check would report a range that only partly reaches into the module
+ as being outside it, so the outside direction gets its own check. */
+#define TXM_MODULE_MANAGER_CHECK_OUTSIDE_DATA(module_instance, obj_ptr, obj_size) \
+ _txm_module_manager_outside_data_check(module_instance, (ALIGN_TYPE) (obj_ptr), (ULONG) (obj_size))
/* Define some internal prototypes to this module port. */
@@ -408,7 +443,10 @@ UINT _txm_module_manager_mm_initialize(VOID);
VOID _txm_module_manager_mm_register_setup(TXM_MODULE_INSTANCE *module_instance); \
VOID _txm_level2_page_clear(TXM_MODULE_INSTANCE *module_instance); \
VOID _txm_module_manager_remove_asid(TXM_MODULE_INSTANCE *module_instance); \
-UINT _txm_module_manager_inside_data_check(ULONG pointer);
+UINT _txm_module_manager_inside_data_check(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE obj_ptr, ULONG obj_size, UINT write_request); \
+UINT _txm_module_manager_outside_data_check(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE obj_ptr, ULONG obj_size); \
+UINT _txm_module_manager_address_probe(ULONG address, UINT write_request); \
+ULONG _txm_module_manager_current_asid_get(VOID);
#define TXM_MODULE_MANAGER_VERSION_ID \
CHAR _txm_module_manager_version_id[] = \
diff --git a/ports_module/cortex_a7/iar/module_manager/src/tx_iar.c b/ports_module/cortex_a7/iar/module_manager/src/tx_iar.c
index 238b485e..ab6c209c 100644
--- a/ports_module/cortex_a7/iar/module_manager/src/tx_iar.c
+++ b/ports_module/cortex_a7/iar/module_manager/src/tx_iar.c
@@ -9,6 +9,7 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
/**************************************************************************/
/**************************************************************************/
@@ -270,7 +271,7 @@ TX_MUTEX *mutex_ptr;
mutex_ptr = &__tx_iar_file_lock_mutexes[__tx_iar_file_lock_next_free_mutex++];
/* Check for wrap-around on the next free mutex. */
- if (__tx_iar_file_lock_next_free_mutex >= _MAX_LOCK)
+ if (__tx_iar_file_lock_next_free_mutex >= _MAX_FLOCK)
{
/* Yes, set the free index back to 0. */
@@ -287,7 +288,7 @@ TX_MUTEX *mutex_ptr;
}
/* Determine if a free mutex was found. */
- if (i >= _MAX_LOCK)
+ if (i >= _MAX_FLOCK)
{
/* Error! No more free mutexes! */
@@ -678,7 +679,7 @@ TX_MUTEX *mutex_ptr;
mutex_ptr = &__tx_iar_file_lock_mutexes[__tx_iar_file_lock_next_free_mutex++];
/* Check for wrap-around on the next free mutex. */
- if (__tx_iar_file_lock_next_free_mutex >= _MAX_LOCK)
+ if (__tx_iar_file_lock_next_free_mutex >= _MAX_FLOCK)
{
/* Yes, set the free index back to 0. */
@@ -695,7 +696,7 @@ TX_MUTEX *mutex_ptr;
}
/* Determine if a free mutex was found. */
- if (i >= _MAX_LOCK)
+ if (i >= _MAX_FLOCK)
{
/* Error! No more free mutexes! */
diff --git a/ports_module/cortex_a7/iar/module_manager/src/tx_thread_system_return.s b/ports_module/cortex_a7/iar/module_manager/src/tx_thread_system_return.s
index f22ca01c..212a1f63 100644
--- a/ports_module/cortex_a7/iar/module_manager/src/tx_thread_system_return.s
+++ b/ports_module/cortex_a7/iar/module_manager/src/tx_thread_system_return.s
@@ -1,5 +1,6 @@
;/***************************************************************************
; * 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
@@ -8,6 +9,7 @@
; * SPDX-License-Identifier: MIT
; **************************************************************************/
;
+; Portions of this file were generated with AI assistance.
;
;/**************************************************************************/
;/**************************************************************************/
@@ -113,7 +115,9 @@ _tx_skip_solicited_vfp_save:
LDR r2, =_tx_timer_time_slice ; Pickup address of time slice
LDR r1, [r2] ; Pickup current time slice
-; /* Save current stack and switch to system stack. */
+; /* Save the current stack pointer in the thread control block. The
+; scheduler runs on the banked SVC mode stack that the startup code
+; set up, so there is no stack switch to perform. */
STR sp, [r0, #8] ; Save thread stack pointer
diff --git a/ports_module/cortex_a7/iar/module_manager/src/txm_module_manager_inside_data_check.c b/ports_module/cortex_a7/iar/module_manager/src/txm_module_manager_inside_data_check.c
new file mode 100644
index 00000000..972cae84
--- /dev/null
+++ b/ports_module/cortex_a7/iar/module_manager/src/txm_module_manager_inside_data_check.c
@@ -0,0 +1,538 @@
+/***************************************************************************
+ * 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.
+ *
+ * AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5).
+ * The AI-generated portions may be considered public domain (CC0-1.0)
+ * and not subject to the project's licence. The human contributor has
+ * reviewed and verified that the code is correct.
+ *
+ * SPDX-License-Identifier: MIT and CC0-1.0
+ **************************************************************************/
+
+
+/**************************************************************************/
+/**************************************************************************/
+/** */
+/** ThreadX Component */
+/** */
+/** Module Manager */
+/** */
+/**************************************************************************/
+/**************************************************************************/
+
+#define TX_SOURCE_CODE
+
+#include "tx_api.h"
+#include "txm_module.h"
+
+
+/* Define the ways a caller-supplied range can sit relative to the module's data region. */
+
+#define TXM_MODULE_DATA_WINDOW_OUTSIDE 0 /* No byte touches the data mapping. */
+#define TXM_MODULE_DATA_WINDOW_CONTAINED 1 /* Every byte is recorded module data. */
+#define TXM_MODULE_DATA_WINDOW_PARTIAL 2 /* Some, but not all, bytes are. */
+
+
+/* Define the page mask derived from the smallest MMU page this port maps. */
+
+#define TXM_MODULE_PAGE_OFFSET_MASK ((ALIGN_TYPE) (TXM_MODULE_MEMORY_ALIGNMENT - 1))
+#define TXM_MODULE_PAGE_BASE_MASK (~TXM_MODULE_PAGE_OFFSET_MASK)
+
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _txm_module_manager_range_end_get Cortex-A7/MMU/IAR */
+/* 6.5.0 */
+/* AUTHOR */
+/* */
+/* Eclipse ThreadX contributors */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function derives the inclusive address of the last byte of a */
+/* caller-supplied range. An empty range is rejected, matching the */
+/* portable check macros, and so is a range whose last byte is not */
+/* representable, so that no caller ever works from a wrapped address. */
+/* */
+/* INPUT */
+/* */
+/* obj_ptr Address of the first byte */
+/* obj_size Size of the range in bytes */
+/* last_byte Destination for the last address */
+/* */
+/* OUTPUT */
+/* */
+/* TX_TRUE if the range is non-empty and does not wrap */
+/* */
+/* CALLS */
+/* */
+/* None */
+/* */
+/* CALLED BY */
+/* */
+/* _txm_module_manager_inside_data_check */
+/* _txm_module_manager_outside_data_check */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* 08-24-2026 Eclipse ThreadX Initial Version 6.5.0 */
+/* contributors */
+/* */
+/**************************************************************************/
+static UINT _txm_module_manager_range_end_get(ALIGN_TYPE obj_ptr, ULONG obj_size, ALIGN_TYPE *last_byte)
+{
+
+ALIGN_TYPE span;
+ALIGN_TYPE highest;
+UINT status;
+
+
+ /* Assume the range cannot be used until proven otherwise. */
+ status = TX_FALSE;
+
+ /* An empty range has no last byte and is rejected, just as the portable macros do. */
+ if (obj_size != ((ULONG) 0))
+ {
+
+ /* Work with the inclusive span so that a range reaching the top of the address
+ space stays representable. */
+ span = ((ALIGN_TYPE) obj_size) - ((ALIGN_TYPE) 1);
+
+ /* Determine the highest first byte this span can start from. */
+ highest = (~((ALIGN_TYPE) 0)) - span;
+
+ /* Determine if the range would run past the end of the address space. */
+ if (obj_ptr <= highest)
+ {
+
+ /* Record the last byte of the range. */
+ *last_byte = obj_ptr + span;
+
+ /* The range is usable. */
+ status = TX_TRUE;
+ }
+ }
+
+ /* Return the completion status. */
+ return(status);
+}
+
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _txm_module_manager_data_window_classify Cortex-A7/MMU/IAR */
+/* 6.5.0 */
+/* AUTHOR */
+/* */
+/* Eclipse ThreadX contributors */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function reports how a range sits relative to the module's own */
+/* data region. The module manager records that region exactly, while */
+/* the MMU can only map it a page at a time, so the mapping may reach */
+/* past the recorded end. The recorded region therefore stays the */
+/* authority for the whole mapped window: a range that leaves the */
+/* recorded region but still lands in the window is reported as */
+/* partial, and its caller rejects it rather than asking the MMU, */
+/* which would accept the rounding slack. */
+/* */
+/* INPUT */
+/* */
+/* module_instance Pointer to module instance */
+/* first_byte Address of the first byte */
+/* last_byte Address of the last byte */
+/* */
+/* OUTPUT */
+/* */
+/* One of the TXM_MODULE_DATA_WINDOW_* classifications */
+/* */
+/* CALLS */
+/* */
+/* None */
+/* */
+/* CALLED BY */
+/* */
+/* _txm_module_manager_inside_data_check */
+/* _txm_module_manager_outside_data_check */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* 08-24-2026 Eclipse ThreadX Initial Version 6.5.0 */
+/* contributors */
+/* */
+/**************************************************************************/
+static UINT _txm_module_manager_data_window_classify(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE first_byte, ALIGN_TYPE last_byte)
+{
+
+ALIGN_TYPE data_start;
+ALIGN_TYPE data_end;
+ALIGN_TYPE window_start;
+ALIGN_TYPE window_end;
+UINT window;
+
+
+ /* Pick up the recorded data region. The end address is inclusive. */
+ data_start = (ALIGN_TYPE) module_instance -> txm_module_instance_data_start;
+ data_end = (ALIGN_TYPE) module_instance -> txm_module_instance_data_end;
+
+ /* Determine if the module has a usable data region at all. */
+ if (data_start > data_end)
+ {
+
+ /* An unset or inverted region owns nothing. */
+ window = TXM_MODULE_DATA_WINDOW_OUTSIDE;
+ }
+ else
+ {
+
+ /* Widen the region to the pages the MMU actually maps for it. */
+ window_start = data_start & TXM_MODULE_PAGE_BASE_MASK;
+ window_end = data_end | TXM_MODULE_PAGE_OFFSET_MASK;
+
+ /* Determine if every byte is recorded module data. */
+ if ((first_byte >= data_start) && (last_byte <= data_end))
+ {
+
+ /* The whole range belongs to the module. */
+ window = TXM_MODULE_DATA_WINDOW_CONTAINED;
+ }
+ else if ((first_byte <= window_end) && (last_byte >= window_start))
+ {
+
+ /* The range overlaps the mapped window without being contained by the
+ recorded region, so it leaves the module's data partway through. */
+ window = TXM_MODULE_DATA_WINDOW_PARTIAL;
+ }
+ else
+ {
+
+ /* The range lies elsewhere, so only the MMU can speak for it. */
+ window = TXM_MODULE_DATA_WINDOW_OUTSIDE;
+ }
+ }
+
+ /* Return the classification. */
+ return(window);
+}
+
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _txm_module_manager_page_walk Cortex-A7/MMU/IAR */
+/* 6.5.0 */
+/* AUTHOR */
+/* */
+/* Eclipse ThreadX contributors */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function translates every page a range touches and reports */
+/* whether all of them answered as expected. The walk stops at the */
+/* first page that disagrees, and a range spanning more pages than */
+/* the configured maximum is refused so that one kernel request can */
+/* never impose unbounded work. */
+/* */
+/* INPUT */
+/* */
+/* first_byte Address of the first byte */
+/* last_byte Address of the last byte */
+/* write_request Access intent to translate for */
+/* expected Result every page must return */
+/* */
+/* OUTPUT */
+/* */
+/* TX_TRUE if every page answered as expected */
+/* */
+/* CALLS */
+/* */
+/* _txm_module_manager_address_probe */
+/* */
+/* CALLED BY */
+/* */
+/* _txm_module_manager_inside_data_check */
+/* _txm_module_manager_outside_data_check */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* 08-24-2026 Eclipse ThreadX Initial Version 6.5.0 */
+/* contributors */
+/* */
+/**************************************************************************/
+static UINT _txm_module_manager_page_walk(ALIGN_TYPE first_byte, ALIGN_TYPE last_byte, UINT write_request, UINT expected)
+{
+
+ALIGN_TYPE first_page;
+ALIGN_TYPE last_page;
+ALIGN_TYPE page;
+ULONG pages;
+ULONG index;
+UINT matched;
+
+
+ /* Reduce the range to the pages it touches. */
+ first_page = first_byte & TXM_MODULE_PAGE_BASE_MASK;
+ last_page = last_byte & TXM_MODULE_PAGE_BASE_MASK;
+
+ /* Count them. Both addresses are page-aligned, so the division is exact. */
+ pages = ((ULONG) ((last_page - first_page) / ((ALIGN_TYPE) TXM_MODULE_MEMORY_ALIGNMENT))) + ((ULONG) 1);
+
+ /* Determine if the range is longer than this port is willing to translate. */
+ if (pages > ((ULONG) TXM_MODULE_MANAGER_DATA_CHECK_MAX_PAGES))
+ {
+
+ /* Refuse rather than spend unbounded time in a kernel request. Refusing is safe
+ for both callers: neither can then claim the range is inside or outside. */
+ matched = TX_FALSE;
+ }
+ else
+ {
+
+ /* Assume every page agrees until one does not. */
+ matched = TX_TRUE;
+ index = (ULONG) 0;
+
+ /* Translate each page in turn, stopping as soon as the answer is settled. The
+ address is rebuilt from the index so that the walk cannot wrap past the top
+ page of the address space. */
+ while ((index < pages) && (matched == TX_TRUE))
+ {
+
+ /* Build the address of this page. */
+ page = first_page + (((ALIGN_TYPE) index) * ((ALIGN_TYPE) TXM_MODULE_MEMORY_ALIGNMENT));
+
+ /* Ask the MMU whether the module may reach this page with the requested access. */
+ if (_txm_module_manager_address_probe((ULONG) page, write_request) != expected)
+ {
+
+ /* This page disagrees, so the range as a whole does. */
+ matched = TX_FALSE;
+ }
+
+ /* Move to the next page. */
+ index++;
+ }
+ }
+
+ /* Return whether the whole range answered as expected. */
+ return(matched);
+}
+
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _txm_module_manager_inside_data_check Cortex-A7/MMU/IAR */
+/* 6.5.0 */
+/* AUTHOR */
+/* */
+/* Eclipse ThreadX contributors */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function determines whether every byte of a caller-supplied */
+/* range lies inside the module's data or shared memory and is */
+/* reachable by the module with the requested access. The module's own */
+/* data region is answered from the manager's own records, which are */
+/* exact. Anything else is answered by translating every page the */
+/* range touches, because this port keeps no record of the shared and */
+/* external regions the application maps into the module. */
+/* */
+/* INPUT */
+/* */
+/* module_instance Pointer to module instance */
+/* obj_ptr Address of the first byte */
+/* obj_size Size of the range in bytes */
+/* write_request TXM_MODULE_MANAGER_ACCESS_READ or */
+/* TXM_MODULE_MANAGER_ACCESS_WRITE */
+/* */
+/* OUTPUT */
+/* */
+/* TX_TRUE if the whole range is reachable with that access */
+/* */
+/* CALLS */
+/* */
+/* _txm_module_manager_range_end_get */
+/* _txm_module_manager_current_asid_get */
+/* _txm_module_manager_data_window_classify */
+/* _txm_module_manager_page_walk */
+/* */
+/* CALLED BY */
+/* */
+/* TXM_MODULE_MANAGER_CHECK_INSIDE_DATA_READ */
+/* TXM_MODULE_MANAGER_CHECK_INSIDE_DATA_WRITE */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* 08-24-2026 Eclipse ThreadX Initial Version 6.5.0 */
+/* contributors */
+/* */
+/**************************************************************************/
+UINT _txm_module_manager_inside_data_check(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE obj_ptr, ULONG obj_size, UINT write_request)
+{
+
+ALIGN_TYPE last_byte;
+UINT window;
+UINT status;
+
+
+ /* Assume the range is not usable until every condition is met. */
+ status = TX_FALSE;
+
+ /* A range can only belong to a module that exists. */
+ if (module_instance != TX_NULL)
+ {
+
+ /* Determine the last byte, rejecting empty and wrapping ranges. */
+ if (_txm_module_manager_range_end_get(obj_ptr, obj_size, &last_byte) == TX_TRUE)
+ {
+
+ /* Address translation answers for whichever context is loaded, so it can only
+ be trusted while the requesting module's context is the loaded one. */
+ if (_txm_module_manager_current_asid_get() == (module_instance -> txm_module_instance_asid))
+ {
+
+ /* Place the range relative to the module's own data region. */
+ window = _txm_module_manager_data_window_classify(module_instance, obj_ptr, last_byte);
+
+ if (window == ((UINT) TXM_MODULE_DATA_WINDOW_CONTAINED))
+ {
+
+ /* The module's data region is mapped for unprivileged reading and
+ writing, so both intents are satisfied without translating. */
+ status = TX_TRUE;
+ }
+ else if (window == ((UINT) TXM_MODULE_DATA_WINDOW_OUTSIDE))
+ {
+
+ /* Shared or external memory: every page must grant the access. */
+ status = _txm_module_manager_page_walk(obj_ptr, last_byte, write_request, TX_TRUE);
+ }
+ else
+ {
+
+ /* The range leaves the module's data partway through. */
+ status = TX_FALSE;
+ }
+ }
+ }
+ }
+
+ /* Return the completion status. */
+ return(status);
+}
+
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _txm_module_manager_outside_data_check Cortex-A7/MMU/IAR */
+/* 6.5.0 */
+/* AUTHOR */
+/* */
+/* Eclipse ThreadX contributors */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function determines whether no byte of a caller-supplied range */
+/* is reachable by the module. It is deliberately not the negation of */
+/* the inside check: a range that reaches into the module's memory */
+/* only partway is inside neither answer, and reporting it as outside */
+/* would let it pass as a kernel object. */
+/* */
+/* INPUT */
+/* */
+/* module_instance Pointer to module instance */
+/* obj_ptr Address of the first byte */
+/* obj_size Size of the range in bytes */
+/* */
+/* OUTPUT */
+/* */
+/* TX_TRUE if no byte of the range is reachable by the module */
+/* */
+/* CALLS */
+/* */
+/* _txm_module_manager_range_end_get */
+/* _txm_module_manager_current_asid_get */
+/* _txm_module_manager_data_window_classify */
+/* _txm_module_manager_page_walk */
+/* */
+/* CALLED BY */
+/* */
+/* TXM_MODULE_MANAGER_CHECK_OUTSIDE_DATA */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* 08-24-2026 Eclipse ThreadX Initial Version 6.5.0 */
+/* contributors */
+/* */
+/**************************************************************************/
+UINT _txm_module_manager_outside_data_check(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE obj_ptr, ULONG obj_size)
+{
+
+ALIGN_TYPE last_byte;
+UINT window;
+UINT status;
+
+
+ /* Assume the range is not provably outside the module. */
+ status = TX_FALSE;
+
+ /* A range can only be placed against a module that exists. */
+ if (module_instance != TX_NULL)
+ {
+
+ /* Determine the last byte, rejecting empty and wrapping ranges. */
+ if (_txm_module_manager_range_end_get(obj_ptr, obj_size, &last_byte) == TX_TRUE)
+ {
+
+ /* Address translation answers for whichever context is loaded, so it can only
+ be trusted while the requesting module's context is the loaded one. */
+ if (_txm_module_manager_current_asid_get() == (module_instance -> txm_module_instance_asid))
+ {
+
+ /* Place the range relative to the module's own data region. */
+ window = _txm_module_manager_data_window_classify(module_instance, obj_ptr, last_byte);
+
+ if (window == ((UINT) TXM_MODULE_DATA_WINDOW_OUTSIDE))
+ {
+
+ /* Clear of the module's data region, so the remaining question is
+ whether any page of it is shared or external memory. */
+ status = _txm_module_manager_page_walk(obj_ptr, last_byte, TXM_MODULE_MANAGER_ACCESS_READ, TX_FALSE);
+ }
+ else
+ {
+
+ /* The range touches the module's data region. */
+ status = TX_FALSE;
+ }
+ }
+ }
+ }
+
+ /* Return the completion status. */
+ return(status);
+}
diff --git a/ports_module/cortex_a7/iar/module_manager/src/txm_module_manager_mm_register_setup.c b/ports_module/cortex_a7/iar/module_manager/src/txm_module_manager_mm_register_setup.c
index 3d477a4a..08c83dc7 100644
--- a/ports_module/cortex_a7/iar/module_manager/src/txm_module_manager_mm_register_setup.c
+++ b/ports_module/cortex_a7/iar/module_manager/src/txm_module_manager_mm_register_setup.c
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -35,24 +37,34 @@ extern ULONG _txm_ttbr1_page_table[TXM_MAXIMUM_MODULES][TXM_MASTER_PAGE_TABLE_EN
/* */
/* FUNCTION RELEASE */
/* */
-/* _txm_module_manager_inside_data_check Cortex-A7/MMU/IAR */
-/* 6.1 */
+/* _txm_module_manager_address_probe Cortex-A7/MMU/IAR */
+/* 6.5.0 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
+/* Eclipse ThreadX contributors */
/* */
/* DESCRIPTION */
/* */
-/* This function determines if pointer is within the module's data or */
-/* shared memory. */
+/* This function asks the MMU whether unprivileged code running in the */
+/* currently loaded translation context may reach one address with the */
+/* requested access. Reading and writing are asked separately, because */
+/* a module's code and its read-only shared memory translate for */
+/* reading while a kernel service writing to them would fault or, */
+/* worse, succeed from privileged mode. */
+/* */
+/* This answers for one address only. Callers that hold a range must */
+/* ask about every page the range touches. */
/* */
/* INPUT */
/* */
-/* pointer Data pointer */
+/* address Address to translate */
+/* write_request TXM_MODULE_MANAGER_ACCESS_READ or */
+/* TXM_MODULE_MANAGER_ACCESS_WRITE */
/* */
/* OUTPUT */
/* */
-/* Completion Status */
+/* TX_TRUE if the translation granted the requested access */
/* */
/* CALLS */
/* */
@@ -60,17 +72,40 @@ extern ULONG _txm_ttbr1_page_table[TXM_MAXIMUM_MODULES][TXM_MASTER_PAGE_TABLE_EN
/* */
/* CALLED BY */
/* */
-/* TXM_MODULE_MANAGER_DATA_POINTER_CHECK */
+/* _txm_module_manager_page_walk */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* 03-08-2023 Scott Larson Initial Version 6.2.1 */
+/* 08-24-2026 Eclipse ThreadX Added the write intent and */
+/* contributors moved range handling to */
+/* the caller, resulting in */
+/* version 6.5.0 */
/* */
/**************************************************************************/
-UINT _txm_module_manager_inside_data_check(ULONG pointer)
+UINT _txm_module_manager_address_probe(ULONG address, UINT write_request)
{
-ULONG translation;
+ULONG translation;
+
+
+ /* Determine which unprivileged access the caller needs. */
+ if (write_request == ((UINT) TXM_MODULE_MANAGER_ACCESS_WRITE))
+ {
+
+ /* ATS1CUW operation on address supplied in address, Stage 1 unprivileged write. */
+ asm("MCR p15, 0, %0, c7, c8, 3" : : "r"(address) : );
+ }
+ else
+ {
+
+ /* ATS1CUR operation on address supplied in address, Stage 1 unprivileged read. */
+ asm("MCR p15, 0, %0, c7, c8, 2" : : "r"(address) : );
+ }
- /* ATS1CUR operation on address supplied in pointer, Stage 1 unprivileged read. */
- asm("MCR p15, 0, %0, c7, c8, 2" : : "r"(pointer) : );
- asm("ISB"); /* Ensure completion of the MCR write to CP15. */
+ asm("ISB"); /* Ensure completion of the MCR write to CP15. */
asm("MRC p15, 0, %0, c7, c4, 0" : "=r"(translation) : : ); /* Read result from 32-bit PAR into translation. */
if (translation & TXM_ADDRESS_TRANSLATION_FAULT_BIT)
@@ -86,6 +121,62 @@ ULONG translation;
/* */
/* FUNCTION RELEASE */
/* */
+/* _txm_module_manager_current_asid_get Cortex-A7/MMU/IAR */
+/* 6.5.0 */
+/* AUTHOR */
+/* */
+/* Eclipse ThreadX contributors */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function returns the ASID of the translation context that is */
+/* currently loaded. Address translation always answers for that */
+/* context, so a caller validating a pointer on behalf of a module */
+/* must confirm that the loaded context is that module's before it */
+/* believes the answer. */
+/* */
+/* INPUT */
+/* */
+/* None */
+/* */
+/* OUTPUT */
+/* */
+/* ASID of the currently loaded translation context */
+/* */
+/* CALLS */
+/* */
+/* None */
+/* */
+/* CALLED BY */
+/* */
+/* _txm_module_manager_inside_data_check */
+/* _txm_module_manager_outside_data_check */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* 08-24-2026 Eclipse ThreadX Initial Version 6.5.0 */
+/* contributors */
+/* */
+/**************************************************************************/
+ULONG _txm_module_manager_current_asid_get(VOID)
+{
+
+ULONG contextidr;
+
+
+ /* Read CONTEXTIDR, whose low byte holds the ASID in the short-descriptor format. */
+ asm("MRC p15, 0, %0, c13, c0, 1" : "=r"(contextidr) : : );
+
+ return(contextidr & TXM_CONTEXTIDR_ASID_MASK);
+}
+
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
/* _txm_module_manager_assign_asid Cortex-A7/MMU/IAR */
/* 6.1 */
/* AUTHOR */