Release ARMv7-M and ARMv8-M architecture ports (#249)

* Release ARMv7-M and ARMv8-M architecture ports

* Add a pipeline to check ports_arch
This commit is contained in:
TiejunZhou
2023-04-18 18:11:20 +08:00
committed by GitHub
parent d64ef2ab06
commit 23680f5e5f
179 changed files with 47913 additions and 0 deletions

View File

@@ -0,0 +1,109 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Module */
/** */
/**************************************************************************/
/**************************************************************************/
IMPORT __use_two_region_memory
IMPORT __scatterload
IMPORT txm_heap
AREA ||.text||, CODE, READONLY
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _txm_module_initialize Cortex-Mx/AC5 */
/* 6.1.9 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function initializes the module c runtime. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* __scatterload Initialize C runtime */
/* */
/* CALLED BY */
/* */
/* _txm_module_thread_shell_entry Start module thread */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-15-2021 Scott Larson Initial Version 6.1.9 */
/* */
/**************************************************************************/
// VOID _txm_module_initialize(VOID)
EXPORT _txm_module_initialize
_txm_module_initialize
PUSH {r4-r12,lr} // Save dregs and LR
B __scatterload // Call ARM func to initialize variables
/* Override __rt_exit function. */
EXPORT __rt_exit
__rt_exit
POP {r4-r12,lr} // Restore dregs and LR
BX lr // Return to caller
EXPORT __user_setup_stackheap
// returns heap start address in R0
// returns heap end address in R2
// does not touch SP, it is already set up before the module runs
__user_setup_stackheap
LDR r1, _tx_heap_offset // load heap offset
ADD r0, r9, r1 // calculate heap base address
MOV r2, #TXM_MODULE_HEAP_SIZE // load heap size
ADD r2, r2, r0 // calculate heap end address
BX lr
ALIGN 4
_tx_heap_offset
DCDO txm_heap
AREA ||.arm_vfe_header||, DATA, READONLY, NOALLOC, ALIGN=2
IMPORT txm_heap [DATA]
// Dummy main function
AREA section_main, CODE, READONLY, ALIGN=2
EXPORT main
main
BX lr
END

View File

@@ -0,0 +1,174 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Module */
/** */
/**************************************************************************/
/**************************************************************************/
#ifndef TXM_MODULE
#define TXM_MODULE
#endif
#ifndef TX_SOURCE_CODE
#define TX_SOURCE_CODE
#endif
/* Include necessary system files. */
#include "txm_module.h"
#include "tx_thread.h"
/* Define the global module entry pointer from the start thread of the module. */
TXM_MODULE_THREAD_ENTRY_INFO *_txm_module_entry_info;
/* Define the dispatch function pointer used in the module implementation. */
ULONG (*_txm_module_kernel_call_dispatcher)(ULONG kernel_request, ULONG param_1, ULONG param_2, ULONG param3);
/* Define the startup code that clears the uninitialized global data and sets up the
preset global variables. */
extern VOID _txm_module_initialize(VOID);
__align(8) UCHAR txm_heap[TXM_MODULE_HEAP_SIZE];
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _txm_module_thread_shell_entry Cortex-Mx/AC5 */
/* 6.1.9 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function calls the specified entry function of the thread. It */
/* also provides a place for the thread's entry function to return. */
/* If the thread returns, this function places the thread in a */
/* "COMPLETED" state. */
/* */
/* INPUT */
/* */
/* thread_ptr Pointer to current thread */
/* thread_info Pointer to thread entry info */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _txm_module_initialize cstartup initialization */
/* thread_entry Thread's entry function */
/* tx_thread_resume Resume the module callback thread */
/* _txm_module_thread_system_suspend Module thread suspension routine */
/* */
/* CALLED BY */
/* */
/* Initial thread stack frame */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-15-2021 Scott Larson Initial Version 6.1.9 */
/* */
/**************************************************************************/
VOID _txm_module_thread_shell_entry(TX_THREAD *thread_ptr, TXM_MODULE_THREAD_ENTRY_INFO *thread_info)
{
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
VOID (*entry_exit_notify)(TX_THREAD *, UINT);
#endif
/* Determine if this is the start thread. If so, we must prepare the module for
execution. If not, simply skip the C startup code. */
if (thread_info -> txm_module_thread_entry_info_start_thread)
{
/* Initialize the C environment. */
_txm_module_initialize();
/* Save the entry info pointer, for later use. */
_txm_module_entry_info = thread_info;
/* Save the kernel function dispatch address. This is used to make all resident calls from
the module. */
_txm_module_kernel_call_dispatcher = thread_info -> txm_module_thread_entry_info_kernel_call_dispatcher;
/* Ensure that we have a valid pointer. */
while (!_txm_module_kernel_call_dispatcher)
{
/* Loop here, if an error is present getting the dispatch function pointer!
An error here typically indicates the resident portion of _tx_thread_schedule
is not supporting the trap to obtain the function pointer. */
}
/* Resume the module's callback thread, already created in the manager. */
_txe_thread_resume(thread_info -> txm_module_thread_entry_info_callback_request_thread);
}
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
/* Pickup the entry/exit application callback routine. */
entry_exit_notify = thread_info -> txm_module_thread_entry_info_exit_notify;
/* Determine if an application callback routine is specified. */
if (entry_exit_notify != TX_NULL)
{
/* Yes, notify application that this thread has been entered! */
(entry_exit_notify)(thread_ptr, TX_THREAD_ENTRY);
}
#endif
/* Call current thread's entry function. */
(thread_info -> txm_module_thread_entry_info_entry) (thread_info -> txm_module_thread_entry_info_parameter);
/* Suspend thread with a "completed" state. */
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
/* Pickup the entry/exit application callback routine again. */
entry_exit_notify = thread_info -> txm_module_thread_entry_info_exit_notify;
/* Determine if an application callback routine is specified. */
if (entry_exit_notify != TX_NULL)
{
/* Yes, notify application that this thread has exited! */
(entry_exit_notify)(thread_ptr, TX_THREAD_EXIT);
}
#endif
/* Call actual thread suspension routine. */
_txm_module_thread_system_suspend(thread_ptr);
#ifdef TX_SAFETY_CRITICAL
/* If we ever get here, raise safety critical exception. */
TX_SAFETY_CRITICAL_EXCEPTION(__FILE__, __LINE__, 0);
#endif
}

View File

@@ -0,0 +1,646 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Thread */
/** */
/**************************************************************************/
/**************************************************************************/
IMPORT _tx_thread_current_ptr
IMPORT _tx_thread_execute_ptr
IMPORT _tx_timer_time_slice
#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
IMPORT _tx_execution_thread_enter
IMPORT _tx_execution_thread_exit
#endif
IMPORT _tx_thread_preempt_disable
IMPORT _txm_module_manager_memory_fault_handler
IMPORT _txm_module_manager_memory_fault_info
IMPORT _txm_module_priv
IMPORT _txm_module_user_mode_exit
AREA ||.text||, CODE, READONLY
THUMB
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_schedule Cortex-Mx/AC5 */
/* 6.2.0 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function waits for a thread control block pointer to appear in */
/* the _tx_thread_execute_ptr variable. Once a thread pointer appears */
/* in the variable, the corresponding thread is resumed. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _tx_initialize_kernel_enter ThreadX entry function */
/* _tx_thread_system_return Return to system from thread */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-15-2021 Scott Larson Initial Version 6.1.9 */
/* 04-25-2022 Scott Larson Optimized MPU configuration, */
/* added BASEPRI support, */
/* resulting in version 6.1.11 */
/* 07-29-2022 Scott Larson Removed the code path to skip */
/* MPU reloading, optional */
/* default MPU settings, */
/* resulting in version 6.1.12 */
/* 10-31-2022 Scott Larson Added low power support, */
/* fixed label syntax, */
/* resulting in version 6.2.0 */
/* */
/**************************************************************************/
// VOID _tx_thread_schedule(VOID)
// {
EXPORT _tx_thread_schedule
_tx_thread_schedule
/* This function should only ever be called on Cortex-M
from the first schedule request. Subsequent scheduling occurs
from the PendSV handling routine below. */
/* Clear the preempt-disable flag to enable rescheduling after initialization on Cortex-M targets. */
MOV r0, #0 // Build value for TX_FALSE
LDR r2, =_tx_thread_preempt_disable // Build address of preempt disable flag
STR r0, [r2, #0] // Clear preempt disable flag
#ifdef __TARGET_FPU_VFP
/* Clear CONTROL.FPCA bit so VFP registers aren't unnecessarily stacked. */
MRS r0, CONTROL // Pickup current CONTROL register
BIC r0, r0, #4 // Clear the FPCA bit
MSR CONTROL, r0 // Setup new CONTROL register
#endif
/* Enable memory fault registers. */
LDR r0, =0xE000ED24 // Build SHCSR address
LDR r1, =0x70000 // Enable Usage, Bus, and MemManage faults
STR r1, [r0] //
/* Enable interrupts */
CPSIE i
/* Enter the scheduler for the first time. */
MOV r0, #0x10000000 // Load PENDSVSET bit
MOV r1, #0xE000E000 // Load NVIC base
STR r0, [r1, #0xD04] // Set PENDSVBIT in ICSR
DSB // Complete all memory accesses
ISB // Flush pipeline
/* Wait here for the PendSV to take place. */
__tx_wait_here
B __tx_wait_here // Wait for the PendSV to happen
// }
/* Memory Exception Handler. */
EXPORT MemManage_Handler
MemManage_Handler
#ifdef TX_PORT_USE_BASEPRI
LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI
MSR BASEPRI, r1
#else
CPSID i // Disable interrupts
#endif /* TX_PORT_USE_BASEPRI */
/* Now pickup and store all the fault related information. */
LDR r12,=_txm_module_manager_memory_fault_info // Pickup fault info struct
LDR r0, =_tx_thread_current_ptr // Build current thread pointer address
LDR r1, [r0] // Pickup the current thread pointer
STR r1, [r12, #0] // Save current thread pointer in fault info structure
LDR r0, =0xE000ED24 // Build SHCSR address
LDR r1, [r0] // Pickup SHCSR
STR r1, [r12, #8] // Save SHCSR
LDR r0, =0xE000ED28 // Build CFSR address
LDR r1, [r0] // Pickup CFSR
STR r1, [r12, #12] // Save CFSR
LDR r0, =0xE000ED34 // Build MMFAR address
LDR r1, [r0] // Pickup MMFAR
STR r1, [r12, #16] // Save MMFAR
LDR r0, =0xE000ED38 // Build BFAR address
LDR r1, [r0] // Pickup BFAR
STR r1, [r12, #20] // Save BFAR
MRS r0, CONTROL // Pickup current CONTROL register
STR r0, [r12, #24] // Save CONTROL
MRS r1, PSP // Pickup thread stack pointer
STR r1, [r12, #28] // Save thread stack pointer
LDR r0, [r1] // Pickup saved r0
STR r0, [r12, #32] // Save r0
LDR r0, [r1, #4] // Pickup saved r1
STR r0, [r12, #36] // Save r1
STR r2, [r12, #40] // Save r2
STR r3, [r12, #44] // Save r3
STR r4, [r12, #48] // Save r4
STR r5, [r12, #52] // Save r5
STR r6, [r12, #56] // Save r6
STR r7, [r12, #60] // Save r7
STR r8, [r12, #64] // Save r8
STR r9, [r12, #68] // Save r9
STR r10,[r12, #72] // Save r10
STR r11,[r12, #76] // Save r11
LDR r0, [r1, #16] // Pickup saved r12
STR r0, [r12, #80] // Save r12
LDR r0, [r1, #20] // Pickup saved lr
STR r0, [r12, #84] // Save lr
LDR r0, [r1, #24] // Pickup instruction address at point of fault
STR r0, [r12, #4] // Save point of fault
LDR r0, [r1, #28] // Pickup xPSR
STR r0, [r12, #88] // Save xPSR
MRS r0, CONTROL // Pickup current CONTROL register
BIC r0, r0, #1 // Clear the UNPRIV bit
MSR CONTROL, r0 // Setup new CONTROL register
LDR r0, =0xE000ED28 // Build the Memory Management Fault Status Register (MMFSR)
LDRB r1, [r0] // Pickup the MMFSR, with the following bit definitions:
// Bit 0 = 1 -> Instruction address violation
// Bit 1 = 1 -> Load/store address violation
// Bit 7 = 1 -> MMFAR is valid
STRB r1, [r0] // Clear the MMFSR
#ifdef __TARGET_FPU_VFP
LDR r0, =0xE000EF34 // Cleanup FPU context: Load FPCCR address
LDR r1, [r0] // Load FPCCR
BIC r1, r1, #1 // Clear the lazy preservation active bit
STR r1, [r0] // Save FPCCR
#endif
BL _txm_module_manager_memory_fault_handler // Call memory manager fault handler
#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
/* Call the thread exit function to indicate the thread is no longer executing. */
CPSID i // Disable interrupts
BL _tx_execution_thread_exit // Call the thread exit function
CPSIE i // Enable interrupts
#endif
MOV r1, #0 // Build NULL value
LDR r0, =_tx_thread_current_ptr // Pickup address of current thread pointer
STR r1, [r0] // Clear current thread pointer
// Return from MemManage_Handler exception
LDR r0, =0xE000ED04 // Load ICSR
LDR r1, =0x10000000 // Set PENDSVSET bit
STR r1, [r0] // Store ICSR
DSB // Wait for memory access to complete
#ifdef TX_PORT_USE_BASEPRI
MOV r0, 0 // Disable BASEPRI masking (enable interrupts)
MSR BASEPRI, r0
#else
CPSIE i // Enable interrupts
#endif
MOV lr, #0xFFFFFFFD // Load exception return code
BX lr // Return from exception
/* Generic context PendSV handler. */
EXPORT PendSV_Handler
EXPORT __tx_PendSVHandler
PendSV_Handler
__tx_PendSVHandler
/* Get current thread value and new thread pointer. */
__tx_ts_handler
#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
/* Call the thread exit function to indicate the thread is no longer executing. */
#ifdef TX_PORT_USE_BASEPRI
LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI
MSR BASEPRI, r1
#else
CPSID i // Disable interrupts
#endif /* TX_PORT_USE_BASEPRI */
PUSH {r0, lr} // Save LR (and r0 just for alignment)
BL _tx_execution_thread_exit // Call the thread exit function
POP {r0, lr} // Recover LR
#ifdef TX_PORT_USE_BASEPRI
MOV r0, 0 // Disable BASEPRI masking (enable interrupts)
MSR BASEPRI, r0
#else
CPSIE i // Enable interrupts
#endif /* TX_PORT_USE_BASEPRI */
#endif /* EXECUTION PROFILE */
LDR r0, =_tx_thread_current_ptr // Build current thread pointer address
LDR r2, =_tx_thread_execute_ptr // Build execute thread pointer address
MOV r3, #0 // Build NULL value
LDR r1, [r0] // Pickup current thread pointer
/* Determine if there is a current thread to finish preserving. */
CBZ r1, __tx_ts_new // If NULL, skip preservation
/* Recover PSP and preserve current thread context. */
STR r3, [r0] // Set _tx_thread_current_ptr to NULL
MRS r12, PSP // Pickup PSP pointer (thread's stack pointer)
STMDB r12!, {r4-r11} // Save its remaining registers
#ifdef __TARGET_FPU_VFP
TST LR, #0x10 // Determine if the VFP extended frame is present
BNE _skip_vfp_save
VSTMDB r12!,{s16-s31} // Yes, save additional VFP registers
_skip_vfp_save
#endif
LDR r4, =_tx_timer_time_slice // Build address of time-slice variable
STMDB r12!, {LR} // Save LR on the stack
/* Determine if time-slice is active. If it isn't, skip time handling processing. */
LDR r5, [r4] // Pickup current time-slice
STR r12, [r1, #8] // Save the thread stack pointer
CBZ r5, __tx_ts_new // If not active, skip processing
/* Time-slice is active, save the current thread's time-slice and clear the global time-slice variable. */
STR r5, [r1, #24] // Save current time-slice
/* Clear the global time-slice. */
STR r3, [r4] // Clear time-slice
/* Executing thread is now completely preserved!!! */
__tx_ts_new
/* Now we are looking for a new thread to execute! */
#ifdef TX_PORT_USE_BASEPRI
LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI
MSR BASEPRI, r1
#else
CPSID i // Disable interrupts
#endif
LDR r1, [r2] // Is there another thread ready to execute?
CBNZ r1, __tx_ts_restore // Yes, schedule it
/* The following is the idle wait processing... in this case, no threads are ready for execution and the
system will simply be idle until an interrupt occurs that makes a thread ready. Note that interrupts
are disabled to allow use of WFI for waiting for a thread to arrive. */
__tx_ts_wait
#ifdef TX_PORT_USE_BASEPRI
LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI
MSR BASEPRI, r1
#else
CPSID i // Disable interrupts
#endif
LDR r1, [r2] // Pickup the next thread to execute pointer
CBNZ r1, __tx_ts_ready // If non-NULL, a new thread is ready!
#ifdef TX_LOW_POWER
PUSH {r0-r3}
BL tx_low_power_enter // Possibly enter low power mode
POP {r0-r3}
#endif
#ifdef TX_ENABLE_WFI
DSB // Ensure no outstanding memory transactions
WFI // Wait for interrupt
ISB // Ensure pipeline is flushed
#endif
#ifdef TX_LOW_POWER
PUSH {r0-r3}
BL tx_low_power_exit // Exit low power mode
POP {r0-r3}
#endif
#ifdef TX_PORT_USE_BASEPRI
MOV r4, #0 // Disable BASEPRI masking (enable interrupts)
MSR BASEPRI, r4
#else
CPSIE i // Enable interrupts
#endif
B __tx_ts_wait // Loop to continue waiting
/* At this point, we have a new thread ready to go. Clear any newly pended PendSV - since we are
already in the handler! */
__tx_ts_ready
MOV r7, #0x08000000 // Build clear PendSV value
MOV r8, #0xE000E000 // Build base NVIC address
STR r7, [r8, #0xD04] // Clear any PendSV
__tx_ts_restore
/* A thread is ready, make the current thread the new thread
and enable interrupts. */
STR r1, [r0] // Setup the current thread pointer to the new thread
#ifdef TX_PORT_USE_BASEPRI
MOV r4, #0 // Disable BASEPRI masking (enable interrupts)
MSR BASEPRI, r4
#else
CPSIE i // Enable interrupts
#endif
/* Increment the thread run count. */
LDR r7, [r1, #4] // Pickup the current thread run count
LDR r4, =_tx_timer_time_slice // Build address of time-slice variable
LDR r5, [r1, #24] // Pickup thread's current time-slice
ADD r7, r7, #1 // Increment the thread run count
STR r7, [r1, #4] // Store the new run count
/* Setup global time-slice with thread's current time-slice. */
STR r5, [r4] // Setup global time-slice
#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
/* Call the thread entry function to indicate the thread is executing. */
PUSH {r0, r1} // Save r0 and r1
BL _tx_execution_thread_enter // Call the thread execution enter function
POP {r0, r1} // Recover r0 and r1
#endif
/* Restore the thread context and PSP. */
LDR r12, [r1, #8] // Pickup thread's stack pointer
MRS r5, CONTROL // Pickup current CONTROL register
LDR r4, [r1, #0x98] // Pickup current user mode flag
BIC r5, r5, #1 // Clear the UNPRIV bit
ORR r4, r4, r5 // Build new CONTROL register
MSR CONTROL, r4 // Setup new CONTROL register
LDR r0, =0xE000ED94 // Build MPU control reg address
MOV r3, #0 // Build disable value
CPSID i // Disable interrupts
STR r3, [r0] // Disable MPU
LDR r0, [r1, #0x90] // Pickup the module instance pointer
#ifdef TXM_MODULE_MPU_DEFAULT
CBZ r0, default_mpu // Is this thread owned by a module? No, default MPU setup
#else
CBZ r0, skip_mpu_setup // Is this thread owned by a module? No, skip MPU setup
#endif
LDR r2, [r0, #0x8C] // Pickup MPU region 5 address
#ifdef TXM_MODULE_MPU_DEFAULT
CBZ r2, default_mpu // Is protection required for this module? No, default MPU setup
#else
CBZ r2, skip_mpu_setup // Is protection required for this module? No, skip MPU setup
#endif
LDR r1, =0xE000ED9C // MPU_RBAR register address
// Use alias registers to quickly load MPU
ADD r0, r0, #100 // Build address of MPU register start in thread control block
#ifdef TXM_MODULE_MPU_DEFAULT
B config_mpu // configure MPU for module
default_mpu
LDR r0, =txm_module_default_mpu_registers // default MPU configuration
#endif
config_mpu
LDM r0!,{r2-r9} // Load MPU regions 0-3
STM r1,{r2-r9} // Store MPU regions 0-3
LDM r0!,{r2-r9} // Load MPU regions 4-7
STM r1,{r2-r9} // Store MPU regions 4-7
#ifdef TXM_MODULE_MANAGER_16_MPU
LDM r0!,{r2-r9} // Load MPU regions 8-11
STM r1,{r2-r9} // Store MPU regions 8-11
// Regions 12-15 are reserved for the user to define.
LDM r0,{r2-r9} // Load MPU regions 12-15
STM r1,{r2-r9} // Store MPU regions 12-15
#endif
_tx_enable_mpu
LDR r0, =0xE000ED94 // Build MPU control reg address
MOV r1, #5 // Build enable value with background region enabled
STR r1, [r0] // Enable MPU
skip_mpu_setup
CPSIE i // Enable interrupts
LDMIA r12!, {LR} // Pickup LR
#ifdef __TARGET_FPU_VFP
TST LR, #0x10 // Determine if the VFP extended frame is present
BNE _skip_vfp_restore // If not, skip VFP restore
VLDMIA r12!, {s16-s31} // Yes, restore additional VFP registers
_skip_vfp_restore
#endif
LDMIA r12!, {r4-r11} // Recover thread's registers
MSR PSP, r12 // Setup the thread's stack pointer
/* Return to thread. */
BX lr // Return to thread!
/* SVC Handler. */
EXPORT SVC_Handler
EXPORT __tx_SVCallHandler
SVC_Handler
__tx_SVCallHandler
MRS r0, PSP // Pickup the PSP stack
LDR r1, [r0, #24] // Pickup the point of interrupt
LDRB r2, [r1, #-2] // Pickup the SVC parameter
/* Determine which SVC trap we are processing */
CMP r2, #1 // Is it the entry into ThreadX?
BNE _tx_thread_user_return // No, return to user mode
/* At this point we have an SVC 1, which means we are entering
the kernel from a module thread with user mode selected. */
LDR r2, =_txm_module_priv // Load address of where we should have come from
SUB r2, r2, #1 // Subtract 1 because of THUMB mode.
CMP r1, r2 // Did we come from user_mode_entry?
IT NE // If no (not equal), then...
BXNE lr // return from where we came.
LDR r3, [r0, #20] // This is the saved LR
LDR r1, =_tx_thread_current_ptr // Build current thread pointer address
LDR r2, [r1] // Pickup current thread pointer
MOV r1, #0 // Build clear value
STR r1, [r2, #0x98] // Clear the current user mode selection for thread
STR r3, [r2, #0xA0] // Save the original LR in thread control block
/* If there is memory protection, use kernel stack */
LDR r0, [r2, #0x90] // Load the module instance ptr
LDR r0, [r0, #0x0C] // Load the module property flags
TST r0, #2 // Check if memory protected
BEQ _tx_skip_kernel_stack_enter
/* Switch to the module thread's kernel stack */
LDR r0, [r2, #0xA8] // Load the module kernel stack end
#ifndef TXM_MODULE_KERNEL_STACK_MAINTENANCE_DISABLE
LDR r1, [r2, #0xA4] // Load the module kernel stack start
LDR r3, [r2, #0xAC] // Load the module kernel stack size
STR r1, [r2, #12] // Set stack start
STR r0, [r2, #16] // Set stack end
STR r3, [r2, #20] // Set stack size
#endif
MRS r3, PSP // Pickup thread stack pointer
#ifdef __TARGET_FPU_VFP
TST lr, #0x10 // Test for extended module stack
ITT EQ
ORREQ r3, r3, #1 // If so, set LSB in thread stack pointer to indicate extended frame
ORREQ lr, lr, #0x10 // Set bit, return with standard frame
#endif
STR r3, [r2, #0xB0] // Save thread stack pointer
#ifdef __TARGET_FPU_VFP
BIC r3, #1 // Clear possibly OR'd bit
#endif
/* Build kernel stack by copying thread stack two registers at a time */
ADD r3, r3, #32 // Start at bottom of hardware stack
LDMDB r3!, {r1-r2}
STMDB r0!, {r1-r2}
LDMDB r3!, {r1-r2}
STMDB r0!, {r1-r2}
LDMDB r3!, {r1-r2}
STMDB r0!, {r1-r2}
LDMDB r3!, {r1-r2}
STMDB r0!, {r1-r2}
MSR PSP, r0 // Set kernel stack pointer
_tx_skip_kernel_stack_enter
MRS r0, CONTROL // Pickup current CONTROL register
BIC r0, r0, #1 // Clear the UNPRIV bit
MSR CONTROL, r0 // Setup new CONTROL register
BX lr // Return to thread
_tx_thread_user_return
LDR r2, =_txm_module_user_mode_exit // Load address of where we should have come from
SUB r2, r2, #1 // Subtract 1 because of THUMB mode.
CMP r1, r2 // Did we come from user_mode_exit?
IT NE // If no (not equal), then...
BXNE lr // return from where we came
LDR r1, =_tx_thread_current_ptr // Build current thread pointer address
LDR r2, [r1] // Pickup current thread pointer
LDR r1, [r2, #0x9C] // Pick up user mode
STR r1, [r2, #0x98] // Set the current user mode selection for thread
/* If there is memory protection, use kernel stack */
LDR r0, [r2, #0x90] // Load the module instance ptr
LDR r0, [r0, #0x0C] // Load the module property flags
TST r0, #2 // Check if memory protected
BEQ _tx_skip_kernel_stack_exit
#ifndef TXM_MODULE_KERNEL_STACK_MAINTENANCE_DISABLE
LDR r0, [r2, #0xB4] // Load the module thread stack start
LDR r1, [r2, #0xB8] // Load the module thread stack end
LDR r3, [r2, #0xBC] // Load the module thread stack size
STR r0, [r2, #12] // Set stack start
STR r1, [r2, #16] // Set stack end
STR r3, [r2, #20] // Set stack size
#endif
#ifdef __TARGET_FPU_VFP
/* If lazy stacking is pending, check if it can be cleared.
if(LSPACT && tx_thread_module_stack_start < FPCAR && FPCAR < tx_thread_module_stack_end)
then clear LSPACT. */
LDR r3, =0xE000EF34 // Address of FPCCR
LDR r3, [r3] // Load FPCCR
TST r3, #1 // Check if LSPACT is set
BEQ _tx_no_lazy_clear // if clear, move on
LDR r1, =0xE000EF38 // Address of FPCAR
LDR r1, [r1] // Load FPCAR
LDR r0, [r2, #0xA4] // Load kernel stack start
CMP r1, r0 // If FPCAR < start, move on
BLO _tx_no_lazy_clear
LDR r0, [r2, #0xA8] // Load kernel stack end
CMP r0, r1 // If end < FPCAR, move on
BLO _tx_no_lazy_clear
BIC r3, #1 // Clear LSPACT
LDR r1, =0xE000EF34 // Address of FPCCR
STR r3, [r1] // Save updated FPCCR
_tx_no_lazy_clear
#endif
LDR r0, [r2, #0xB0] // Load the module thread stack pointer
MRS r3, PSP // Pickup kernel stack pointer
#ifdef __TARGET_FPU_VFP
TST r0, #1 // Is module stack extended?
ITTE NE // If so...
BICNE lr, #0x10 // Clear bit, return with extended frame
BICNE r0, #1 // Clear bit that indicates extended module frame
ORREQ lr, lr, #0x10 // Else set bit, return with standard frame
#endif
/* Copy kernel hardware stack to module thread stack. */
LDM r3!, {r1-r2} // Get r0, r1 from kernel stack
STM r0!, {r1-r2} // Insert r0, r1 into thread stack
LDM r3!, {r1-r2} // Get r2, r3 from kernel stack
STM r0!, {r1-r2} // Insert r2, r3 into thread stack
LDM r3!, {r1-r2} // Get r12, lr from kernel stack
STM r0!, {r1-r2} // Insert r12, lr into thread stack
LDM r3!, {r1-r2} // Get pc, xpsr from kernel stack
STM r0!, {r1-r2} // Insert pc, xpsr into thread stack
SUB r0, r0, #32 // Subtract 32 to get back to top of stack
MSR PSP, r0 // Set thread stack pointer
LDR r1, =_tx_thread_current_ptr // Build current thread pointer address
LDR r2, [r1] // Pickup current thread pointer
LDR r1, [r2, #0x9C] // Pick up user mode
_tx_skip_kernel_stack_exit
MRS r0, CONTROL // Pickup current CONTROL register
ORR r0, r0, r1 // OR in the user mode bit
MSR CONTROL, r0 // Setup new CONTROL register
BX lr // Return to thread
#ifdef __TARGET_FPU_VFP
EXPORT tx_thread_fpu_enable
tx_thread_fpu_enable
EXPORT tx_thread_fpu_disable
tx_thread_fpu_disable
/* Automatic VPF logic is supported, this function is present only for
backward compatibility purposes and therefore simply returns. */
BX LR // Return to caller
EXPORT _tx_vfp_access
_tx_vfp_access
VMOV.F32 s0, s0 // Simply access the VFP
BX lr // Return to caller
#endif
ALIGN 4
END

View File

@@ -0,0 +1,138 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Module Manager */
/** */
/**************************************************************************/
/**************************************************************************/
AREA ||.text||, CODE, READONLY
THUMB
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _txm_module_manager_thread_stack_build Cortex-Mx/AC5 */
/* 6.1.9 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function builds a stack frame on the supplied thread's stack. */
/* The stack frame results in a fake interrupt return to the supplied */
/* function pointer. */
/* */
/* INPUT */
/* */
/* thread_ptr Pointer to thread */
/* function_ptr Pointer to shell function */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _tx_thread_create Create thread service */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-15-2021 Scott Larson Initial Version 6.1.9 */
/* */
/**************************************************************************/
// VOID _txm_module_manager_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(TX_THREAD *, TXM_MODULE_INSTANCE *))
// {
EXPORT _txm_module_manager_thread_stack_build
_txm_module_manager_thread_stack_build
/* Build a fake interrupt frame. The form of the fake interrupt stack
on the Cortex-M should look like the following after it is built:
Stack Top:
lr Interrupted lr (lr at time of PENDSV)
r4 Initial value for r4
r5 Initial value for r5
r6 Initial value for r6
r7 Initial value for r7
r8 Initial value for r8
r9 Initial value for r9
r10 Initial value for r10
r11 Initial value for r11
r0 Initial value for r0 (Hardware stack starts here!!)
r1 Initial value for r1
r2 Initial value for r2
r3 Initial value for r3
r12 Initial value for r12
lr Initial value for lr
pc Initial value for pc
xPSR Initial value for xPSR
Stack Bottom: (higher memory address) */
LDR r2, [r0, #16] // Pickup end of stack area
BIC r2, r2, #0x7 // Align frame
SUB r2, r2, #68 // Subtract frame size
LDR r3, =0xFFFFFFFD // Build initial LR value
STR r3, [r2, #0] // Save on the stack
/* Actually build the stack frame. */
MOV r3, #0 // Build initial register value
STR r3, [r2, #4] // Store initial r4
STR r3, [r2, #8] // Store initial r5
STR r3, [r2, #12] // Store initial r6
STR r3, [r2, #16] // Store initial r7
STR r3, [r2, #20] // Store initial r8
STR r3, [r2, #28] // Store initial r10
STR r3, [r2, #32] // Store initial r11
/* Hardware stack follows. */
STR r0, [r2, #36] // Store initial r0, which is the thread control block
LDR r3, [r0, #8] // Pickup thread entry info pointer,which is in the stack pointer position of the thread control block.
// It was setup in the txm_module_manager_thread_create function. It will be overwritten later in this
// function with the actual, initial stack pointer.
STR r3, [r2, #40] // Store initial r1, which is the module entry information.
LDR r3, [r3, #8] // Pickup data base register from the module information
STR r3, [r2, #24] // Store initial r9 (data base register)
MOV r3, #0 // Clear r3 again
STR r3, [r2, #44] // Store initial r2
STR r3, [r2, #48] // Store initial r3
STR r3, [r2, #52] // Store initial r12
MOV r3, #0xFFFFFFFF // Poison EXC_RETURN value
STR r3, [r2, #56] // Store initial lr
STR r1, [r2, #60] // Store initial pc
MOV r3, #0x01000000 // Only T-bit need be set
STR r3, [r2, #64] // Store initial xPSR
/* Setup stack pointer. */
// thread_ptr -> tx_thread_stack_ptr = r2;
STR r2, [r0, #8] // Save stack pointer in thread's control block
BX lr // Return to caller
// }
END

View File

@@ -0,0 +1,88 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Module Manager */
/** */
/**************************************************************************/
/**************************************************************************/
IMPORT _txm_module_manager_kernel_dispatch
IMPORT _tx_thread_current_ptr
AREA ||.text||, CODE, READONLY, ALIGN=5
THUMB
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _txm_module_manager_user_mode_entry Cortex-Mx/AC5 */
/* 6.1.9 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function allows modules to enter kernel mode. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* SVC 1 Enter kernel mode */
/* SVC 2 Exit kernel mode */
/* */
/* CALLED BY */
/* */
/* Modules in user mode */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-15-2021 Scott Larson Initial Version 6.1.9 */
/* */
/**************************************************************************/
// VOID _txm_module_manager_user_mode_entry(VOID)
// {
EXPORT _txm_module_manager_user_mode_entry
_txm_module_manager_user_mode_entry
SVC 1 // Enter kernel
EXPORT _txm_module_priv
_txm_module_priv
// At this point, we are out of user mode. The original LR has been saved in the
// thread control block. Simply call the kernel dispatch function.
BL _txm_module_manager_kernel_dispatch
// Pickup the original LR value while still in privileged mode
LDR r2, =_tx_thread_current_ptr // Build current thread pointer address
LDR r3, [r2] // Pickup current thread pointer
LDR lr, [r3, #0xA0] // Pickup saved LR from original call
SVC 2 // Exit kernel and return to user mode
EXPORT _txm_module_user_mode_exit
_txm_module_user_mode_exit
BX lr // Return to the caller
// }
ALIGN 32
END

View File

@@ -0,0 +1,91 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Module */
/** */
/**************************************************************************/
/**************************************************************************/
.global __use_two_region_memory
.global __scatterload
.eabi_attribute Tag_ABI_PCS_RO_data, 1
.eabi_attribute Tag_ABI_PCS_R9_use, 1
.eabi_attribute Tag_ABI_PCS_RW_data, 2
.text
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _txm_module_initialize Cortex-Mx/AC6 */
/* 6.1.10 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function initializes the module c runtime. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* __scatterload Initialize C runtime */
/* */
/* CALLED BY */
/* */
/* _txm_module_thread_shell_entry Start module thread */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-15-2021 Scott Larson Initial Version 6.1.9 */
/* 01-31-2022 Scott Larson Modified comments and made */
/* heap user configurable, */
/* resulting in version 6.1.10 */
/* */
/**************************************************************************/
// VOID _txm_module_initialize(VOID)
.global _txm_module_initialize
.thumb_func
_txm_module_initialize:
PUSH {r0-r12,lr} // Save dregs and LR
B __scatterload // Call ARM func to initialize variables
// Override the __rt_exit function.
.global __rt_exit
.thumb_func
__rt_exit:
POP {r4-r12,lr} // Restore dregs and LR
BX lr // Return to caller
.global __rt_entry
.type __rt_entry, %function
__rt_entry:
POP {r0-r1}
BL __rt_lib_init
POP {r2-r12,lr} // Restore dregs and LR
BX lr // Return to caller

View File

@@ -0,0 +1,178 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Module */
/** */
/**************************************************************************/
/**************************************************************************/
#ifndef TXM_MODULE
#define TXM_MODULE
#endif
#ifndef TX_SOURCE_CODE
#define TX_SOURCE_CODE
#endif
/* Include necessary system files. */
#include "txm_module.h"
#include "tx_thread.h"
/* Define the global module entry pointer from the start thread of the module. */
TXM_MODULE_THREAD_ENTRY_INFO *_txm_module_entry_info;
/* Define the dispatch function pointer used in the module implementation. */
ULONG (*_txm_module_kernel_call_dispatcher)(ULONG kernel_request, ULONG param_1, ULONG param_2, ULONG param3);
/* Define the module's heap and align it to 8 bytes. */
__attribute__((aligned(8))) UCHAR txm_heap[TXM_MODULE_HEAP_SIZE];
/* Use our asm routine that calls the ARM code to initialize data and heap. */
extern VOID _txm_module_initialize(VOID *heap_base, VOID *heap_top);
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _txm_module_thread_shell_entry Cortex-Mx/AC6 */
/* 6.1.10 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function calls the specified entry function of the thread. It */
/* also provides a place for the thread's entry function to return. */
/* If the thread returns, this function places the thread in a */
/* "COMPLETED" state. */
/* */
/* INPUT */
/* */
/* thread_ptr Pointer to current thread */
/* thread_info Pointer to thread entry info */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _txm_module_initialize cstartup initialization */
/* thread_entry Thread's entry function */
/* tx_thread_resume Resume the module callback thread */
/* _txm_module_thread_system_suspend Module thread suspension routine */
/* */
/* CALLED BY */
/* */
/* Initial thread stack frame */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-15-2021 Scott Larson Initial Version 6.1.9 */
/* 01-31-2022 Scott Larson Modified comments and made */
/* heap user configurable, */
/* resulting in version 6.1.10 */
/* */
/**************************************************************************/
VOID _txm_module_thread_shell_entry(TX_THREAD *thread_ptr, TXM_MODULE_THREAD_ENTRY_INFO *thread_info)
{
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
VOID (*entry_exit_notify)(TX_THREAD *, UINT);
#endif
/* Determine if this is the start thread. If so, we must prepare the module for
execution. If not, simply skip the C startup code. */
if (thread_info -> txm_module_thread_entry_info_start_thread)
{
/* Initialize the C environment. */
_txm_module_initialize(&txm_heap[0], &txm_heap[TXM_MODULE_HEAP_SIZE-1]);
/* Save the entry info pointer, for later use. */
_txm_module_entry_info = thread_info;
/* Save the kernel function dispatch address. This is used to make all resident calls from
the module. */
_txm_module_kernel_call_dispatcher = thread_info -> txm_module_thread_entry_info_kernel_call_dispatcher;
/* Ensure that we have a valid pointer. */
while (!_txm_module_kernel_call_dispatcher)
{
/* Loop here, if an error is present getting the dispatch function pointer!
An error here typically indicates the resident portion of _tx_thread_schedule
is not supporting the trap to obtain the function pointer. */
}
/* Resume the module's callback thread, already created in the manager. */
_txe_thread_resume(thread_info -> txm_module_thread_entry_info_callback_request_thread);
}
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
/* Pickup the entry/exit application callback routine. */
entry_exit_notify = thread_info -> txm_module_thread_entry_info_exit_notify;
/* Determine if an application callback routine is specified. */
if (entry_exit_notify != TX_NULL)
{
/* Yes, notify application that this thread has been entered! */
(entry_exit_notify)(thread_ptr, TX_THREAD_ENTRY);
}
#endif
/* Call current thread's entry function. */
(thread_info -> txm_module_thread_entry_info_entry) (thread_info -> txm_module_thread_entry_info_parameter);
/* Suspend thread with a "completed" state. */
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
/* Pickup the entry/exit application callback routine again. */
entry_exit_notify = thread_info -> txm_module_thread_entry_info_exit_notify;
/* Determine if an application callback routine is specified. */
if (entry_exit_notify != TX_NULL)
{
/* Yes, notify application that this thread has exited! */
(entry_exit_notify)(thread_ptr, TX_THREAD_EXIT);
}
#endif
/* Call actual thread suspension routine. */
_txm_module_thread_system_suspend(thread_ptr);
#ifdef TX_SAFETY_CRITICAL
/* If we ever get here, raise safety critical exception. */
TX_SAFETY_CRITICAL_EXCEPTION(__FILE__, __LINE__, 0);
#endif
}

View File

@@ -0,0 +1,686 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Thread */
/** */
/**************************************************************************/
/**************************************************************************/
.global _tx_thread_current_ptr
.global _tx_thread_execute_ptr
.global _tx_timer_time_slice
.global _tx_thread_preempt_disable
.global _txm_module_manager_memory_fault_handler
.global _txm_module_manager_memory_fault_info
#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
.global _tx_execution_thread_enter
.global _tx_execution_thread_exit
#endif
#ifdef TX_LOW_POWER
.global tx_low_power_enter
.global tx_low_power_exit
#endif
.text
.align 4
.syntax unified
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_schedule Cortex-Mx/AC6 */
/* 6.2.0 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function waits for a thread control block pointer to appear in */
/* the _tx_thread_execute_ptr variable. Once a thread pointer appears */
/* in the variable, the corresponding thread is resumed. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _tx_initialize_kernel_enter ThreadX entry function */
/* _tx_thread_system_return Return to system from thread */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-15-2021 Scott Larson Initial Version 6.1.9 */
/* 04-25-2022 Scott Larson Optimized MPU configuration, */
/* added BASEPRI support, */
/* resulting in version 6.1.11 */
/* 07-29-2022 Scott Larson Removed the code path to skip */
/* MPU reloading, optional */
/* default MPU settings, */
/* resulting in version 6.1.12 */
/* 10-31-2022 Scott Larson Added low power support, */
/* resulting in version 6.2.0 */
/* */
/**************************************************************************/
// VOID _tx_thread_schedule(VOID)
// {
.global _tx_thread_schedule
.thumb_func
_tx_thread_schedule:
/* This function should only ever be called on Cortex-M
from the first schedule request. Subsequent scheduling occurs
from the PendSV handling routine below. */
/* Clear the preempt-disable flag to enable rescheduling after initialization on Cortex-M targets. */
MOV r0, #0 // Build value for TX_FALSE
LDR r2, =_tx_thread_preempt_disable // Build address of preempt disable flag
STR r0, [r2, #0] // Clear preempt disable flag
#ifdef __ARM_FP
/* Clear CONTROL.FPCA bit so VFP registers aren't unnecessarily stacked. */
MRS r0, CONTROL // Pickup current CONTROL register
BIC r0, r0, #4 // Clear the FPCA bit
MSR CONTROL, r0 // Setup new CONTROL register
#endif
/* Enable memory fault registers. */
LDR r0, =0xE000ED24 // Build SHCSR address
LDR r1, =0x70000 // Enable Usage, Bus, and MemManage faults
STR r1, [r0] //
/* Enable interrupts */
CPSIE i
/* Enter the scheduler for the first time. */
MOV r0, #0x10000000 // Load PENDSVSET bit
MOV r1, #0xE000E000 // Load NVIC base
STR r0, [r1, #0xD04] // Set PENDSVBIT in ICSR
DSB // Complete all memory accesses
ISB // Flush pipeline
/* Wait here for the PendSV to take place. */
__tx_wait_here:
B __tx_wait_here // Wait for the PendSV to happen
// }
/* Memory Exception Handler. */
.global MemManage_Handler
.global BusFault_Handler
.global UsageFault_Handler
.thumb_func
MemManage_Handler:
.thumb_func
BusFault_Handler:
.thumb_func
UsageFault_Handler:
#ifdef TX_PORT_USE_BASEPRI
LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI
MSR BASEPRI, r1
#else
CPSID i // Disable interrupts
#endif /* TX_PORT_USE_BASEPRI */
/* Now pickup and store all the fault related information. */
LDR r12,=_txm_module_manager_memory_fault_info // Pickup fault info struct
LDR r0, =_tx_thread_current_ptr // Build current thread pointer address
LDR r1, [r0] // Pickup the current thread pointer
STR r1, [r12, #0] // Save current thread pointer in fault info structure
LDR r0, =0xE000ED24 // Build SHCSR address
LDR r1, [r0] // Pickup SHCSR
STR r1, [r12, #8] // Save SHCSR
LDR r0, =0xE000ED28 // Build CFSR address
LDR r1, [r0] // Pickup CFSR
STR r1, [r12, #12] // Save CFSR
LDR r0, =0xE000ED34 // Build MMFAR address
LDR r1, [r0] // Pickup MMFAR
STR r1, [r12, #16] // Save MMFAR
LDR r0, =0xE000ED38 // Build BFAR address
LDR r1, [r0] // Pickup BFAR
STR r1, [r12, #20] // Save BFAR
MRS r0, CONTROL // Pickup current CONTROL register
STR r0, [r12, #24] // Save CONTROL
MRS r1, PSP // Pickup thread stack pointer
STR r1, [r12, #28] // Save thread stack pointer
LDR r0, [r1] // Pickup saved r0
STR r0, [r12, #32] // Save r0
LDR r0, [r1, #4] // Pickup saved r1
STR r0, [r12, #36] // Save r1
STR r2, [r12, #40] // Save r2
STR r3, [r12, #44] // Save r3
STR r4, [r12, #48] // Save r4
STR r5, [r12, #52] // Save r5
STR r6, [r12, #56] // Save r6
STR r7, [r12, #60] // Save r7
STR r8, [r12, #64] // Save r8
STR r9, [r12, #68] // Save r9
STR r10,[r12, #72] // Save r10
STR r11,[r12, #76] // Save r11
LDR r0, [r1, #16] // Pickup saved r12
STR r0, [r12, #80] // Save r12
LDR r0, [r1, #20] // Pickup saved lr
STR r0, [r12, #84] // Save lr
LDR r0, [r1, #24] // Pickup instruction address at point of fault
STR r0, [r12, #4] // Save point of fault
LDR r0, [r1, #28] // Pickup xPSR
STR r0, [r12, #88] // Save xPSR
MRS r0, CONTROL // Pickup current CONTROL register
BIC r0, r0, #1 // Clear the UNPRIV bit
MSR CONTROL, r0 // Setup new CONTROL register
LDR r0, =0xE000ED28 // Build the Memory Management Fault Status Register (MMFSR)
LDRB r1, [r0] // Pickup the MMFSR, with the following bit definitions:
// Bit 0 = 1 -> Instruction address violation
// Bit 1 = 1 -> Load/store address violation
// Bit 7 = 1 -> MMFAR is valid
STRB r1, [r0] // Clear the MMFSR
#ifdef __ARM_FP
LDR r0, =0xE000EF34 // Cleanup FPU context: Load FPCCR address
LDR r1, [r0] // Load FPCCR
BIC r1, r1, #1 // Clear the lazy preservation active bit
STR r1, [r0] // Save FPCCR
#endif
BL _txm_module_manager_memory_fault_handler // Call memory manager fault handler
#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
/* Call the thread exit function to indicate the thread is no longer executing. */
CPSID i // Disable interrupts
BL _tx_execution_thread_exit // Call the thread exit function
CPSIE i // Enable interrupts
#endif
MOV r1, #0 // Build NULL value
LDR r0, =_tx_thread_current_ptr // Pickup address of current thread pointer
STR r1, [r0] // Clear current thread pointer
// Return from MemManage_Handler exception
LDR r0, =0xE000ED04 // Load ICSR
LDR r1, =0x10000000 // Set PENDSVSET bit
STR r1, [r0] // Store ICSR
DSB // Wait for memory access to complete
#ifdef TX_PORT_USE_BASEPRI
MOV r0, 0 // Disable BASEPRI masking (enable interrupts)
MSR BASEPRI, r0
#else
CPSIE i // Enable interrupts
#endif
MOV lr, #0xFFFFFFFD // Load exception return code
BX lr // Return from exception
/* Generic context PendSV handler. */
.global PendSV_Handler
.global __tx_PendSVHandler
.syntax unified
.thumb_func
PendSV_Handler:
.thumb_func
__tx_PendSVHandler:
/* Get current thread value and new thread pointer. */
__tx_ts_handler:
#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
/* Call the thread exit function to indicate the thread is no longer executing. */
#ifdef TX_PORT_USE_BASEPRI
LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI
MSR BASEPRI, r1
#else
CPSID i // Disable interrupts
#endif /* TX_PORT_USE_BASEPRI */
PUSH {r0, lr} // Save LR (and r0 just for alignment)
BL _tx_execution_thread_exit // Call the thread exit function
POP {r0, lr} // Recover LR
#ifdef TX_PORT_USE_BASEPRI
MOV r0, 0 // Disable BASEPRI masking (enable interrupts)
MSR BASEPRI, r0
#else
CPSIE i // Enable interrupts
#endif /* TX_PORT_USE_BASEPRI */
#endif /* EXECUTION PROFILE */
LDR r0, =_tx_thread_current_ptr // Build current thread pointer address
LDR r2, =_tx_thread_execute_ptr // Build execute thread pointer address
MOV r3, #0 // Build NULL value
LDR r1, [r0] // Pickup current thread pointer
/* Determine if there is a current thread to finish preserving. */
CBZ r1, __tx_ts_new // If NULL, skip preservation
/* Recover PSP and preserve current thread context. */
STR r3, [r0] // Set _tx_thread_current_ptr to NULL
MRS r12, PSP // Pickup PSP pointer (thread's stack pointer)
STMDB r12!, {r4-r11} // Save its remaining registers
#ifdef __ARM_FP
TST LR, #0x10 // Determine if the VFP extended frame is present
BNE _skip_vfp_save
VSTMDB r12!,{s16-s31} // Yes, save additional VFP registers
_skip_vfp_save:
#endif
LDR r4, =_tx_timer_time_slice // Build address of time-slice variable
STMDB r12!, {LR} // Save LR on the stack
/* Determine if time-slice is active. If it isn't, skip time handling processing. */
LDR r5, [r4] // Pickup current time-slice
STR r12, [r1, #8] // Save the thread stack pointer
CBZ r5, __tx_ts_new // If not active, skip processing
/* Time-slice is active, save the current thread's time-slice and clear the global time-slice variable. */
STR r5, [r1, #24] // Save current time-slice
/* Clear the global time-slice. */
STR r3, [r4] // Clear time-slice
/* Executing thread is now completely preserved!!! */
__tx_ts_new:
/* Now we are looking for a new thread to execute! */
#ifdef TX_PORT_USE_BASEPRI
LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI
MSR BASEPRI, r1
#else
CPSID i // Disable interrupts
#endif
LDR r1, [r2] // Is there another thread ready to execute?
CBNZ r1, __tx_ts_restore // Yes, schedule it
/* The following is the idle wait processing... in this case, no threads are ready for execution and the
system will simply be idle until an interrupt occurs that makes a thread ready. Note that interrupts
are disabled to allow use of WFI for waiting for a thread to arrive. */
__tx_ts_wait:
#ifdef TX_PORT_USE_BASEPRI
LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI
MSR BASEPRI, r1
#else
CPSID i // Disable interrupts
#endif
LDR r1, [r2] // Pickup the next thread to execute pointer
CBNZ r1, __tx_ts_ready // If non-NULL, a new thread is ready!
#ifdef TX_LOW_POWER
PUSH {r0-r3}
BL tx_low_power_enter // Possibly enter low power mode
POP {r0-r3}
#endif
#ifdef TX_ENABLE_WFI
DSB // Ensure no outstanding memory transactions
WFI // Wait for interrupt
ISB // Ensure pipeline is flushed
#endif
#ifdef TX_LOW_POWER
PUSH {r0-r3}
BL tx_low_power_exit // Exit low power mode
POP {r0-r3}
#endif
#ifdef TX_PORT_USE_BASEPRI
MOV r4, #0 // Disable BASEPRI masking (enable interrupts)
MSR BASEPRI, r4
#else
CPSIE i // Enable interrupts
#endif
B __tx_ts_wait // Loop to continue waiting
/* At this point, we have a new thread ready to go. Clear any newly pended PendSV - since we are
already in the handler! */
__tx_ts_ready:
MOV r7, #0x08000000 // Build clear PendSV value
MOV r8, #0xE000E000 // Build base NVIC address
STR r7, [r8, #0xD04] // Clear any PendSV
__tx_ts_restore:
/* A thread is ready, make the current thread the new thread
and enable interrupts. */
STR r1, [r0] // Setup the current thread pointer to the new thread
#ifdef TX_PORT_USE_BASEPRI
MOV r4, #0 // Disable BASEPRI masking (enable interrupts)
MSR BASEPRI, r4
#else
CPSIE i // Enable interrupts
#endif
/* Increment the thread run count. */
LDR r7, [r1, #4] // Pickup the current thread run count
LDR r4, =_tx_timer_time_slice // Build address of time-slice variable
LDR r5, [r1, #24] // Pickup thread's current time-slice
ADD r7, r7, #1 // Increment the thread run count
STR r7, [r1, #4] // Store the new run count
/* Setup global time-slice with thread's current time-slice. */
STR r5, [r4] // Setup global time-slice
#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
/* Call the thread entry function to indicate the thread is executing. */
PUSH {r0, r1} // Save r0 and r1
BL _tx_execution_thread_enter // Call the thread execution enter function
POP {r0, r1} // Recover r0 and r1
#endif
/* Restore the thread context and PSP. */
LDR r12, [r1, #8] // Pickup thread's stack pointer
MRS r5, CONTROL // Pickup current CONTROL register
LDR r4, [r1, #0x98] // Pickup current user mode flag
BIC r5, r5, #1 // Clear the UNPRIV bit
ORR r4, r4, r5 // Build new CONTROL register
MSR CONTROL, r4 // Setup new CONTROL register
LDR r0, =0xE000ED94 // Build MPU control reg address
MOV r3, #0 // Build disable value
CPSID i // Disable interrupts
STR r3, [r0] // Disable MPU
LDR r0, [r1, #0x90] // Pickup the module instance pointer
#ifdef TXM_MODULE_MPU_DEFAULT
CBZ r0, default_mpu // Is this thread owned by a module? No, default MPU setup
#else
CBZ r0, skip_mpu_setup // Is this thread owned by a module? No, skip MPU setup
#endif
LDR r2, [r0, #0x8C] // Pickup MPU region 5 address
#ifdef TXM_MODULE_MPU_DEFAULT
CBZ r2, default_mpu // Is protection required for this module? No, default MPU setup
#else
CBZ r2, skip_mpu_setup // Is protection required for this module? No, skip MPU setup
#endif
LDR r1, =0xE000ED9C // MPU_RBAR register address
// Use alias registers to quickly load MPU
ADD r0, r0, #100 // Build address of MPU register start in thread control block
#ifdef TXM_MODULE_MPU_DEFAULT
B config_mpu // configure MPU for module
default_mpu:
LDR r0, =txm_module_default_mpu_registers // default MPU configuration
#endif
config_mpu:
LDM r0!,{r2-r9} // Load MPU regions 0-3
STM r1,{r2-r9} // Store MPU regions 0-3
LDM r0!,{r2-r9} // Load MPU regions 4-7
STM r1,{r2-r9} // Store MPU regions 4-7
#ifdef TXM_MODULE_MANAGER_16_MPU
LDM r0!,{r2-r9} // Load MPU regions 8-11
STM r1,{r2-r9} // Store MPU regions 8-11
// Regions 12-15 are reserved for the user to define.
LDM r0,{r2-r9} // Load MPU regions 12-15
STM r1,{r2-r9} // Store MPU regions 12-15
#endif
_tx_enable_mpu:
LDR r0, =0xE000ED94 // Build MPU control reg address
MOV r1, #5 // Build enable value with background region enabled
STR r1, [r0] // Enable MPU
skip_mpu_setup:
CPSIE i // Enable interrupts
LDMIA r12!, {LR} // Pickup LR
#ifdef __ARM_FP
TST LR, #0x10 // Determine if the VFP extended frame is present
BNE _skip_vfp_restore // If not, skip VFP restore
VLDMIA r12!, {s16-s31} // Yes, restore additional VFP registers
_skip_vfp_restore:
#endif
LDMIA r12!, {r4-r11} // Recover thread's registers
MSR PSP, r12 // Setup the thread's stack pointer
/* Return to thread. */
BX lr // Return to thread!
/* SVC Handler. */
.global SVC_Handler
.thumb_func
SVC_Handler:
.global __tx_SVCallHandler
.thumb_func
__tx_SVCallHandler:
MRS r0, PSP // Pickup the PSP stack
LDR r1, [r0, #24] // Pickup the point of interrupt
LDRB r2, [r1, #-2] // Pickup the SVC parameter
/* Determine which SVC trap we are processing */
CMP r2, #1 // Is it the entry into ThreadX?
BNE _tx_thread_user_return // No, return to user mode
/* At this point we have an SVC 1, which means we are entering
the kernel from a module thread with user mode selected. */
LDR r2, =_txm_module_priv // Load address of where we should have come from
CMP r1, r2 // Did we come from user_mode_entry?
IT NE // If no (not equal), then...
BXNE lr // return from where we came.
LDR r3, [r0, #20] // This is the saved LR
LDR r1, =_tx_thread_current_ptr // Build current thread pointer address
LDR r2, [r1] // Pickup current thread pointer
MOV r1, #0 // Build clear value
STR r1, [r2, #0x98] // Clear the current user mode selection for thread
STR r3, [r2, #0xA0] // Save the original LR in thread control block
/* If there is memory protection, use kernel stack */
LDR r0, [r2, #0x90] // Load the module instance ptr
LDR r0, [r0, #0x0C] // Load the module property flags
TST r0, #2 // Check if memory protected
BEQ _tx_skip_kernel_stack_enter
/* Switch to the module thread's kernel stack */
LDR r0, [r2, #0xA8] // Load the module kernel stack end
#ifndef TXM_MODULE_KERNEL_STACK_MAINTENANCE_DISABLE
LDR r1, [r2, #0xA4] // Load the module kernel stack start
LDR r3, [r2, #0xAC] // Load the module kernel stack size
STR r1, [r2, #12] // Set stack start
STR r0, [r2, #16] // Set stack end
STR r3, [r2, #20] // Set stack size
#endif
MRS r3, PSP // Pickup thread stack pointer
#ifdef __ARM_FP
TST lr, #0x10 // Test for extended module stack
ITT EQ
ORREQ r3, r3, #1 // If so, set LSB in thread stack pointer to indicate extended frame
ORREQ lr, lr, #0x10 // Set bit, return with standard frame
#endif
STR r3, [r2, #0xB0] // Save thread stack pointer
#ifdef __ARM_FP
BIC r3, #1 // Clear possibly OR'd bit
#endif
/* Build kernel stack by copying thread stack two registers at a time */
ADD r3, r3, #32 // Start at bottom of hardware stack
LDMDB r3!, {r1-r2}
STMDB r0!, {r1-r2}
LDMDB r3!, {r1-r2}
STMDB r0!, {r1-r2}
LDMDB r3!, {r1-r2}
STMDB r0!, {r1-r2}
LDMDB r3!, {r1-r2}
STMDB r0!, {r1-r2}
MSR PSP, r0 // Set kernel stack pointer
_tx_skip_kernel_stack_enter:
MRS r0, CONTROL // Pickup current CONTROL register
BIC r0, r0, #1 // Clear the UNPRIV bit
MSR CONTROL, r0 // Setup new CONTROL register
BX lr // Return to thread
_tx_thread_user_return:
LDR r2, =_txm_module_user_mode_exit // Load address of where we should have come from
CMP r1, r2 // Did we come from user_mode_exit?
IT NE // If no (not equal), then...
BXNE lr // return from where we came
LDR r1, =_tx_thread_current_ptr // Build current thread pointer address
LDR r2, [r1] // Pickup current thread pointer
LDR r1, [r2, #0x9C] // Pick up user mode
STR r1, [r2, #0x98] // Set the current user mode selection for thread
/* If there is memory protection, use kernel stack */
LDR r0, [r2, #0x90] // Load the module instance ptr
LDR r0, [r0, #0x0C] // Load the module property flags
TST r0, #2 // Check if memory protected
BEQ _tx_skip_kernel_stack_exit
#ifndef TXM_MODULE_KERNEL_STACK_MAINTENANCE_DISABLE
LDR r0, [r2, #0xB4] // Load the module thread stack start
LDR r1, [r2, #0xB8] // Load the module thread stack end
LDR r3, [r2, #0xBC] // Load the module thread stack size
STR r0, [r2, #12] // Set stack start
STR r1, [r2, #16] // Set stack end
STR r3, [r2, #20] // Set stack size
#endif
#ifdef __ARM_FP
/* If lazy stacking is pending, check if it can be cleared.
if(LSPACT && tx_thread_module_stack_start < FPCAR && FPCAR < tx_thread_module_stack_end)
then clear LSPACT. */
LDR r3, =0xE000EF34 // Address of FPCCR
LDR r3, [r3] // Load FPCCR
TST r3, #1 // Check if LSPACT is set
BEQ _tx_no_lazy_clear // if clear, move on
LDR r1, =0xE000EF38 // Address of FPCAR
LDR r1, [r1] // Load FPCAR
LDR r0, [r2, #0xA4] // Load kernel stack start
CMP r1, r0 // If FPCAR < start, move on
BLO _tx_no_lazy_clear
LDR r0, [r2, #0xA8] // Load kernel stack end
CMP r0, r1 // If end < FPCAR, move on
BLO _tx_no_lazy_clear
BIC r3, #1 // Clear LSPACT
LDR r1, =0xE000EF34 // Address of FPCCR
STR r3, [r1] // Save updated FPCCR
_tx_no_lazy_clear:
#endif
LDR r0, [r2, #0xB0] // Load the module thread stack pointer
MRS r3, PSP // Pickup kernel stack pointer
#ifdef __ARM_FP
TST r0, #1 // Is module stack extended?
ITTE NE // If so...
BICNE lr, #0x10 // Clear bit, return with extended frame
BICNE r0, #1 // Clear bit that indicates extended module frame
ORREQ lr, lr, #0x10 // Else set bit, return with standard frame
#endif
/* Copy kernel hardware stack to module thread stack. */
LDM r3!, {r1-r2} // Get r0, r1 from kernel stack
STM r0!, {r1-r2} // Insert r0, r1 into thread stack
LDM r3!, {r1-r2} // Get r2, r3 from kernel stack
STM r0!, {r1-r2} // Insert r2, r3 into thread stack
LDM r3!, {r1-r2} // Get r12, lr from kernel stack
STM r0!, {r1-r2} // Insert r12, lr into thread stack
LDM r3!, {r1-r2} // Get pc, xpsr from kernel stack
STM r0!, {r1-r2} // Insert pc, xpsr into thread stack
SUB r0, r0, #32 // Subtract 32 to get back to top of stack
MSR PSP, r0 // Set thread stack pointer
LDR r1, =_tx_thread_current_ptr // Build current thread pointer address
LDR r2, [r1] // Pickup current thread pointer
LDR r1, [r2, #0x9C] // Pick up user mode
_tx_skip_kernel_stack_exit:
MRS r0, CONTROL // Pickup current CONTROL register
ORR r0, r0, r1 // OR in the user mode bit
MSR CONTROL, r0 // Setup new CONTROL register
BX lr // Return to thread
/* Kernel entry function from user mode. */
.global _txm_module_manager_kernel_dispatch
.align 5
.syntax unified
// VOID _txm_module_manager_user_mode_entry(VOID)
// {
.global _txm_module_manager_user_mode_entry
.thumb_func
_txm_module_manager_user_mode_entry:
SVC 1 // Enter kernel
_txm_module_priv:
/* At this point, we are out of user mode. The original LR has been saved in the
thread control block. Simply call the kernel dispatch function. */
BL _txm_module_manager_kernel_dispatch
/* Pickup the original LR value while still in privileged mode */
LDR r2, =_tx_thread_current_ptr // Build current thread pointer address
LDR r3, [r2] // Pickup current thread pointer
LDR lr, [r3, #0xA0] // Pickup saved LR from original call
SVC 2 // Exit kernel and return to user mode
_txm_module_user_mode_exit:
BX lr // Return to the caller
NOP
NOP
NOP
NOP
// }
#ifdef __ARM_FP
.global tx_thread_fpu_enable
.thumb_func
tx_thread_fpu_enable:
.global tx_thread_fpu_disable
.thumb_func
tx_thread_fpu_disable:
/* Automatic VPF logic is supported, this function is present only for
backward compatibility purposes and therefore simply returns. */
BX LR // Return to caller
#endif

View File

@@ -0,0 +1,139 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Module Manager */
/** */
/**************************************************************************/
/**************************************************************************/
.text
.align 4
.syntax unified
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _txm_module_manager_thread_stack_build Cortex-Mx/AC6 */
/* 6.1.9 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function builds a stack frame on the supplied thread's stack. */
/* The stack frame results in a fake interrupt return to the supplied */
/* function pointer. */
/* */
/* INPUT */
/* */
/* thread_ptr Pointer to thread */
/* function_ptr Pointer to shell function */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _tx_thread_create Create thread service */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-15-2021 Scott Larson Initial Version 6.1.9 */
/* */
/**************************************************************************/
// VOID _txm_module_manager_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(TX_THREAD *, TXM_MODULE_INSTANCE *))
// {
.global _txm_module_manager_thread_stack_build
.thumb_func
_txm_module_manager_thread_stack_build:
/* Build a fake interrupt frame. The form of the fake interrupt stack
on the Cortex-M should look like the following after it is built:
Stack Top:
lr Interrupted lr (lr at time of PENDSV)
r4 Initial value for r4
r5 Initial value for r5
r6 Initial value for r6
r7 Initial value for r7
r8 Initial value for r8
r9 Initial value for r9
r10 Initial value for r10
r11 Initial value for r11
r0 Initial value for r0 (Hardware stack starts here!!)
r1 Initial value for r1
r2 Initial value for r2
r3 Initial value for r3
r12 Initial value for r12
lr Initial value for lr
pc Initial value for pc
xPSR Initial value for xPSR
Stack Bottom: (higher memory address) */
LDR r2, [r0, #16] // Pickup end of stack area
BIC r2, r2, #0x7 // Align frame
SUB r2, r2, #68 // Subtract frame size
LDR r3, =0xFFFFFFFD // Build initial LR value
STR r3, [r2, #0] // Save on the stack
/* Actually build the stack frame. */
MOV r3, #0 // Build initial register value
STR r3, [r2, #4] // Store initial r4
STR r3, [r2, #8] // Store initial r5
STR r3, [r2, #12] // Store initial r6
STR r3, [r2, #16] // Store initial r7
STR r3, [r2, #20] // Store initial r8
STR r3, [r2, #28] // Store initial r10
STR r3, [r2, #32] // Store initial r11
/* Hardware stack follows. */
STR r0, [r2, #36] // Store initial r0, which is the thread control block
LDR r3, [r0, #8] // Pickup thread entry info pointer,which is in the stack pointer position of the thread control block.
// It was setup in the txm_module_manager_thread_create function. It will be overwritten later in this
// function with the actual, initial stack pointer.
STR r3, [r2, #40] // Store initial r1, which is the module entry information.
LDR r3, [r3, #8] // Pickup data base register from the module information
STR r3, [r2, #24] // Store initial r9 (data base register)
MOV r3, #0 // Clear r3 again
STR r3, [r2, #44] // Store initial r2
STR r3, [r2, #48] // Store initial r3
STR r3, [r2, #52] // Store initial r12
MOV r3, #0xFFFFFFFF // Poison EXC_RETURN value
STR r3, [r2, #56] // Store initial lr
STR r1, [r2, #60] // Store initial pc
MOV r3, #0x01000000 // Only T-bit need be set
STR r3, [r2, #64] // Store initial xPSR
/* Setup stack pointer. */
// thread_ptr -> tx_thread_stack_ptr = r2;
STR r2, [r0, #8] // Save stack pointer in thread's control block
BX lr // Return to caller
// }

View File

@@ -0,0 +1,448 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Module Manager */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
#include "tx_api.h"
#include "txm_module.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _txm_power_of_two_block_size Cortex-Mx */
/* 6.1.9 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function calculates a power of two size at or immediately above*/
/* the input size and returns it to the caller. */
/* */
/* INPUT */
/* */
/* size Block size */
/* */
/* OUTPUT */
/* */
/* calculated size Rounded up to power of two */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _txm_module_manager_alignment_adjust Adjust alignment for Cortex-M */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-15-2021 Scott Larson Initial Version 6.1.9 */
/* */
/**************************************************************************/
ULONG _txm_power_of_two_block_size(ULONG size)
{
/* Check for 0 size. */
if(size == 0)
return 0;
/* Minimum MPU block size is 32. */
if(size <= 32)
return 32;
/* Bit twiddling trick to round to next high power of 2
(if original size is power of 2, it will return original size. Perfect!) */
size--;
size |= size >> 1;
size |= size >> 2;
size |= size >> 4;
size |= size >> 8;
size |= size >> 16;
size++;
/* Return a power of 2 size at or above the input size. */
return(size);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _txm_module_manager_alignment_adjust Cortex-Mx */
/* 6.1.9 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function adjusts the alignment and size of the code and data */
/* section for a given module implementation. */
/* */
/* INPUT */
/* */
/* module_preamble Pointer to module preamble */
/* code_size Size of the code area (updated) */
/* code_alignment Code area alignment (updated) */
/* data_size Size of data area (updated) */
/* data_alignment Data area alignment (updated) */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _txm_power_of_two_block_size Calculate power of two size */
/* */
/* CALLED BY */
/* */
/* Initial thread stack frame */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-15-2021 Scott Larson Initial Version 6.1.9 */
/* */
/**************************************************************************/
VOID _txm_module_manager_alignment_adjust(TXM_MODULE_PREAMBLE *module_preamble,
ULONG *code_size,
ULONG *code_alignment,
ULONG *data_size,
ULONG *data_alignment)
{
#ifdef TXM_MODULE_MANAGER_16_MPU
ULONG local_code_size;
ULONG local_code_alignment;
ULONG local_data_size;
ULONG local_data_alignment;
ULONG code_size_accum;
ULONG data_size_accum;
/* Copy the input parameters into local variables for ease of use. */
local_code_size = *code_size;
local_code_alignment = *code_alignment;
local_data_size = *data_size;
local_data_alignment = *data_alignment;
/* Determine code block sizes. Minimize the alignment requirement.
There are 4 MPU code entries available. The following is how the code size
will be distributed:
1. 1/4 of the largest power of two that is greater than or equal to code size.
2. 1/4 of the largest power of two that is greater than or equal to code size.
3. Largest power of 2 that fits in the remaining space.
4. Smallest power of 2 that exceeds the remaining space, minimum 32. */
local_code_alignment = _txm_power_of_two_block_size(local_code_size) >> 2;
code_size_accum = local_code_alignment + local_code_alignment;
code_size_accum = code_size_accum + (_txm_power_of_two_block_size(local_code_size - code_size_accum) >> 1);
code_size_accum = code_size_accum + _txm_power_of_two_block_size(local_code_size - code_size_accum);
local_code_size = code_size_accum;
/* Determine data block sizes. Minimize the alignment requirement.
There are 4 MPU data entries available. The following is how the data size
will be distributed:
1. 1/4 of the largest power of two that is greater than or equal to data size.
2. 1/4 of the largest power of two that is greater than or equal to data size.
3. Largest power of 2 that fits in the remaining space.
4. Smallest power of 2 that exceeds the remaining space, minimum 32. */
local_data_alignment = _txm_power_of_two_block_size(local_data_size) >> 2;
data_size_accum = local_data_alignment + local_data_alignment;
data_size_accum = data_size_accum + (_txm_power_of_two_block_size(local_data_size - data_size_accum) >> 1);
data_size_accum = data_size_accum + _txm_power_of_two_block_size(local_data_size - data_size_accum);
local_data_size = data_size_accum;
/* Return all the information to the caller. */
*code_size = local_code_size;
*code_alignment = local_code_alignment;
*data_size = local_data_size;
*data_alignment = local_data_alignment;
#else
ULONG local_code_size;
ULONG local_code_alignment;
ULONG local_data_size;
ULONG local_data_alignment;
ULONG code_block_size;
ULONG data_block_size;
ULONG code_size_accum;
ULONG data_size_accum;
/* Copy the input parameters into local variables for ease of use. */
local_code_size = *code_size;
local_code_alignment = *code_alignment;
local_data_size = *data_size;
local_data_alignment = *data_alignment;
/* Test for external memory enabled in preamble. */
if(module_preamble -> txm_module_preamble_property_flags & TXM_MODULE_SHARED_EXTERNAL_MEMORY_ACCESS)
{
/* External/shared memory enabled. TXM_MODULE_MANAGER_CODE_MPU_ENTRIES-1 code entries will be used. */
if (local_code_size <= (32*(TXM_MODULE_MANAGER_CODE_MPU_ENTRIES - 1)))
{
/* Block size of 32 is best. */
code_block_size = 32;
}
else if (local_code_size <= (64*(TXM_MODULE_MANAGER_CODE_MPU_ENTRIES - 1)))
{
/* Block size of 64 is best. */
code_block_size = 64;
}
else if (local_code_size <= (128*(TXM_MODULE_MANAGER_CODE_MPU_ENTRIES - 1)))
{
/* Block size of 128 is best. */
code_block_size = 128;
}
else if (local_code_size <= (256*(TXM_MODULE_MANAGER_CODE_MPU_ENTRIES - 1)))
{
/* Block size of 256 is best. */
code_block_size = 256;
}
else if (local_code_size <= (512*(TXM_MODULE_MANAGER_CODE_MPU_ENTRIES - 1)))
{
/* Block size of 512 is best. */
code_block_size = 512;
}
else if (local_code_size <= (1024*(TXM_MODULE_MANAGER_CODE_MPU_ENTRIES - 1)))
{
/* Block size of 1024 is best. */
code_block_size = 1024;
}
else if (local_code_size <= (2048*(TXM_MODULE_MANAGER_CODE_MPU_ENTRIES - 1)))
{
/* Block size of 2048 is best. */
code_block_size = 2048;
}
else if (local_code_size <= (4096*(TXM_MODULE_MANAGER_CODE_MPU_ENTRIES - 1)))
{
/* Block size of 4096 is best. */
code_block_size = 4096;
}
else if (local_code_size <= (8192*(TXM_MODULE_MANAGER_CODE_MPU_ENTRIES - 1)))
{
/* Block size of 8192 is best. */
code_block_size = 8192;
}
else if (local_code_size <= (16384*(TXM_MODULE_MANAGER_CODE_MPU_ENTRIES - 1)))
{
/* Block size of 16384 is best. */
code_block_size = 16384;
}
else if (local_code_size <= (32768*(TXM_MODULE_MANAGER_CODE_MPU_ENTRIES - 1)))
{
/* Block size of 32768 is best. */
code_block_size = 32768;
}
else if (local_code_size <= (65536*(TXM_MODULE_MANAGER_CODE_MPU_ENTRIES - 1)))
{
/* Block size of 65536 is best. */
code_block_size = 65536;
}
else if (local_code_size <= (131072*(TXM_MODULE_MANAGER_CODE_MPU_ENTRIES - 1)))
{
/* Block size of 131072 is best. */
code_block_size = 131072;
}
else if (local_code_size <= (262144*(TXM_MODULE_MANAGER_CODE_MPU_ENTRIES - 1)))
{
/* Block size of 262144 is best. */
code_block_size = 262144;
}
else if (local_code_size <= (524288*(TXM_MODULE_MANAGER_CODE_MPU_ENTRIES - 1)))
{
/* Block size of 524288 is best. */
code_block_size = 524288;
}
else if (local_code_size <= (1048576*(TXM_MODULE_MANAGER_CODE_MPU_ENTRIES - 1)))
{
/* Block size of 1048576 is best. */
code_block_size = 1048576;
}
else if (local_code_size <= (2097152*(TXM_MODULE_MANAGER_CODE_MPU_ENTRIES - 1)))
{
/* Block size of 2097152 is best. */
code_block_size = 2097152;
}
else if (local_code_size <= (4194304*(TXM_MODULE_MANAGER_CODE_MPU_ENTRIES - 1)))
{
/* Block size of 4194304 is best. */
code_block_size = 4194304;
}
else
{
/* Just set block size to 32MB just to create an allocation error! */
code_block_size = 33554432;
}
/* Calculate the new code size. */
local_code_size = code_block_size*(TXM_MODULE_MANAGER_CODE_MPU_ENTRIES - 1);
/* Determine if the code block size is greater than the current alignment. If so, use block size
as the alignment. */
if (code_block_size > local_code_alignment)
local_code_alignment = code_block_size;
}
else
{
/* Determine code block sizes. Minimize the alignment requirement.
There are 4 MPU code entries available. The following is how the code size
will be distributed:
1. 1/4 of the largest power of two that is greater than or equal to code size.
2. 1/4 of the largest power of two that is greater than or equal to code size.
3. Largest power of 2 that fits in the remaining space.
4. Smallest power of 2 that exceeds the remaining space, minimum 32. */
local_code_alignment = _txm_power_of_two_block_size(local_code_size) >> 2;
code_size_accum = local_code_alignment + local_code_alignment;
code_size_accum = code_size_accum + (_txm_power_of_two_block_size(local_code_size - code_size_accum) >> 1);
code_size_accum = code_size_accum + _txm_power_of_two_block_size(local_code_size - code_size_accum);
local_code_size = code_size_accum;
}
/* Determine the best data block size, which in our case is the minimal alignment. */
if (local_data_size <= (32*TXM_MODULE_MANAGER_DATA_MPU_ENTRIES))
{
/* Block size of 32 is best. */
data_block_size = 32;
}
else if (local_data_size <= (64*TXM_MODULE_MANAGER_DATA_MPU_ENTRIES))
{
/* Block size of 64 is best. */
data_block_size = 64;
}
else if (local_data_size <= (128*TXM_MODULE_MANAGER_DATA_MPU_ENTRIES))
{
/* Block size of 128 is best. */
data_block_size = 128;
}
else if (local_data_size <= (256*TXM_MODULE_MANAGER_DATA_MPU_ENTRIES))
{
/* Block size of 256 is best. */
data_block_size = 256;
}
else if (local_data_size <= (512*TXM_MODULE_MANAGER_DATA_MPU_ENTRIES))
{
/* Block size of 512 is best. */
data_block_size = 512;
}
else if (local_data_size <= (1024*TXM_MODULE_MANAGER_DATA_MPU_ENTRIES))
{
/* Block size of 1024 is best. */
data_block_size = 1024;
}
else if (local_data_size <= (2048*TXM_MODULE_MANAGER_DATA_MPU_ENTRIES))
{
/* Block size of 2048 is best. */
data_block_size = 2048;
}
else if (local_data_size <= (4096*TXM_MODULE_MANAGER_DATA_MPU_ENTRIES))
{
/* Block size of 4096 is best. */
data_block_size = 4096;
}
else if (local_data_size <= (8192*TXM_MODULE_MANAGER_DATA_MPU_ENTRIES))
{
/* Block size of 8192 is best. */
data_block_size = 8192;
}
else if (local_data_size <= (16384*TXM_MODULE_MANAGER_DATA_MPU_ENTRIES))
{
/* Block size of 16384 is best. */
data_block_size = 16384;
}
else if (local_data_size <= (32768*TXM_MODULE_MANAGER_DATA_MPU_ENTRIES))
{
/* Block size of 32768 is best. */
data_block_size = 32768;
}
else if (local_data_size <= (65536*TXM_MODULE_MANAGER_DATA_MPU_ENTRIES))
{
/* Block size of 65536 is best. */
data_block_size = 65536;
}
else if (local_data_size <= (131072*TXM_MODULE_MANAGER_DATA_MPU_ENTRIES))
{
/* Block size of 131072 is best. */
data_block_size = 131072;
}
else if (local_data_size <= (262144*TXM_MODULE_MANAGER_DATA_MPU_ENTRIES))
{
/* Block size of 262144 is best. */
data_block_size = 262144;
}
else if (local_data_size <= (524288*TXM_MODULE_MANAGER_DATA_MPU_ENTRIES))
{
/* Block size of 524288 is best. */
data_block_size = 524288;
}
else if (local_data_size <= (1048576*TXM_MODULE_MANAGER_DATA_MPU_ENTRIES))
{
/* Block size of 1048576 is best. */
data_block_size = 1048576;
}
else if (local_data_size <= (2097152*TXM_MODULE_MANAGER_DATA_MPU_ENTRIES))
{
/* Block size of 2097152 is best. */
data_block_size = 2097152;
}
else if (local_data_size <= (4194304*TXM_MODULE_MANAGER_DATA_MPU_ENTRIES))
{
/* Block size of 4194304 is best. */
data_block_size = 4194304;
}
else
{
/* Just set data block size to 32MB just to create an allocation error! */
data_block_size = 33554432;
}
/* Calculate the new data size. */
data_size_accum = data_block_size;
while(data_size_accum < local_data_size)
{
data_size_accum += data_block_size;
}
local_data_size = data_size_accum;
/* Determine if the data block size is greater than the current alignment. If so, use block size
as the alignment. */
if (data_block_size > local_data_alignment)
{
local_data_alignment = data_block_size;
}
/* Return all the information to the caller. */
*code_size = local_code_size;
*code_alignment = local_code_alignment;
*data_size = local_data_size;
*data_alignment = local_data_alignment;
#endif
}

View File

@@ -0,0 +1,297 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Module Manager */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
#include "tx_api.h"
#include "tx_mutex.h"
#include "tx_queue.h"
#include "tx_thread.h"
#include "txm_module.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _txm_module_manager_external_memory_enable Cortex-Mx */
/* 6.2.1 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function creates an entry in the MPU table for a shared */
/* memory space. */
/* */
/* INPUT */
/* */
/* module_instance Module instance pointer */
/* start_address Start address of memory */
/* length Length of external memory */
/* attributes Memory attributes (r/w) */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _tx_mutex_get Get protection mutex */
/* _tx_mutex_put Release protection mutex */
/* _txm_power_of_two_block_size Round length to power of two */
/* _txm_module_manager_mm_register_setup Reconfigure MPU registers */
/* */
/* CALLED BY */
/* */
/* Application code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-15-2021 Scott Larson Initial Version 6.1.9 */
/* 03-08-2023 Scott Larson Update defines, */
/* resulting in version 6.2.1 */
/* */
/**************************************************************************/
UINT _txm_module_manager_external_memory_enable(TXM_MODULE_INSTANCE *module_instance,
VOID *start_address,
ULONG length,
UINT attributes)
{
#ifdef TXM_MODULE_MANAGER_16_MPU
ULONG block_size;
ULONG region_size;
ULONG srd_bits;
ULONG size_register;
ULONG address;
ULONG shared_index;
ULONG attributes_check = 0;
/* Determine if the module manager has not been initialized yet. */
if (_txm_module_manager_ready != TX_TRUE)
{
/* Module manager has not been initialized. */
return(TX_NOT_AVAILABLE);
}
/* Determine if the module is valid. */
if (module_instance == TX_NULL)
{
/* Invalid module pointer. */
return(TX_PTR_ERROR);
}
/* Get module manager protection mutex. */
_tx_mutex_get(&_txm_module_manager_mutex, TX_WAIT_FOREVER);
/* Determine if the module instance is valid. */
if (module_instance -> txm_module_instance_id != TXM_MODULE_ID)
{
/* Release the protection mutex. */
_tx_mutex_put(&_txm_module_manager_mutex);
/* Invalid module pointer. */
return(TX_PTR_ERROR);
}
/* Determine if the module instance is in the loaded state. */
if (module_instance -> txm_module_instance_state != TXM_MODULE_LOADED)
{
/* Release the protection mutex. */
_tx_mutex_put(&_txm_module_manager_mutex);
/* Return error if the module is not ready. */
return(TX_START_ERROR);
}
/* Determine if there are shared memory entries available. */
if(module_instance -> txm_module_instance_shared_memory_count >= TXM_MODULE_MANAGER_MPU_SHARED_ENTRIES)
{
/* Release the protection mutex. */
_tx_mutex_put(&_txm_module_manager_mutex);
/* No more entries available. */
return(TX_NO_MEMORY);
}
/* Start address and length must adhere to Cortex-M7 MPU.
The address must align with the block size. */
block_size = _txm_power_of_two_block_size(length);
address = (ULONG) start_address;
if(address != (address & ~(block_size - 1)))
{
/* Release the protection mutex. */
_tx_mutex_put(&_txm_module_manager_mutex);
/* Return alignment error. */
return(TXM_MODULE_ALIGNMENT_ERROR);
}
/* At this point, we have a valid address and block size.
Set up MPU registers. */
/* Pick up index into shared memory entries. */
shared_index = TXM_MODULE_MANAGER_MPU_SHARED_INDEX + module_instance -> txm_module_instance_shared_memory_count;
/* Save address register with address, MPU region, set Valid bit. */
module_instance -> txm_module_instance_mpu_registers[shared_index].txm_module_mpu_region_address = address | shared_index | TXM_MPU_VALID_BIT;
/* Calculate the region size. */
region_size = _txm_module_manager_region_size_get(block_size);
/* Calculate the subregion bits. */
srd_bits = _txm_module_manager_calculate_srd_bits(block_size, length);
/* Generate SRD, size, and enable attributes. */
size_register = srd_bits | (region_size << 1) | TXM_ENABLE_REGION | TXM_MODULE_MPU_SHARED_ACCESS_CONTROL;
/* Check for optional write attribute. */
if(attributes & TXM_MODULE_MANAGER_SHARED_ATTRIBUTE_WRITE)
{
attributes_check = TXM_MODULE_MANAGER_ATTRIBUTE_WRITE_MPU_BIT;
}
/* Save attribute-size register. */
module_instance -> txm_module_instance_mpu_registers[shared_index].txm_module_mpu_region_attribute_size = attributes_check | size_register;
/* Keep track of shared memory address and length in module instance. */
module_instance -> txm_module_instance_shared_memory_address[module_instance -> txm_module_instance_shared_memory_count] = address;
module_instance -> txm_module_instance_shared_memory_length[module_instance -> txm_module_instance_shared_memory_count] = length;
/* Increment counter. */
module_instance -> txm_module_instance_shared_memory_count++;
/* Release the protection mutex. */
_tx_mutex_put(&_txm_module_manager_mutex);
/* Return success. */
return(TX_SUCCESS);
#else
ULONG block_size;
ULONG region_size;
ULONG subregion_bits;
ULONG address;
UINT attributes_check = 0;
TXM_MODULE_PREAMBLE *module_preamble;
/* Determine if the module manager has not been initialized yet. */
if (_txm_module_manager_ready != TX_TRUE)
{
/* Module manager has not been initialized. */
return(TX_NOT_AVAILABLE);
}
/* Determine if the module is valid. */
if (module_instance == TX_NULL)
{
/* Invalid module pointer. */
return(TX_PTR_ERROR);
}
/* Get module manager protection mutex. */
_tx_mutex_get(&_txm_module_manager_mutex, TX_WAIT_FOREVER);
/* Determine if the module instance is valid. */
if (module_instance -> txm_module_instance_id != TXM_MODULE_ID)
{
/* Release the protection mutex. */
_tx_mutex_put(&_txm_module_manager_mutex);
/* Invalid module pointer. */
return(TX_PTR_ERROR);
}
/* Determine if the module instance is in the loaded state. */
if (module_instance -> txm_module_instance_state != TXM_MODULE_LOADED)
{
/* Release the protection mutex. */
_tx_mutex_put(&_txm_module_manager_mutex);
/* Return error if the module is not ready. */
return(TX_START_ERROR);
}
/* Check if preamble shared mem and mem protection property bits are set. */
module_preamble = module_instance -> txm_module_instance_preamble_ptr;
if((module_preamble -> txm_module_preamble_property_flags & (TXM_MODULE_MEMORY_PROTECTION | TXM_MODULE_SHARED_EXTERNAL_MEMORY_ACCESS))
!= (TXM_MODULE_MEMORY_PROTECTION | TXM_MODULE_SHARED_EXTERNAL_MEMORY_ACCESS))
{
/* Release the protection mutex. */
_tx_mutex_put(&_txm_module_manager_mutex);
/* Return error if bit not set. */
return(TXM_MODULE_INVALID_PROPERTIES);
}
/* Start address and length must adhere to Cortex-M MPU.
The address must align with the block size. */
block_size = _txm_power_of_two_block_size(length);
address = (ULONG) start_address;
if(address != (address & ~(block_size - 1)))
{
/* Release the protection mutex. */
_tx_mutex_put(&_txm_module_manager_mutex);
/* Return alignment error. */
return(TXM_MODULE_ALIGNMENT_ERROR);
}
/* At this point, we have a valid address and block size.
Set up MPU registers. */
module_instance -> txm_module_instance_mpu_registers[TXM_MODULE_MANAGER_SHARED_MPU_REGION].txm_module_mpu_region_address = address | TXM_MODULE_MANAGER_SHARED_MPU_REGION | TXM_MPU_VALID_BIT;
/* Calculate the region size. */
region_size = _txm_module_manager_region_size_get(block_size);
/* Calculate the subregion bits. */
subregion_bits = _txm_module_manager_calculate_srd_bits(block_size, length);
/* Check for valid attributes. */
if(attributes & TXM_MODULE_MANAGER_SHARED_ATTRIBUTE_WRITE)
{
attributes_check = TXM_MODULE_MANAGER_ATTRIBUTE_WRITE_MPU_BIT;
}
/* Build register with attributes. */
module_instance -> txm_module_instance_mpu_registers[TXM_MODULE_MANAGER_SHARED_MPU_REGION].txm_module_mpu_region_attribute_size = (region_size << 1) | subregion_bits | attributes_check | TXM_MODULE_MPU_SHARED_ACCESS_CONTROL | TXM_ENABLE_REGION;
/* Keep track of shared memory address and length in module instance. */
module_instance -> txm_module_instance_shared_memory_address = address;
module_instance -> txm_module_instance_shared_memory_length = length;
/* Recalculate MPU settings. */
_txm_module_manager_mm_register_setup(module_instance);
/* Release the protection mutex. */
_tx_mutex_put(&_txm_module_manager_mutex);
/* Return success. */
return(TX_SUCCESS);
#endif
}

View File

@@ -0,0 +1,110 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Module Manager */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
#include "tx_api.h"
#include "tx_thread.h"
#include "txm_module.h"
/* Define the user's fault notification callback function pointer. This is
setup via the txm_module_manager_memory_fault_notify API. */
VOID (*_txm_module_manager_fault_notify)(TX_THREAD *, TXM_MODULE_INSTANCE *);
/* Define a macro that can be used to allocate global variables useful to
store information about the last fault. This macro is defined in
txm_module_port.h and is usually populated in the assembly language
fault handling prior to the code calling _txm_module_manager_memory_fault_handler. */
TXM_MODULE_MANAGER_FAULT_INFO
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _txm_module_manager_memory_fault_handler Cortex-Mx */
/* 6.1.9 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function handles a fault associated with a memory protected */
/* module. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _tx_thread_terminate Terminate thread */
/* */
/* CALLED BY */
/* */
/* Fault handler */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-15-2021 Scott Larson Initial Version 6.1.9 */
/* */
/**************************************************************************/
VOID _txm_module_manager_memory_fault_handler(VOID)
{
TXM_MODULE_INSTANCE *module_instance_ptr;
TX_THREAD *thread_ptr;
/* Pickup the current thread. */
thread_ptr = _tx_thread_current_ptr;
/* Initialize the module instance pointer to NULL. */
module_instance_ptr = TX_NULL;
/* Is there a thread? */
if (thread_ptr)
{
/* Pickup the module instance. */
module_instance_ptr = thread_ptr -> tx_thread_module_instance_ptr;
/* Terminate the current thread. */
_tx_thread_terminate(_tx_thread_current_ptr);
}
/* Determine if there is a user memory fault notification callback. */
if (_txm_module_manager_fault_notify)
{
/* Yes, call the user's notification memory fault callback. */
(_txm_module_manager_fault_notify)(thread_ptr, module_instance_ptr);
}
}

View File

@@ -0,0 +1,84 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Module Manager */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
#include "tx_api.h"
#include "tx_thread.h"
#include "txm_module.h"
/* Define the external user's fault notification callback function pointer. This is
setup via the txm_module_manager_memory_fault_notify API. */
extern VOID (*_txm_module_manager_fault_notify)(TX_THREAD *, TXM_MODULE_INSTANCE *);
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _txm_module_manager_memory_fault_notify Cortex-Mx */
/* 6.1.9 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function registers an application callback when/if a memory */
/* fault occurs. The supplied thread is automatically terminated, but */
/* any other threads in the same module may still execute. */
/* */
/* INPUT */
/* */
/* notify_function Memory fault notification */
/* function, NULL disables. */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-15-2021 Scott Larson Initial Version 6.1.9 */
/* */
/**************************************************************************/
UINT _txm_module_manager_memory_fault_notify(VOID (*notify_function)(TX_THREAD *, TXM_MODULE_INSTANCE *))
{
/* Setup notification function. */
_txm_module_manager_fault_notify = notify_function;
/* Return success. */
return(TX_SUCCESS);
}

View File

@@ -0,0 +1,860 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Module Manager */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
#include "tx_api.h"
#include "txm_module.h"
#ifdef TXM_MODULE_MPU_DEFAULT
const ULONG txm_module_default_mpu_registers[32] =
{
TXM_MODULE_MPU_DEFAULT_RBAR_0,
TXM_MODULE_MPU_DEFAULT_RASR_0,
TXM_MODULE_MPU_DEFAULT_RBAR_1,
TXM_MODULE_MPU_DEFAULT_RASR_1,
TXM_MODULE_MPU_DEFAULT_RBAR_2,
TXM_MODULE_MPU_DEFAULT_RASR_2,
TXM_MODULE_MPU_DEFAULT_RBAR_3,
TXM_MODULE_MPU_DEFAULT_RASR_3,
TXM_MODULE_MPU_DEFAULT_RBAR_4,
TXM_MODULE_MPU_DEFAULT_RASR_4,
TXM_MODULE_MPU_DEFAULT_RBAR_5,
TXM_MODULE_MPU_DEFAULT_RASR_5,
TXM_MODULE_MPU_DEFAULT_RBAR_6,
TXM_MODULE_MPU_DEFAULT_RASR_6,
TXM_MODULE_MPU_DEFAULT_RBAR_7,
TXM_MODULE_MPU_DEFAULT_RASR_7,
TXM_MODULE_MPU_DEFAULT_RBAR_8,
TXM_MODULE_MPU_DEFAULT_RASR_8,
TXM_MODULE_MPU_DEFAULT_RBAR_9,
TXM_MODULE_MPU_DEFAULT_RASR_9,
TXM_MODULE_MPU_DEFAULT_RBAR_10,
TXM_MODULE_MPU_DEFAULT_RASR_10,
TXM_MODULE_MPU_DEFAULT_RBAR_11,
TXM_MODULE_MPU_DEFAULT_RASR_11,
TXM_MODULE_MPU_DEFAULT_RBAR_12,
TXM_MODULE_MPU_DEFAULT_RASR_12,
TXM_MODULE_MPU_DEFAULT_RBAR_13,
TXM_MODULE_MPU_DEFAULT_RASR_13,
TXM_MODULE_MPU_DEFAULT_RBAR_14,
TXM_MODULE_MPU_DEFAULT_RASR_14,
TXM_MODULE_MPU_DEFAULT_RBAR_15,
TXM_MODULE_MPU_DEFAULT_RASR_15
};
#endif
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _txm_module_manager_region_size_get Cortex-Mx */
/* 6.2.1 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function converts the region size in bytes to the block size */
/* for the Cortex-Mx MPU specification. */
/* */
/* INPUT */
/* */
/* block_size Size of the block in bytes */
/* Must be a power of two */
/* */
/* OUTPUT */
/* */
/* MPU size specification */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _txm_module_manager_mm_register_setup */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-15-2021 Scott Larson Initial Version 6.1.9 */
/* 03-08-2023 Scott Larson Changed from lookup table to */
/* calculation and check for */
/* minumum block size, */
/* resulting in version 6.2.1 */
/* */
/**************************************************************************/
ULONG _txm_module_manager_region_size_get(ULONG block_size)
{
ULONG return_value = 5; /* 5 is the region size for 64 byte block. */
/* Check if at or below minumum block size. */
if (block_size <= 32)
{
/* Return minimum region size. */
return 0x04;
}
/* Remove some trailing zeros from block_size. */
block_size = block_size >> 6;
/* Increment return_value until block_size lsb is set. */
while((block_size & 1) == 0)
{
block_size = block_size >> 1;
return_value++;
}
return(return_value);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _txm_module_manager_calculate_srd_bits Cortex-Mx */
/* 6.1.9 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function calculates the SRD bits that need to be set to */
/* protect "length" bytes in a block. */
/* */
/* INPUT */
/* */
/* block_size Size of the block in bytes */
/* length Actual length in bytes */
/* */
/* OUTPUT */
/* */
/* SRD bits to be OR'ed with region attribute register. */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _txm_module_manager_mm_register_setup */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-15-2021 Scott Larson Initial Version 6.1.9 */
/* */
/**************************************************************************/
ULONG _txm_module_manager_calculate_srd_bits(ULONG block_size, ULONG length)
{
ULONG srd_bits = 0;
UINT srd_bit_index;
/* length is smaller than block_size, set SRD bits if block_size is 256 or more. */
if((block_size >= 256) && (length < block_size))
{
/* Divide block_size by 8 by shifting right 3. Result is size of subregion. */
block_size = block_size >> 3;
/* Set SRD index into attribute register. */
srd_bit_index = 8;
/* If subregion overlaps length, move to the next subregion. */
while(length > block_size)
{
length = length - block_size;
srd_bit_index++;
}
/* Check for a portion of code remaining. */
if(length)
{
srd_bit_index++;
}
/* Set unused subregion bits. */
while(srd_bit_index < 16)
{
srd_bits = srd_bits | (0x1 << srd_bit_index);
srd_bit_index++;
}
}
return(srd_bits);
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _txm_module_manager_mm_register_setup Cortex-Mx */
/* 6.2.1 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function sets up the MPU register definitions based on the */
/* module's memory characteristics. */
/* */
/* Default MPU layout: */
/* Entry Description */
/* 0 Kernel mode entry */
/* 1 Module code region */
/* 2 Module code region */
/* 3 Module code region */
/* 4 Module code region [optional shared memory region] */
/* 5 Module data region */
/* 6 Module data region */
/* 7 Module data region */
/* */
/* If TXM_MODULE_MANAGER_16_MPU is defined, there are 16 MPU slots. */
/* MPU layout for the Cortex-M7: */
/* Entry Description */
/* 0 Kernel mode entry */
/* 1 Module code region */
/* 2 Module code region */
/* 3 Module code region */
/* 4 Module code region */
/* 5 Module data region */
/* 6 Module data region */
/* 7 Module data region */
/* 8 Module data region */
/* 9 Module shared memory region */
/* 10 Module shared memory region */
/* 11 Module shared memory region */
/* 12 User-defined region */
/* 13 User-defined region */
/* 14 User-defined region */
/* 15 User-defined region */
/* */
/* */
/* INPUT */
/* */
/* module_instance Pointer to module instance */
/* */
/* OUTPUT */
/* */
/* MPU specifications for module in module_instance */
/* */
/* CALLS */
/* */
/* _txm_module_manager_region_size_get */
/* */
/* CALLED BY */
/* */
/* _txm_module_manager_thread_create */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-15-2021 Scott Larson Initial Version 6.1.9 */
/* 07-29-2022 Scott Larson Enable user defined regions, */
/* resulting in version 6.1.12 */
/* 03-08-2023 Scott Larson Initialize unused MPU region, */
/* fix MPU settings for region */
/* size less than 32 bytes, */
/* resulting in version 6.2.1 */
/* */
/**************************************************************************/
VOID _txm_module_manager_mm_register_setup(TXM_MODULE_INSTANCE *module_instance)
{
#ifdef TXM_MODULE_MANAGER_16_MPU
ULONG code_address;
ULONG code_size;
ULONG data_address;
ULONG data_size;
ULONG start_stop_stack_size;
ULONG callback_stack_size;
ULONG block_size;
ULONG region_size;
ULONG srd_bits = 0;
UINT mpu_table_index = 1;
UINT i;
/* Setup the first MPU region for kernel mode entry. */
/* Set address register to user mode entry function address, which is guaranteed to be at least 32-byte aligned.
Mask address to proper range, region 0, set Valid bit. */
module_instance -> txm_module_instance_mpu_registers[TXM_MODULE_MANAGER_MPU_KERNEL_ENTRY_INDEX].txm_module_mpu_region_address = ((ULONG) _txm_module_manager_user_mode_entry & 0xFFFFFFE0) | TXM_MPU_VALID_BIT;
/* Set the attributes, region size (32 bytes), and enable bit. */
module_instance -> txm_module_instance_mpu_registers[TXM_MODULE_MANAGER_MPU_KERNEL_ENTRY_INDEX].txm_module_mpu_region_attribute_size = TXM_MODULE_MPU_CODE_ACCESS_CONTROL | 0x08 | TXM_ENABLE_REGION;
/* End of kernel mode entry setup. */
/* Setup code protection. */
/* Pickup code starting address and actual size. */
code_address = (ULONG) module_instance -> txm_module_instance_code_start;
code_size = module_instance -> txm_module_instance_preamble_ptr -> txm_module_preamble_code_size;
/* Determine code block sizes. Minimize the alignment requirement.
There are 4 MPU code entries available. The following is how the code size
will be distributed:
1. 1/4 of the largest power of two that is greater than or equal to code size.
2. 1/4 of the largest power of two that is greater than or equal to code size.
3. Largest power of 2 that fits in the remaining space.
4. Smallest power of 2 that exceeds the remaining space, minimum 32. */
/* Now loop through to setup MPU protection for the code area. */
for (i = 0; i < TXM_MODULE_MANAGER_MPU_CODE_ENTRIES; i++)
{
switch(i)
{
/* First two MPU blocks are 1/4 of the largest power of two
that is greater than or equal to code size. */
case 0:
{
block_size = _txm_power_of_two_block_size(code_size) >> 2;
break;
}
case 2:
{
/* Third MPU block is the largest power of 2 that fits within the remaining space. */
/* Subtract (block_size*2) from code_size to calculate remaining space. */
code_size = code_size - (block_size << 1);
block_size = _txm_power_of_two_block_size(code_size);
/* Minimum block size is 32. */
if(block_size > 32)
{
/* POW2 function result is divided by two to fit in the remaining space. */
block_size = block_size >> 1;
}
break;
}
case 3:
{
/* Last MPU block is the smallest power of 2 that exceeds the remaining space, minimum 32. */
/* Calculate remaining space. */
if(code_size - block_size > code_size)
{
/* Case 2 covered the remaining code size. This region will not be used. */
block_size = 0;
}
else
{
code_size = code_size - block_size;
block_size = _txm_power_of_two_block_size(code_size);
srd_bits = _txm_module_manager_calculate_srd_bits(block_size, code_size);
}
break;
}
default:
{
/* Case 1 is the same as 0 - the block size was already calculated. */
break;
}
}
/* Build the base address register with address, MPU region, set Valid bit. */
module_instance -> txm_module_instance_mpu_registers[mpu_table_index].txm_module_mpu_region_address = (code_address & ~(block_size - 1)) | mpu_table_index | TXM_MPU_VALID_BIT;
/* Only configure attribute register if the block is valid. */
if(block_size)
{
/* Calculate the region size information. */
region_size = _txm_module_manager_region_size_get(block_size);
/* Build the attribute-size register with permissions, SRD, size, enable. */
module_instance -> txm_module_instance_mpu_registers[mpu_table_index].txm_module_mpu_region_attribute_size = TXM_MODULE_MPU_CODE_ACCESS_CONTROL | srd_bits | (region_size << 1) | TXM_ENABLE_REGION;
/* Adjust the code address. */
code_address = code_address + block_size;
}
else
{
module_instance -> txm_module_instance_mpu_registers[mpu_table_index].txm_module_mpu_region_attribute_size = 0;
}
/* Increment MPU table index. */
mpu_table_index++;
}
/* End of code protection. */
/* Setup data protection. */
/* Reset SRD bitfield. */
srd_bits = 0;
/* Pickup data starting address and actual size. */
data_address = (ULONG) module_instance -> txm_module_instance_data_start;
/* Adjust the size of the module elements to be aligned to the default alignment. We do this
so that when we partition the allocated memory, we can simply place these regions right beside
each other without having to align their pointers. Note this only works when they all have
the same alignment. */
data_size = module_instance -> txm_module_instance_preamble_ptr -> txm_module_preamble_data_size;
start_stop_stack_size = module_instance -> txm_module_instance_preamble_ptr -> txm_module_preamble_start_stop_stack_size;
callback_stack_size = module_instance -> txm_module_instance_preamble_ptr -> txm_module_preamble_callback_stack_size;
data_size = ((data_size + TXM_MODULE_DATA_ALIGNMENT - 1)/TXM_MODULE_DATA_ALIGNMENT) * TXM_MODULE_DATA_ALIGNMENT;
start_stop_stack_size = ((start_stop_stack_size + TXM_MODULE_DATA_ALIGNMENT - 1)/TXM_MODULE_DATA_ALIGNMENT) * TXM_MODULE_DATA_ALIGNMENT;
callback_stack_size = ((callback_stack_size + TXM_MODULE_DATA_ALIGNMENT - 1)/TXM_MODULE_DATA_ALIGNMENT) * TXM_MODULE_DATA_ALIGNMENT;
/* Update the data size to include thread stacks. */
data_size = data_size + start_stop_stack_size + callback_stack_size;
/* Determine data block sizes. Minimize the alignment requirement.
There are 4 MPU data entries available. The following is how the data size
will be distributed:
1. 1/4 of the largest power of two that is greater than or equal to data size.
2. 1/4 of the largest power of two that is greater than or equal to data size.
3. Largest power of 2 that fits in the remaining space.
4. Smallest power of 2 that exceeds the remaining space, minimum 32. */
/* Now loop through to setup MPU protection for the data area. */
for (i = 0; i < TXM_MODULE_MANAGER_MPU_DATA_ENTRIES; i++)
{
switch(i)
{
/* First two MPU blocks are 1/4 of the largest power of two
that is greater than or equal to data size. */
case 0:
{
block_size = _txm_power_of_two_block_size(data_size) >> 2;
break;
}
case 2:
{
/* Third MPU block is the largest power of 2 that fits within the remaining space. */
/* Subtract (block_size*2) from data_size to calculate remaining space. */
data_size = data_size - (block_size << 1);
block_size = _txm_power_of_two_block_size(data_size);
/* Minimum block size is 32. */
if(block_size > 32)
{
/* POW2 function result is divided by two to fit in the remaining space. */
block_size = block_size >> 1;
}
break;
}
case 3:
{
/* Last MPU block is the smallest power of 2 that exceeds the remaining space, minimum 32. */
/* Calculate remaining space. */
if(data_size - block_size > data_size)
{
/* Case 2 covered the remaining data size. This region will not be used. */
block_size = 0;
}
else
{
data_size = data_size - block_size;
block_size = _txm_power_of_two_block_size(data_size);
srd_bits = _txm_module_manager_calculate_srd_bits(block_size, data_size);
}
break;
}
default:
{
/* Case 1 is the same as 0 - the block size was already calculated. */
break;
}
}
/* Build the base address register with address, MPU region, set Valid bit. */
module_instance -> txm_module_instance_mpu_registers[mpu_table_index].txm_module_mpu_region_address = (data_address & ~(block_size - 1)) | mpu_table_index | TXM_MPU_VALID_BIT;
/* Only configure attribute register if the block is valid. */
if(block_size)
{
/* Calculate the region size information. */
region_size = _txm_module_manager_region_size_get(block_size);
/* Build the attribute-size register with permissions, SRD, size, enable. */
module_instance -> txm_module_instance_mpu_registers[mpu_table_index].txm_module_mpu_region_attribute_size = TXM_MODULE_MPU_DATA_ACCESS_CONTROL | srd_bits | (region_size << 1) | TXM_ENABLE_REGION;
/* Adjust the data address. */
data_address = data_address + block_size;
}
else
{
module_instance -> txm_module_instance_mpu_registers[mpu_table_index].txm_module_mpu_region_attribute_size = 0;
}
/* Increment MPU table index. */
mpu_table_index++;
}
/* End of data protection. */
/* Setup MPU for the shared regions. */
while (mpu_table_index < TXM_MODULE_MANAGER_MPU_USER_REGION_INDEX)
{
/* Build the base address register with address, MPU region, set Valid bit. */
module_instance -> txm_module_instance_mpu_registers[mpu_table_index].txm_module_mpu_region_address = mpu_table_index | TXM_MPU_VALID_BIT;
/* Increment MPU table index. */
mpu_table_index++;
}
/* Setup user-defined regions (12-15). */
module_instance -> txm_module_instance_mpu_registers[12].txm_module_mpu_region_address = TXM_MODULE_MPU_USER_DEFINED_RBAR_12;
module_instance -> txm_module_instance_mpu_registers[12].txm_module_mpu_region_attribute_size = TXM_MODULE_MPU_USER_DEFINED_RASR_12;
module_instance -> txm_module_instance_mpu_registers[13].txm_module_mpu_region_address = TXM_MODULE_MPU_USER_DEFINED_RBAR_13;
module_instance -> txm_module_instance_mpu_registers[13].txm_module_mpu_region_attribute_size = TXM_MODULE_MPU_USER_DEFINED_RASR_13;
module_instance -> txm_module_instance_mpu_registers[14].txm_module_mpu_region_address = TXM_MODULE_MPU_USER_DEFINED_RBAR_14;
module_instance -> txm_module_instance_mpu_registers[14].txm_module_mpu_region_attribute_size = TXM_MODULE_MPU_USER_DEFINED_RASR_14;
module_instance -> txm_module_instance_mpu_registers[15].txm_module_mpu_region_address = TXM_MODULE_MPU_USER_DEFINED_RBAR_15;
module_instance -> txm_module_instance_mpu_registers[15].txm_module_mpu_region_attribute_size = TXM_MODULE_MPU_USER_DEFINED_RASR_15;
#else /* TXM_MODULE_MANAGER_16_MPU is not defined, only 8 MPU regions. */
ULONG code_address;
ULONG code_size;
ULONG data_address;
ULONG data_size;
ULONG start_stop_stack_size;
ULONG callback_stack_size;
ULONG block_size;
ULONG base_attribute_register;
ULONG region_size;
ULONG srd_bits = 0;
UINT mpu_table_index = 1;
UINT i;
/* Setup the first MPU region for kernel mode entry. */
/* Set address register to user mode entry function address, which is guaranteed to be at least 32-byte aligned.
Mask address to proper range, region 0, set Valid bit. */
module_instance -> txm_module_instance_mpu_registers[TXM_MODULE_MANAGER_MPU_KERNEL_ENTRY_INDEX].txm_module_mpu_region_address = ((ULONG) _txm_module_manager_user_mode_entry & 0xFFFFFFE0) | TXM_MPU_VALID_BIT;
/* Set the attributes, region size (32 bytes), and enable bit. */
module_instance -> txm_module_instance_mpu_registers[TXM_MODULE_MANAGER_MPU_KERNEL_ENTRY_INDEX].txm_module_mpu_region_attribute_size = TXM_MODULE_MPU_CODE_ACCESS_CONTROL | 0x08 | TXM_ENABLE_REGION;
/* End of kernel mode entry setup. */
/* Setup code protection. */
/* Pickup code starting address and actual size. */
code_address = (ULONG) module_instance -> txm_module_instance_code_start;
code_size = module_instance -> txm_module_instance_preamble_ptr -> txm_module_preamble_code_size;
/* Check if shared memory was set up. If so, only 3 entries are available for
code protection. If not set up, 4 code entries are available. */
if(module_instance -> txm_module_instance_mpu_registers[TXM_MODULE_MANAGER_SHARED_MPU_REGION].txm_module_mpu_region_address == 0)
{
/* Determine code block sizes. Minimize the alignment requirement.
There are 4 MPU code entries available. The following is how the code size
will be distributed:
1. 1/4 of the largest power of two that is greater than or equal to code size.
2. 1/4 of the largest power of two that is greater than or equal to code size.
3. Largest power of 2 that fits in the remaining space.
4. Smallest power of 2 that exceeds the remaining space, minimum 32. */
/* Now loop through to setup MPU protection for the code area. */
for (i = 0; i < TXM_MODULE_MANAGER_CODE_MPU_ENTRIES; i++)
{
switch(i)
{
/* First two MPU blocks are 1/4 of the largest power of two
that is greater than or equal to code size. */
case 0:
{
block_size = _txm_power_of_two_block_size(code_size) >> 2;
break;
}
case 2:
{
/* Third MPU block is the largest power of 2 that fits within the remaining space. */
/* Subtract (block_size*2) from code_size to calculate remaining space. */
code_size = code_size - (block_size << 1);
block_size = _txm_power_of_two_block_size(code_size);
/* Minimum block size is 32. */
if(block_size > 32)
{
/* POW2 function result is divided by two to fit in the remaining space. */
block_size = block_size >> 1;
}
break;
}
case 3:
{
/* Last MPU block is the smallest power of 2 that exceeds the remaining space, minimum 32. */
/* Calculate remaining space. */
if(code_size - block_size > code_size)
{
/* Case 2 covered the remaining code size. This region will not be used. */
block_size = 0;
}
else
{
code_size = code_size - block_size;
block_size = _txm_power_of_two_block_size(code_size);
srd_bits = _txm_module_manager_calculate_srd_bits(block_size, code_size);
}
break;
}
default:
{
/* Case 1 is the same as 0 - the block size was already calculated. */
break;
}
}
/* Build the base address register with address, MPU region, set Valid bit. */
module_instance -> txm_module_instance_mpu_registers[mpu_table_index].txm_module_mpu_region_address = (code_address & ~(block_size - 1)) | mpu_table_index | TXM_MPU_VALID_BIT;
/* Only configure attribute register if the block is valid. */
if(block_size)
{
/* Calculate the region size information. */
region_size = _txm_module_manager_region_size_get(block_size);
/* Build the attribute-size register with permissions, SRD, size, enable. */
module_instance -> txm_module_instance_mpu_registers[mpu_table_index].txm_module_mpu_region_attribute_size = TXM_MODULE_MPU_CODE_ACCESS_CONTROL | srd_bits | (region_size << 1) | TXM_ENABLE_REGION;
/* Adjust the code address. */
code_address = code_address + block_size;
}
else
{
module_instance -> txm_module_instance_mpu_registers[mpu_table_index].txm_module_mpu_region_attribute_size = 0;
}
/* Increment MPU table index. */
mpu_table_index++;
}
}
/* Only 3 code entries available. */
else
{
/* Calculate block size, one code entry taken up by shared memory. */
block_size = _txm_power_of_two_block_size(code_size / (TXM_MODULE_MANAGER_CODE_MPU_ENTRIES - 1));
/* Calculate the region size and pre-shift it so we don't need to shift it multiple times in the for loop. */
region_size = _txm_module_manager_region_size_get(block_size) << 1;
/* Now loop through to setup MPU protection for the code area. */
for (i = 0; i < TXM_MODULE_MANAGER_CODE_MPU_ENTRIES - 1; i++)
{
/* Build the base address register with address, MPU region, set Valid bit. */
module_instance -> txm_module_instance_mpu_registers[mpu_table_index].txm_module_mpu_region_address = (code_address & ~(block_size - 1)) | mpu_table_index | TXM_MPU_VALID_BIT;
/* Check if SRD bits need to be set. */
if (code_size < block_size)
{
srd_bits = _txm_module_manager_calculate_srd_bits(block_size, code_size);
}
/* Build the base attribute register. */
base_attribute_register = region_size | srd_bits | TXM_MODULE_MPU_CODE_ACCESS_CONTROL;
/* Is there still some code? If so set the region enable bit. */
if (code_size)
{
/* Set the region enable bit. */
base_attribute_register |= TXM_ENABLE_REGION;
}
/* Setup the MPU Base Attribute Register. */
module_instance -> txm_module_instance_mpu_registers[mpu_table_index].txm_module_mpu_region_attribute_size = base_attribute_register;
/* Adjust the code address. */
code_address = code_address + block_size;
/* Decrement the code size. */
if (code_size > block_size)
{
code_size = code_size - block_size;
}
else
{
code_size = 0;
}
/* Increment MPU table index. */
mpu_table_index++;
}
/* Data protection is already set up so we can simply return here. */
return;
}
/* Setup values for data area. */
data_address = (ULONG) module_instance -> txm_module_instance_data_start;
/* Adjust the size of the module elements to be aligned to the default alignment. We do this
so that when we partition the allocated memory, we can simply place these regions right beside
each other without having to align their pointers. Note this only works when they all have
the same alignment. */
data_size = module_instance -> txm_module_instance_preamble_ptr -> txm_module_preamble_data_size;
start_stop_stack_size = module_instance -> txm_module_instance_preamble_ptr -> txm_module_preamble_start_stop_stack_size;
callback_stack_size = module_instance -> txm_module_instance_preamble_ptr -> txm_module_preamble_callback_stack_size;
data_size = ((data_size + TXM_MODULE_DATA_ALIGNMENT - 1)/TXM_MODULE_DATA_ALIGNMENT) * TXM_MODULE_DATA_ALIGNMENT;
start_stop_stack_size = ((start_stop_stack_size + TXM_MODULE_DATA_ALIGNMENT - 1)/TXM_MODULE_DATA_ALIGNMENT) * TXM_MODULE_DATA_ALIGNMENT;
callback_stack_size = ((callback_stack_size + TXM_MODULE_DATA_ALIGNMENT - 1)/TXM_MODULE_DATA_ALIGNMENT) * TXM_MODULE_DATA_ALIGNMENT;
/* Update the data size to include thread stacks. */
data_size = data_size + start_stop_stack_size + callback_stack_size;
block_size = _txm_power_of_two_block_size(data_size / TXM_MODULE_MANAGER_DATA_MPU_ENTRIES);
/* Reset SRD bitfield. */
srd_bits = 0;
/* Calculate the region size and pre-shift it so we don't need to shift it multiple times in the for loop. */
region_size = _txm_module_manager_region_size_get(block_size) << 1;
/* Now loop through to setup MPU protection for the data area. */
for (i = 0; i < TXM_MODULE_MANAGER_DATA_MPU_ENTRIES; i++)
{
/* Build the base address register with address, MPU region, set Valid bit. */
module_instance -> txm_module_instance_mpu_registers[mpu_table_index].txm_module_mpu_region_address = (data_address & ~(block_size - 1)) | mpu_table_index | TXM_MPU_VALID_BIT;
/* Check if SRD bits need to be set. */
if (data_size < block_size)
{
srd_bits = _txm_module_manager_calculate_srd_bits(block_size, data_size);
}
/* Build the attribute-size register with permissions, SRD, size. */
base_attribute_register = region_size | srd_bits | TXM_MODULE_MPU_DATA_ACCESS_CONTROL;
/* Is there still some data? If so set the region enable bit. */
if (data_size)
{
/* Set the region enable bit. */
base_attribute_register |= TXM_ENABLE_REGION;
}
/* Setup the MPU Base Attribute Register. */
module_instance -> txm_module_instance_mpu_registers[mpu_table_index].txm_module_mpu_region_attribute_size = base_attribute_register;
/* Adjust the data address. */
data_address = data_address + block_size;
/* Decrement the data size. */
if (data_size > block_size)
{
data_size = data_size - block_size;
}
else
{
data_size = 0;
}
/* Increment MPU table index. */
mpu_table_index++;
}
#endif
}
#ifdef TXM_MODULE_MANAGER_16_MPU
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _txm_module_manager_inside_data_check Cortex-Mx */
/* 6.1.9 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function checks if the specified object is inside shared */
/* memory. */
/* */
/* INPUT */
/* */
/* module_instance Pointer to module instance */
/* obj_ptr Pointer to the object */
/* obj_size Size of the object */
/* */
/* OUTPUT */
/* */
/* Whether the object is inside the shared memory region. */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Module dispatch check functions */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-15-2021 Scott Larson Initial Version 6.1.9 */
/* */
/**************************************************************************/
UINT _txm_module_manager_inside_data_check(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE obj_ptr, UINT obj_size)
{
UINT shared_memory_index;
UINT num_shared_memory_mpu_entries;
ALIGN_TYPE shared_memory_address_start;
ALIGN_TYPE shared_memory_address_end;
/* Check for overflow. */
if ((obj_ptr) > ((obj_ptr) + (obj_size)))
{
return(TX_FALSE);
}
/* Check if the object is inside the module data. */
if ((obj_ptr >= (ALIGN_TYPE) module_instance -> txm_module_instance_data_start) &&
((obj_ptr + obj_size) <= ((ALIGN_TYPE) module_instance -> txm_module_instance_data_end + 1)))
{
return(TX_TRUE);
}
/* Check if the object is inside the shared memory. */
num_shared_memory_mpu_entries = module_instance -> txm_module_instance_shared_memory_count;
for (shared_memory_index = 0; shared_memory_index < num_shared_memory_mpu_entries; shared_memory_index++)
{
shared_memory_address_start = (ALIGN_TYPE) module_instance -> txm_module_instance_shared_memory_address[shared_memory_index];
shared_memory_address_end = shared_memory_address_start + module_instance -> txm_module_instance_shared_memory_length[shared_memory_index];
if ((obj_ptr >= (ALIGN_TYPE) shared_memory_address_start) &&
((obj_ptr + obj_size) <= (ALIGN_TYPE) shared_memory_address_end))
{
return(TX_TRUE);
}
}
return(TX_FALSE);
}
#endif

View File

@@ -0,0 +1,173 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Module */
/** */
/**************************************************************************/
/**************************************************************************/
#ifndef TXM_MODULE
#define TXM_MODULE
#endif
#ifndef TX_SOURCE_CODE
#define TX_SOURCE_CODE
#endif
/* Include necessary system files. */
#include "txm_module.h"
#include "tx_thread.h"
/* Define the global module entry pointer from the start thread of the module. */
TXM_MODULE_THREAD_ENTRY_INFO *_txm_module_entry_info;
/* Define the dispatch function pointer used in the module implementation. */
ULONG (*_txm_module_kernel_call_dispatcher)(ULONG kernel_request, ULONG param_1, ULONG param_2, ULONG param3);
/* Define the startup code that clears the uninitialized global data and sets up the
preset global variables. */
extern VOID _gcc_setup(TXM_MODULE_INSTANCE *);
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _txm_module_thread_shell_entry Cortex-Mx/GNU */
/* 6.1.9 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function calls the specified entry function of the thread. It */
/* also provides a place for the thread's entry function to return. */
/* If the thread returns, this function places the thread in a */
/* "COMPLETED" state. */
/* */
/* INPUT */
/* */
/* thread_ptr Pointer to current thread */
/* thread_info Pointer to thread entry info */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _gcc_setup cstartup initialization */
/* thread_entry Thread's entry function */
/* tx_thread_resume Resume the module callback thread */
/* _txm_module_thread_system_suspend Module thread suspension routine */
/* */
/* CALLED BY */
/* */
/* Initial thread stack frame */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-15-2021 Scott Larson Initial Version 6.1.9 */
/* */
/**************************************************************************/
VOID _txm_module_thread_shell_entry(TX_THREAD *thread_ptr, TXM_MODULE_THREAD_ENTRY_INFO *thread_info)
{
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
VOID (*entry_exit_notify)(TX_THREAD *, UINT);
#endif
/* Determine if this is the start thread. If so, we must prepare the module for
execution. If not, simply skip the C startup code. */
if (thread_info -> txm_module_thread_entry_info_start_thread)
{
/* Initialize the C environment. */
_gcc_setup(thread_info -> txm_module_thread_entry_info_code_base_address);
/* Save the entry info pointer, for later use. */
_txm_module_entry_info = thread_info;
/* Save the kernel function dispatch address. This is used to make all resident calls from
the module. */
_txm_module_kernel_call_dispatcher = thread_info -> txm_module_thread_entry_info_kernel_call_dispatcher;
/* Ensure that we have a valid pointer. */
while (!_txm_module_kernel_call_dispatcher)
{
/* Loop here, if an error is present getting the dispatch function pointer!
An error here typically indicates the resident portion of _tx_thread_schedule
is not supporting the trap to obtain the function pointer. */
}
/* Resume the module's callback thread, already created in the manager. */
_txe_thread_resume(thread_info -> txm_module_thread_entry_info_callback_request_thread);
}
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
/* Pickup the entry/exit application callback routine. */
entry_exit_notify = thread_info -> txm_module_thread_entry_info_exit_notify;
/* Determine if an application callback routine is specified. */
if (entry_exit_notify != TX_NULL)
{
/* Yes, notify application that this thread has been entered! */
(entry_exit_notify)(thread_ptr, TX_THREAD_ENTRY);
}
#endif
/* Call current thread's entry function. */
(thread_info -> txm_module_thread_entry_info_entry) (thread_info -> txm_module_thread_entry_info_parameter);
/* Suspend thread with a "completed" state. */
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
/* Pickup the entry/exit application callback routine again. */
entry_exit_notify = thread_info -> txm_module_thread_entry_info_exit_notify;
/* Determine if an application callback routine is specified. */
if (entry_exit_notify != TX_NULL)
{
/* Yes, notify application that this thread has exited! */
(entry_exit_notify)(thread_ptr, TX_THREAD_EXIT);
}
#endif
/* Call actual thread suspension routine. */
_txm_module_thread_system_suspend(thread_ptr);
#ifdef TX_SAFETY_CRITICAL
/* If we ever get here, raise safety critical exception. */
TX_SAFETY_CRITICAL_EXCEPTION(__FILE__, __LINE__, 0);
#endif
}

View File

@@ -0,0 +1,687 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Thread */
/** */
/**************************************************************************/
/**************************************************************************/
.global _tx_thread_current_ptr
.global _tx_thread_execute_ptr
.global _tx_timer_time_slice
.global _tx_execution_thread_enter
.global _tx_execution_thread_exit
.global _tx_thread_preempt_disable
.global _txm_module_manager_memory_fault_handler
.global _txm_module_manager_memory_fault_info
#ifdef TX_LOW_POWER
.global tx_low_power_enter
.global tx_low_power_exit
#endif
.text
.align 4
.syntax unified
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_schedule Cortex-Mx/GNU */
/* 6.2.0 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function waits for a thread control block pointer to appear in */
/* the _tx_thread_execute_ptr variable. Once a thread pointer appears */
/* in the variable, the corresponding thread is resumed. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _tx_initialize_kernel_enter ThreadX entry function */
/* _tx_thread_system_return Return to system from thread */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-15-2021 Scott Larson Initial Version 6.1.9 */
/* 01-31-2022 Scott Larson Fixed predefined macro name, */
/* resulting in version 6.1.10 */
/* 04-25-2022 Scott Larson Optimized MPU configuration, */
/* added BASEPRI support, */
/* resulting in version 6.1.11 */
/* 07-29-2022 Scott Larson Removed the code path to skip */
/* MPU reloading, optional */
/* default MPU settings, */
/* resulting in version 6.1.12 */
/* 10-31-2022 Scott Larson Added low power support, */
/* resulting in version 6.2.0 */
/* */
/**************************************************************************/
// VOID _tx_thread_schedule(VOID)
// {
.global _tx_thread_schedule
.thumb_func
_tx_thread_schedule:
/* This function should only ever be called on Cortex-M
from the first schedule request. Subsequent scheduling occurs
from the PendSV handling routine below. */
/* Clear the preempt-disable flag to enable rescheduling after initialization on Cortex-M targets. */
MOV r0, #0 // Build value for TX_FALSE
LDR r2, =_tx_thread_preempt_disable // Build address of preempt disable flag
STR r0, [r2, #0] // Clear preempt disable flag
#ifdef __ARM_FP
/* Clear CONTROL.FPCA bit so VFP registers aren't unnecessarily stacked. */
MRS r0, CONTROL // Pickup current CONTROL register
BIC r0, r0, #4 // Clear the FPCA bit
MSR CONTROL, r0 // Setup new CONTROL register
#endif
/* Enable memory fault registers. */
LDR r0, =0xE000ED24 // Build SHCSR address
LDR r1, =0x70000 // Enable Usage, Bus, and MemManage faults
STR r1, [r0] //
/* Enable interrupts */
CPSIE i
/* Enter the scheduler for the first time. */
MOV r0, #0x10000000 // Load PENDSVSET bit
MOV r1, #0xE000E000 // Load NVIC base
STR r0, [r1, #0xD04] // Set PENDSVBIT in ICSR
DSB // Complete all memory accesses
ISB // Flush pipeline
/* Wait here for the PendSV to take place. */
__tx_wait_here:
B __tx_wait_here // Wait for the PendSV to happen
// }
/* Memory Exception Handler. */
.global MemManage_Handler
.global BusFault_Handler
.global UsageFault_Handler
.thumb_func
MemManage_Handler:
.thumb_func
BusFault_Handler:
.thumb_func
UsageFault_Handler:
#ifdef TX_PORT_USE_BASEPRI
LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI
MSR BASEPRI, r1
#else
CPSID i // Disable interrupts
#endif /* TX_PORT_USE_BASEPRI */
/* Now pickup and store all the fault related information. */
LDR r12,=_txm_module_manager_memory_fault_info // Pickup fault info struct
LDR r0, =_tx_thread_current_ptr // Build current thread pointer address
LDR r1, [r0] // Pickup the current thread pointer
STR r1, [r12, #0] // Save current thread pointer in fault info structure
LDR r0, =0xE000ED24 // Build SHCSR address
LDR r1, [r0] // Pickup SHCSR
STR r1, [r12, #8] // Save SHCSR
LDR r0, =0xE000ED28 // Build CFSR address
LDR r1, [r0] // Pickup CFSR
STR r1, [r12, #12] // Save CFSR
LDR r0, =0xE000ED34 // Build MMFAR address
LDR r1, [r0] // Pickup MMFAR
STR r1, [r12, #16] // Save MMFAR
LDR r0, =0xE000ED38 // Build BFAR address
LDR r1, [r0] // Pickup BFAR
STR r1, [r12, #20] // Save BFAR
MRS r0, CONTROL // Pickup current CONTROL register
STR r0, [r12, #24] // Save CONTROL
MRS r1, PSP // Pickup thread stack pointer
STR r1, [r12, #28] // Save thread stack pointer
LDR r0, [r1] // Pickup saved r0
STR r0, [r12, #32] // Save r0
LDR r0, [r1, #4] // Pickup saved r1
STR r0, [r12, #36] // Save r1
STR r2, [r12, #40] // Save r2
STR r3, [r12, #44] // Save r3
STR r4, [r12, #48] // Save r4
STR r5, [r12, #52] // Save r5
STR r6, [r12, #56] // Save r6
STR r7, [r12, #60] // Save r7
STR r8, [r12, #64] // Save r8
STR r9, [r12, #68] // Save r9
STR r10,[r12, #72] // Save r10
STR r11,[r12, #76] // Save r11
LDR r0, [r1, #16] // Pickup saved r12
STR r0, [r12, #80] // Save r12
LDR r0, [r1, #20] // Pickup saved lr
STR r0, [r12, #84] // Save lr
LDR r0, [r1, #24] // Pickup instruction address at point of fault
STR r0, [r12, #4] // Save point of fault
LDR r0, [r1, #28] // Pickup xPSR
STR r0, [r12, #88] // Save xPSR
MRS r0, CONTROL // Pickup current CONTROL register
BIC r0, r0, #1 // Clear the UNPRIV bit
MSR CONTROL, r0 // Setup new CONTROL register
LDR r0, =0xE000ED28 // Build the Memory Management Fault Status Register (MMFSR)
LDRB r1, [r0] // Pickup the MMFSR, with the following bit definitions:
// Bit 0 = 1 -> Instruction address violation
// Bit 1 = 1 -> Load/store address violation
// Bit 7 = 1 -> MMFAR is valid
STRB r1, [r0] // Clear the MMFSR
#ifdef __ARM_FP
LDR r0, =0xE000EF34 // Cleanup FPU context: Load FPCCR address
LDR r1, [r0] // Load FPCCR
BIC r1, r1, #1 // Clear the lazy preservation active bit
STR r1, [r0] // Save FPCCR
#endif
BL _txm_module_manager_memory_fault_handler // Call memory manager fault handler
#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
/* Call the thread exit function to indicate the thread is no longer executing. */
CPSID i // Disable interrupts
BL _tx_execution_thread_exit // Call the thread exit function
CPSIE i // Enable interrupts
#endif
MOV r1, #0 // Build NULL value
LDR r0, =_tx_thread_current_ptr // Pickup address of current thread pointer
STR r1, [r0] // Clear current thread pointer
// Return from MemManage_Handler exception
LDR r0, =0xE000ED04 // Load ICSR
LDR r1, =0x10000000 // Set PENDSVSET bit
STR r1, [r0] // Store ICSR
DSB // Wait for memory access to complete
#ifdef TX_PORT_USE_BASEPRI
MOV r0, 0 // Disable BASEPRI masking (enable interrupts)
MSR BASEPRI, r0
#else
CPSIE i // Enable interrupts
#endif
MOV lr, #0xFFFFFFFD // Load exception return code
BX lr // Return from exception
/* Generic context PendSV handler. */
.global PendSV_Handler
.global __tx_PendSVHandler
.syntax unified
.thumb_func
PendSV_Handler:
.thumb_func
__tx_PendSVHandler:
/* Get current thread value and new thread pointer. */
__tx_ts_handler:
#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
/* Call the thread exit function to indicate the thread is no longer executing. */
#ifdef TX_PORT_USE_BASEPRI
LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI
MSR BASEPRI, r1
#else
CPSID i // Disable interrupts
#endif /* TX_PORT_USE_BASEPRI */
PUSH {r0, lr} // Save LR (and r0 just for alignment)
BL _tx_execution_thread_exit // Call the thread exit function
POP {r0, lr} // Recover LR
#ifdef TX_PORT_USE_BASEPRI
MOV r0, 0 // Disable BASEPRI masking (enable interrupts)
MSR BASEPRI, r0
#else
CPSIE i // Enable interrupts
#endif /* TX_PORT_USE_BASEPRI */
#endif /* EXECUTION PROFILE */
LDR r0, =_tx_thread_current_ptr // Build current thread pointer address
LDR r2, =_tx_thread_execute_ptr // Build execute thread pointer address
MOV r3, #0 // Build NULL value
LDR r1, [r0] // Pickup current thread pointer
/* Determine if there is a current thread to finish preserving. */
CBZ r1, __tx_ts_new // If NULL, skip preservation
/* Recover PSP and preserve current thread context. */
STR r3, [r0] // Set _tx_thread_current_ptr to NULL
MRS r12, PSP // Pickup PSP pointer (thread's stack pointer)
STMDB r12!, {r4-r11} // Save its remaining registers
#ifdef __ARM_FP
TST LR, #0x10 // Determine if the VFP extended frame is present
BNE _skip_vfp_save
VSTMDB r12!,{s16-s31} // Yes, save additional VFP registers
_skip_vfp_save:
#endif
LDR r4, =_tx_timer_time_slice // Build address of time-slice variable
STMDB r12!, {LR} // Save LR on the stack
/* Determine if time-slice is active. If it isn't, skip time handling processing. */
LDR r5, [r4] // Pickup current time-slice
STR r12, [r1, #8] // Save the thread stack pointer
CBZ r5, __tx_ts_new // If not active, skip processing
/* Time-slice is active, save the current thread's time-slice and clear the global time-slice variable. */
STR r5, [r1, #24] // Save current time-slice
/* Clear the global time-slice. */
STR r3, [r4] // Clear time-slice
/* Executing thread is now completely preserved!!! */
__tx_ts_new:
/* Now we are looking for a new thread to execute! */
#ifdef TX_PORT_USE_BASEPRI
LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI
MSR BASEPRI, r1
#else
CPSID i // Disable interrupts
#endif
LDR r1, [r2] // Is there another thread ready to execute?
CBNZ r1, __tx_ts_restore // Yes, schedule it
/* The following is the idle wait processing... in this case, no threads are ready for execution and the
system will simply be idle until an interrupt occurs that makes a thread ready. Note that interrupts
are disabled to allow use of WFI for waiting for a thread to arrive. */
__tx_ts_wait:
#ifdef TX_PORT_USE_BASEPRI
LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI
MSR BASEPRI, r1
#else
CPSID i // Disable interrupts
#endif
LDR r1, [r2] // Pickup the next thread to execute pointer
CBNZ r1, __tx_ts_ready // If non-NULL, a new thread is ready!
#ifdef TX_LOW_POWER
PUSH {r0-r3}
BL tx_low_power_enter // Possibly enter low power mode
POP {r0-r3}
#endif
#ifdef TX_ENABLE_WFI
DSB // Ensure no outstanding memory transactions
WFI // Wait for interrupt
ISB // Ensure pipeline is flushed
#endif
#ifdef TX_LOW_POWER
PUSH {r0-r3}
BL tx_low_power_exit // Exit low power mode
POP {r0-r3}
#endif
#ifdef TX_PORT_USE_BASEPRI
MOV r4, #0 // Disable BASEPRI masking (enable interrupts)
MSR BASEPRI, r4
#else
CPSIE i // Enable interrupts
#endif
B __tx_ts_wait // Loop to continue waiting
/* At this point, we have a new thread ready to go. Clear any newly pended PendSV - since we are
already in the handler! */
__tx_ts_ready:
MOV r7, #0x08000000 // Build clear PendSV value
MOV r8, #0xE000E000 // Build base NVIC address
STR r7, [r8, #0xD04] // Clear any PendSV
__tx_ts_restore:
/* A thread is ready, make the current thread the new thread
and enable interrupts. */
STR r1, [r0] // Setup the current thread pointer to the new thread
#ifdef TX_PORT_USE_BASEPRI
MOV r4, #0 // Disable BASEPRI masking (enable interrupts)
MSR BASEPRI, r4
#else
CPSIE i // Enable interrupts
#endif
/* Increment the thread run count. */
LDR r7, [r1, #4] // Pickup the current thread run count
LDR r4, =_tx_timer_time_slice // Build address of time-slice variable
LDR r5, [r1, #24] // Pickup thread's current time-slice
ADD r7, r7, #1 // Increment the thread run count
STR r7, [r1, #4] // Store the new run count
/* Setup global time-slice with thread's current time-slice. */
STR r5, [r4] // Setup global time-slice
#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
/* Call the thread entry function to indicate the thread is executing. */
PUSH {r0, r1} // Save r0 and r1
BL _tx_execution_thread_enter // Call the thread execution enter function
POP {r0, r1} // Recover r0 and r1
#endif
/* Restore the thread context and PSP. */
LDR r12, [r1, #8] // Pickup thread's stack pointer
MRS r5, CONTROL // Pickup current CONTROL register
LDR r4, [r1, #0x98] // Pickup current user mode flag
BIC r5, r5, #1 // Clear the UNPRIV bit
ORR r4, r4, r5 // Build new CONTROL register
MSR CONTROL, r4 // Setup new CONTROL register
LDR r0, =0xE000ED94 // Build MPU control reg address
MOV r3, #0 // Build disable value
CPSID i // Disable interrupts
STR r3, [r0] // Disable MPU
LDR r0, [r1, #0x90] // Pickup the module instance pointer
#ifdef TXM_MODULE_MPU_DEFAULT
CBZ r0, default_mpu // Is this thread owned by a module? No, default MPU setup
#else
CBZ r0, skip_mpu_setup // Is this thread owned by a module? No, skip MPU setup
#endif
LDR r2, [r0, #0x8C] // Pickup MPU region 5 address
#ifdef TXM_MODULE_MPU_DEFAULT
CBZ r2, default_mpu // Is protection required for this module? No, default MPU setup
#else
CBZ r2, skip_mpu_setup // Is protection required for this module? No, skip MPU setup
#endif
LDR r1, =0xE000ED9C // MPU_RBAR register address
// Use alias registers to quickly load MPU
ADD r0, r0, #100 // Build address of MPU register start in thread control block
#ifdef TXM_MODULE_MPU_DEFAULT
B config_mpu // configure MPU for module
default_mpu:
LDR r0, =txm_module_default_mpu_registers // default MPU configuration
#endif
config_mpu:
LDM r0!,{r2-r9} // Load MPU regions 0-3
STM r1,{r2-r9} // Store MPU regions 0-3
LDM r0!,{r2-r9} // Load MPU regions 4-7
STM r1,{r2-r9} // Store MPU regions 4-7
#ifdef TXM_MODULE_MANAGER_16_MPU
LDM r0!,{r2-r9} // Load MPU regions 8-11
STM r1,{r2-r9} // Store MPU regions 8-11
// Regions 12-15 are reserved for the user to define.
LDM r0,{r2-r9} // Load MPU regions 12-15
STM r1,{r2-r9} // Store MPU regions 12-15
#endif
_tx_enable_mpu:
LDR r0, =0xE000ED94 // Build MPU control reg address
MOV r1, #5 // Build enable value with background region enabled
STR r1, [r0] // Enable MPU
skip_mpu_setup:
CPSIE i // Enable interrupts
LDMIA r12!, {LR} // Pickup LR
#ifdef __ARM_FP
TST LR, #0x10 // Determine if the VFP extended frame is present
BNE _skip_vfp_restore // If not, skip VFP restore
VLDMIA r12!, {s16-s31} // Yes, restore additional VFP registers
_skip_vfp_restore:
#endif
LDMIA r12!, {r4-r11} // Recover thread's registers
MSR PSP, r12 // Setup the thread's stack pointer
/* Return to thread. */
BX lr // Return to thread!
/* SVC Handler. */
.global SVC_Handler
.global __tx_SVCallHandler
.syntax unified
.thumb_func
SVC_Handler:
.thumb_func
__tx_SVCallHandler:
MRS r0, PSP // Pickup the PSP stack
LDR r1, [r0, #24] // Pickup the point of interrupt
LDRB r2, [r1, #-2] // Pickup the SVC parameter
/* Determine which SVC trap we are processing */
CMP r2, #1 // Is it the entry into ThreadX?
BNE _tx_thread_user_return // No, return to user mode
/* At this point we have an SVC 1, which means we are entering
the kernel from a module thread with user mode selected. */
LDR r2, =_txm_module_priv // Load address of where we should have come from
CMP r1, r2 // Did we come from user_mode_entry?
IT NE // If no (not equal), then...
BXNE lr // return from where we came.
LDR r3, [r0, #20] // This is the saved LR
LDR r1, =_tx_thread_current_ptr // Build current thread pointer address
LDR r2, [r1] // Pickup current thread pointer
MOV r1, #0 // Build clear value
STR r1, [r2, #0x98] // Clear the current user mode selection for thread
STR r3, [r2, #0xA0] // Save the original LR in thread control block
/* If there is memory protection, use kernel stack */
LDR r0, [r2, #0x90] // Load the module instance ptr
LDR r0, [r0, #0x0C] // Load the module property flags
TST r0, #2 // Check if memory protected
BEQ _tx_skip_kernel_stack_enter
/* Switch to the module thread's kernel stack */
LDR r0, [r2, #0xA8] // Load the module kernel stack end
#ifndef TXM_MODULE_KERNEL_STACK_MAINTENANCE_DISABLE
LDR r1, [r2, #0xA4] // Load the module kernel stack start
LDR r3, [r2, #0xAC] // Load the module kernel stack size
STR r1, [r2, #12] // Set stack start
STR r0, [r2, #16] // Set stack end
STR r3, [r2, #20] // Set stack size
#endif
MRS r3, PSP // Pickup thread stack pointer
#ifdef __ARM_FP
TST lr, #0x10 // Test for extended module stack
ITT EQ
ORREQ r3, r3, #1 // If so, set LSB in thread stack pointer to indicate extended frame
ORREQ lr, lr, #0x10 // Set bit, return with standard frame
#endif
STR r3, [r2, #0xB0] // Save thread stack pointer
#ifdef __ARM_FP
BIC r3, #1 // Clear possibly OR'd bit
#endif
/* Build kernel stack by copying thread stack two registers at a time */
ADD r3, r3, #32 // Start at bottom of hardware stack
LDMDB r3!, {r1-r2}
STMDB r0!, {r1-r2}
LDMDB r3!, {r1-r2}
STMDB r0!, {r1-r2}
LDMDB r3!, {r1-r2}
STMDB r0!, {r1-r2}
LDMDB r3!, {r1-r2}
STMDB r0!, {r1-r2}
MSR PSP, r0 // Set kernel stack pointer
_tx_skip_kernel_stack_enter:
MRS r0, CONTROL // Pickup current CONTROL register
BIC r0, r0, #1 // Clear the UNPRIV bit
MSR CONTROL, r0 // Setup new CONTROL register
BX lr // Return to thread
_tx_thread_user_return:
LDR r2, =_txm_module_user_mode_exit // Load address of where we should have come from
CMP r1, r2 // Did we come from user_mode_exit?
IT NE // If no (not equal), then...
BXNE lr // return from where we came
LDR r1, =_tx_thread_current_ptr // Build current thread pointer address
LDR r2, [r1] // Pickup current thread pointer
LDR r1, [r2, #0x9C] // Pick up user mode
STR r1, [r2, #0x98] // Set the current user mode selection for thread
/* If there is memory protection, use kernel stack */
LDR r0, [r2, #0x90] // Load the module instance ptr
LDR r0, [r0, #0x0C] // Load the module property flags
TST r0, #2 // Check if memory protected
BEQ _tx_skip_kernel_stack_exit
#ifndef TXM_MODULE_KERNEL_STACK_MAINTENANCE_DISABLE
LDR r0, [r2, #0xB4] // Load the module thread stack start
LDR r1, [r2, #0xB8] // Load the module thread stack end
LDR r3, [r2, #0xBC] // Load the module thread stack size
STR r0, [r2, #12] // Set stack start
STR r1, [r2, #16] // Set stack end
STR r3, [r2, #20] // Set stack size
#endif
#ifdef __ARM_FP
/* If lazy stacking is pending, check if it can be cleared.
if(LSPACT && tx_thread_module_stack_start < FPCAR && FPCAR < tx_thread_module_stack_end)
then clear LSPACT. */
LDR r3, =0xE000EF34 // Address of FPCCR
LDR r3, [r3] // Load FPCCR
TST r3, #1 // Check if LSPACT is set
BEQ _tx_no_lazy_clear // if clear, move on
LDR r1, =0xE000EF38 // Address of FPCAR
LDR r1, [r1] // Load FPCAR
LDR r0, [r2, #0xA4] // Load kernel stack start
CMP r1, r0 // If FPCAR < start, move on
BLO _tx_no_lazy_clear
LDR r0, [r2, #0xA8] // Load kernel stack end
CMP r0, r1 // If end < FPCAR, move on
BLO _tx_no_lazy_clear
BIC r3, #1 // Clear LSPACT
LDR r1, =0xE000EF34 // Address of FPCCR
STR r3, [r1] // Save updated FPCCR
_tx_no_lazy_clear:
#endif
LDR r0, [r2, #0xB0] // Load the module thread stack pointer
MRS r3, PSP // Pickup kernel stack pointer
#ifdef __ARM_FP
TST r0, #1 // Is module stack extended?
ITTE NE // If so...
BICNE lr, #0x10 // Clear bit, return with extended frame
BICNE r0, #1 // Clear bit that indicates extended module frame
ORREQ lr, lr, #0x10 // Else set bit, return with standard frame
#endif
/* Copy kernel hardware stack to module thread stack. */
LDM r3!, {r1-r2} // Get r0, r1 from kernel stack
STM r0!, {r1-r2} // Insert r0, r1 into thread stack
LDM r3!, {r1-r2} // Get r2, r3 from kernel stack
STM r0!, {r1-r2} // Insert r2, r3 into thread stack
LDM r3!, {r1-r2} // Get r12, lr from kernel stack
STM r0!, {r1-r2} // Insert r12, lr into thread stack
LDM r3!, {r1-r2} // Get pc, xpsr from kernel stack
STM r0!, {r1-r2} // Insert pc, xpsr into thread stack
SUB r0, r0, #32 // Subtract 32 to get back to top of stack
MSR PSP, r0 // Set thread stack pointer
LDR r1, =_tx_thread_current_ptr // Build current thread pointer address
LDR r2, [r1] // Pickup current thread pointer
LDR r1, [r2, #0x9C] // Pick up user mode
_tx_skip_kernel_stack_exit:
MRS r0, CONTROL // Pickup current CONTROL register
ORR r0, r0, r1 // OR in the user mode bit
MSR CONTROL, r0 // Setup new CONTROL register
BX lr // Return to thread
/* Kernel entry function from user mode. */
.global _txm_module_manager_kernel_dispatch
.align 5
.syntax unified
// VOID _txm_module_manager_user_mode_entry(VOID)
// {
.global _txm_module_manager_user_mode_entry
.thumb_func
_txm_module_manager_user_mode_entry:
SVC 1 // Enter kernel
_txm_module_priv:
/* At this point, we are out of user mode. The original LR has been saved in the
thread control block. Simply call the kernel dispatch function. */
BL _txm_module_manager_kernel_dispatch
/* Pickup the original LR value while still in privileged mode */
LDR r2, =_tx_thread_current_ptr // Build current thread pointer address
LDR r3, [r2] // Pickup current thread pointer
LDR lr, [r3, #0xA0] // Pickup saved LR from original call
SVC 2 // Exit kernel and return to user mode
_txm_module_user_mode_exit:
BX lr // Return to the caller
NOP
NOP
NOP
NOP
// }
#ifdef __ARM_FP
.global tx_thread_fpu_enable
.thumb_func
tx_thread_fpu_enable:
.global tx_thread_fpu_disable
.thumb_func
tx_thread_fpu_disable:
/* Automatic VPF logic is supported, this function is present only for
backward compatibility purposes and therefore simply returns. */
BX LR // Return to caller
#endif

View File

@@ -0,0 +1,139 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Module Manager */
/** */
/**************************************************************************/
/**************************************************************************/
.text
.align 4
.syntax unified
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _txm_module_manager_thread_stack_build Cortex-Mx/GNU */
/* 6.1.9 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function builds a stack frame on the supplied thread's stack. */
/* The stack frame results in a fake interrupt return to the supplied */
/* function pointer. */
/* */
/* INPUT */
/* */
/* thread_ptr Pointer to thread */
/* function_ptr Pointer to shell function */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _tx_thread_create Create thread service */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-15-2021 Scott Larson Initial Version 6.1.9 */
/* */
/**************************************************************************/
// VOID _txm_module_manager_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(TX_THREAD *, TXM_MODULE_INSTANCE *))
// {
.global _txm_module_manager_thread_stack_build
.thumb_func
_txm_module_manager_thread_stack_build:
/* Build a fake interrupt frame. The form of the fake interrupt stack
on the Cortex-M should look like the following after it is built:
Stack Top:
lr Interrupted lr (lr at time of PENDSV)
r4 Initial value for r4
r5 Initial value for r5
r6 Initial value for r6
r7 Initial value for r7
r8 Initial value for r8
r9 Initial value for r9
r10 Initial value for r10
r11 Initial value for r11
r0 Initial value for r0 (Hardware stack starts here!!)
r1 Initial value for r1
r2 Initial value for r2
r3 Initial value for r3
r12 Initial value for r12
lr Initial value for lr
pc Initial value for pc
xPSR Initial value for xPSR
Stack Bottom: (higher memory address) */
LDR r2, [r0, #16] // Pickup end of stack area
BIC r2, r2, #0x7 // Align frame
SUB r2, r2, #68 // Subtract frame size
LDR r3, =0xFFFFFFFD // Build initial LR value
STR r3, [r2, #0] // Save on the stack
/* Actually build the stack frame. */
MOV r3, #0 // Build initial register value
STR r3, [r2, #4] // Store initial r4
STR r3, [r2, #8] // Store initial r5
STR r3, [r2, #12] // Store initial r6
STR r3, [r2, #16] // Store initial r7
STR r3, [r2, #20] // Store initial r8
STR r3, [r2, #28] // Store initial r10
STR r3, [r2, #32] // Store initial r11
/* Hardware stack follows. */
STR r0, [r2, #36] // Store initial r0, which is the thread control block
LDR r3, [r0, #8] // Pickup thread entry info pointer,which is in the stack pointer position of the thread control block.
// It was setup in the txm_module_manager_thread_create function. It will be overwritten later in this
// function with the actual, initial stack pointer.
STR r3, [r2, #40] // Store initial r1, which is the module entry information.
LDR r3, [r3, #8] // Pickup data base register from the module information
STR r3, [r2, #24] // Store initial r9 (data base register)
MOV r3, #0 // Clear r3 again
STR r3, [r2, #44] // Store initial r2
STR r3, [r2, #48] // Store initial r3
STR r3, [r2, #52] // Store initial r12
MOV r3, #0xFFFFFFFF // Poison EXC_RETURN value
STR r3, [r2, #56] // Store initial lr
STR r1, [r2, #60] // Store initial pc
MOV r3, #0x01000000 // Only T-bit need be set
STR r3, [r2, #64] // Store initial xPSR
/* Setup stack pointer. */
// thread_ptr -> tx_thread_stack_ptr = r2;
STR r2, [r0, #8] // Save stack pointer in thread's control block
BX lr // Return to caller
// }

View File

@@ -0,0 +1,173 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Module */
/** */
/**************************************************************************/
/**************************************************************************/
#ifndef TXM_MODULE
#define TXM_MODULE
#endif
#ifndef TX_SOURCE_CODE
#define TX_SOURCE_CODE
#endif
/* Include necessary system files. */
#include "txm_module.h"
#include "tx_thread.h"
/* Define the global module entry pointer from the start thread of the module. */
TXM_MODULE_THREAD_ENTRY_INFO *_txm_module_entry_info;
/* Define the dispatch function pointer used in the module implementation. */
ULONG (*_txm_module_kernel_call_dispatcher)(ULONG kernel_request, ULONG param_1, ULONG param_2, ULONG param3);
/* Define the startup code that clears the uninitialized global data and sets up the
preset global variables. */
extern VOID __iar_data_init3(VOID);
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _txm_module_thread_shell_entry Cortex-Mx/IAR */
/* 6.1.9 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function calls the specified entry function of the thread. It */
/* also provides a place for the thread's entry function to return. */
/* If the thread returns, this function places the thread in a */
/* "COMPLETED" state. */
/* */
/* INPUT */
/* */
/* thread_ptr Pointer to current thread */
/* thread_info Pointer to thread entry info */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* __iar_data_init3 cstartup initialization */
/* thread_entry Thread's entry function */
/* tx_thread_resume Resume the module callback thread */
/* _txm_module_thread_system_suspend Module thread suspension routine */
/* */
/* CALLED BY */
/* */
/* Initial thread stack frame */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-15-2021 Scott Larson Initial Version 6.1.9 */
/* */
/**************************************************************************/
VOID _txm_module_thread_shell_entry(TX_THREAD *thread_ptr, TXM_MODULE_THREAD_ENTRY_INFO *thread_info)
{
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
VOID (*entry_exit_notify)(TX_THREAD *, UINT);
#endif
/* Determine if this is the start thread. If so, we must prepare the module for
execution. If not, simply skip the C startup code. */
if (thread_info -> txm_module_thread_entry_info_start_thread)
{
/* Initialize the C environment. */
__iar_data_init3();
/* Save the entry info pointer, for later use. */
_txm_module_entry_info = thread_info;
/* Save the kernel function dispatch address. This is used to make all resident calls from
the module. */
_txm_module_kernel_call_dispatcher = thread_info -> txm_module_thread_entry_info_kernel_call_dispatcher;
/* Ensure that we have a valid pointer. */
while (!_txm_module_kernel_call_dispatcher)
{
/* Loop here, if an error is present getting the dispatch function pointer!
An error here typically indicates the resident portion of _tx_thread_schedule
is not supporting the trap to obtain the function pointer. */
}
/* Resume the module's callback thread, already created in the manager. */
_txe_thread_resume(thread_info -> txm_module_thread_entry_info_callback_request_thread);
}
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
/* Pickup the entry/exit application callback routine. */
entry_exit_notify = thread_info -> txm_module_thread_entry_info_exit_notify;
/* Determine if an application callback routine is specified. */
if (entry_exit_notify != TX_NULL)
{
/* Yes, notify application that this thread has been entered! */
(entry_exit_notify)(thread_ptr, TX_THREAD_ENTRY);
}
#endif
/* Call current thread's entry function. */
(thread_info -> txm_module_thread_entry_info_entry) (thread_info -> txm_module_thread_entry_info_parameter);
/* Suspend thread with a "completed" state. */
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
/* Pickup the entry/exit application callback routine again. */
entry_exit_notify = thread_info -> txm_module_thread_entry_info_exit_notify;
/* Determine if an application callback routine is specified. */
if (entry_exit_notify != TX_NULL)
{
/* Yes, notify application that this thread has exited! */
(entry_exit_notify)(thread_ptr, TX_THREAD_EXIT);
}
#endif
/* Call actual thread suspension routine. */
_txm_module_thread_system_suspend(thread_ptr);
#ifdef TX_SAFETY_CRITICAL
/* If we ever get here, raise safety critical exception. */
TX_SAFETY_CRITICAL_EXCEPTION(__FILE__, __LINE__, 0);
#endif
}

View File

@@ -0,0 +1,804 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** IAR Multithreaded Library Support */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
/* Define IAR library for tools prior to version 8. */
#if (__VER__ < 8000000)
/* IAR version 7 and below. */
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_initialize.h"
#include "tx_thread.h"
#include "tx_mutex.h"
/* This implementation requires that the following macros are defined in the
tx_port.h file and <yvals.h> is included with the following code segments:
#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT
#include <yvals.h>
#endif
#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT
#define TX_THREAD_EXTENSION_2 VOID *tx_thread_iar_tls_pointer;
#else
#define TX_THREAD_EXTENSION_2
#endif
#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT
#define TX_THREAD_CREATE_EXTENSION(thread_ptr) thread_ptr -> tx_thread_iar_tls_pointer = __iar_dlib_perthread_allocate();
#define TX_THREAD_DELETE_EXTENSION(thread_ptr) __iar_dlib_perthread_deallocate(thread_ptr -> tx_thread_iar_tls_pointer); \
thread_ptr -> tx_thread_iar_tls_pointer = TX_NULL;
#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION __iar_dlib_perthread_access(0);
#else
#define TX_THREAD_CREATE_EXTENSION(thread_ptr)
#define TX_THREAD_DELETE_EXTENSION(thread_ptr)
#endif
This should be done automatically if TX_ENABLE_IAR_LIBRARY_SUPPORT is defined while building the ThreadX library and the
application.
Finally, the project options General Options -> Library Configuration should have the "Enable thread support in library" box selected.
*/
#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT
#include <yvals.h>
#if _MULTI_THREAD
TX_MUTEX __tx_iar_system_lock_mutexes[_MAX_LOCK];
UINT __tx_iar_system_lock_next_free_mutex = 0;
/* Define error counters, just for debug purposes. */
UINT __tx_iar_system_lock_no_mutexes;
UINT __tx_iar_system_lock_internal_errors;
UINT __tx_iar_system_lock_isr_caller;
/* Define the TLS access function for the IAR library. */
void _DLIB_TLS_MEMORY *__iar_dlib_perthread_access(void _DLIB_TLS_MEMORY *symbp)
{
char _DLIB_TLS_MEMORY *p = 0;
/* Is there a current thread? */
if (_tx_thread_current_ptr)
p = (char _DLIB_TLS_MEMORY *) _tx_thread_current_ptr -> tx_thread_iar_tls_pointer;
else
p = (void _DLIB_TLS_MEMORY *) __segment_begin("__DLIB_PERTHREAD");
p += __IAR_DLIB_PERTHREAD_SYMBOL_OFFSET(symbp);
return (void _DLIB_TLS_MEMORY *) p;
}
/* Define mutexes for IAR library. */
void __iar_system_Mtxinit(__iar_Rmtx *m)
{
UINT i;
UINT status;
TX_MUTEX *mutex_ptr;
/* First, find a free mutex in the list. */
for (i = 0; i < _MAX_LOCK; i++)
{
/* Setup a pointer to the start of the next free mutex. */
mutex_ptr = &__tx_iar_system_lock_mutexes[__tx_iar_system_lock_next_free_mutex++];
/* Check for wrap-around on the next free mutex. */
if (__tx_iar_system_lock_next_free_mutex >= _MAX_LOCK)
{
/* Yes, set the free index back to 0. */
__tx_iar_system_lock_next_free_mutex = 0;
}
/* Is this mutex free? */
if (mutex_ptr -> tx_mutex_id != TX_MUTEX_ID)
{
/* Yes, this mutex is free, get out of the loop! */
break;
}
}
/* Determine if a free mutex was found. */
if (i >= _MAX_LOCK)
{
/* Error! No more free mutexes! */
/* Increment the no mutexes error counter. */
__tx_iar_system_lock_no_mutexes++;
/* Set return pointer to NULL. */
*m = TX_NULL;
/* Return. */
return;
}
/* Now create the ThreadX mutex for the IAR library. */
status = _tx_mutex_create(mutex_ptr, "IAR System Library Lock", TX_NO_INHERIT);
/* Determine if the creation was successful. */
if (status == TX_SUCCESS)
{
/* Yes, successful creation, return mutex pointer. */
*m = (VOID *) mutex_ptr;
}
else
{
/* Increment the internal error counter. */
__tx_iar_system_lock_internal_errors++;
/* Return a NULL pointer to indicate an error. */
*m = TX_NULL;
}
}
void __iar_system_Mtxdst(__iar_Rmtx *m)
{
/* Simply delete the mutex. */
_tx_mutex_delete((TX_MUTEX *) *m);
}
void __iar_system_Mtxlock(__iar_Rmtx *m)
{
UINT status;
/* Determine the caller's context. Mutex locks are only available from initialization and
threads. */
if ((_tx_thread_system_state == 0) || (_tx_thread_system_state >= TX_INITIALIZE_IN_PROGRESS))
{
/* Get the mutex. */
status = _tx_mutex_get((TX_MUTEX *) *m, TX_WAIT_FOREVER);
/* Check the status of the mutex release. */
if (status)
{
/* Internal error, increment the counter. */
__tx_iar_system_lock_internal_errors++;
}
}
else
{
/* Increment the ISR caller error. */
__tx_iar_system_lock_isr_caller++;
}
}
void __iar_system_Mtxunlock(__iar_Rmtx *m)
{
UINT status;
/* Determine the caller's context. Mutex unlocks are only available from initialization and
threads. */
if ((_tx_thread_system_state == 0) || (_tx_thread_system_state >= TX_INITIALIZE_IN_PROGRESS))
{
/* Release the mutex. */
status = _tx_mutex_put((TX_MUTEX *) *m);
/* Check the status of the mutex release. */
if (status)
{
/* Internal error, increment the counter. */
__tx_iar_system_lock_internal_errors++;
}
}
else
{
/* Increment the ISR caller error. */
__tx_iar_system_lock_isr_caller++;
}
}
#if _DLIB_FILE_DESCRIPTOR
TX_MUTEX __tx_iar_file_lock_mutexes[_MAX_FLOCK];
UINT __tx_iar_file_lock_next_free_mutex = 0;
/* Define error counters, just for debug purposes. */
UINT __tx_iar_file_lock_no_mutexes;
UINT __tx_iar_file_lock_internal_errors;
UINT __tx_iar_file_lock_isr_caller;
void __iar_file_Mtxinit(__iar_Rmtx *m)
{
UINT i;
UINT status;
TX_MUTEX *mutex_ptr;
/* First, find a free mutex in the list. */
for (i = 0; i < _MAX_FLOCK; i++)
{
/* Setup a pointer to the start of the next free mutex. */
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)
{
/* Yes, set the free index back to 0. */
__tx_iar_file_lock_next_free_mutex = 0;
}
/* Is this mutex free? */
if (mutex_ptr -> tx_mutex_id != TX_MUTEX_ID)
{
/* Yes, this mutex is free, get out of the loop! */
break;
}
}
/* Determine if a free mutex was found. */
if (i >= _MAX_LOCK)
{
/* Error! No more free mutexes! */
/* Increment the no mutexes error counter. */
__tx_iar_file_lock_no_mutexes++;
/* Set return pointer to NULL. */
*m = TX_NULL;
/* Return. */
return;
}
/* Now create the ThreadX mutex for the IAR library. */
status = _tx_mutex_create(mutex_ptr, "IAR File Library Lock", TX_NO_INHERIT);
/* Determine if the creation was successful. */
if (status == TX_SUCCESS)
{
/* Yes, successful creation, return mutex pointer. */
*m = (VOID *) mutex_ptr;
}
else
{
/* Increment the internal error counter. */
__tx_iar_file_lock_internal_errors++;
/* Return a NULL pointer to indicate an error. */
*m = TX_NULL;
}
}
void __iar_file_Mtxdst(__iar_Rmtx *m)
{
/* Simply delete the mutex. */
_tx_mutex_delete((TX_MUTEX *) *m);
}
void __iar_file_Mtxlock(__iar_Rmtx *m)
{
UINT status;
/* Determine the caller's context. Mutex locks are only available from initialization and
threads. */
if ((_tx_thread_system_state == 0) || (_tx_thread_system_state >= TX_INITIALIZE_IN_PROGRESS))
{
/* Get the mutex. */
status = _tx_mutex_get((TX_MUTEX *) *m, TX_WAIT_FOREVER);
/* Check the status of the mutex release. */
if (status)
{
/* Internal error, increment the counter. */
__tx_iar_file_lock_internal_errors++;
}
}
else
{
/* Increment the ISR caller error. */
__tx_iar_file_lock_isr_caller++;
}
}
void __iar_file_Mtxunlock(__iar_Rmtx *m)
{
UINT status;
/* Determine the caller's context. Mutex unlocks are only available from initialization and
threads. */
if ((_tx_thread_system_state == 0) || (_tx_thread_system_state >= TX_INITIALIZE_IN_PROGRESS))
{
/* Release the mutex. */
status = _tx_mutex_put((TX_MUTEX *) *m);
/* Check the status of the mutex release. */
if (status)
{
/* Internal error, increment the counter. */
__tx_iar_file_lock_internal_errors++;
}
}
else
{
/* Increment the ISR caller error. */
__tx_iar_file_lock_isr_caller++;
}
}
#endif /* _DLIB_FILE_DESCRIPTOR */
#endif /* _MULTI_THREAD */
#endif /* TX_ENABLE_IAR_LIBRARY_SUPPORT */
#else /* IAR version 8 and above. */
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_initialize.h"
#include "tx_thread.h"
#include "tx_mutex.h"
/* This implementation requires that the following macros are defined in the
tx_port.h file and <yvals.h> is included with the following code segments:
#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT
#include <yvals.h>
#endif
#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT
#define TX_THREAD_EXTENSION_2 VOID *tx_thread_iar_tls_pointer;
#else
#define TX_THREAD_EXTENSION_2
#endif
#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT
void *_tx_iar_create_per_thread_tls_area(void);
void _tx_iar_destroy_per_thread_tls_area(void *tls_ptr);
void __iar_Initlocks(void);
#define TX_THREAD_CREATE_EXTENSION(thread_ptr) thread_ptr -> tx_thread_iar_tls_pointer = __iar_dlib_perthread_allocate();
#define TX_THREAD_DELETE_EXTENSION(thread_ptr) do {__iar_dlib_perthread_deallocate(thread_ptr -> tx_thread_iar_tls_pointer); \
thread_ptr -> tx_thread_iar_tls_pointer = TX_NULL; } while(0);
#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION do {__iar_Initlocks();} while(0);
#else
#define TX_THREAD_CREATE_EXTENSION(thread_ptr)
#define TX_THREAD_DELETE_EXTENSION(thread_ptr)
#endif
This should be done automatically if TX_ENABLE_IAR_LIBRARY_SUPPORT is defined while building the ThreadX library and the
application.
Finally, the project options General Options -> Library Configuration should have the "Enable thread support in library" box selected.
*/
#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT
#include <DLib_threads.h>
void * __aeabi_read_tp();
void* _tx_iar_create_per_thread_tls_area();
void _tx_iar_destroy_per_thread_tls_area(void *tls_ptr);
#pragma section="__iar_tls$$DATA"
/* Define the TLS access function for the IAR library. */
void * __aeabi_read_tp(void)
{
void *p = 0;
TX_THREAD *thread_ptr = _tx_thread_current_ptr;
if (thread_ptr)
{
p = thread_ptr->tx_thread_iar_tls_pointer;
}
else
{
p = __section_begin("__iar_tls$$DATA");
}
return p;
}
/* Define the TLS creation and destruction to use malloc/free. */
void* _tx_iar_create_per_thread_tls_area()
{
UINT tls_size = __iar_tls_size();
/* Get memory for TLS. */
void *p = malloc(tls_size);
/* Initialize TLS-area and run constructors for objects in TLS */
__iar_tls_init(p);
return p;
}
void _tx_iar_destroy_per_thread_tls_area(void *tls_ptr)
{
/* Destroy objects living in TLS */
__call_thread_dtors();
free(tls_ptr);
}
#ifndef _MAX_LOCK
#define _MAX_LOCK 4
#endif
static TX_MUTEX __tx_iar_system_lock_mutexes[_MAX_LOCK];
static UINT __tx_iar_system_lock_next_free_mutex = 0;
/* Define error counters, just for debug purposes. */
UINT __tx_iar_system_lock_no_mutexes;
UINT __tx_iar_system_lock_internal_errors;
UINT __tx_iar_system_lock_isr_caller;
/* Define mutexes for IAR library. */
void __iar_system_Mtxinit(__iar_Rmtx *m)
{
UINT i;
UINT status;
TX_MUTEX *mutex_ptr;
/* First, find a free mutex in the list. */
for (i = 0; i < _MAX_LOCK; i++)
{
/* Setup a pointer to the start of the next free mutex. */
mutex_ptr = &__tx_iar_system_lock_mutexes[__tx_iar_system_lock_next_free_mutex++];
/* Check for wrap-around on the next free mutex. */
if (__tx_iar_system_lock_next_free_mutex >= _MAX_LOCK)
{
/* Yes, set the free index back to 0. */
__tx_iar_system_lock_next_free_mutex = 0;
}
/* Is this mutex free? */
if (mutex_ptr -> tx_mutex_id != TX_MUTEX_ID)
{
/* Yes, this mutex is free, get out of the loop! */
break;
}
}
/* Determine if a free mutex was found. */
if (i >= _MAX_LOCK)
{
/* Error! No more free mutexes! */
/* Increment the no mutexes error counter. */
__tx_iar_system_lock_no_mutexes++;
/* Set return pointer to NULL. */
*m = TX_NULL;
/* Return. */
return;
}
/* Now create the ThreadX mutex for the IAR library. */
status = _tx_mutex_create(mutex_ptr, "IAR System Library Lock", TX_NO_INHERIT);
/* Determine if the creation was successful. */
if (status == TX_SUCCESS)
{
/* Yes, successful creation, return mutex pointer. */
*m = (VOID *) mutex_ptr;
}
else
{
/* Increment the internal error counter. */
__tx_iar_system_lock_internal_errors++;
/* Return a NULL pointer to indicate an error. */
*m = TX_NULL;
}
}
void __iar_system_Mtxdst(__iar_Rmtx *m)
{
/* Simply delete the mutex. */
_tx_mutex_delete((TX_MUTEX *) *m);
}
void __iar_system_Mtxlock(__iar_Rmtx *m)
{
if (*m)
{
UINT status;
/* Determine the caller's context. Mutex locks are only available from initialization and
threads. */
if ((_tx_thread_system_state == 0) || (_tx_thread_system_state >= TX_INITIALIZE_IN_PROGRESS))
{
/* Get the mutex. */
status = _tx_mutex_get((TX_MUTEX *) *m, TX_WAIT_FOREVER);
/* Check the status of the mutex release. */
if (status)
{
/* Internal error, increment the counter. */
__tx_iar_system_lock_internal_errors++;
}
}
else
{
/* Increment the ISR caller error. */
__tx_iar_system_lock_isr_caller++;
}
}
}
void __iar_system_Mtxunlock(__iar_Rmtx *m)
{
if (*m)
{
UINT status;
/* Determine the caller's context. Mutex unlocks are only available from initialization and
threads. */
if ((_tx_thread_system_state == 0) || (_tx_thread_system_state >= TX_INITIALIZE_IN_PROGRESS))
{
/* Release the mutex. */
status = _tx_mutex_put((TX_MUTEX *) *m);
/* Check the status of the mutex release. */
if (status)
{
/* Internal error, increment the counter. */
__tx_iar_system_lock_internal_errors++;
}
}
else
{
/* Increment the ISR caller error. */
__tx_iar_system_lock_isr_caller++;
}
}
}
#if _DLIB_FILE_DESCRIPTOR
#include <stdio.h> /* Added to get access to FOPEN_MAX */
#ifndef _MAX_FLOCK
#define _MAX_FLOCK FOPEN_MAX /* Define _MAX_FLOCK as the maximum number of open files */
#endif
TX_MUTEX __tx_iar_file_lock_mutexes[_MAX_FLOCK];
UINT __tx_iar_file_lock_next_free_mutex = 0;
/* Define error counters, just for debug purposes. */
UINT __tx_iar_file_lock_no_mutexes;
UINT __tx_iar_file_lock_internal_errors;
UINT __tx_iar_file_lock_isr_caller;
void __iar_file_Mtxinit(__iar_Rmtx *m)
{
UINT i;
UINT status;
TX_MUTEX *mutex_ptr;
/* First, find a free mutex in the list. */
for (i = 0; i < _MAX_FLOCK; i++)
{
/* Setup a pointer to the start of the next free mutex. */
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)
{
/* Yes, set the free index back to 0. */
__tx_iar_file_lock_next_free_mutex = 0;
}
/* Is this mutex free? */
if (mutex_ptr -> tx_mutex_id != TX_MUTEX_ID)
{
/* Yes, this mutex is free, get out of the loop! */
break;
}
}
/* Determine if a free mutex was found. */
if (i >= _MAX_LOCK)
{
/* Error! No more free mutexes! */
/* Increment the no mutexes error counter. */
__tx_iar_file_lock_no_mutexes++;
/* Set return pointer to NULL. */
*m = TX_NULL;
/* Return. */
return;
}
/* Now create the ThreadX mutex for the IAR library. */
status = _tx_mutex_create(mutex_ptr, "IAR File Library Lock", TX_NO_INHERIT);
/* Determine if the creation was successful. */
if (status == TX_SUCCESS)
{
/* Yes, successful creation, return mutex pointer. */
*m = (VOID *) mutex_ptr;
}
else
{
/* Increment the internal error counter. */
__tx_iar_file_lock_internal_errors++;
/* Return a NULL pointer to indicate an error. */
*m = TX_NULL;
}
}
void __iar_file_Mtxdst(__iar_Rmtx *m)
{
/* Simply delete the mutex. */
_tx_mutex_delete((TX_MUTEX *) *m);
}
void __iar_file_Mtxlock(__iar_Rmtx *m)
{
UINT status;
/* Determine the caller's context. Mutex locks are only available from initialization and
threads. */
if ((_tx_thread_system_state == 0) || (_tx_thread_system_state >= TX_INITIALIZE_IN_PROGRESS))
{
/* Get the mutex. */
status = _tx_mutex_get((TX_MUTEX *) *m, TX_WAIT_FOREVER);
/* Check the status of the mutex release. */
if (status)
{
/* Internal error, increment the counter. */
__tx_iar_file_lock_internal_errors++;
}
}
else
{
/* Increment the ISR caller error. */
__tx_iar_file_lock_isr_caller++;
}
}
void __iar_file_Mtxunlock(__iar_Rmtx *m)
{
UINT status;
/* Determine the caller's context. Mutex unlocks are only available from initialization and
threads. */
if ((_tx_thread_system_state == 0) || (_tx_thread_system_state >= TX_INITIALIZE_IN_PROGRESS))
{
/* Release the mutex. */
status = _tx_mutex_put((TX_MUTEX *) *m);
/* Check the status of the mutex release. */
if (status)
{
/* Internal error, increment the counter. */
__tx_iar_file_lock_internal_errors++;
}
}
else
{
/* Increment the ISR caller error. */
__tx_iar_file_lock_isr_caller++;
}
}
#endif /* _DLIB_FILE_DESCRIPTOR */
#endif /* TX_ENABLE_IAR_LIBRARY_SUPPORT */
#endif /* IAR version 8 and above. */

View File

@@ -0,0 +1,763 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** ThreadX MISRA Compliance */
/** */
/**************************************************************************/
/**************************************************************************/
#define SHT_PROGBITS 0x1
EXTERN __aeabi_memset
EXTERN _tx_thread_current_ptr
EXTERN _tx_thread_interrupt_disable
EXTERN _tx_thread_interrupt_restore
EXTERN _tx_thread_stack_analyze
EXTERN _tx_thread_stack_error_handler
EXTERN _tx_thread_system_state
#ifdef TX_ENABLE_EVENT_TRACE
EXTERN _tx_trace_buffer_current_ptr
EXTERN _tx_trace_buffer_end_ptr
EXTERN _tx_trace_buffer_start_ptr
EXTERN _tx_trace_event_enable_bits
EXTERN _tx_trace_full_notify_function
EXTERN _tx_trace_header_ptr
#endif
PUBLIC _tx_misra_always_true
PUBLIC _tx_misra_block_pool_to_uchar_pointer_convert
PUBLIC _tx_misra_byte_pool_to_uchar_pointer_convert
PUBLIC _tx_misra_char_to_uchar_pointer_convert
PUBLIC _tx_misra_const_char_to_char_pointer_convert
#ifdef TX_ENABLE_EVENT_TRACE
PUBLIC _tx_misra_entry_to_uchar_pointer_convert
#endif
PUBLIC _tx_misra_indirect_void_to_uchar_pointer_convert
PUBLIC _tx_misra_memset
PUBLIC _tx_misra_message_copy
#ifdef TX_ENABLE_EVENT_TRACE
PUBLIC _tx_misra_object_to_uchar_pointer_convert
#endif
PUBLIC _tx_misra_pointer_to_ulong_convert
PUBLIC _tx_misra_status_get
PUBLIC _tx_misra_thread_stack_check
#ifdef TX_ENABLE_EVENT_TRACE
PUBLIC _tx_misra_time_stamp_get
#endif
PUBLIC _tx_misra_timer_indirect_to_void_pointer_convert
PUBLIC _tx_misra_timer_pointer_add
PUBLIC _tx_misra_timer_pointer_dif
#ifdef TX_ENABLE_EVENT_TRACE
PUBLIC _tx_misra_trace_event_insert
#endif
PUBLIC _tx_misra_uchar_pointer_add
PUBLIC _tx_misra_uchar_pointer_dif
PUBLIC _tx_misra_uchar_pointer_sub
PUBLIC _tx_misra_uchar_to_align_type_pointer_convert
PUBLIC _tx_misra_uchar_to_block_pool_pointer_convert
#ifdef TX_ENABLE_EVENT_TRACE
PUBLIC _tx_misra_uchar_to_entry_pointer_convert
PUBLIC _tx_misra_uchar_to_header_pointer_convert
#endif
PUBLIC _tx_misra_uchar_to_indirect_byte_pool_pointer_convert
PUBLIC _tx_misra_uchar_to_indirect_uchar_pointer_convert
#ifdef TX_ENABLE_EVENT_TRACE
PUBLIC _tx_misra_uchar_to_object_pointer_convert
#endif
PUBLIC _tx_misra_uchar_to_void_pointer_convert
PUBLIC _tx_misra_ulong_pointer_add
PUBLIC _tx_misra_ulong_pointer_dif
PUBLIC _tx_misra_ulong_pointer_sub
PUBLIC _tx_misra_ulong_to_pointer_convert
PUBLIC _tx_misra_ulong_to_thread_pointer_convert
PUBLIC _tx_misra_user_timer_pointer_get
PUBLIC _tx_misra_void_to_block_pool_pointer_convert
PUBLIC _tx_misra_void_to_byte_pool_pointer_convert
PUBLIC _tx_misra_void_to_event_flags_pointer_convert
PUBLIC _tx_misra_void_to_indirect_uchar_pointer_convert
PUBLIC _tx_misra_void_to_mutex_pointer_convert
PUBLIC _tx_misra_void_to_queue_pointer_convert
PUBLIC _tx_misra_void_to_semaphore_pointer_convert
PUBLIC _tx_misra_void_to_thread_pointer_convert
PUBLIC _tx_misra_void_to_uchar_pointer_convert
PUBLIC _tx_misra_void_to_ulong_pointer_convert
PUBLIC _tx_misra_ipsr_get
PUBLIC _tx_misra_control_get
PUBLIC _tx_misra_control_set
#ifdef __ARMVFP__
PUBLIC _tx_misra_fpccr_get
PUBLIC _tx_misra_vfp_touch
#endif
PUBLIC _tx_misra_event_flags_group_not_used
PUBLIC _tx_misra_event_flags_set_notify_not_used
PUBLIC _tx_misra_queue_not_used
PUBLIC _tx_misra_queue_send_notify_not_used
PUBLIC _tx_misra_semaphore_not_used
PUBLIC _tx_misra_semaphore_put_notify_not_used
PUBLIC _tx_misra_thread_entry_exit_notify_not_used
PUBLIC _tx_misra_thread_not_used
#ifdef TX_MISRA_ENABLE
PUBLIC _tx_version_id
SECTION `.data`:DATA:REORDER:NOROOT(2)
DATA
// 51 CHAR _tx_version_id[100] = "Copyright (c) Microsoft Corporation. All rights reserved. * ThreadX 6.1 MISRA C Compliant *";
_tx_version_id:
DC8 43H, 6FH, 70H, 79H, 72H, 69H, 67H, 68H
DC8 74H, 20H, 28H, 63H, 29H, 20H, 31H, 39H
DC8 39H, 36H, 2DH, 32H, 30H, 31H, 38H, 20H
DC8 45H, 78H, 70H, 72H, 65H, 73H, 73H, 20H
DC8 4CH, 6FH, 67H, 69H, 63H, 20H, 49H, 6EH
DC8 63H, 2EH, 20H, 2AH, 20H, 54H, 68H, 72H
DC8 65H, 61H, 64H, 58H, 20H, 36H, 2EH, 31H
DC8 20H, 4DH, 49H, 53H, 52H, 41H, 20H, 43H
DC8 20H, 43H, 6FH, 6DH, 70H, 6CH, 69H, 61H
DC8 6EH, 74H, 20H, 2AH, 0
DC8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
#endif //TX_MISRA_ENABLE
/**************************************************************************/
/**************************************************************************/
/** */
/** VOID _tx_misra_memset(VOID *ptr, UINT value, UINT size); */
/** */
/**************************************************************************/
/**************************************************************************/
SECTION `.text`:CODE:NOROOT(1)
THUMB
_tx_misra_memset:
PUSH {R4,LR}
MOVS R4,R0
MOVS R0,R2
MOVS R2,R1
MOVS R1,R0
MOVS R0,R4
BL __aeabi_memset
POP {R4,PC} // return
/**************************************************************************/
/**************************************************************************/
/** */
/** UCHAR *_tx_misra_uchar_pointer_add(UCHAR *ptr, ULONG amount); */
/** */
/**************************************************************************/
/**************************************************************************/
SECTION `.text`:CODE:NOROOT(1)
THUMB
_tx_misra_uchar_pointer_add:
ADD R0,R0,R1
BX LR // return
/**************************************************************************/
/**************************************************************************/
/** */
/** UCHAR *_tx_misra_uchar_pointer_sub(UCHAR *ptr, ULONG amount); */
/** */
/**************************************************************************/
/**************************************************************************/
SECTION `.text`:CODE:NOROOT(1)
THUMB
_tx_misra_uchar_pointer_sub:
RSBS R1,R1,#+0
ADD R0,R0,R1
BX LR // return
/**************************************************************************/
/**************************************************************************/
/** */
/** ULONG _tx_misra_uchar_pointer_dif(UCHAR *ptr1, UCHAR *ptr2); */
/** */
/**************************************************************************/
/**************************************************************************/
SECTION `.text`:CODE:NOROOT(1)
THUMB
_tx_misra_uchar_pointer_dif:
SUBS R0,R0,R1
BX LR // return
/************************************************************************************************************************************/
/************************************************************************************************************************************/
/** */
/** This single function serves all of the below prototypes. */
/** */
/** ULONG _tx_misra_pointer_to_ulong_convert(VOID *ptr); */
/** VOID *_tx_misra_ulong_to_pointer_convert(ULONG input); */
/** UCHAR **_tx_misra_indirect_void_to_uchar_pointer_convert(VOID **return_ptr); */
/** UCHAR **_tx_misra_uchar_to_indirect_uchar_pointer_convert(UCHAR *pointer); */
/** UCHAR *_tx_misra_block_pool_to_uchar_pointer_convert(TX_BLOCK_POOL *pool); */
/** TX_BLOCK_POOL *_tx_misra_void_to_block_pool_pointer_convert(VOID *pointer); */
/** UCHAR *_tx_misra_void_to_uchar_pointer_convert(VOID *pointer); */
/** TX_BLOCK_POOL *_tx_misra_uchar_to_block_pool_pointer_convert(UCHAR *pointer); */
/** UCHAR **_tx_misra_void_to_indirect_uchar_pointer_convert(VOID *pointer); */
/** TX_BYTE_POOL *_tx_misra_void_to_byte_pool_pointer_convert(VOID *pointer); */
/** UCHAR *_tx_misra_byte_pool_to_uchar_pointer_convert(TX_BYTE_POOL *pool); */
/** ALIGN_TYPE *_tx_misra_uchar_to_align_type_pointer_convert(UCHAR *pointer); */
/** TX_BYTE_POOL **_tx_misra_uchar_to_indirect_byte_pool_pointer_convert(UCHAR *pointer); */
/** TX_EVENT_FLAGS_GROUP *_tx_misra_void_to_event_flags_pointer_convert(VOID *pointer); */
/** ULONG *_tx_misra_void_to_ulong_pointer_convert(VOID *pointer); */
/** TX_MUTEX *_tx_misra_void_to_mutex_pointer_convert(VOID *pointer); */
/** TX_QUEUE *_tx_misra_void_to_queue_pointer_convert(VOID *pointer); */
/** TX_SEMAPHORE *_tx_misra_void_to_semaphore_pointer_convert(VOID *pointer); */
/** VOID *_tx_misra_uchar_to_void_pointer_convert(UCHAR *pointer); */
/** TX_THREAD *_tx_misra_ulong_to_thread_pointer_convert(ULONG value); */
/** VOID *_tx_misra_timer_indirect_to_void_pointer_convert(TX_TIMER_INTERNAL **pointer); */
/** CHAR *_tx_misra_const_char_to_char_pointer_convert(const char *pointer); */
/** TX_THREAD *_tx_misra_void_to_thread_pointer_convert(void *pointer); */
/** UCHAR *_tx_misra_object_to_uchar_pointer_convert(TX_TRACE_OBJECT_ENTRY *pointer); */
/** TX_TRACE_OBJECT_ENTRY *_tx_misra_uchar_to_object_pointer_convert(UCHAR *pointer); */
/** TX_TRACE_HEADER *_tx_misra_uchar_to_header_pointer_convert(UCHAR *pointer); */
/** TX_TRACE_BUFFER_ENTRY *_tx_misra_uchar_to_entry_pointer_convert(UCHAR *pointer); */
/** UCHAR *_tx_misra_entry_to_uchar_pointer_convert(TX_TRACE_BUFFER_ENTRY *pointer); */
/** UCHAR *_tx_misra_char_to_uchar_pointer_convert(CHAR *pointer); */
/** VOID _tx_misra_event_flags_group_not_used(TX_EVENT_FLAGS_GROUP *group_ptr); */
/** VOID _tx_misra_event_flags_set_notify_not_used(VOID (*events_set_notify)(TX_EVENT_FLAGS_GROUP *notify_group_ptr)); */
/** VOID _tx_misra_queue_not_used(TX_QUEUE *queue_ptr); */
/** VOID _tx_misra_queue_send_notify_not_used(VOID (*queue_send_notify)(TX_QUEUE *notify_queue_ptr)); */
/** VOID _tx_misra_semaphore_not_used(TX_SEMAPHORE *semaphore_ptr); */
/** VOID _tx_misra_semaphore_put_notify_not_used(VOID (*semaphore_put_notify)(TX_SEMAPHORE *notify_semaphore_ptr)); */
/** VOID _tx_misra_thread_not_used(TX_THREAD *thread_ptr); */
/** VOID _tx_misra_thread_entry_exit_notify_not_used(VOID (*thread_entry_exit_notify)(TX_THREAD *notify_thread_ptr, UINT id)); */
/** */
/************************************************************************************************************************************/
/************************************************************************************************************************************/
SECTION `.text`:CODE:NOROOT(1)
THUMB
_tx_misra_pointer_to_ulong_convert:
_tx_misra_ulong_to_pointer_convert:
_tx_misra_indirect_void_to_uchar_pointer_convert:
_tx_misra_uchar_to_indirect_uchar_pointer_convert:
_tx_misra_block_pool_to_uchar_pointer_convert:
_tx_misra_void_to_block_pool_pointer_convert:
_tx_misra_void_to_uchar_pointer_convert:
_tx_misra_uchar_to_block_pool_pointer_convert:
_tx_misra_void_to_indirect_uchar_pointer_convert:
_tx_misra_void_to_byte_pool_pointer_convert:
_tx_misra_byte_pool_to_uchar_pointer_convert:
_tx_misra_uchar_to_align_type_pointer_convert:
_tx_misra_uchar_to_indirect_byte_pool_pointer_convert:
_tx_misra_void_to_event_flags_pointer_convert:
_tx_misra_void_to_ulong_pointer_convert:
_tx_misra_void_to_mutex_pointer_convert:
_tx_misra_void_to_queue_pointer_convert:
_tx_misra_void_to_semaphore_pointer_convert:
_tx_misra_uchar_to_void_pointer_convert:
_tx_misra_ulong_to_thread_pointer_convert:
_tx_misra_timer_indirect_to_void_pointer_convert:
_tx_misra_const_char_to_char_pointer_convert:
_tx_misra_void_to_thread_pointer_convert:
#ifdef TX_ENABLE_EVENT_TRACE
_tx_misra_object_to_uchar_pointer_convert:
_tx_misra_uchar_to_object_pointer_convert:
_tx_misra_uchar_to_header_pointer_convert:
_tx_misra_uchar_to_entry_pointer_convert:
_tx_misra_entry_to_uchar_pointer_convert:
#endif
_tx_misra_char_to_uchar_pointer_convert:
_tx_misra_event_flags_group_not_used:
_tx_misra_event_flags_set_notify_not_used:
_tx_misra_queue_not_used:
_tx_misra_queue_send_notify_not_used:
_tx_misra_semaphore_not_used:
_tx_misra_semaphore_put_notify_not_used:
_tx_misra_thread_entry_exit_notify_not_used:
_tx_misra_thread_not_used:
BX LR // return
/**************************************************************************/
/**************************************************************************/
/** */
/** ULONG *_tx_misra_ulong_pointer_add(ULONG *ptr, ULONG amount); */
/** */
/**************************************************************************/
/**************************************************************************/
SECTION `.text`:CODE:NOROOT(1)
THUMB
_tx_misra_ulong_pointer_add:
ADD R0,R0,R1, LSL #+2
BX LR // return
/**************************************************************************/
/**************************************************************************/
/** */
/** ULONG *_tx_misra_ulong_pointer_sub(ULONG *ptr, ULONG amount); */
/** */
/**************************************************************************/
/**************************************************************************/
SECTION `.text`:CODE:NOROOT(1)
THUMB
_tx_misra_ulong_pointer_sub:
MVNS R2,#+3
MULS R1,R2,R1
ADD R0,R0,R1
BX LR // return
/**************************************************************************/
/**************************************************************************/
/** */
/** ULONG _tx_misra_ulong_pointer_dif(ULONG *ptr1, ULONG *ptr2); */
/** */
/**************************************************************************/
/**************************************************************************/
SECTION `.text`:CODE:NOROOT(1)
THUMB
_tx_misra_ulong_pointer_dif:
SUBS R0,R0,R1
ASRS R0,R0,#+2
BX LR // return
/**************************************************************************/
/**************************************************************************/
/** */
/** VOID _tx_misra_message_copy(ULONG **source, ULONG **destination, */
/** UINT size); */
/** */
/**************************************************************************/
/**************************************************************************/
SECTION `.text`:CODE:NOROOT(1)
THUMB
_tx_misra_message_copy:
PUSH {R4,R5}
LDR R3,[R0, #+0]
LDR R4,[R1, #+0]
LDR R5,[R3, #+0]
STR R5,[R4, #+0]
ADDS R4,R4,#+4
ADDS R3,R3,#+4
CMP R2,#+2
BCC.N ??_tx_misra_message_copy_0
SUBS R2,R2,#+1
B.N ??_tx_misra_message_copy_1
??_tx_misra_message_copy_2:
LDR R5,[R3, #+0]
STR R5,[R4, #+0]
ADDS R4,R4,#+4
ADDS R3,R3,#+4
SUBS R2,R2,#+1
??_tx_misra_message_copy_1:
CMP R2,#+0
BNE.N ??_tx_misra_message_copy_2
??_tx_misra_message_copy_0:
STR R3,[R0, #+0]
STR R4,[R1, #+0]
POP {R4,R5}
BX LR // return
/**************************************************************************/
/**************************************************************************/
/** */
/** ULONG _tx_misra_timer_pointer_dif(TX_TIMER_INTERNAL **ptr1, */
/** TX_TIMER_INTERNAL **ptr2); */
/** */
/**************************************************************************/
/**************************************************************************/
SECTION `.text`:CODE:NOROOT(1)
THUMB
_tx_misra_timer_pointer_dif:
SUBS R0,R0,R1
ASRS R0,R0,#+2
BX LR // return
/**************************************************************************/
/**************************************************************************/
/** */
/** TX_TIMER_INTERNAL **_tx_misra_timer_pointer_add(TX_TIMER_INTERNAL */
/** **ptr1, ULONG size); */
/** */
/**************************************************************************/
/**************************************************************************/
SECTION `.text`:CODE:NOROOT(1)
THUMB
_tx_misra_timer_pointer_add:
ADD R0,R0,R1, LSL #+2
BX LR // return
/**************************************************************************/
/**************************************************************************/
/** */
/** VOID _tx_misra_user_timer_pointer_get(TX_TIMER_INTERNAL */
/** *internal_timer, TX_TIMER **user_timer); */
/** */
/**************************************************************************/
/**************************************************************************/
SECTION `.text`:CODE:NOROOT(1)
THUMB
_tx_misra_user_timer_pointer_get:
SUBS R0,#8
STR R0,[R1, #+0]
BX LR // return
/**************************************************************************/
/**************************************************************************/
/** */
/** VOID _tx_misra_thread_stack_check(TX_THREAD *thread_ptr, */
/** VOID **highest_stack); */
/** */
/**************************************************************************/
/**************************************************************************/
SECTION `.text`:CODE:NOROOT(1)
THUMB
_tx_misra_thread_stack_check:
PUSH {R3-R5,LR}
MOVS R4,R0
MOVS R5,R1
BL _tx_thread_interrupt_disable
CMP R4,#+0
BEQ.N ??_tx_misra_thread_stack_check_0
LDR R1,[R4, #+0]
LDR.N R2,??DataTable2 // 0x54485244
CMP R1,R2
BNE.N ??_tx_misra_thread_stack_check_0
LDR R1,[R4, #+8]
LDR R2,[R5, #+0]
CMP R1,R2
BCS.N ??_tx_misra_thread_stack_check_1
LDR R1,[R4, #+8]
STR R1,[R5, #+0]
??_tx_misra_thread_stack_check_1:
LDR R1,[R4, #+12]
LDR R1,[R1, #+0]
CMP R1,#-269488145
BNE.N ??_tx_misra_thread_stack_check_2
LDR R1,[R4, #+16]
LDR R1,[R1, #+1]
CMP R1,#-269488145
BNE.N ??_tx_misra_thread_stack_check_2
LDR R1,[R5, #+0]
LDR R2,[R4, #+12]
CMP R1,R2
BCS.N ??_tx_misra_thread_stack_check_3
??_tx_misra_thread_stack_check_2:
BL _tx_thread_interrupt_restore
MOVS R0,R4
BL _tx_thread_stack_error_handler
BL _tx_thread_interrupt_disable
??_tx_misra_thread_stack_check_3:
LDR R1,[R5, #+0]
LDR R1,[R1, #-4]
CMP R1,#-269488145
BEQ.N ??_tx_misra_thread_stack_check_0
BL _tx_thread_interrupt_restore
MOVS R0,R4
BL _tx_thread_stack_analyze
BL _tx_thread_interrupt_disable
??_tx_misra_thread_stack_check_0:
BL _tx_thread_interrupt_restore
POP {R0,R4,R5,PC} // return
#ifdef TX_ENABLE_EVENT_TRACE
/**************************************************************************/
/**************************************************************************/
/** */
/** VOID _tx_misra_trace_event_insert(ULONG event_id, */
/** VOID *info_field_1, ULONG info_field_2, ULONG info_field_3, */
/** ULONG info_field_4, ULONG filter, ULONG time_stamp); */
/** */
/**************************************************************************/
/**************************************************************************/
SECTION `.text`:CODE:NOROOT(1)
THUMB
_tx_misra_trace_event_insert:
PUSH {R3-R7,LR}
LDR.N R4,??DataTable2_1
LDR R4,[R4, #+0]
CMP R4,#+0
BEQ.N ??_tx_misra_trace_event_insert_0
LDR.N R5,??DataTable2_2
LDR R5,[R5, #+0]
LDR R6,[SP, #+28]
TST R5,R6
BEQ.N ??_tx_misra_trace_event_insert_0
LDR.N R5,??DataTable2_3
LDR R5,[R5, #+0]
LDR.N R6,??DataTable2_4
LDR R6,[R6, #+0]
CMP R5,#+0
BNE.N ??_tx_misra_trace_event_insert_1
LDR R5,[R6, #+44]
LDR R7,[R6, #+60]
LSLS R7,R7,#+16
ORRS R7,R7,#0x80000000
ORRS R5,R7,R5
B.N ??_tx_misra_trace_event_insert_2
??_tx_misra_trace_event_insert_1:
CMP R5,#-252645136
BCS.N ??_tx_misra_trace_event_insert_3
MOVS R5,R6
MOVS R6,#-1
B.N ??_tx_misra_trace_event_insert_2
??_tx_misra_trace_event_insert_3:
MOVS R6,#-252645136
MOVS R5,#+0
??_tx_misra_trace_event_insert_2:
STR R6,[R4, #+0]
STR R5,[R4, #+4]
STR R0,[R4, #+8]
LDR R0,[SP, #+32]
STR R0,[R4, #+12]
STR R1,[R4, #+16]
STR R2,[R4, #+20]
STR R3,[R4, #+24]
LDR R0,[SP, #+24]
STR R0,[R4, #+28]
ADDS R4,R4,#+32
LDR.N R0,??DataTable2_5
LDR R0,[R0, #+0]
CMP R4,R0
BCC.N ??_tx_misra_trace_event_insert_4
LDR.N R0,??DataTable2_6
LDR R4,[R0, #+0]
LDR.N R0,??DataTable2_1
STR R4,[R0, #+0]
LDR.N R0,??DataTable2_7
LDR R0,[R0, #+0]
STR R4,[R0, #+32]
LDR.N R0,??DataTable2_8
LDR R0,[R0, #+0]
CMP R0,#+0
BEQ.N ??_tx_misra_trace_event_insert_0
LDR.N R0,??DataTable2_7
LDR R0,[R0, #+0]
LDR.N R1,??DataTable2_8
LDR R1,[R1, #+0]
BLX R1
B.N ??_tx_misra_trace_event_insert_0
??_tx_misra_trace_event_insert_4:
LDR.N R0,??DataTable2_1
STR R4,[R0, #+0]
LDR.N R0,??DataTable2_7
LDR R0,[R0, #+0]
STR R4,[R0, #+32]
??_tx_misra_trace_event_insert_0:
POP {R0,R4-R7,PC} // return
SECTION `.text`:CODE:NOROOT(2)
SECTION_TYPE SHT_PROGBITS, 0
DATA
??DataTable2_1:
DC32 _tx_trace_buffer_current_ptr
SECTION `.text`:CODE:NOROOT(2)
SECTION_TYPE SHT_PROGBITS, 0
DATA
??DataTable2_2:
DC32 _tx_trace_event_enable_bits
SECTION `.text`:CODE:NOROOT(2)
SECTION_TYPE SHT_PROGBITS, 0
DATA
??DataTable2_5:
DC32 _tx_trace_buffer_end_ptr
SECTION `.text`:CODE:NOROOT(2)
SECTION_TYPE SHT_PROGBITS, 0
DATA
??DataTable2_6:
DC32 _tx_trace_buffer_start_ptr
SECTION `.text`:CODE:NOROOT(2)
SECTION_TYPE SHT_PROGBITS, 0
DATA
??DataTable2_7:
DC32 _tx_trace_header_ptr
SECTION `.text`:CODE:NOROOT(2)
SECTION_TYPE SHT_PROGBITS, 0
DATA
??DataTable2_8:
DC32 _tx_trace_full_notify_function
/**************************************************************************/
/**************************************************************************/
/** */
/** ULONG _tx_misra_time_stamp_get(VOID); */
/** */
/**************************************************************************/
/**************************************************************************/
SECTION `.text`:CODE:NOROOT(1)
THUMB
_tx_misra_time_stamp_get:
MOVS R0,#+0
BX LR // return
#endif
SECTION `.text`:CODE:NOROOT(2)
SECTION_TYPE SHT_PROGBITS, 0
DATA
??DataTable2:
DC32 0x54485244
SECTION `.text`:CODE:NOROOT(2)
SECTION_TYPE SHT_PROGBITS, 0
DATA
??DataTable2_3:
DC32 _tx_thread_system_state
SECTION `.text`:CODE:NOROOT(2)
SECTION_TYPE SHT_PROGBITS, 0
DATA
??DataTable2_4:
DC32 _tx_thread_current_ptr
/**************************************************************************/
/**************************************************************************/
/** */
/** UINT _tx_misra_always_true(void); */
/** */
/**************************************************************************/
/**************************************************************************/
SECTION `.text`:CODE:NOROOT(1)
THUMB
_tx_misra_always_true:
MOVS R0,#+1
BX LR // return
/**************************************************************************/
/**************************************************************************/
/** */
/** UINT _tx_misra_status_get(UINT status); */
/** */
/**************************************************************************/
/**************************************************************************/
SECTION `.text`:CODE:NOROOT(1)
THUMB
_tx_misra_status_get:
MOVS R0,#+0
BX LR // return
/***********************************************************************************************/
/***********************************************************************************************/
/** */
/** ULONG _tx_misra_ipsr_get(void); */
/** */
/***********************************************************************************************/
/***********************************************************************************************/
SECTION `.text`:CODE:NOROOT(1)
THUMB
_tx_misra_ipsr_get:
MRS R0, IPSR
BX LR // return
/***********************************************************************************************/
/***********************************************************************************************/
/** */
/** ULONG _tx_misra_control_get(void); */
/** */
/***********************************************************************************************/
/***********************************************************************************************/
SECTION `.text`:CODE:NOROOT(1)
THUMB
_tx_misra_control_get:
MRS R0, CONTROL
BX LR // return
/***********************************************************************************************/
/***********************************************************************************************/
/** */
/** void _tx_misra_control_set(ULONG value); */
/** */
/***********************************************************************************************/
/***********************************************************************************************/
SECTION `.text`:CODE:NOROOT(1)
THUMB
_tx_misra_control_set:
MSR CONTROL, R0
BX LR // return
#ifdef __ARMVFP__
/***********************************************************************************************/
/***********************************************************************************************/
/** */
/** ULONG _tx_misra_fpccr_get(void); */
/** */
/***********************************************************************************************/
/***********************************************************************************************/
SECTION `.text`:CODE:NOROOT(2)
THUMB
_tx_misra_fpccr_get:
LDR r0, =0xE000EF34 // Build FPCCR address
LDR r0, [r0] // Load FPCCR value
BX LR // return
/***********************************************************************************************/
/***********************************************************************************************/
/** */
/** void _tx_misra_vfp_touch(void); */
/** */
/***********************************************************************************************/
/***********************************************************************************************/
SECTION `.text`:CODE:NOROOT(1)
THUMB
_tx_misra_vfp_touch:
vmov.f32 s0, s0
BX LR // return
#endif
SECTION `.iar_vfe_header`:DATA:NOALLOC:NOROOT(2)
SECTION_TYPE SHT_PROGBITS, 0
DATA
DC32 0
END

View File

@@ -0,0 +1,673 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Thread */
/** */
/**************************************************************************/
/**************************************************************************/
EXTERN _tx_thread_current_ptr
EXTERN _tx_thread_execute_ptr
EXTERN _tx_timer_time_slice
EXTERN _tx_execution_thread_enter
EXTERN _tx_execution_thread_exit
EXTERN _tx_thread_preempt_disable
EXTERN _txm_module_manager_memory_fault_handler
EXTERN _txm_module_manager_memory_fault_info
EXTERN txm_module_default_mpu_registers
SECTION `.text`:CODE:NOROOT(2)
THUMB
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_schedule Cortex-Mx/IAR */
/* 6.2.0 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function waits for a thread control block pointer to appear in */
/* the _tx_thread_execute_ptr variable. Once a thread pointer appears */
/* in the variable, the corresponding thread is resumed. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _tx_initialize_kernel_enter ThreadX entry function */
/* _tx_thread_system_return Return to system from thread */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-15-2021 Scott Larson Initial Version 6.1.9 */
/* 04-25-2022 Scott Larson Optimized MPU configuration, */
/* added BASEPRI support, */
/* resulting in version 6.1.11 */
/* 07-29-2022 Scott Larson Removed the code path to skip */
/* MPU reloading, optional */
/* default MPU settings, */
/* resulting in version 6.1.12 */
/* 10-31-2022 Scott Larson Added low power support, */
/* resulting in version 6.2.0 */
/* */
/**************************************************************************/
// VOID _tx_thread_schedule(VOID)
// {
PUBLIC _tx_thread_schedule
_tx_thread_schedule:
/* This function should only ever be called on Cortex-M
from the first schedule request. Subsequent scheduling occurs
from the PendSV handling routine below. */
/* Clear the preempt-disable flag to enable rescheduling after initialization on Cortex-M targets. */
MOV r0, #0 // Build value for TX_FALSE
LDR r2, =_tx_thread_preempt_disable // Build address of preempt disable flag
STR r0, [r2, #0] // Clear preempt disable flag
#ifdef __ARMVFP__
/* Clear CONTROL.FPCA bit so VFP registers aren't unnecessarily stacked. */
MRS r0, CONTROL // Pickup current CONTROL register
BIC r0, r0, #4 // Clear the FPCA bit
MSR CONTROL, r0 // Setup new CONTROL register
#endif
/* Enable memory fault registers. */
LDR r0, =0xE000ED24 // Build SHCSR address
LDR r1, =0x70000 // Enable Usage, Bus, and MemManage faults
STR r1, [r0] //
/* Enable interrupts */
CPSIE i
/* Enter the scheduler for the first time. */
MOV r0, #0x10000000 // Load PENDSVSET bit
MOV r1, #0xE000E000 // Load NVIC base
STR r0, [r1, #0xD04] // Set PENDSVBIT in ICSR
DSB // Complete all memory accesses
ISB // Flush pipeline
/* Wait here for the PendSV to take place. */
__tx_wait_here:
B __tx_wait_here // Wait for the PendSV to happen
// }
/* Memory Exception Handler. */
PUBLIC MemManage_Handler
PUBLIC BusFault_Handler
PUBLIC UsageFault_Handler
MemManage_Handler:
BusFault_Handler:
UsageFault_Handler:
#ifdef TX_PORT_USE_BASEPRI
LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI
MSR BASEPRI, r1
#else
CPSID i // Disable interrupts
#endif /* TX_PORT_USE_BASEPRI */
/* Now pickup and store all the fault related information. */
LDR r12,=_txm_module_manager_memory_fault_info // Pickup fault info struct
LDR r0, =_tx_thread_current_ptr // Build current thread pointer address
LDR r1, [r0] // Pickup the current thread pointer
STR r1, [r12, #0] // Save current thread pointer in fault info structure
LDR r0, =0xE000ED24 // Build SHCSR address
LDR r1, [r0] // Pickup SHCSR
STR r1, [r12, #8] // Save SHCSR
LDR r0, =0xE000ED28 // Build CFSR address
LDR r1, [r0] // Pickup CFSR
STR r1, [r12, #12] // Save CFSR
LDR r0, =0xE000ED34 // Build MMFAR address
LDR r1, [r0] // Pickup MMFAR
STR r1, [r12, #16] // Save MMFAR
LDR r0, =0xE000ED38 // Build BFAR address
LDR r1, [r0] // Pickup BFAR
STR r1, [r12, #20] // Save BFAR
MRS r0, CONTROL // Pickup current CONTROL register
STR r0, [r12, #24] // Save CONTROL
MRS r1, PSP // Pickup thread stack pointer
STR r1, [r12, #28] // Save thread stack pointer
LDR r0, [r1] // Pickup saved r0
STR r0, [r12, #32] // Save r0
LDR r0, [r1, #4] // Pickup saved r1
STR r0, [r12, #36] // Save r1
STR r2, [r12, #40] // Save r2
STR r3, [r12, #44] // Save r3
STR r4, [r12, #48] // Save r4
STR r5, [r12, #52] // Save r5
STR r6, [r12, #56] // Save r6
STR r7, [r12, #60] // Save r7
STR r8, [r12, #64] // Save r8
STR r9, [r12, #68] // Save r9
STR r10,[r12, #72] // Save r10
STR r11,[r12, #76] // Save r11
LDR r0, [r1, #16] // Pickup saved r12
STR r0, [r12, #80] // Save r12
LDR r0, [r1, #20] // Pickup saved lr
STR r0, [r12, #84] // Save lr
LDR r0, [r1, #24] // Pickup instruction address at point of fault
STR r0, [r12, #4] // Save point of fault
LDR r0, [r1, #28] // Pickup xPSR
STR r0, [r12, #88] // Save xPSR
MRS r0, CONTROL // Pickup current CONTROL register
BIC r0, r0, #1 // Clear the UNPRIV bit
MSR CONTROL, r0 // Setup new CONTROL register
LDR r0, =0xE000ED28 // Build the Memory Management Fault Status Register (MMFSR)
LDRB r1, [r0] // Pickup the MMFSR, with the following bit definitions:
// Bit 0 = 1 -> Instruction address violation
// Bit 1 = 1 -> Load/store address violation
// Bit 7 = 1 -> MMFAR is valid
STRB r1, [r0] // Clear the MMFSR
#ifdef __ARMVFP__
LDR r0, =0xE000EF34 // Cleanup FPU context: Load FPCCR address
LDR r1, [r0] // Load FPCCR
BIC r1, r1, #1 // Clear the lazy preservation active bit
STR r1, [r0] // Store the value
#endif
BL _txm_module_manager_memory_fault_handler // Call memory manager fault handler
#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
/* Call the thread exit function to indicate the thread is no longer executing. */
CPSID i // Disable interrupts
BL _tx_execution_thread_exit // Call the thread exit function
CPSIE i // Enable interrupts
#endif
MOV r1, #0 // Build NULL value
LDR r0, =_tx_thread_current_ptr // Pickup address of current thread pointer
STR r1, [r0] // Clear current thread pointer
// Return from MemManage_Handler exception
LDR r0, =0xE000ED04 // Load ICSR
LDR r1, =0x10000000 // Set PENDSVSET bit
STR r1, [r0] // Store ICSR
DSB // Wait for memory access to complete
#ifdef TX_PORT_USE_BASEPRI
MOV r0, 0 // Disable BASEPRI masking (enable interrupts)
MSR BASEPRI, r0
#else
CPSIE i // Enable interrupts
#endif
MOV lr, #0xFFFFFFFD // Load exception return code
BX lr // Return from exception
/* Generic context PendSV handler. */
PUBLIC PendSV_Handler
PUBLIC __tx_PendSVHandler
PendSV_Handler:
__tx_PendSVHandler:
/* Get current thread value and new thread pointer. */
__tx_ts_handler:
#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
/* Call the thread exit function to indicate the thread is no longer executing. */
#ifdef TX_PORT_USE_BASEPRI
LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI
MSR BASEPRI, r1
#else
CPSID i // Disable interrupts
#endif /* TX_PORT_USE_BASEPRI */
PUSH {r0, lr} // Save LR (and r0 just for alignment)
BL _tx_execution_thread_exit // Call the thread exit function
POP {r0, lr} // Recover LR
#ifdef TX_PORT_USE_BASEPRI
MOV r0, 0 // Disable BASEPRI masking (enable interrupts)
MSR BASEPRI, r0
#else
CPSIE i // Enable interrupts
#endif /* TX_PORT_USE_BASEPRI */
#endif /* EXECUTION PROFILE */
LDR r0, =_tx_thread_current_ptr // Build current thread pointer address
LDR r2, =_tx_thread_execute_ptr // Build execute thread pointer address
MOV r3, #0 // Build NULL value
LDR r1, [r0] // Pickup current thread pointer
/* Determine if there is a current thread to finish preserving. */
CBZ r1, __tx_ts_new // If NULL, skip preservation
/* Recover PSP and preserve current thread context. */
STR r3, [r0] // Set _tx_thread_current_ptr to NULL
MRS r12, PSP // Pickup PSP pointer (thread's stack pointer)
STMDB r12!, {r4-r11} // Save its remaining registers
#ifdef __ARMVFP__
TST LR, #0x10 // Determine if the VFP extended frame is present
BNE _skip_vfp_save
VSTMDB r12!,{s16-s31} // Yes, save additional VFP registers
_skip_vfp_save:
#endif
LDR r4, =_tx_timer_time_slice // Build address of time-slice variable
STMDB r12!, {LR} // Save LR on the stack
/* Determine if time-slice is active. If it isn't, skip time handling processing. */
LDR r5, [r4] // Pickup current time-slice
STR r12, [r1, #8] // Save the thread stack pointer
CBZ r5, __tx_ts_new // If not active, skip processing
/* Time-slice is active, save the current thread's time-slice and clear the global time-slice variable. */
STR r5, [r1, #24] // Save current time-slice
/* Clear the global time-slice. */
STR r3, [r4] // Clear time-slice
/* Executing thread is now completely preserved!!! */
__tx_ts_new:
/* Now we are looking for a new thread to execute! */
#ifdef TX_PORT_USE_BASEPRI
LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI
MSR BASEPRI, r1
#else
CPSID i // Disable interrupts
#endif
LDR r1, [r2] // Is there another thread ready to execute?
CBNZ r1, __tx_ts_restore // Yes, schedule it
/* The following is the idle wait processing... in this case, no threads are ready for execution and the
system will simply be idle until an interrupt occurs that makes a thread ready. Note that interrupts
are disabled to allow use of WFI for waiting for a thread to arrive. */
__tx_ts_wait:
#ifdef TX_PORT_USE_BASEPRI
LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI
MSR BASEPRI, r1
#else
CPSID i // Disable interrupts
#endif
LDR r1, [r2] // Pickup the next thread to execute pointer
CBNZ r1, __tx_ts_ready // If non-NULL, a new thread is ready!
#ifdef TX_LOW_POWER
PUSH {r0-r3}
BL tx_low_power_enter // Possibly enter low power mode
POP {r0-r3}
#endif
#ifdef TX_ENABLE_WFI
DSB // Ensure no outstanding memory transactions
WFI // Wait for interrupt
ISB // Ensure pipeline is flushed
#endif
#ifdef TX_LOW_POWER
PUSH {r0-r3}
BL tx_low_power_exit // Exit low power mode
POP {r0-r3}
#endif
#ifdef TX_PORT_USE_BASEPRI
MOV r4, #0 // Disable BASEPRI masking (enable interrupts)
MSR BASEPRI, r4
#else
CPSIE i // Enable interrupts
#endif
B __tx_ts_wait // Loop to continue waiting
/* At this point, we have a new thread ready to go. Clear any newly pended PendSV - since we are
already in the handler! */
__tx_ts_ready:
MOV r7, #0x08000000 // Build clear PendSV value
MOV r8, #0xE000E000 // Build base NVIC address
STR r7, [r8, #0xD04] // Clear any PendSV
__tx_ts_restore:
/* A thread is ready, make the current thread the new thread
and enable interrupts. */
STR r1, [r0] // Setup the current thread pointer to the new thread
#ifdef TX_PORT_USE_BASEPRI
MOV r4, #0 // Disable BASEPRI masking (enable interrupts)
MSR BASEPRI, r4
#else
CPSIE i // Enable interrupts
#endif
/* Increment the thread run count. */
LDR r7, [r1, #4] // Pickup the current thread run count
LDR r4, =_tx_timer_time_slice // Build address of time-slice variable
LDR r5, [r1, #24] // Pickup thread's current time-slice
ADD r7, r7, #1 // Increment the thread run count
STR r7, [r1, #4] // Store the new run count
/* Setup global time-slice with thread's current time-slice. */
STR r5, [r4] // Setup global time-slice
#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
/* Call the thread entry function to indicate the thread is executing. */
PUSH {r0, r1} // Save r0 and r1
BL _tx_execution_thread_enter // Call the thread execution enter function
POP {r0, r1} // Recover r0 and r1
#endif
/* Restore the thread context and PSP. */
LDR r12, [r1, #8] // Pickup thread's stack pointer
MRS r5, CONTROL // Pickup current CONTROL register
LDR r4, [r1, #0x98] // Pickup current user mode flag
BIC r5, r5, #1 // Clear the UNPRIV bit
ORR r4, r4, r5 // Build new CONTROL register
MSR CONTROL, r4 // Setup new CONTROL register
LDR r0, =0xE000ED94 // Build MPU control reg address
MOV r3, #0 // Build disable value
CPSID i // Disable interrupts
STR r3, [r0] // Disable MPU
LDR r0, [r1, #0x90] // Pickup the module instance pointer
#ifdef TXM_MODULE_MPU_DEFAULT
CBZ r0, default_mpu // Is this thread owned by a module? No, default MPU setup
#else
CBZ r0, skip_mpu_setup // Is this thread owned by a module? No, skip MPU setup
#endif
LDR r2, [r0, #0x8C] // Pickup MPU region 5 address
#ifdef TXM_MODULE_MPU_DEFAULT
CBZ r2, default_mpu // Is protection required for this module? No, default MPU setup
#else
CBZ r2, skip_mpu_setup // Is protection required for this module? No, skip MPU setup
#endif
LDR r1, =0xE000ED9C // MPU_RBAR register address
// Use alias registers to quickly load MPU
ADD r0, r0, #100 // Build address of MPU register start in thread control block
#ifdef TXM_MODULE_MPU_DEFAULT
B config_mpu // configure MPU for module
default_mpu:
LDR r0, =txm_module_default_mpu_registers // default MPU configuration
#endif
config_mpu:
LDM r0!,{r2-r9} // Load MPU regions 0-3
STM r1,{r2-r9} // Store MPU regions 0-3
LDM r0!,{r2-r9} // Load MPU regions 4-7
STM r1,{r2-r9} // Store MPU regions 4-7
#ifdef TXM_MODULE_MANAGER_16_MPU
LDM r0!,{r2-r9} // Load MPU regions 8-11
STM r1,{r2-r9} // Store MPU regions 8-11
// Regions 12-15 are reserved for the user to define.
LDM r0,{r2-r9} // Load MPU regions 12-15
STM r1,{r2-r9} // Store MPU regions 12-15
#endif
_tx_enable_mpu:
LDR r0, =0xE000ED94 // Build MPU control reg address
MOV r1, #5 // Build enable value with background region enabled
STR r1, [r0] // Enable MPU
skip_mpu_setup:
CPSIE i // Enable interrupts
LDMIA r12!, {LR} // Pickup LR
#ifdef __ARMVFP__
TST LR, #0x10 // Determine if the VFP extended frame is present
BNE _skip_vfp_restore // If not, skip VFP restore
VLDMIA r12!, {s16-s31} // Yes, restore additional VFP registers
_skip_vfp_restore:
#endif
LDMIA r12!, {r4-r11} // Recover thread's registers
MSR PSP, r12 // Setup the thread's stack pointer
/* Return to thread. */
BX lr // Return to thread!
/* SVC Handler. */
PUBLIC SVC_Handler
PUBLIC __tx_SVCallHandler
SVC_Handler:
__tx_SVCallHandler:
MRS r0, PSP // Pickup the PSP stack
LDR r1, [r0, #24] // Pickup the point of interrupt
LDRB r2, [r1, #-2] // Pickup the SVC parameter
/* Determine which SVC trap we are processing */
CMP r2, #1 // Is it the entry into ThreadX?
BNE _tx_thread_user_return // No, return to user mode
/* At this point we have an SVC 1, which means we are entering
the kernel from a module thread with user mode selected. */
LDR r2, =_txm_module_priv-1 // Load address of where we should have come from
// Subtract 1 because of THUMB mode.
CMP r1, r2 // Did we come from user_mode_entry?
IT NE // If no (not equal), then...
BXNE lr // return from where we came.
LDR r3, [r0, #20] // This is the saved LR
LDR r1, =_tx_thread_current_ptr // Build current thread pointer address
LDR r2, [r1] // Pickup current thread pointer
MOV r1, #0 // Build clear value
STR r1, [r2, #0x98] // Clear the current user mode selection for thread
STR r3, [r2, #0xA0] // Save the original LR in thread control block
/* If there is memory protection, use kernel stack */
LDR r0, [r2, #0x90] // Load the module instance ptr
LDR r0, [r0, #0x0C] // Load the module property flags
TST r0, #2 // Check if memory protected
BEQ _tx_skip_kernel_stack_enter
/* Switch to the module thread's kernel stack */
LDR r0, [r2, #0xA8] // Load the module kernel stack end
#ifndef TXM_MODULE_KERNEL_STACK_MAINTENANCE_DISABLE
LDR r1, [r2, #0xA4] // Load the module kernel stack start
LDR r3, [r2, #0xAC] // Load the module kernel stack size
STR r1, [r2, #12] // Set stack start
STR r0, [r2, #16] // Set stack end
STR r3, [r2, #20] // Set stack size
#endif
MRS r3, PSP // Pickup thread stack pointer
#ifdef __ARMVFP__
TST lr, #0x10 // Test for extended module stack
ITT EQ
ORREQ r3, r3, #1 // If so, set LSB in thread stack pointer to indicate extended frame
ORREQ lr, lr, #0x10 // Set bit, return with standard frame
#endif
STR r3, [r2, #0xB0] // Save thread stack pointer
#ifdef __ARMVFP__
BIC r3, #1 // Clear possibly OR'd bit
#endif
/* Build kernel stack by copying thread stack two registers at a time */
ADD r3, r3, #32 // Start at bottom of hardware stack
LDMDB r3!, {r1-r2}
STMDB r0!, {r1-r2}
LDMDB r3!, {r1-r2}
STMDB r0!, {r1-r2}
LDMDB r3!, {r1-r2}
STMDB r0!, {r1-r2}
LDMDB r3!, {r1-r2}
STMDB r0!, {r1-r2}
MSR PSP, r0 // Set kernel stack pointer
_tx_skip_kernel_stack_enter:
MRS r0, CONTROL // Pickup current CONTROL register
BIC r0, r0, #1 // Clear the UNPRIV bit
MSR CONTROL, r0 // Setup new CONTROL register
BX lr // Return to thread
_tx_thread_user_return:
LDR r2, =_txm_module_user_mode_exit-1 // Load address of where we should have come from
// Subtract 1 because of THUMB mode.
CMP r1, r2 // Did we come from user_mode_exit?
IT NE // If no (not equal), then...
BXNE lr // return from where we came
LDR r1, =_tx_thread_current_ptr // Build current thread pointer address
LDR r2, [r1] // Pickup current thread pointer
LDR r1, [r2, #0x9C] // Pick up user mode
STR r1, [r2, #0x98] // Set the current user mode selection for thread
/* If there is memory protection, use kernel stack */
LDR r0, [r2, #0x90] // Load the module instance ptr
LDR r0, [r0, #0x0C] // Load the module property flags
TST r0, #2 // Check if memory protected
BEQ _tx_skip_kernel_stack_exit
#ifndef TXM_MODULE_KERNEL_STACK_MAINTENANCE_DISABLE
LDR r0, [r2, #0xB4] // Load the module thread stack start
LDR r1, [r2, #0xB8] // Load the module thread stack end
LDR r3, [r2, #0xBC] // Load the module thread stack size
STR r0, [r2, #12] // Set stack start
STR r1, [r2, #16] // Set stack end
STR r3, [r2, #20] // Set stack size
#endif
#ifdef __ARMVFP__
/* If lazy stacking is pending, check if it can be cleared.
if(LSPACT && tx_thread_module_stack_start < FPCAR && FPCAR < tx_thread_module_stack_end)
then clear LSPACT. */
LDR r3, =0xE000EF34 // Address of FPCCR
LDR r3, [r3] // Load FPCCR
TST r3, #1 // Check if LSPACT is set
BEQ _tx_no_lazy_clear // if clear, move on
LDR r1, =0xE000EF38 // Address of FPCAR
LDR r1, [r1] // Load FPCAR
LDR r0, [r2, #0xA4] // Load kernel stack start
CMP r1, r0 // If FPCAR < start, move on
BLO _tx_no_lazy_clear
LDR r0, [r2, #0xA8] // Load kernel stack end
CMP r0, r1 // If end < FPCAR, move on
BLO _tx_no_lazy_clear
BIC r3, #1 // Clear LSPACT
LDR r1, =0xE000EF34 // Address of FPCCR
STR r3, [r1] // Save updated FPCCR
_tx_no_lazy_clear:
#endif
LDR r0, [r2, #0xB0] // Load the module thread stack pointer
MRS r3, PSP // Pickup kernel stack pointer
#ifdef __ARMVFP__
TST r0, #1 // Is module stack extended?
ITTE NE // If so...
BICNE lr, #0x10 // Clear bit, return with extended frame
BICNE r0, #1 // Clear bit that indicates extended module frame
ORREQ lr, lr, #0x10 // Else set bit, return with standard frame
#endif
/* Copy kernel hardware stack to module thread stack. */
LDM r3!, {r1-r2} // Get r0, r1 from kernel stack
STM r0!, {r1-r2} // Insert r0, r1 into thread stack
LDM r3!, {r1-r2} // Get r2, r3 from kernel stack
STM r0!, {r1-r2} // Insert r2, r3 into thread stack
LDM r3!, {r1-r2} // Get r12, lr from kernel stack
STM r0!, {r1-r2} // Insert r12, lr into thread stack
LDM r3!, {r1-r2} // Get pc, xpsr from kernel stack
STM r0!, {r1-r2} // Insert pc, xpsr into thread stack
SUB r0, r0, #32 // Subtract 32 to get back to top of stack
MSR PSP, r0 // Set thread stack pointer
LDR r1, =_tx_thread_current_ptr // Build current thread pointer address
LDR r2, [r1] // Pickup current thread pointer
LDR r1, [r2, #0x9C] // Pick up user mode
_tx_skip_kernel_stack_exit:
MRS r0, CONTROL // Pickup current CONTROL register
ORR r0, r0, r1 // OR in the user mode bit
MSR CONTROL, r0 // Setup new CONTROL register
BX lr // Return to thread
/* Kernel entry function from user mode. */
EXTERN _txm_module_manager_kernel_dispatch
SECTION `.text`:CODE:NOROOT(5)
THUMB
ALIGNROM 5
// VOID _txm_module_manager_user_mode_entry(VOID)
// {
PUBLIC _txm_module_manager_user_mode_entry
_txm_module_manager_user_mode_entry:
SVC 1 // Enter kernel
_txm_module_priv:
/* At this point, we are out of user mode. The original LR has been saved in the
thread control block. Simply call the kernel dispatch function. */
BL _txm_module_manager_kernel_dispatch
/* Pickup the original LR value while still in privileged mode */
LDR r2, =_tx_thread_current_ptr // Build current thread pointer address
LDR r3, [r2] // Pickup current thread pointer
LDR lr, [r3, #0xA0] // Pickup saved LR from original call
SVC 2 // Exit kernel and return to user mode
_txm_module_user_mode_exit:
BX lr // Return to the caller
NOP
NOP
NOP
NOP
// }
#ifdef __ARMVFP__
PUBLIC tx_thread_fpu_enable
tx_thread_fpu_enable:
PUBLIC tx_thread_fpu_disable
tx_thread_fpu_disable:
/* Automatic VPF logic is supported, this function is present only for
backward compatibility purposes and therefore simply returns. */
BX LR // Return to caller
#endif
END

View File

@@ -0,0 +1,138 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Module Manager */
/** */
/**************************************************************************/
/**************************************************************************/
SECTION `.text`:CODE:NOROOT(2)
THUMB
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _txm_module_manager_thread_stack_build Cortex-Mx/IAR */
/* 6.1.9 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function builds a stack frame on the supplied thread's stack. */
/* The stack frame results in a fake interrupt return to the supplied */
/* function pointer. */
/* */
/* INPUT */
/* */
/* thread_ptr Pointer to thread */
/* function_ptr Pointer to shell function */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _tx_thread_create Create thread service */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-15-2021 Scott Larson Initial Version 6.1.9 */
/* */
/**************************************************************************/
// VOID _txm_module_manager_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(TX_THREAD *, TXM_MODULE_INSTANCE *))
// {
PUBLIC _txm_module_manager_thread_stack_build
_txm_module_manager_thread_stack_build:
/* Build a fake interrupt frame. The form of the fake interrupt stack
on the Cortex-M should look like the following after it is built:
Stack Top:
lr Interrupted lr (lr at time of PENDSV)
r4 Initial value for r4
r5 Initial value for r5
r6 Initial value for r6
r7 Initial value for r7
r8 Initial value for r8
r9 Initial value for r9
r10 Initial value for r10
r11 Initial value for r11
r0 Initial value for r0 (Hardware stack starts here!!)
r1 Initial value for r1
r2 Initial value for r2
r3 Initial value for r3
r12 Initial value for r12
lr Initial value for lr
pc Initial value for pc
xPSR Initial value for xPSR
Stack Bottom: (higher memory address) */
LDR r2, [r0, #16] // Pickup end of stack area
BIC r2, r2, #0x7 // Align frame
SUB r2, r2, #68 // Subtract frame size
LDR r3, =0xFFFFFFFD // Build initial LR value
STR r3, [r2, #0] // Save on the stack
/* Actually build the stack frame. */
MOV r3, #0 // Build initial register value
STR r3, [r2, #4] // Store initial r4
STR r3, [r2, #8] // Store initial r5
STR r3, [r2, #12] // Store initial r6
STR r3, [r2, #16] // Store initial r7
STR r3, [r2, #20] // Store initial r8
STR r3, [r2, #28] // Store initial r10
STR r3, [r2, #32] // Store initial r11
/* Hardware stack follows. */
STR r0, [r2, #36] // Store initial r0, which is the thread control block
LDR r3, [r0, #8] // Pickup thread entry info pointer,which is in the stack pointer position of the thread control block.
// It was setup in the txm_module_manager_thread_create function. It will be overwritten later in this
// function with the actual, initial stack pointer.
STR r3, [r2, #40] // Store initial r1, which is the module entry information.
LDR r3, [r3, #8] // Pickup data base register from the module information
STR r3, [r2, #24] // Store initial r9 (data base register)
MOV r3, #0 // Clear r3 again
STR r3, [r2, #44] // Store initial r2
STR r3, [r2, #48] // Store initial r3
STR r3, [r2, #52] // Store initial r12
MOV r3, #0xFFFFFFFF // Poison EXC_RETURN value
STR r3, [r2, #56] // Store initial lr
STR r1, [r2, #60] // Store initial pc
MOV r3, #0x01000000 // Only T-bit need be set
STR r3, [r2, #64] // Store initial xPSR
/* Setup stack pointer. */
// thread_ptr -> tx_thread_stack_ptr = r2;
STR r2, [r0, #8] // Save stack pointer in thread's control block
BX lr // Return to caller
// }
END

View File

@@ -0,0 +1,732 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Port Specific */
/** */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/* */
/* PORT SPECIFIC C INFORMATION RELEASE */
/* */
/* tx_port.h Cortex-Mx */
/* 6.2.0 */
/* */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This file contains data type definitions that make the ThreadX */
/* real-time kernel function identically on a variety of different */
/* processor architectures. For example, the size or number of bits */
/* in an "int" data type vary between microprocessor architectures and */
/* even C compilers for the same microprocessor. ThreadX does not */
/* directly use native C data types. Instead, ThreadX creates its */
/* own special types that can be mapped to actual data types by this */
/* file to guarantee consistency in the interface and functionality. */
/* */
/* This file replaces the previous Cortex-M3/M4/M7 files. It unifies */
/* the ARMv7-M architecture and compilers into one common file. */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-15-2021 Scott Larson Initial Version 6.1.9 */
/* 04-25-2022 Scott Larson Modified comments and added */
/* volatile to registers, */
/* resulting in version 6.1.11 */
/* */
/**************************************************************************/
#ifndef TX_PORT_H
#define TX_PORT_H
/* Determine if the optional ThreadX user define file should be used. */
#ifdef TX_INCLUDE_USER_DEFINE_FILE
/* Yes, include the user defines in tx_user.h. The defines in this file may
alternately be defined on the command line. */
#include "tx_user.h"
#endif /* TX_INCLUDE_USER_DEFINE_FILE */
/* Define compiler library include files. */
#include <stdlib.h>
#include <string.h>
#ifdef __ICCARM__
#include <intrinsics.h> /* IAR Intrinsics */
#define __asm__ __asm /* Define to make all inline asm look similar */
#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT
#include <yvals.h>
#endif /* TX_ENABLE_IAR_LIBRARY_SUPPORT */
#endif /* __ICCARM__ */
#ifdef __ghs__
#include <arm_ghs.h>
#include "tx_ghs.h"
#endif /* __ghs__ */
#if !defined(__GNUC__) && !defined(__CC_ARM)
#define __get_control_value __get_CONTROL
#define __set_control_value __set_CONTROL
#endif
#ifndef __GNUC__
#define __get_ipsr_value __get_IPSR
#endif
/* Define ThreadX basic types for this port. */
#define VOID void
typedef char CHAR;
typedef unsigned char UCHAR;
typedef int INT;
typedef unsigned int UINT;
typedef long LONG;
typedef unsigned long ULONG;
typedef unsigned long long ULONG64;
typedef short SHORT;
typedef unsigned short USHORT;
#define ULONG64_DEFINED
/* Define the priority levels for ThreadX. Legal values range
from 32 to 1024 and MUST be evenly divisible by 32. */
#ifndef TX_MAX_PRIORITIES
#define TX_MAX_PRIORITIES 32
#endif
/* Define the minimum stack for a ThreadX thread on this processor. If the size supplied during
thread creation is less than this value, the thread create call will return an error. */
#ifndef TX_MINIMUM_STACK
#define TX_MINIMUM_STACK 200 /* Minimum stack size for this port */
#endif
/* Define the system timer thread's default stack size and priority. These are only applicable
if TX_TIMER_PROCESS_IN_ISR is not defined. */
#ifndef TX_TIMER_THREAD_STACK_SIZE
#define TX_TIMER_THREAD_STACK_SIZE 1024 /* Default timer thread stack size */
#endif
#ifndef TX_TIMER_THREAD_PRIORITY
#define TX_TIMER_THREAD_PRIORITY 0 /* Default timer thread priority */
#endif
/* By default, ThreadX for Cortex-M uses the PRIMASK register to enable/disable interrupts.
If using BASEPRI is desired, define the following two symbols for both c and assembly files:
TX_PORT_USE_BASEPRI - This tells ThreadX to use BASEPRI instead of PRIMASK.
TX_PORT_BASEPRI = (priority_mask << (8 - number_priority_bits)) - this defines the maximum priority level to mask.
Any interrupt with a higher priority than priority_mask will not be masked, thus the interrupt will run.
*/
/* Define various constants for the ThreadX Cortex-M port. */
#define TX_INT_DISABLE 1 /* Disable interrupts */
#define TX_INT_ENABLE 0 /* Enable interrupts */
/* Define the clock source for trace event entry time stamp. The following two item are port specific.
For example, if the time source is at the address 0x0a800024 and is 16-bits in size, the clock
source constants would be:
#define TX_TRACE_TIME_SOURCE *((volatile ULONG *) 0x0a800024)
#define TX_TRACE_TIME_MASK 0x0000FFFFUL
*/
#ifndef TX_MISRA_ENABLE
#ifndef TX_TRACE_TIME_SOURCE
#define TX_TRACE_TIME_SOURCE *((volatile ULONG *) 0xE0001004)
#endif
#else
ULONG _tx_misra_time_stamp_get(VOID);
#define TX_TRACE_TIME_SOURCE _tx_misra_time_stamp_get()
#endif
#ifndef TX_TRACE_TIME_MASK
#define TX_TRACE_TIME_MASK 0xFFFFFFFFUL
#endif
/* Define the port specific options for the _tx_build_options variable. This variable indicates
how the ThreadX library was built. */
#define TX_PORT_SPECIFIC_BUILD_OPTIONS (0)
/* Define the in-line initialization constant so that modules with in-line
initialization capabilities can prevent their initialization from being
a function call. */
#ifdef TX_MISRA_ENABLE
#define TX_DISABLE_INLINE
#else
#define TX_INLINE_INITIALIZATION
#endif
/* Determine whether or not stack checking is enabled. By default, ThreadX stack checking is
disabled. When the following is defined, ThreadX thread stack checking is enabled. If stack
checking is enabled (TX_ENABLE_STACK_CHECKING is defined), the TX_DISABLE_STACK_FILLING
define is negated, thereby forcing the stack fill which is necessary for the stack checking
logic. */
#ifndef TX_MISRA_ENABLE
#ifdef TX_ENABLE_STACK_CHECKING
#undef TX_DISABLE_STACK_FILLING
#endif
#endif
/* Define the TX_THREAD control block extensions for this port. The main reason
for the multiple macros is so that backward compatibility can be maintained with
existing ThreadX kernel awareness modules. */
#define TX_THREAD_EXTENSION_0
#define TX_THREAD_EXTENSION_1
#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT
#define TX_THREAD_EXTENSION_2 VOID *tx_thread_module_instance_ptr; \
VOID *tx_thread_module_entry_info_ptr; \
ULONG tx_thread_module_current_user_mode; \
ULONG tx_thread_module_user_mode; \
ULONG tx_thread_module_saved_lr; \
VOID *tx_thread_module_kernel_stack_start; \
VOID *tx_thread_module_kernel_stack_end; \
ULONG tx_thread_module_kernel_stack_size; \
VOID *tx_thread_module_stack_ptr; \
VOID *tx_thread_module_stack_start; \
VOID *tx_thread_module_stack_end; \
ULONG tx_thread_module_stack_size; \
VOID *tx_thread_module_reserved; \
VOID *tx_thread_iar_tls_pointer;
#else
#define TX_THREAD_EXTENSION_2 VOID *tx_thread_module_instance_ptr; \
VOID *tx_thread_module_entry_info_ptr; \
ULONG tx_thread_module_current_user_mode; \
ULONG tx_thread_module_user_mode; \
ULONG tx_thread_module_saved_lr; \
VOID *tx_thread_module_kernel_stack_start; \
VOID *tx_thread_module_kernel_stack_end; \
ULONG tx_thread_module_kernel_stack_size; \
VOID *tx_thread_module_stack_ptr; \
VOID *tx_thread_module_stack_start; \
VOID *tx_thread_module_stack_end; \
ULONG tx_thread_module_stack_size; \
VOID *tx_thread_module_reserved;
#endif
#ifndef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
#define TX_THREAD_EXTENSION_3
#else
#define TX_THREAD_EXTENSION_3 unsigned long long tx_thread_execution_time_total; \
unsigned long long tx_thread_execution_time_last_start;
#endif
/* Define the port extensions of the remaining ThreadX objects. */
#define TX_BLOCK_POOL_EXTENSION
#define TX_BYTE_POOL_EXTENSION
#define TX_MUTEX_EXTENSION
#define TX_EVENT_FLAGS_GROUP_EXTENSION VOID *tx_event_flags_group_module_instance; \
VOID (*tx_event_flags_group_set_module_notify)(struct TX_EVENT_FLAGS_GROUP_STRUCT *group_ptr);
#define TX_QUEUE_EXTENSION VOID *tx_queue_module_instance; \
VOID (*tx_queue_send_module_notify)(struct TX_QUEUE_STRUCT *queue_ptr);
#define TX_SEMAPHORE_EXTENSION VOID *tx_semaphore_module_instance; \
VOID (*tx_semaphore_put_module_notify)(struct TX_SEMAPHORE_STRUCT *semaphore_ptr);
#define TX_TIMER_EXTENSION VOID *tx_timer_module_instance; \
VOID (*tx_timer_module_expiration_function)(ULONG id);
/* Define the user extension field of the thread control block. Nothing
additional is needed for this port so it is defined as white space. */
#ifndef TX_THREAD_USER_EXTENSION
#define TX_THREAD_USER_EXTENSION
#endif
/* Define the macros for processing extensions in tx_thread_create, tx_thread_delete,
tx_thread_shell_entry, and tx_thread_terminate. */
#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT
#if (__VER__ < 8000000)
#define TX_THREAD_CREATE_EXTENSION(thread_ptr) thread_ptr -> tx_thread_iar_tls_pointer = __iar_dlib_perthread_allocate();
#define TX_THREAD_DELETE_EXTENSION(thread_ptr) __iar_dlib_perthread_deallocate(thread_ptr -> tx_thread_iar_tls_pointer); \
thread_ptr -> tx_thread_iar_tls_pointer = TX_NULL;
#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION __iar_dlib_perthread_access(0);
#else
void *_tx_iar_create_per_thread_tls_area(void);
void _tx_iar_destroy_per_thread_tls_area(void *tls_ptr);
void __iar_Initlocks(void);
#define TX_THREAD_CREATE_EXTENSION(thread_ptr) thread_ptr -> tx_thread_iar_tls_pointer = _tx_iar_create_per_thread_tls_area();
#define TX_THREAD_DELETE_EXTENSION(thread_ptr) do {_tx_iar_destroy_per_thread_tls_area(thread_ptr -> tx_thread_iar_tls_pointer); \
thread_ptr -> tx_thread_iar_tls_pointer = TX_NULL; } while(0);
#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION do {__iar_Initlocks();} while(0);
#endif
#else
#define TX_THREAD_CREATE_EXTENSION(thread_ptr)
#define TX_THREAD_DELETE_EXTENSION(thread_ptr)
#endif
#if defined(__ARMVFP__) || defined(__ARM_PCS_VFP) || defined(__ARM_FP) || defined(__TARGET_FPU_VFP) || defined(__VFP__)
#ifdef TX_MISRA_ENABLE
ULONG _tx_misra_control_get(void);
void _tx_misra_control_set(ULONG value);
ULONG _tx_misra_fpccr_get(void);
void _tx_misra_vfp_touch(void);
#else /* TX_MISRA_ENABLE not defined */
/* Define some helper functions (these are intrinsics in some compilers). */
#ifdef __GNUC__ /* GCC and ARM Compiler 6 */
__attribute__( ( always_inline ) ) static inline ULONG __get_control_value(void)
{
ULONG control_value;
__asm__ volatile (" MRS %0,CONTROL ": "=r" (control_value) );
return(control_value);
}
__attribute__( ( always_inline ) ) static inline void __set_control_value(ULONG control_value)
{
__asm__ volatile (" MSR CONTROL,%0": : "r" (control_value): "memory" );
}
#define TX_VFP_TOUCH() __asm__ volatile ("VMOV.F32 s0, s0");
#elif defined(__CC_ARM) /* ARM Compiler 5 */
__attribute__( ( always_inline ) ) ULONG __get_control_value(void)
{
ULONG control_value;
__asm volatile ("MRS control_value,CONTROL");
return(control_value);
}
__attribute__( ( always_inline ) ) void __set_control_value(ULONG control_value)
{
__asm__ volatile ("MSR CONTROL,control_value");
}
/* Can't access VFP registers with inline asm, so define this in tx_thread_schedule. */
void _tx_vfp_access(void);
#define TX_VFP_TOUCH() _tx_vfp_access();
#elif defined(__ICCARM__) /* IAR */
#define TX_VFP_TOUCH() __asm__ volatile ("VMOV.F32 s0, s0");
#endif /* Helper functions for different compilers */
#endif /* TX_MISRA_ENABLE */
/* A completed thread falls into _thread_shell_entry and we can simply deactivate the FPU via CONTROL.FPCA
in order to ensure no lazy stacking will occur. */
#ifndef TX_MISRA_ENABLE
#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) { \
ULONG _tx_vfp_state; \
_tx_vfp_state = __get_control_value(); \
_tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \
__set_control_value(_tx_vfp_state); \
}
#else
#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) { \
ULONG _tx_vfp_state; \
_tx_vfp_state = _tx_misra_control_get(); \
_tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \
_tx_misra_control_set(_tx_vfp_state); \
}
#endif
/* A thread can be terminated by another thread, so we first check if it's self-terminating and not in an ISR.
If so, deactivate the FPU via CONTROL.FPCA. Otherwise we are in an interrupt or another thread is terminating
this one, so if the FPCCR.LSPACT bit is set, we need to save the CONTROL.FPCA state, touch the FPU to flush
the lazy FPU save, then restore the CONTROL.FPCA state. */
#ifndef TX_MISRA_ENABLE
#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) { \
ULONG _tx_system_state; \
_tx_system_state = TX_THREAD_GET_SYSTEM_STATE(); \
if ((_tx_system_state == ((ULONG) 0)) && ((thread_ptr) == _tx_thread_current_ptr)) \
{ \
ULONG _tx_vfp_state; \
_tx_vfp_state = __get_control_value(); \
_tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \
__set_control_value(_tx_vfp_state); \
} \
else \
{ \
ULONG _tx_fpccr; \
_tx_fpccr = *((volatile ULONG *) 0xE000EF34); \
_tx_fpccr = _tx_fpccr & ((ULONG) 0x01); \
if (_tx_fpccr == ((ULONG) 0x01)) \
{ \
ULONG _tx_vfp_state; \
_tx_vfp_state = __get_control_value(); \
_tx_vfp_state = _tx_vfp_state & ((ULONG) 0x4); \
TX_VFP_TOUCH(); \
if (_tx_vfp_state == ((ULONG) 0)) \
{ \
_tx_vfp_state = __get_control_value(); \
_tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \
__set_control_value(_tx_vfp_state); \
} \
} \
} \
}
#else
#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) { \
ULONG _tx_system_state; \
_tx_system_state = TX_THREAD_GET_SYSTEM_STATE(); \
if ((_tx_system_state == ((ULONG) 0)) && ((thread_ptr) == _tx_thread_current_ptr)) \
{ \
ULONG _tx_vfp_state; \
_tx_vfp_state = _tx_misra_control_get(); \
_tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \
_tx_misra_control_set(_tx_vfp_state); \
} \
else \
{ \
ULONG _tx_fpccr; \
_tx_fpccr = _tx_misra_fpccr_get(); \
_tx_fpccr = _tx_fpccr & ((ULONG) 0x01); \
if (_tx_fpccr == ((ULONG) 0x01)) \
{ \
ULONG _tx_vfp_state; \
_tx_vfp_state = _tx_misra_control_get(); \
_tx_vfp_state = _tx_vfp_state & ((ULONG) 0x4); \
_tx_misra_vfp_touch(); \
if (_tx_vfp_state == ((ULONG) 0)) \
{ \
_tx_vfp_state = _tx_misra_control_get(); \
_tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \
_tx_misra_control_set(_tx_vfp_state); \
} \
} \
} \
}
#endif
#else /* No VFP in use */
#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr)
#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr)
#endif /* defined(__ARMVFP__) || defined(__ARM_PCS_VFP) || defined(__ARM_FP) || defined(__TARGET_FPU_VFP) || defined(__VFP__) */
/* Define the ThreadX object creation extensions for the remaining objects. */
#define TX_BLOCK_POOL_CREATE_EXTENSION(pool_ptr)
#define TX_BYTE_POOL_CREATE_EXTENSION(pool_ptr)
#define TX_EVENT_FLAGS_GROUP_CREATE_EXTENSION(group_ptr)
#define TX_MUTEX_CREATE_EXTENSION(mutex_ptr)
#define TX_QUEUE_CREATE_EXTENSION(queue_ptr)
#define TX_SEMAPHORE_CREATE_EXTENSION(semaphore_ptr)
#define TX_TIMER_CREATE_EXTENSION(timer_ptr)
/* Define the ThreadX object deletion extensions for the remaining objects. */
#define TX_BLOCK_POOL_DELETE_EXTENSION(pool_ptr)
#define TX_BYTE_POOL_DELETE_EXTENSION(pool_ptr)
#define TX_EVENT_FLAGS_GROUP_DELETE_EXTENSION(group_ptr)
#define TX_MUTEX_DELETE_EXTENSION(mutex_ptr)
#define TX_QUEUE_DELETE_EXTENSION(queue_ptr)
#define TX_SEMAPHORE_DELETE_EXTENSION(semaphore_ptr)
#define TX_TIMER_DELETE_EXTENSION(timer_ptr)
/* Define the get system state macro. */
#ifndef TX_THREAD_GET_SYSTEM_STATE
#ifndef TX_MISRA_ENABLE
#ifdef __CC_ARM /* ARM Compiler 5 */
register unsigned int _ipsr __asm("ipsr");
#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | _ipsr)
#elif defined(__GNUC__) /* GCC and ARM Compiler 6 */
__attribute__( ( always_inline ) ) static inline unsigned int __get_ipsr_value(void)
{
unsigned int ipsr_value;
__asm__ volatile (" MRS %0,IPSR ": "=r" (ipsr_value) );
return(ipsr_value);
}
#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | __get_ipsr_value())
#elif defined(__ICCARM__) /* IAR */
#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | __get_IPSR())
#endif /* TX_THREAD_GET_SYSTEM_STATE for different compilers */
#else /* TX_MISRA_ENABLE is defined, use MISRA function. */
ULONG _tx_misra_ipsr_get(VOID);
#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | _tx_misra_ipsr_get())
#endif /* TX_MISRA_ENABLE */
#endif /* TX_THREAD_GET_SYSTEM_STATE */
/* Define the check for whether or not to call the _tx_thread_system_return function. A non-zero value
indicates that _tx_thread_system_return should not be called. This overrides the definition in tx_thread.h
for Cortex-M since so we don't waste time checking the _tx_thread_system_state variable that is always
zero after initialization for Cortex-M ports. */
#ifndef TX_THREAD_SYSTEM_RETURN_CHECK
#define TX_THREAD_SYSTEM_RETURN_CHECK(c) (c) = ((ULONG) _tx_thread_preempt_disable);
#endif
/* Define the macro to ensure _tx_thread_preempt_disable is set early in initialization in order to
prevent early scheduling on Cortex-M parts. */
#define TX_PORT_SPECIFIC_POST_INITIALIZATION _tx_thread_preempt_disable++;
#ifndef TX_DISABLE_INLINE
/* Define the TX_LOWEST_SET_BIT_CALCULATE macro for each compiler. */
#ifdef __ICCARM__ /* IAR Compiler */
#define TX_LOWEST_SET_BIT_CALCULATE(m, b) (b) = (UINT) __CLZ(__RBIT((m)));
#elif defined(__CC_ARM) /* AC5 Compiler */
#define TX_LOWEST_SET_BIT_CALCULATE(m, b) (b) = (UINT) __clz(__rbit((m)));
#elif defined(__GNUC__) /* GCC and AC6 Compiler */
#define TX_LOWEST_SET_BIT_CALCULATE(m, b) __asm__ volatile (" RBIT %0,%1 ": "=r" (m) : "r" (m) ); \
__asm__ volatile (" CLZ %0,%1 ": "=r" (b) : "r" (m) );
#else
#error "Compiler not supported."
#endif
/* Define the interrupt disable/restore macros for each compiler. */
#if defined(__GNUC__) || defined(__ICCARM__)
/*** GCC/AC6 and IAR ***/
__attribute__( ( always_inline ) ) static inline UINT __get_interrupt_posture(void)
{
UINT posture;
#ifdef TX_PORT_USE_BASEPRI
__asm__ volatile ("MRS %0, BASEPRI ": "=r" (posture));
#else
__asm__ volatile ("MRS %0, PRIMASK ": "=r" (posture));
#endif
return(posture);
}
#ifdef TX_PORT_USE_BASEPRI
__attribute__( ( always_inline ) ) static inline void __set_basepri_value(UINT basepri_value)
{
__asm__ volatile ("MSR BASEPRI,%0 ": : "r" (basepri_value));
}
#else
__attribute__( ( always_inline ) ) static inline void __enable_interrupts(void)
{
__asm__ volatile ("CPSIE i": : : "memory");
}
#endif
__attribute__( ( always_inline ) ) static inline void __restore_interrupt(UINT int_posture)
{
#ifdef TX_PORT_USE_BASEPRI
__set_basepri_value(int_posture);
#else
__asm__ volatile ("MSR PRIMASK,%0": : "r" (int_posture): "memory");
#endif
}
__attribute__( ( always_inline ) ) static inline UINT __disable_interrupts(void)
{
UINT int_posture;
int_posture = __get_interrupt_posture();
#ifdef TX_PORT_USE_BASEPRI
__set_basepri_value(TX_PORT_BASEPRI);
#else
__asm__ volatile ("CPSID i" : : : "memory");
#endif
return(int_posture);
}
__attribute__( ( always_inline ) ) static inline void _tx_thread_system_return_inline(void)
{
UINT interrupt_save;
/* Set PendSV to invoke ThreadX scheduler. */
*((volatile ULONG *) 0xE000ED04) = ((ULONG) 0x10000000);
if (__get_ipsr_value() == 0)
{
interrupt_save = __get_interrupt_posture();
#ifdef TX_PORT_USE_BASEPRI
__set_basepri_value(0);
#else
__enable_interrupts();
#endif
__restore_interrupt(interrupt_save);
}
}
#define TX_INTERRUPT_SAVE_AREA UINT interrupt_save;
#define TX_DISABLE interrupt_save = __disable_interrupts();
#define TX_RESTORE __restore_interrupt(interrupt_save);
/*** End GCC/AC6 and IAR ***/
#elif defined(__CC_ARM)
/*** AC5 ***/
static __inline unsigned int __get_interrupt_posture(void)
{
unsigned int posture;
#ifdef TX_PORT_USE_BASEPRI
__asm__ volatile ("MRS #posture, BASEPRI");
#else
__asm__ volatile ("MRS #posture, PRIMASK");
#endif
return(posture);
}
#ifdef TX_PORT_USE_BASEPRI
static __inline void __set_basepri_value(unsigned int basepri_value)
{
__asm__ volatile ("MSR BASEPRI, #basepri_value");
}
#endif
static __inline unsigned int __disable_interrupts(void)
{
unsigned int int_posture;
int_posture = __get_interrupt_posture();
#ifdef TX_PORT_USE_BASEPRI
__set_basepri_value(TX_PORT_BASEPRI);
#else
__asm__ volatile ("CPSID i");
#endif
return(int_posture);
}
static __inline void __restore_interrupt(unsigned int int_posture)
{
#ifdef TX_PORT_USE_BASEPRI
__set_basepri_value(int_posture);
#else
__asm__ volatile ("MSR PRIMASK, #int_posture");
#endif
}
static void _tx_thread_system_return_inline(void)
{
unsigned int interrupt_save;
/* Set PendSV to invoke ThreadX scheduler. */
*((volatile ULONG *) 0xE000ED04) = ((ULONG) 0x10000000);
if (_ipsr == 0)
{
#ifdef TX_PORT_USE_BASEPRI
interrupt_save = __get_interrupt_posture();
__set_basepri_value(0);
__set_basepri_value(interrupt_save);
#else
interrupt_save = __disable_irq();
__enable_irq();
if (interrupt_save != 0)
__disable_irq();
#endif
}
}
#define TX_INTERRUPT_SAVE_AREA UINT interrupt_save;
#define TX_DISABLE interrupt_save = __disable_interrupts();
#define TX_RESTORE __restore_interrupt(interrupt_save);
/*** End AC5 ***/
#endif /* Interrupt disable/restore macros for each compiler. */
/* Redefine _tx_thread_system_return for improved performance. */
#define _tx_thread_system_return _tx_thread_system_return_inline
#else /* TX_DISABLE_INLINE is defined */
UINT _tx_thread_interrupt_disable(VOID);
VOID _tx_thread_interrupt_restore(UINT previous_posture);
#define TX_INTERRUPT_SAVE_AREA register UINT interrupt_save;
#define TX_DISABLE interrupt_save = _tx_thread_interrupt_disable();
#define TX_RESTORE _tx_thread_interrupt_restore(interrupt_save);
#endif /* TX_DISABLE_INLINE */
/* Define FPU extension for the Cortex-M. Each is assumed to be called in the context of the executing
thread. These are no longer needed, but are preserved for backward compatibility only. */
void tx_thread_fpu_enable(void);
void tx_thread_fpu_disable(void);
/* Define the version ID of ThreadX. This may be utilized by the application. */
#ifdef TX_THREAD_INIT
CHAR _tx_version_id[] =
"Copyright (c) Microsoft Corporation. All rights reserved. * ThreadX Cortex-Mx Version 6.2.1 *";
#else
#ifdef TX_MISRA_ENABLE
extern CHAR _tx_version_id[100];
#else
extern CHAR _tx_version_id[];
#endif
#endif
#endif

View File

@@ -0,0 +1,469 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Module */
/** */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/* */
/* APPLICATION INTERFACE DEFINITION RELEASE */
/* */
/* txm_module_port.h Cortex-Mx */
/* 6.2.1 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This file defines the basic module constants, interface structures, */
/* and function prototypes. */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 10-15-2021 Scott Larson Initial Version 6.1.9 */
/* 01-31-2022 Scott Larson Modified comments and made */
/* heap user-configurable, */
/* resulting in version 6.1.10 */
/* 07-29-2022 Scott Larson Enabled user-defined and */
/* default MPU settings, */
/* resulting in version 6.1.12 */
/* 10-31-2022 Scott Larson Configure heap size, */
/* resulting in version 6.2.0 */
/* 03-08-2023 Scott Larson Set default values for RBAR, */
/* unify this file for all */
/* compilers, */
/* resulting in version 6.2.1 */
/* */
/**************************************************************************/
#ifndef TXM_MODULE_PORT_H
#define TXM_MODULE_PORT_H
/* Determine if the optional Modules user define file should be used. */
#ifdef TXM_MODULE_INCLUDE_USER_DEFINE_FILE
/* Yes, include the user defines in txm_module_user.h. The defines in this file may
alternately be defined on the command line. */
#include "txm_module_user.h"
#endif
/* It is assumed that the base ThreadX tx_port.h file has been modified to add the
following extensions to the ThreadX thread control block (this code should replace
the corresponding macro define in tx_port.h):
#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT
#define TX_THREAD_EXTENSION_2 VOID *tx_thread_module_instance_ptr; \
VOID *tx_thread_module_entry_info_ptr; \
ULONG tx_thread_module_current_user_mode; \
ULONG tx_thread_module_user_mode; \
ULONG tx_thread_module_saved_lr; \
VOID *tx_thread_module_kernel_stack_start; \
VOID *tx_thread_module_kernel_stack_end; \
ULONG tx_thread_module_kernel_stack_size; \
VOID *tx_thread_module_stack_ptr; \
VOID *tx_thread_module_stack_start; \
VOID *tx_thread_module_stack_end; \
ULONG tx_thread_module_stack_size; \
VOID *tx_thread_module_reserved; \
VOID *tx_thread_iar_tls_pointer;
#else
#define TX_THREAD_EXTENSION_2 VOID *tx_thread_module_instance_ptr; \
VOID *tx_thread_module_entry_info_ptr; \
ULONG tx_thread_module_current_user_mode; \
ULONG tx_thread_module_user_mode; \
ULONG tx_thread_module_saved_lr; \
VOID *tx_thread_module_kernel_stack_start; \
VOID *tx_thread_module_kernel_stack_end; \
ULONG tx_thread_module_kernel_stack_size; \
VOID *tx_thread_module_stack_ptr; \
VOID *tx_thread_module_stack_start; \
VOID *tx_thread_module_stack_end; \
ULONG tx_thread_module_stack_size; \
VOID *tx_thread_module_reserved;
#endif
The following extensions must also be defined in tx_port.h:
#define TX_EVENT_FLAGS_GROUP_EXTENSION VOID *tx_event_flags_group_module_instance; \
VOID (*tx_event_flags_group_set_module_notify)(struct TX_EVENT_FLAGS_GROUP_STRUCT *group_ptr);
#define TX_QUEUE_EXTENSION VOID *tx_queue_module_instance; \
VOID (*tx_queue_send_module_notify)(struct TX_QUEUE_STRUCT *queue_ptr);
#define TX_SEMAPHORE_EXTENSION VOID *tx_semaphore_module_instance; \
VOID (*tx_semaphore_put_module_notify)(struct TX_SEMAPHORE_STRUCT *semaphore_ptr);
#define TX_TIMER_EXTENSION VOID *tx_timer_module_instance; \
VOID (*tx_timer_module_expiration_function)(ULONG id);
*/
/* Users can define the module heap size. */
#ifndef TXM_MODULE_HEAP_SIZE
#define TXM_MODULE_HEAP_SIZE 512
#endif
/* Define the kernel stack size for a module thread. */
#ifndef TXM_MODULE_KERNEL_STACK_SIZE
#define TXM_MODULE_KERNEL_STACK_SIZE 768
#endif
/* For the following 3 access control settings, change TEX and C, B, S (bits 21 through 16 of MPU_RASR)
* to reflect your system memory attributes (cache, shareable, memory type). */
/* Code region access control: privileged read-only, outer & inner write-back, normal memory, shareable. */
#ifndef TXM_MODULE_MPU_CODE_ACCESS_CONTROL
#define TXM_MODULE_MPU_CODE_ACCESS_CONTROL 0x06070000
#endif
/* Data region access control: execute never, read/write, outer & inner write-back, normal memory, shareable. */
#ifndef TXM_MODULE_MPU_DATA_ACCESS_CONTROL
#define TXM_MODULE_MPU_DATA_ACCESS_CONTROL 0x13070000
#endif
/* Shared region access control: execute never, read-only, outer & inner write-back, normal memory, shareable. */
#ifndef TXM_MODULE_MPU_SHARED_ACCESS_CONTROL
#define TXM_MODULE_MPU_SHARED_ACCESS_CONTROL 0x12070000
#endif
/* For Cortex-M devices with 16 MPU regions, the last four regions (12-15)
are not used by ThreadX. These may be defined by the user.
RBAR needs the valid bit and region number set, as MPU alias registers are used. */
#define TXM_MODULE_MPU_USER_DEFINED_RBAR_12 0x1C
#define TXM_MODULE_MPU_USER_DEFINED_RASR_12 0
#define TXM_MODULE_MPU_USER_DEFINED_RBAR_13 0x1D
#define TXM_MODULE_MPU_USER_DEFINED_RASR_13 0
#define TXM_MODULE_MPU_USER_DEFINED_RBAR_14 0x1E
#define TXM_MODULE_MPU_USER_DEFINED_RASR_14 0
#define TXM_MODULE_MPU_USER_DEFINED_RBAR_15 0x1F
#define TXM_MODULE_MPU_USER_DEFINED_RASR_15 0
/* Users can define these default MPU configuration values.
If TXM_MODULE_MPU_DEFAULT is *not* defined, the MPU is disabled
when a thread that is not owned by a module is running
and the defines below are not used.
If TXM_MODULE_MPU_DEFAULT is defined, the MPU is configured to the
below values when a thread that is not owned by a module is running.
RBAR needs the valid bit and region number set, as MPU alias registers are used. */
#define TXM_MODULE_MPU_DEFAULT_RBAR_0 0x10
#define TXM_MODULE_MPU_DEFAULT_RASR_0 0
#define TXM_MODULE_MPU_DEFAULT_RBAR_1 0x11
#define TXM_MODULE_MPU_DEFAULT_RASR_1 0
#define TXM_MODULE_MPU_DEFAULT_RBAR_2 0x12
#define TXM_MODULE_MPU_DEFAULT_RASR_2 0
#define TXM_MODULE_MPU_DEFAULT_RBAR_3 0x13
#define TXM_MODULE_MPU_DEFAULT_RASR_3 0
#define TXM_MODULE_MPU_DEFAULT_RBAR_4 0x14
#define TXM_MODULE_MPU_DEFAULT_RASR_4 0
#define TXM_MODULE_MPU_DEFAULT_RBAR_5 0x15
#define TXM_MODULE_MPU_DEFAULT_RASR_5 0
#define TXM_MODULE_MPU_DEFAULT_RBAR_6 0x16
#define TXM_MODULE_MPU_DEFAULT_RASR_6 0
#define TXM_MODULE_MPU_DEFAULT_RBAR_7 0x17
#define TXM_MODULE_MPU_DEFAULT_RASR_7 0
#define TXM_MODULE_MPU_DEFAULT_RBAR_8 0x18
#define TXM_MODULE_MPU_DEFAULT_RASR_8 0
#define TXM_MODULE_MPU_DEFAULT_RBAR_9 0x19
#define TXM_MODULE_MPU_DEFAULT_RASR_9 0
#define TXM_MODULE_MPU_DEFAULT_RBAR_10 0x1A
#define TXM_MODULE_MPU_DEFAULT_RASR_10 0
#define TXM_MODULE_MPU_DEFAULT_RBAR_11 0x1B
#define TXM_MODULE_MPU_DEFAULT_RASR_11 0
#define TXM_MODULE_MPU_DEFAULT_RBAR_12 0x1C
#define TXM_MODULE_MPU_DEFAULT_RASR_12 0
#define TXM_MODULE_MPU_DEFAULT_RBAR_13 0x1D
#define TXM_MODULE_MPU_DEFAULT_RASR_13 0
#define TXM_MODULE_MPU_DEFAULT_RBAR_14 0x1E
#define TXM_MODULE_MPU_DEFAULT_RASR_14 0
#define TXM_MODULE_MPU_DEFAULT_RBAR_15 0x1F
#define TXM_MODULE_MPU_DEFAULT_RASR_15 0
/* Define constants specific to the tools the module can be built with for this particular modules port. */
#define TXM_MODULE_IAR_COMPILER 0x00000000
#define TXM_MODULE_RVDS_COMPILER 0x01000000
#define TXM_MODULE_GNU_COMPILER 0x02000000
#define TXM_MODULE_COMPILER_MASK 0xFF000000
#define TXM_MODULE_OPTIONS_MASK 0x000000FF
/* Define the properties for this particular module port. */
#define TXM_MODULE_MEMORY_PROTECTION_ENABLED
#ifdef TXM_MODULE_MEMORY_PROTECTION_ENABLED
#define TXM_MODULE_REQUIRE_ALLOCATED_OBJECT_MEMORY
#else
#define TXM_MODULE_REQUIRE_LOCAL_OBJECT_MEMORY
#endif
#define TXM_MODULE_USER_MODE 0x00000001
#define TXM_MODULE_MEMORY_PROTECTION 0x00000002
#define TXM_MODULE_SHARED_EXTERNAL_MEMORY_ACCESS 0x00000004
/* Define the supported options for this module. */
#define TXM_MODULE_MANAGER_SUPPORTED_OPTIONS (TXM_MODULE_USER_MODE | TXM_MODULE_MEMORY_PROTECTION | TXM_MODULE_SHARED_EXTERNAL_MEMORY_ACCESS)
#define TXM_MODULE_MANAGER_REQUIRED_OPTIONS 0
/* Define offset adjustments according to the compiler used to build the module. */
#define TXM_MODULE_IAR_SHELL_ADJUST 24
#define TXM_MODULE_IAR_START_ADJUST 28
#define TXM_MODULE_IAR_STOP_ADJUST 32
#define TXM_MODULE_IAR_CALLBACK_ADJUST 44
#define TXM_MODULE_RVDS_SHELL_ADJUST 0
#define TXM_MODULE_RVDS_START_ADJUST 0
#define TXM_MODULE_RVDS_STOP_ADJUST 0
#define TXM_MODULE_RVDS_CALLBACK_ADJUST 0
#define TXM_MODULE_GNU_SHELL_ADJUST 24
#define TXM_MODULE_GNU_START_ADJUST 28
#define TXM_MODULE_GNU_STOP_ADJUST 32
#define TXM_MODULE_GNU_CALLBACK_ADJUST 44
/* Define other module port-specific constants. */
/* Define INLINE_DECLARE to inline for this compiler. */
#define INLINE_DECLARE inline
#define TXM_MPU_VALID_BIT 0x10
#define TXM_ENABLE_REGION 0x01
#define TXM_MODULE_MANAGER_MPU_KERNEL_ENTRY_INDEX 0
/* Shared memory region attributes. */
#define TXM_MODULE_MANAGER_SHARED_ATTRIBUTE_WRITE 1
#define TXM_MODULE_MANAGER_ATTRIBUTE_WRITE_MPU_BIT 0x01000000
/* There are 2 registers to set up each MPU region: MPU_RBAR, MPU_RASR. */
typedef struct TXM_MODULE_MPU_INFO_STRUCT
{
ULONG txm_module_mpu_region_address;
ULONG txm_module_mpu_region_attribute_size;
} TXM_MODULE_MPU_INFO;
#ifdef TXM_MODULE_MANAGER_16_MPU
/* Define the number of MPU entries assigned to the code and data sections.
On some Cortex-M7 parts, there are 16 total entries. ThreadX uses one for access
to the kernel entry function, thus 15 remain for code and data protection. */
#define TXM_MODULE_MANAGER_MPU_TOTAL_ENTRIES 16
#define TXM_MODULE_MANAGER_MPU_CODE_ENTRIES 4
#define TXM_MODULE_MANAGER_MPU_DATA_ENTRIES 4
#define TXM_MODULE_MANAGER_MPU_SHARED_ENTRIES 3
#define TXM_MODULE_MANAGER_MPU_SHARED_INDEX 9
#define TXM_MODULE_MANAGER_MPU_USER_REGION_INDEX 12
/* Define the port-extensions to the module manager instance structure. */
#define TXM_MODULE_MANAGER_PORT_EXTENSION \
TXM_MODULE_MPU_INFO txm_module_instance_mpu_registers[TXM_MODULE_MANAGER_MPU_TOTAL_ENTRIES]; \
ULONG txm_module_instance_shared_memory_count; \
ULONG txm_module_instance_shared_memory_address[TXM_MODULE_MANAGER_MPU_SHARED_ENTRIES]; \
ULONG txm_module_instance_shared_memory_length[TXM_MODULE_MANAGER_MPU_SHARED_ENTRIES];
#else /* TXM_MODULE_MANAGER_16_MPU is not defined */
/* Define the number of MPU entries assigned to the code and data sections.
On Cortex-M3, M4, and some M7 parts, there are 8 total entries. ThreadX uses one for access
to the kernel entry function, thus 7 remain for code and data protection. */
#define TXM_MODULE_MANAGER_MPU_TOTAL_ENTRIES 8
#define TXM_MODULE_MANAGER_CODE_MPU_ENTRIES 4
#define TXM_MODULE_MANAGER_DATA_MPU_ENTRIES 3
#define TXM_MODULE_MANAGER_SHARED_MPU_REGION 4
/* Define the port-extensions to the module manager instance structure. */
#define TXM_MODULE_MANAGER_PORT_EXTENSION \
TXM_MODULE_MPU_INFO txm_module_instance_mpu_registers[TXM_MODULE_MANAGER_MPU_TOTAL_ENTRIES]; \
ULONG txm_module_instance_shared_memory_address; \
ULONG txm_module_instance_shared_memory_length;
#endif /* TXM_MODULE_MANAGER_16_MPU */
/* Define the memory fault information structure that is populated when a memory fault occurs. */
typedef struct TXM_MODULE_MANAGER_MEMORY_FAULT_INFO_STRUCT
{
TX_THREAD *txm_module_manager_memory_fault_info_thread_ptr;
VOID *txm_module_manager_memory_fault_info_code_location;
ULONG txm_module_manager_memory_fault_info_shcsr;
ULONG txm_module_manager_memory_fault_info_cfsr;
ULONG txm_module_manager_memory_fault_info_mmfar;
ULONG txm_module_manager_memory_fault_info_bfar;
ULONG txm_module_manager_memory_fault_info_control;
ULONG txm_module_manager_memory_fault_info_sp;
ULONG txm_module_manager_memory_fault_info_r0;
ULONG txm_module_manager_memory_fault_info_r1;
ULONG txm_module_manager_memory_fault_info_r2;
ULONG txm_module_manager_memory_fault_info_r3;
ULONG txm_module_manager_memory_fault_info_r4;
ULONG txm_module_manager_memory_fault_info_r5;
ULONG txm_module_manager_memory_fault_info_r6;
ULONG txm_module_manager_memory_fault_info_r7;
ULONG txm_module_manager_memory_fault_info_r8;
ULONG txm_module_manager_memory_fault_info_r9;
ULONG txm_module_manager_memory_fault_info_r10;
ULONG txm_module_manager_memory_fault_info_r11;
ULONG txm_module_manager_memory_fault_info_r12;
ULONG txm_module_manager_memory_fault_info_lr;
ULONG txm_module_manager_memory_fault_info_xpsr;
} TXM_MODULE_MANAGER_MEMORY_FAULT_INFO;
#define TXM_MODULE_MANAGER_FAULT_INFO \
TXM_MODULE_MANAGER_MEMORY_FAULT_INFO _txm_module_manager_memory_fault_info;
/* Define the macro to check the code alignment. */
#define TXM_MODULE_MANAGER_CHECK_CODE_ALIGNMENT(module_location, code_alignment) \
{ \
ULONG temp; \
temp = (ULONG) module_location; \
temp = temp & (code_alignment - 1); \
if (temp) \
{ \
_tx_mutex_put(&_txm_module_manager_mutex); \
return(TXM_MODULE_ALIGNMENT_ERROR); \
} \
}
/* Define the macro to adjust the alignment and size for code/data areas. */
#define TXM_MODULE_MANAGER_ALIGNMENT_ADJUST(module_preamble, code_size, code_alignment, data_size, data_alignment) _txm_module_manager_alignment_adjust(module_preamble, &code_size, &code_alignment, &data_size, &data_alignment);
/* Define the macro to adjust the symbols in the module preamble. */
#define TXM_MODULE_MANAGER_CALCULATE_ADJUSTMENTS(properties, shell_function_adjust, start_function_adjust, stop_function_adjust, callback_function_adjust) \
if ((properties & TXM_MODULE_COMPILER_MASK) == TXM_MODULE_IAR_COMPILER) \
{ \
shell_function_adjust = TXM_MODULE_IAR_SHELL_ADJUST; \
start_function_adjust = TXM_MODULE_IAR_START_ADJUST; \
stop_function_adjust = TXM_MODULE_IAR_STOP_ADJUST; \
callback_function_adjust = TXM_MODULE_IAR_CALLBACK_ADJUST; \
} \
else if ((properties & TXM_MODULE_COMPILER_MASK) == TXM_MODULE_RVDS_COMPILER) \
{ \
shell_function_adjust = TXM_MODULE_RVDS_SHELL_ADJUST; \
start_function_adjust = TXM_MODULE_RVDS_START_ADJUST; \
stop_function_adjust = TXM_MODULE_RVDS_STOP_ADJUST; \
callback_function_adjust = TXM_MODULE_RVDS_CALLBACK_ADJUST; \
} \
else \
{ \
shell_function_adjust = TXM_MODULE_GNU_SHELL_ADJUST; \
start_function_adjust = TXM_MODULE_GNU_START_ADJUST; \
stop_function_adjust = TXM_MODULE_GNU_STOP_ADJUST; \
callback_function_adjust = TXM_MODULE_GNU_CALLBACK_ADJUST; \
}
/* Define the macro to populate the thread control block with module port-specific information.
Check if the module is in user mode and set up txm_module_thread_entry_info_kernel_call_dispatcher accordingly.
*/
#define TXM_MODULE_MANAGER_THREAD_SETUP(thread_ptr, module_instance) \
thread_ptr -> tx_thread_module_current_user_mode = module_instance -> txm_module_instance_property_flags & TXM_MODULE_USER_MODE; \
thread_ptr -> tx_thread_module_user_mode = module_instance -> txm_module_instance_property_flags & TXM_MODULE_USER_MODE; \
if (thread_ptr -> tx_thread_module_user_mode) \
{ \
thread_entry_info -> txm_module_thread_entry_info_kernel_call_dispatcher = _txm_module_manager_user_mode_entry; \
} \
else \
{ \
thread_entry_info -> txm_module_thread_entry_info_kernel_call_dispatcher = _txm_module_manager_kernel_dispatch; \
}
/* Define the macro to populate the module control block with module port-specific information.
If memory protection is enabled, set up the MPU registers.
*/
#define TXM_MODULE_MANAGER_MODULE_SETUP(module_instance) \
if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_USER_MODE) \
{ \
if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) \
{ \
_txm_module_manager_mm_register_setup(module_instance); \
} \
} \
else \
{ \
/* Do nothing. */ \
}
/* Define the macro to perform port-specific functions when unloading the module. */
/* Nothing needs to be done for this port. */
#define TXM_MODULE_MANAGER_MODULE_UNLOAD(module_instance)
/* 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. */
#ifdef TXM_MODULE_MANAGER_16_MPU
#define TXM_MODULE_MANAGER_CHECK_INSIDE_DATA(module_instance, obj_ptr, obj_size) \
_txm_module_manager_inside_data_check(module_instance, obj_ptr, obj_size)
#else
#define TXM_MODULE_MANAGER_CHECK_INSIDE_DATA(module_instance, obj_ptr, obj_size) \
/* Check for overflow. */ \
(((obj_ptr) < ((obj_ptr) + (obj_size))) && \
/* Check if it's inside module data. */ \
((((obj_ptr) >= (ALIGN_TYPE) module_instance -> txm_module_instance_data_start) && \
(((obj_ptr) + (obj_size)) <= ((ALIGN_TYPE) module_instance -> txm_module_instance_data_end + 1))) || \
/* Check if it's inside shared memory. */ \
(((obj_ptr) >= (ALIGN_TYPE) module_instance -> txm_module_instance_shared_memory_address) && \
(((obj_ptr) + (obj_size)) <= (ALIGN_TYPE) (module_instance -> txm_module_instance_shared_memory_address + module_instance -> txm_module_instance_shared_memory_length)))))
#endif
/* Define some internal prototypes to this module port. */
#ifndef TX_SOURCE_CODE
#define txm_module_manager_memory_fault_notify _txm_module_manager_memory_fault_notify
#endif
#define TXM_MODULE_MANAGER_ADDITIONAL_PROTOTYPES \
VOID _txm_module_manager_alignment_adjust(TXM_MODULE_PREAMBLE *module_preamble, ULONG *code_size, ULONG *code_alignment, ULONG *data_size, ULONG *data_alignment); \
VOID _txm_module_manager_memory_fault_handler(VOID); \
UINT _txm_module_manager_memory_fault_notify(VOID (*notify_function)(TX_THREAD *, TXM_MODULE_INSTANCE *)); \
VOID _txm_module_manager_mm_register_setup(TXM_MODULE_INSTANCE *module_instance); \
ULONG _txm_power_of_two_block_size(ULONG size); \
ULONG _txm_module_manager_calculate_srd_bits(ULONG block_size, ULONG length); \
ULONG _txm_module_manager_region_size_get(ULONG block_size); \
UINT _txm_module_manager_inside_data_check(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE obj_ptr, UINT obj_size);
#define TXM_MODULE_MANAGER_VERSION_ID \
CHAR _txm_module_manager_version_id[] = \
"Copyright (c) Microsoft Corporation. All rights reserved. * ThreadX Module Cortex-Mx Version 6.2.1 *";
#endif