diff options
Diffstat (limited to 'ports_module/cortex_a7')
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 */ |
