diff --git a/.github/workflows/ports_arch_check.yml b/.github/workflows/ports_arch_check.yml new file mode 100644 index 00000000..bc6d5440 --- /dev/null +++ b/.github/workflows/ports_arch_check.yml @@ -0,0 +1,45 @@ +# This is a basic workflow to help you get started with Actions + +name: ports_arch_check + +# Controls when the action will run. Triggers the workflow on push or pull request +# events but only for the master branch +on: + pull_request: + branches: [ master ] + paths: + - ".github/workflows/ports_arch_check.yml" + - 'common/**' + - 'common_modules/**' + - 'common_smp/**' + - 'ports/**' + - 'ports_modules/**' + - 'ports_smp/**' + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - name: Checkout sources recursively + uses: actions/checkout@v2 + with: + token: ${{ secrets.REPO_SCOPED_TOKEN }} + submodules: true + + # Copy ports arch + - name: Copy ports arch + run: | + scripts/copy_armv7_m.sh && scripts/copy_armv8_m.sh && scripts/copy_module_armv7_m.sh + if [[ -n $(git status --porcelain) ]]; then + echo "Ports for ARM architecture is not updated" + exit 1 + fi + + + diff --git a/ports_arch/ARMv7-M/README.md b/ports_arch/ARMv7-M/README.md new file mode 100644 index 00000000..19863cdb --- /dev/null +++ b/ports_arch/ARMv7-M/README.md @@ -0,0 +1,5 @@ +# ARMv7-M architecture ports + +The ThreadX, ThreadX SMP, ThreadX Modules and ThreadX SMP Modules ports for ARMv7 share many files in common. +To make work more efficient these files are internally tracked only once and copied over to specific ports for users. + diff --git a/ports_arch/ARMv7-M/threadx/ac5/example_build/build_threadx.bat b/ports_arch/ARMv7-M/threadx/ac5/example_build/build_threadx.bat new file mode 100644 index 00000000..686a3e0f --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac5/example_build/build_threadx.bat @@ -0,0 +1,231 @@ +del tx.a +armasm -g --cpu=cortex-m4 --cpreproc --fpu=vfpv3 --apcs=interwork tx_initialize_low_level.s +armasm -g --cpu=cortex-m4 --cpreproc --fpu=vfpv3 --apcs=interwork ../src/tx_thread_stack_build.s +armasm -g --cpu=cortex-m4 --cpreproc --fpu=vfpv3 --apcs=interwork ../src/tx_thread_schedule.s +armasm -g --cpu=cortex-m4 --cpreproc --fpu=vfpv3 --apcs=interwork ../src/tx_thread_system_return.s +armasm -g --cpu=cortex-m4 --cpreproc --fpu=vfpv3 --apcs=interwork ../src/tx_thread_context_save.s +armasm -g --cpu=cortex-m4 --cpreproc --fpu=vfpv3 --apcs=interwork ../src/tx_thread_context_restore.s +armasm -g --cpu=cortex-m4 --cpreproc --fpu=vfpv3 --apcs=interwork ../src/tx_thread_interrupt_control.s +armasm -g --cpu=cortex-m4 --cpreproc --fpu=vfpv3 --apcs=interwork ../src/tx_thread_interrupt_disable.s +armasm -g --cpu=cortex-m4 --cpreproc --fpu=vfpv3 --apcs=interwork ../src/tx_thread_interrupt_restore.s +armasm -g --cpu=cortex-m4 --cpreproc --fpu=vfpv3 --apcs=interwork ../src/tx_timer_interrupt.s + +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_block_allocate.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_block_pool_cleanup.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_block_pool_create.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_block_pool_delete.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_block_pool_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_block_pool_initialize.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_block_pool_performance_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_block_pool_performance_system_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_block_pool_prioritize.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_block_release.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_byte_allocate.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_byte_pool_cleanup.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_byte_pool_create.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_byte_pool_delete.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_byte_pool_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_byte_pool_initialize.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_byte_pool_performance_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_byte_pool_performance_system_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_byte_pool_prioritize.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_byte_pool_search.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_byte_release.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_event_flags_cleanup.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_event_flags_create.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_event_flags_delete.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_event_flags_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_event_flags_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_event_flags_initialize.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_event_flags_performance_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_event_flags_performance_system_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_event_flags_set.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_event_flags_set_notify.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_initialize_high_level.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_initialize_kernel_enter.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_initialize_kernel_setup.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_mutex_cleanup.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_mutex_create.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_mutex_delete.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_mutex_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_mutex_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_mutex_initialize.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_mutex_performance_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_mutex_performance_system_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_mutex_prioritize.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_mutex_priority_change.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_mutex_put.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_queue_cleanup.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_queue_create.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_queue_delete.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_queue_flush.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_queue_front_send.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_queue_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_queue_initialize.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_queue_performance_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_queue_performance_system_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_queue_prioritize.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_queue_receive.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_queue_send.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_queue_send_notify.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_semaphore_ceiling_put.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_semaphore_cleanup.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_semaphore_create.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_semaphore_delete.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_semaphore_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_semaphore_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_semaphore_initialize.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_semaphore_performance_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_semaphore_performance_system_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_semaphore_prioritize.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_semaphore_put.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_semaphore_put_notify.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_create.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_delete.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_entry_exit_notify.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_identify.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_initialize.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_performance_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_performance_system_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_preemption_change.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_priority_change.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_relinquish.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_reset.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_resume.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_shell_entry.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_sleep.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_stack_analyze.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_stack_error_handler.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_stack_error_notify.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_suspend.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_system_preempt_check.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_system_resume.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_system_suspend.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_terminate.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_time_slice.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_time_slice_change.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_timeout.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_wait_abort.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_time_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_time_set.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_timer_activate.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_timer_change.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_timer_create.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_timer_deactivate.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_timer_delete.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_timer_expiration_process.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_timer_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_timer_initialize.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_timer_performance_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_timer_performance_system_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_timer_system_activate.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_timer_system_deactivate.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_timer_thread_entry.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_trace_buffer_full_notify.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_trace_enable.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_trace_event_filter.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_trace_event_unfilter.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_trace_disable.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_trace_initialize.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_trace_interrupt_control.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_trace_isr_enter_insert.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_trace_isr_exit_insert.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_trace_object_register.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_trace_object_unregister.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/tx_trace_user_event_insert.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_block_allocate.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_block_pool_create.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_block_pool_delete.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_block_pool_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_block_pool_prioritize.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_block_release.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_byte_allocate.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_byte_pool_create.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_byte_pool_delete.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_byte_pool_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_byte_pool_prioritize.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_byte_release.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_event_flags_create.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_event_flags_delete.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_event_flags_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_event_flags_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_event_flags_set.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_event_flags_set_notify.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_mutex_create.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_mutex_delete.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_mutex_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_mutex_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_mutex_prioritize.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_mutex_put.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_queue_create.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_queue_delete.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_queue_flush.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_queue_front_send.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_queue_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_queue_prioritize.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_queue_receive.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_queue_send.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_queue_send_notify.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_semaphore_ceiling_put.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_semaphore_create.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_semaphore_delete.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_semaphore_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_semaphore_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_semaphore_prioritize.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_semaphore_put.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_semaphore_put_notify.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_thread_create.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_thread_delete.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_thread_entry_exit_notify.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_thread_info_get.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_thread_preemption_change.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_thread_priority_change.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_thread_relinquish.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_thread_reset.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_thread_resume.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_thread_suspend.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_thread_terminate.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_thread_time_slice_change.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_thread_wait_abort.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_timer_activate.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_timer_change.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_timer_create.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_timer_deactivate.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_timer_delete.c +armcc -g --cpu=cortex-m4 --fpu=vfpv3 -Otime -O2 -Odiv -c --data_reorder -I../../../../common/inc -I../../inc ../../../../common/src/txe_timer_info_get.c +armar --create tx.a tx_thread_stack_build.o tx_thread_schedule.o tx_thread_system_return.o tx_thread_context_save.o tx_thread_context_restore.o tx_timer_interrupt.o tx_thread_interrupt_control.o +armar -r tx.a tx_initialize_low_level.o tx_thread_interrupt_disable.o tx_thread_interrupt_restore.o +armar -r tx.a tx_block_allocate.o tx_block_pool_cleanup.o tx_block_pool_create.o tx_block_pool_delete.o tx_block_pool_info_get.o +armar -r tx.a tx_block_pool_initialize.o tx_block_pool_performance_info_get.o tx_block_pool_performance_system_info_get.o tx_block_pool_prioritize.o +armar -r tx.a tx_block_release.o tx_byte_allocate.o tx_byte_pool_cleanup.o tx_byte_pool_create.o tx_byte_pool_delete.o tx_byte_pool_info_get.o +armar -r tx.a tx_byte_pool_initialize.o tx_byte_pool_performance_info_get.o tx_byte_pool_performance_system_info_get.o tx_byte_pool_prioritize.o +armar -r tx.a tx_byte_pool_search.o tx_byte_release.o tx_event_flags_cleanup.o tx_event_flags_create.o tx_event_flags_delete.o tx_event_flags_get.o +armar -r tx.a tx_event_flags_info_get.o tx_event_flags_initialize.o tx_event_flags_performance_info_get.o tx_event_flags_performance_system_info_get.o +armar -r tx.a tx_event_flags_set.o tx_event_flags_set_notify.o tx_initialize_high_level.o tx_initialize_kernel_enter.o tx_initialize_kernel_setup.o +armar -r tx.a tx_mutex_cleanup.o tx_mutex_create.o tx_mutex_delete.o tx_mutex_get.o tx_mutex_info_get.o tx_mutex_initialize.o tx_mutex_performance_info_get.o +armar -r tx.a tx_mutex_performance_system_info_get.o tx_mutex_prioritize.o tx_mutex_priority_change.o tx_mutex_put.o tx_queue_cleanup.o tx_queue_create.o +armar -r tx.a tx_queue_delete.o tx_queue_flush.o tx_queue_front_send.o tx_queue_info_get.o tx_queue_initialize.o tx_queue_performance_info_get.o +armar -r tx.a tx_queue_performance_system_info_get.o tx_queue_prioritize.o tx_queue_receive.o tx_queue_send.o tx_queue_send_notify.o tx_semaphore_ceiling_put.o +armar -r tx.a tx_semaphore_cleanup.o tx_semaphore_create.o tx_semaphore_delete.o tx_semaphore_get.o tx_semaphore_info_get.o tx_semaphore_initialize.o +armar -r tx.a tx_semaphore_performance_info_get.o tx_semaphore_performance_system_info_get.o tx_semaphore_prioritize.o tx_semaphore_put.o tx_semaphore_put_notify.o +armar -r tx.a tx_thread_create.o tx_thread_delete.o tx_thread_entry_exit_notify.o tx_thread_identify.o tx_thread_info_get.o tx_thread_initialize.o +armar -r tx.a tx_thread_performance_info_get.o tx_thread_performance_system_info_get.o tx_thread_preemption_change.o tx_thread_priority_change.o tx_thread_relinquish.o +armar -r tx.a tx_thread_reset.o tx_thread_resume.o tx_thread_shell_entry.o tx_thread_sleep.o tx_thread_stack_analyze.o tx_thread_stack_error_handler.o +armar -r tx.a tx_thread_stack_error_notify.o tx_thread_suspend.o tx_thread_system_preempt_check.o tx_thread_system_resume.o tx_thread_system_suspend.o +armar -r tx.a tx_thread_terminate.o tx_thread_time_slice.o tx_thread_time_slice_change.o tx_thread_timeout.o tx_thread_wait_abort.o tx_time_get.o +armar -r tx.a tx_time_set.o tx_timer_activate.o tx_timer_change.o tx_timer_create.o tx_timer_deactivate.o tx_timer_delete.o tx_timer_expiration_process.o +armar -r tx.a tx_timer_info_get.o tx_timer_initialize.o tx_timer_performance_info_get.o tx_timer_performance_system_info_get.o tx_timer_system_activate.o +armar -r tx.a tx_timer_system_deactivate.o tx_timer_thread_entry.o tx_trace_enable.o tx_trace_disable.o tx_trace_initialize.o tx_trace_interrupt_control.o +armar -r tx.a tx_trace_isr_enter_insert.o tx_trace_isr_exit_insert.o tx_trace_object_register.o tx_trace_object_unregister.o tx_trace_user_event_insert.o +armar -r tx.a tx_trace_buffer_full_notify.o tx_trace_event_filter.o tx_trace_event_unfilter.o +armar -r tx.a txe_block_allocate.o txe_block_pool_create.o txe_block_pool_delete.o txe_block_pool_info_get.o txe_block_pool_prioritize.o txe_block_release.o +armar -r tx.a txe_byte_allocate.o txe_byte_pool_create.o txe_byte_pool_delete.o txe_byte_pool_info_get.o txe_byte_pool_prioritize.o txe_byte_release.o +armar -r tx.a txe_event_flags_create.o txe_event_flags_delete.o txe_event_flags_get.o txe_event_flags_info_get.o txe_event_flags_set.o +armar -r tx.a txe_event_flags_set_notify.o txe_mutex_create.o txe_mutex_delete.o txe_mutex_get.o txe_mutex_info_get.o txe_mutex_prioritize.o +armar -r tx.a txe_mutex_put.o txe_queue_create.o txe_queue_delete.o txe_queue_flush.o txe_queue_front_send.o txe_queue_info_get.o txe_queue_prioritize.o +armar -r tx.a txe_queue_receive.o txe_queue_send.o txe_queue_send_notify.o txe_semaphore_ceiling_put.o txe_semaphore_create.o txe_semaphore_delete.o +armar -r tx.a txe_semaphore_get.o txe_semaphore_info_get.o txe_semaphore_prioritize.o txe_semaphore_put.o txe_semaphore_put_notify.o txe_thread_create.o +armar -r tx.a txe_thread_delete.o txe_thread_entry_exit_notify.o txe_thread_info_get.o txe_thread_preemption_change.o txe_thread_priority_change.o +armar -r tx.a txe_thread_relinquish.o txe_thread_reset.o txe_thread_resume.o txe_thread_suspend.o txe_thread_terminate.o txe_thread_time_slice_change.o +armar -r tx.a txe_thread_wait_abort.o txe_timer_activate.o txe_timer_change.o txe_timer_create.o txe_timer_deactivate.o txe_timer_delete.o txe_timer_info_get.o diff --git a/ports_arch/ARMv7-M/threadx/ac5/example_build/build_threadx_sample.bat b/ports_arch/ARMv7-M/threadx/ac5/example_build/build_threadx_sample.bat new file mode 100644 index 00000000..420ab366 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac5/example_build/build_threadx_sample.bat @@ -0,0 +1,4 @@ +armasm -g --cpu=cortex-m4 --cpreproc --apcs=interwork tx_initialize_low_level.s +armcc -c -g --cpu=cortex-m4 -O2 -I../../../../common/inc -I../../inc sample_threadx.c +armlink -d -o sample_threadx.axf --elf --map --ro-base=0x00000000 --rw-base=0x20000000 --first __tx_vectors --datacompressor=off --inline --info=inline --callgraph --list sample_threadx.map tx_initialize_low_level.o sample_threadx.o tx.a + diff --git a/ports_arch/ARMv7-M/threadx/ac5/example_build/sample_threadx.c b/ports_arch/ARMv7-M/threadx/ac5/example_build/sample_threadx.c new file mode 100644 index 00000000..418ec634 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac5/example_build/sample_threadx.c @@ -0,0 +1,369 @@ +/* This is a small demo of the high-performance ThreadX kernel. It includes examples of eight + threads of different priorities, using a message queue, semaphore, mutex, event flags group, + byte pool, and block pool. */ + +#include "tx_api.h" + +#define DEMO_STACK_SIZE 1024 +#define DEMO_BYTE_POOL_SIZE 9120 +#define DEMO_BLOCK_POOL_SIZE 100 +#define DEMO_QUEUE_SIZE 100 + + +/* Define the ThreadX object control blocks... */ + +TX_THREAD thread_0; +TX_THREAD thread_1; +TX_THREAD thread_2; +TX_THREAD thread_3; +TX_THREAD thread_4; +TX_THREAD thread_5; +TX_THREAD thread_6; +TX_THREAD thread_7; +TX_QUEUE queue_0; +TX_SEMAPHORE semaphore_0; +TX_MUTEX mutex_0; +TX_EVENT_FLAGS_GROUP event_flags_0; +TX_BYTE_POOL byte_pool_0; +TX_BLOCK_POOL block_pool_0; + + +/* Define the counters used in the demo application... */ + +ULONG thread_0_counter; +ULONG thread_1_counter; +ULONG thread_1_messages_sent; +ULONG thread_2_counter; +ULONG thread_2_messages_received; +ULONG thread_3_counter; +ULONG thread_4_counter; +ULONG thread_5_counter; +ULONG thread_6_counter; +ULONG thread_7_counter; + + +/* Define thread prototypes. */ + +void thread_0_entry(ULONG thread_input); +void thread_1_entry(ULONG thread_input); +void thread_2_entry(ULONG thread_input); +void thread_3_and_4_entry(ULONG thread_input); +void thread_5_entry(ULONG thread_input); +void thread_6_and_7_entry(ULONG thread_input); + + +/* Define main entry point. */ + +int main() +{ + + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); +} + + +/* Define what the initial system looks like. */ + +void tx_application_define(void *first_unused_memory) +{ + +CHAR *pointer = TX_NULL; + + + /* Create a byte memory pool from which to allocate the thread stacks. */ + tx_byte_pool_create(&byte_pool_0, "byte pool 0", first_unused_memory, DEMO_BYTE_POOL_SIZE); + + /* Put system definition stuff in here, e.g. thread creates and other assorted + create information. */ + + /* Allocate the stack for thread 0. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create the main thread. */ + tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0, + pointer, DEMO_STACK_SIZE, + 1, 1, TX_NO_TIME_SLICE, TX_AUTO_START); + + + /* Allocate the stack for thread 1. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create threads 1 and 2. These threads pass information through a ThreadX + message queue. It is also interesting to note that these threads have a time + slice. */ + tx_thread_create(&thread_1, "thread 1", thread_1_entry, 1, + pointer, DEMO_STACK_SIZE, + 16, 16, 4, TX_AUTO_START); + + /* Allocate the stack for thread 2. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + tx_thread_create(&thread_2, "thread 2", thread_2_entry, 2, + pointer, DEMO_STACK_SIZE, + 16, 16, 4, TX_AUTO_START); + + /* Allocate the stack for thread 3. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create threads 3 and 4. These threads compete for a ThreadX counting semaphore. + An interesting thing here is that both threads share the same instruction area. */ + tx_thread_create(&thread_3, "thread 3", thread_3_and_4_entry, 3, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 4. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + tx_thread_create(&thread_4, "thread 4", thread_3_and_4_entry, 4, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 5. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create thread 5. This thread simply pends on an event flag which will be set + by thread_0. */ + tx_thread_create(&thread_5, "thread 5", thread_5_entry, 5, + pointer, DEMO_STACK_SIZE, + 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 6. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create threads 6 and 7. These threads compete for a ThreadX mutex. */ + tx_thread_create(&thread_6, "thread 6", thread_6_and_7_entry, 6, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 7. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + tx_thread_create(&thread_7, "thread 7", thread_6_and_7_entry, 7, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the message queue. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_QUEUE_SIZE*sizeof(ULONG), TX_NO_WAIT); + + /* Create the message queue shared by threads 1 and 2. */ + tx_queue_create(&queue_0, "queue 0", TX_1_ULONG, pointer, DEMO_QUEUE_SIZE*sizeof(ULONG)); + + /* Create the semaphore used by threads 3 and 4. */ + tx_semaphore_create(&semaphore_0, "semaphore 0", 1); + + /* Create the event flags group used by threads 1 and 5. */ + tx_event_flags_create(&event_flags_0, "event flags 0"); + + /* Create the mutex used by thread 6 and 7 without priority inheritance. */ + tx_mutex_create(&mutex_0, "mutex 0", TX_NO_INHERIT); + + /* Allocate the memory for a small block pool. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_BLOCK_POOL_SIZE, TX_NO_WAIT); + + /* Create a block memory pool to allocate a message buffer from. */ + tx_block_pool_create(&block_pool_0, "block pool 0", sizeof(ULONG), pointer, DEMO_BLOCK_POOL_SIZE); + + /* Allocate a block and release the block memory. */ + tx_block_allocate(&block_pool_0, (VOID **) &pointer, TX_NO_WAIT); + + /* Release the block back to the pool. */ + tx_block_release(pointer); +} + + + +/* Define the test threads. */ + +void thread_0_entry(ULONG thread_input) +{ + +UINT status; + + + /* This thread simply sits in while-forever-sleep loop. */ + while(1) + { + + /* Increment the thread counter. */ + thread_0_counter++; + + /* Sleep for 10 ticks. */ + tx_thread_sleep(10); + + /* Set event flag 0 to wakeup thread 5. */ + status = tx_event_flags_set(&event_flags_0, 0x1, TX_OR); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + } +} + + +void thread_1_entry(ULONG thread_input) +{ + +UINT status; + + + /* This thread simply sends messages to a queue shared by thread 2. */ + while(1) + { + + /* Increment the thread counter. */ + thread_1_counter++; + + /* Send message to queue 0. */ + status = tx_queue_send(&queue_0, &thread_1_messages_sent, TX_WAIT_FOREVER); + + /* Check completion status. */ + if (status != TX_SUCCESS) + break; + + /* Increment the message sent. */ + thread_1_messages_sent++; + } +} + + +void thread_2_entry(ULONG thread_input) +{ + +ULONG received_message; +UINT status; + + /* This thread retrieves messages placed on the queue by thread 1. */ + while(1) + { + + /* Increment the thread counter. */ + thread_2_counter++; + + /* Retrieve a message from the queue. */ + status = tx_queue_receive(&queue_0, &received_message, TX_WAIT_FOREVER); + + /* Check completion status and make sure the message is what we + expected. */ + if ((status != TX_SUCCESS) || (received_message != thread_2_messages_received)) + break; + + /* Otherwise, all is okay. Increment the received message count. */ + thread_2_messages_received++; + } +} + + +void thread_3_and_4_entry(ULONG thread_input) +{ + +UINT status; + + + /* This function is executed from thread 3 and thread 4. As the loop + below shows, these function compete for ownership of semaphore_0. */ + while(1) + { + + /* Increment the thread counter. */ + if (thread_input == 3) + thread_3_counter++; + else + thread_4_counter++; + + /* Get the semaphore with suspension. */ + status = tx_semaphore_get(&semaphore_0, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Sleep for 2 ticks to hold the semaphore. */ + tx_thread_sleep(2); + + /* Release the semaphore. */ + status = tx_semaphore_put(&semaphore_0); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + } +} + + +void thread_5_entry(ULONG thread_input) +{ + +UINT status; +ULONG actual_flags; + + + /* This thread simply waits for an event in a forever loop. */ + while(1) + { + + /* Increment the thread counter. */ + thread_5_counter++; + + /* Wait for event flag 0. */ + status = tx_event_flags_get(&event_flags_0, 0x1, TX_OR_CLEAR, + &actual_flags, TX_WAIT_FOREVER); + + /* Check status. */ + if ((status != TX_SUCCESS) || (actual_flags != 0x1)) + break; + } +} + + +void thread_6_and_7_entry(ULONG thread_input) +{ + +UINT status; + + + /* This function is executed from thread 6 and thread 7. As the loop + below shows, these function compete for ownership of mutex_0. */ + while(1) + { + + /* Increment the thread counter. */ + if (thread_input == 6) + thread_6_counter++; + else + thread_7_counter++; + + /* Get the mutex with suspension. */ + status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Get the mutex again with suspension. This shows + that an owning thread may retrieve the mutex it + owns multiple times. */ + status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Sleep for 2 ticks to hold the mutex. */ + tx_thread_sleep(2); + + /* Release the mutex. */ + status = tx_mutex_put(&mutex_0); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Release the mutex again. This will actually + release ownership since it was obtained twice. */ + status = tx_mutex_put(&mutex_0); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + } +} diff --git a/ports_arch/ARMv7-M/threadx/ac5/example_build/tx_initialize_low_level.s b/ports_arch/ARMv7-M/threadx/ac5/example_build/tx_initialize_low_level.s new file mode 100644 index 00000000..0a9bb7b6 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac5/example_build/tx_initialize_low_level.s @@ -0,0 +1,266 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Initialize */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + IMPORT _tx_thread_system_stack_ptr + IMPORT _tx_initialize_unused_memory + IMPORT _tx_thread_context_save + IMPORT _tx_thread_context_restore +#ifndef TX_NO_TIMER + IMPORT _tx_timer_interrupt +#endif + IMPORT __main + IMPORT |Image$$RO$$Limit| + IMPORT |Image$$RW$$Base| + IMPORT |Image$$ZI$$Base| + IMPORT |Image$$ZI$$Limit| + IMPORT PendSV_Handler + + +SYSTEM_CLOCK EQU 6000000 +SYSTICK_CYCLES EQU ((SYSTEM_CLOCK / 100) -1) + + +/* Setup the stack and heap areas. */ + +STACK_SIZE EQU 0x00000400 +HEAP_SIZE EQU 0x00000000 + + AREA STACK, NOINIT, READWRITE, ALIGN=3 +StackMem + SPACE STACK_SIZE +__initial_sp + + + AREA HEAP, NOINIT, READWRITE, ALIGN=3 +__heap_base +HeapMem + SPACE HEAP_SIZE +__heap_limit + + + AREA RESET, CODE, READONLY + + EXPORT __tx_vectors +__tx_vectors + DCD __initial_sp // Reset and system stack ptr + DCD Reset_Handler // Reset goes to startup function + DCD __tx_NMIHandler // NMI + DCD __tx_BadHandler // HardFault + DCD 0 // MemManage + DCD 0 // BusFault + DCD 0 // UsageFault + DCD 0 // 7 + DCD 0 // 8 + DCD 0 // 9 + DCD 0 // 10 + DCD __tx_SVCallHandler // SVCall + DCD __tx_DBGHandler // Monitor + DCD 0 // 13 + DCD PendSV_Handler // PendSV +#ifndef TX_NO_TIMER + DCD __tx_SysTickHandler // SysTick +#else + DCD 0 // SysTick +#endif + DCD __tx_IntHandler // Int 0 + DCD __tx_IntHandler // Int 1 + DCD __tx_IntHandler // Int 2 + DCD __tx_IntHandler // Int 3 + + + AREA ||.text||, CODE, READONLY + EXPORT Reset_Handler +Reset_Handler + CPSID i +#ifdef __TARGET_FPU_VFP + LDR r0, =0xE000ED88 // Pickup address of CPACR + LDR r1, [r0] // Pickup CPACR + MOV32 r2, 0x00F00000 // Build enable value + ORR r1, r1, r2 // Or in enable value + STR r1, [r0] // Setup CPACR +#endif + LDR r0, =__main + BX r0 + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_initialize_low_level Cortex-Mx/AC5 */ +/* 6.1.10 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for any low-level processor */ +/* initialization, including setting up interrupt vectors, setting */ +/* up a periodic timer interrupt source, saving the system stack */ +/* pointer for use in ISR processing later, and finding the first */ +/* available RAM memory address for tx_application_define. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_initialize_kernel_enter ThreadX entry function */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 01-31-2022 Scott Larson Modified comment(s), added */ +/* TX_NO_TIMER support, */ +/* resulting in version 6.1.10 */ +/* */ +/**************************************************************************/ +// VOID _tx_initialize_low_level(VOID) +// { + EXPORT _tx_initialize_low_level +_tx_initialize_low_level + + /* Ensure that interrupts are disabled. */ + CPSID i + + + /* Set base of available memory to end of non-initialised RAM area. */ + LDR r0, =_tx_initialize_unused_memory // Build address of unused memory pointer + LDR r1, =|Image$$ZI$$Limit| // Build first free address + ADD r1, r1, #4 // Add 4 to get to next free word + STR r1, [r0] // Setup first unused memory pointer + + /* Setup Vector Table Offset Register. */ + MOV r0, #0xE000E000 // Build address of NVIC registers + LDR r1, =__tx_vectors // Pickup address of vector table + STR r1, [r0, #0xD08] // Set vector table address + + /* Set system stack pointer from vector value. */ + LDR r0, =_tx_thread_system_stack_ptr // Build address of system stack pointer + LDR r1, =__tx_vectors // Pickup address of vector table + LDR r1, [r1] // Pickup reset stack pointer + STR r1, [r0] // Save system stack pointer + +#ifndef TX_NO_TIMER + /* Configure SysTick. */ + MOV r0, #0xE000E000 // Build address of NVIC registers + LDR r1, =SYSTICK_CYCLES + STR r1, [r0, #0x14] // Setup SysTick Reload Value + MOV r1, #0x7 // Build SysTick Control Enable Value + STR r1, [r0, #0x10] // Setup SysTick Control +#endif + + /* Configure handler priorities. */ + LDR r1, =0x00000000 // Rsrv, UsgF, BusF, MemM + STR r1, [r0, #0xD18] // Setup System Handlers 4-7 Priority Registers + LDR r1, =0xFF000000 // SVCl, Rsrv, Rsrv, Rsrv + STR r1, [r0, #0xD1C] // Setup System Handlers 8-11 Priority Registers + // Note: SVC must be lowest priority, which is 0xFF + LDR r1, =0x40FF0000 // SysT, PnSV, Rsrv, DbgM + STR r1, [r0, #0xD20] // Setup System Handlers 12-15 Priority Registers + // Note: PnSV must be lowest priority, which is 0xFF + + /* Return to caller. */ + BX lr +// } + + +/* Define initial heap/stack routine for the ARM RVCT startup code. + This routine will set the initial stack and heap locations */ + + EXPORT __user_initial_stackheap +__user_initial_stackheap + LDR r0, =HeapMem + LDR r1, =(StackMem + STACK_SIZE) + LDR r2, =(HeapMem + HEAP_SIZE) + LDR r3, =StackMem + BX lr + + +/* Define shells for each of the unused vectors. */ + + EXPORT __tx_BadHandler +__tx_BadHandler + B __tx_BadHandler + + EXPORT __tx_SVCallHandler +__tx_SVCallHandler + B __tx_SVCallHandler + + EXPORT __tx_IntHandler +__tx_IntHandler +// VOID InterruptHandler (VOID) +// { + PUSH {r0, lr} +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + BL _tx_execution_isr_enter // Call the ISR enter function +#endif + /* Do interrupt handler work here */ + /* .... */ +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + BL _tx_execution_isr_exit // Call the ISR exit function +#endif + POP {r0, lr} + BX lr +// } + +#ifndef TX_NO_TIMER + EXPORT __tx_SysTickHandler +__tx_SysTickHandler +// VOID TimerInterruptHandler (VOID) +// { + PUSH {r0, lr} +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + BL _tx_execution_isr_enter // Call the ISR enter function +#endif + BL _tx_timer_interrupt +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + BL _tx_execution_isr_exit // Call the ISR exit function +#endif + POP {r0, lr} + BX lr +// } +#endif + + EXPORT __tx_NMIHandler +__tx_NMIHandler + B __tx_NMIHandler + + EXPORT __tx_DBGHandler +__tx_DBGHandler + B __tx_DBGHandler + + ALIGN + LTORG + END diff --git a/ports_arch/ARMv7-M/threadx/ac5/readme_threadx.txt b/ports_arch/ARMv7-M/threadx/ac5/readme_threadx.txt new file mode 100644 index 00000000..b7b7cee9 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac5/readme_threadx.txt @@ -0,0 +1,208 @@ + Microsoft's Azure RTOS ThreadX for ARMv7-M + (Cortex-M3, Cortex-M4, Cortex-M7) + Using ARM Compiler 5 (AC5) + + +1. Building the ThreadX run-time Library + +Navigate to the "example_build" directory. Ensure that +you have setup your path and other environment variables necessary for the AC5 +compiler. At this point you may run the build_threadx.bat batch file. This will +build the ThreadX run-time environment in the "example_build" directory. + +You should observe assembly and compilation of a series of ThreadX source +files. At the end of the batch file, they are all combined into the +run-time library file: tx.a. This file must be linked with your +application in order to use ThreadX. + + +2. Demonstration System + +The ThreadX demonstration is designed to execute under the ARM DS Cortex-M +simulator. + +Building the demonstration is easy; simply execute the build_threadx_sample.bat +batch file while inside the "example_build" directory. + +You should observe the compilation of sample_threadx.c (which is the demonstration +application) and linking with tx.a. The resulting file sample_threadx.axf +is a binary file that can be downloaded and executed on the ARM DS Cortex-M +simulator. + + +3. System Initialization + +The entry point in ThreadX for the Cortex-M using AC5 tools is at label +__main. This is defined within the AC5 compiler's startup code. In +addition, this is where all static and global pre-set C variable +initialization processing takes place. + +The ThreadX tx_initialize_low_level.s file is responsible for setting up +various system data structures, the vector area, and a periodic timer interrupt +source. + +In addition, _tx_initialize_low_level determines the first available +address for use by the application, which is supplied as the sole input +parameter to your application definition function, tx_application_define. + + +4. Register Usage and Stack Frames + +The following defines the saved context stack frames for context switches +that occur as a result of interrupt handling or from thread-level API calls. +All suspended threads have the same stack frame in the Cortex-M version of +ThreadX. The top of the suspended thread's stack is pointed to by +tx_thread_stack_ptr in the associated thread control block TX_THREAD. + +Non-FPU Stack Frame: + + Stack Offset Stack Contents + + 0x00 lr Interrupted lr (lr at time of PENDSV) + 0x04 r4 Software stacked GP registers + 0x08 r5 + 0x0C r6 + 0x10 r7 + 0x14 r8 + 0x18 r9 + 0x1C r10 + 0x20 r11 + 0x24 r0 Hardware stacked registers + 0x28 r1 + 0x2C r2 + 0x30 r3 + 0x34 r12 + 0x38 lr + 0x3C pc + 0x40 xPSR + +FPU Stack Frame (only interrupted thread with FPU enabled): + + Stack Offset Stack Contents + + 0x00 lr Interrupted lr (lr at time of PENDSV) + 0x04 s16 Software stacked FPU registers + 0x08 s17 + 0x0C s18 + 0x10 s19 + 0x14 s20 + 0x18 s21 + 0x1C s22 + 0x20 s23 + 0x24 s24 + 0x28 s25 + 0x2C s26 + 0x30 s27 + 0x34 s28 + 0x38 s29 + 0x3C s30 + 0x40 s31 + 0x44 r4 Software stacked registers + 0x48 r5 + 0x4C r6 + 0x50 r7 + 0x54 r8 + 0x58 r9 + 0x5C r10 + 0x60 r11 + 0x64 r0 Hardware stacked registers + 0x68 r1 + 0x6C r2 + 0x70 r3 + 0x74 r12 + 0x78 lr + 0x7C pc + 0x80 xPSR + 0x84 s0 Hardware stacked FPU registers + 0x88 s1 + 0x8C s2 + 0x90 s3 + 0x94 s4 + 0x98 s5 + 0x9C s6 + 0xA0 s7 + 0xA4 s8 + 0xA8 s9 + 0xAC s10 + 0xB0 s11 + 0xB4 s12 + 0xB8 s13 + 0xBC s14 + 0xC0 s15 + 0xC4 fpscr + + +5. Improving Performance + +The distribution version of ThreadX is built without any compiler +optimizations. This makes it easy to debug because you can trace or set +breakpoints inside of ThreadX itself. Of course, this costs some +performance. To make it run faster, you can change the ThreadX library +project to enable various compiler optimizations. + +In addition, you can eliminate the ThreadX basic API error checking by +compiling your application code with the symbol TX_DISABLE_ERROR_CHECKING +defined. + + +6. Interrupt Handling + +ThreadX provides complete and high-performance interrupt handling for Cortex-M +targets. There are a certain set of requirements that are defined in the +following sub-sections: + + +6.1 Vector Area + +The Cortex-M vectors start at the label __tx_vectors. The application may modify +the vector area according to its needs. + + +6.2 Managed Interrupts + +ISRs for Cortex-M can be written completely in C (or assembly language) without any +calls to _tx_thread_context_save or _tx_thread_context_restore. These ISRs are allowed +access to the ThreadX API that is available to ISRs. + +ISRs written in C will take the form (where "your_C_isr" is an entry in the vector table): + +void your_C_isr(void) +{ + + /* ISR processing goes here, including any needed function calls. */ +} + +ISRs written in assembly language will take the form: + + EXPORT your_assembly_isr +your_assembly_isr + + PUSH {r0, lr} + + ; ISR processing goes here, including any needed function calls. + + POP {r0, lr} + BX lr + + +7. FPU Support + +ThreadX for Cortex-M supports automatic ("lazy") VFP support, which means that applications threads +can simply use the VFP and ThreadX automatically maintains the VFP registers as part of the thread +context - no additional setup by the application. + + +8. Revision History + +For generic code revision information, please refer to the readme_threadx_generic.txt +file, which is included in your distribution. The following details the revision +information associated with this specific port of ThreadX: + +06-02-2021 Initial ThreadX version 6.1.7 for Cortex-M using AC5 tools. + + +Copyright(c) 1996-2021 Microsoft Corporation + + +https://azure.com/rtos + diff --git a/ports_arch/ARMv7-M/threadx/ac5/src/tx_thread_context_restore.s b/ports_arch/ARMv7-M/threadx/ac5/src/tx_thread_context_restore.s new file mode 100644 index 00000000..00c88632 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac5/src/tx_thread_context_restore.s @@ -0,0 +1,83 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + IMPORT _tx_execution_isr_exit +#endif + + AREA ||.text||, CODE, READONLY + PRESERVE8 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_restore Cortex-Mx/AC5 */ +/* 6.1.7 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is only needed for legacy applications and it should */ +/* not be called in any new development on a Cortex-M. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* [_tx_execution_isr_exit] Execution profiling ISR exit */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs Interrupt Service Routines */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_context_restore(VOID) +// { + EXPORT _tx_thread_context_restore +_tx_thread_context_restore + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the ISR exit function to indicate an ISR is complete. */ + PUSH {r0, lr} // Save return address + BL _tx_execution_isr_exit // Call the ISR exit function + POP {r0, lr} // Recover return address +#endif + + BX lr +// } + ALIGN + LTORG + END diff --git a/ports_arch/ARMv7-M/threadx/ac5/src/tx_thread_context_save.s b/ports_arch/ARMv7-M/threadx/ac5/src/tx_thread_context_save.s new file mode 100644 index 00000000..e7913e7d --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac5/src/tx_thread_context_save.s @@ -0,0 +1,85 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + IMPORT _tx_execution_isr_enter +#endif + + AREA ||.text||, CODE, READONLY + PRESERVE8 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_save Cortex-Mx/AC5 */ +/* 6.1.7 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is only needed for legacy applications and it should */ +/* not be called in any new development on a Cortex-M. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* [_tx_execution_isr_enter] Execution profiling ISR enter */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_context_save(VOID) +// { + EXPORT _tx_thread_context_save +_tx_thread_context_save + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the ISR enter function to indicate an ISR is starting. */ + PUSH {r0, lr} // Save return address + BL _tx_execution_isr_enter // Call the ISR enter function + POP {r0, lr} // Recover return address +#endif + + /* Context is already saved - just return. */ + + BX lr +// } + ALIGN + LTORG + END diff --git a/ports_arch/ARMv7-M/threadx/ac5/src/tx_thread_interrupt_control.s b/ports_arch/ARMv7-M/threadx/ac5/src/tx_thread_interrupt_control.s new file mode 100644 index 00000000..657ed26b --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac5/src/tx_thread_interrupt_control.s @@ -0,0 +1,77 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + AREA ||.text||, CODE, READONLY +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_control Cortex-Mx/AC5 */ +/* 6.1.7 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for changing the interrupt lockout */ +/* posture of the system. */ +/* */ +/* INPUT */ +/* */ +/* new_posture New interrupt lockout posture */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_interrupt_control(UINT new_posture) +// { + EXPORT _tx_thread_interrupt_control +_tx_thread_interrupt_control +#ifdef TX_PORT_USE_BASEPRI + MRS r1, BASEPRI // Pickup current interrupt posture + MSR BASEPRI, r0 // Apply the new interrupt posture + MOV r0, r1 // Transfer old to return register +#else + MRS r1, PRIMASK // Pickup current interrupt lockout + MSR PRIMASK, r0 // Apply the new interrupt lockout + MOV r0, r1 // Transfer old to return register +#endif + BX lr // Return to caller +// } + END diff --git a/ports_arch/ARMv7-M/threadx/ac5/src/tx_thread_interrupt_disable.s b/ports_arch/ARMv7-M/threadx/ac5/src/tx_thread_interrupt_disable.s new file mode 100644 index 00000000..34708d62 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac5/src/tx_thread_interrupt_disable.s @@ -0,0 +1,77 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + AREA ||.text||, CODE, READONLY +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_disable Cortex-Mx/AC5 */ +/* 6.1.7 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for disabling interrupts and returning */ +/* the previous interrupt lockout posture. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_interrupt_disable(VOID) +// { + EXPORT _tx_thread_interrupt_disable +_tx_thread_interrupt_disable + /* Return current interrupt lockout posture. */ +#ifdef TX_PORT_USE_BASEPRI + MRS r0, BASEPRI + LDR r1, =TX_PORT_BASEPRI + MSR BASEPRI, r1 +#else + MRS r0, PRIMASK + CPSID i +#endif + BX lr +// } + END diff --git a/ports_arch/ARMv7-M/threadx/ac5/src/tx_thread_interrupt_restore.s b/ports_arch/ARMv7-M/threadx/ac5/src/tx_thread_interrupt_restore.s new file mode 100644 index 00000000..2415032d --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac5/src/tx_thread_interrupt_restore.s @@ -0,0 +1,75 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + AREA ||.text||, CODE, READONLY +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_restore Cortex-Mx/AC5 */ +/* 6.1.7 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for restoring the previous */ +/* interrupt lockout posture. */ +/* */ +/* INPUT */ +/* */ +/* previous_posture Previous interrupt posture */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_interrupt_restore(UINT previous_posture) +// { + EXPORT _tx_thread_interrupt_restore +_tx_thread_interrupt_restore + + /* Restore previous interrupt lockout posture. */ +#ifdef TX_PORT_USE_BASEPRI + MSR BASEPRI, r0 +#else + MSR PRIMASK, r0 +#endif + BX lr +// } + END diff --git a/ports_arch/ARMv7-M/threadx/ac5/src/tx_thread_schedule.s b/ports_arch/ARMv7-M/threadx/ac5/src/tx_thread_schedule.s new file mode 100644 index 00000000..c5dc3a2e --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac5/src/tx_thread_schedule.s @@ -0,0 +1,325 @@ +/**************************************************************************/ +/* */ +/* 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 + IMPORT _tx_thread_system_stack_ptr + IMPORT _tx_thread_preempt_disable +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + IMPORT _tx_execution_thread_enter + IMPORT _tx_execution_thread_exit +#endif + + AREA ||.text||, CODE, READONLY + PRESERVE8 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_schedule Cortex-Mx/AC5 */ +/* 6.1.11 */ +/* 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 */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 04-25-2022 Scott Larson Added BASEPRI support, */ +/* resulting in version 6.1.11 */ +/* */ +/**************************************************************************/ +// 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 + + /* Clear CONTROL.FPCA bit so VFP registers aren't unnecessarily stacked. */ + +#ifdef __TARGET_FPU_VFP + MRS r0, CONTROL // Pickup current CONTROL register + BIC r0, r0, #4 // Clear the FPCA bit + MSR CONTROL, r0 // Setup new CONTROL register +#endif + + /* 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 +// } + + /* Generic context switching PendSV handler. */ + + EXPORT __tx_PendSVHandler + EXPORT PendSV_Handler +__tx_PendSVHandler +PendSV_Handler + + /* 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? + CBZ r1, __tx_ts_wait // No, skip to the wait processing + + /* Yes, another thread is ready for else, make the current thread the new thread. */ + + 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. */ + +__tx_ts_restore + 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 + 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! + + /* 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 + STR r1, [r0] // Store it in the current 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 + + /* Re-enable interrupts and restore new thread. */ +#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_restore // Restore the 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 + LTORG + END diff --git a/ports_arch/ARMv7-M/threadx/ac5/src/tx_thread_stack_build.s b/ports_arch/ARMv7-M/threadx/ac5/src/tx_thread_stack_build.s new file mode 100644 index 00000000..6f1c452f --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac5/src/tx_thread_stack_build.s @@ -0,0 +1,131 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + AREA ||.text||, CODE, READONLY +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_stack_build Cortex-Mx/AC5 */ +/* 6.1.7 */ +/* 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 control blk */ +/* function_ptr Pointer to return function */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_create Create thread service */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID)) +// { + EXPORT _tx_thread_stack_build +_tx_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 for 8-byte alignment + 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, #24] // Store initial r9 + STR r3, [r2, #28] // Store initial r10 + STR r3, [r2, #32] // Store initial r11 + + /* Hardware stack follows. */ + + STR r3, [r2, #36] // Store initial r0 + STR r3, [r2, #40] // Store initial r1 + 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 diff --git a/ports_arch/ARMv7-M/threadx/ac5/src/tx_thread_system_return.s b/ports_arch/ARMv7-M/threadx/ac5/src/tx_thread_system_return.s new file mode 100644 index 00000000..0feb88c6 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac5/src/tx_thread_system_return.s @@ -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 */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + AREA ||.text||, CODE, READONLY +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_system_return Cortex-Mx/AC5 */ +/* 6.1.7 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is target processor specific. It is used to transfer */ +/* control from a thread back to the ThreadX system. Only a */ +/* minimal context is saved since the compiler assumes temp registers */ +/* are going to get slicked by a function call anyway. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_schedule Thread scheduling loop */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX components */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_system_return(VOID) +// { + EXPORT _tx_thread_system_return +_tx_thread_system_return + + /* Return to real scheduler via PendSV. Note that this routine is often + replaced with in-line assembly in tx_port.h to improved performance. */ + + MOV r0, #0x10000000 // Load PENDSVSET bit + MOV r1, #0xE000E000 // Load NVIC base + STR r0, [r1, #0xD04] // Set PENDSVBIT in ICSR + MRS r0, IPSR // Pickup IPSR + CMP r0, #0 // Is it a thread returning? + BNE _isr_context // If ISR, skip interrupt enable +#ifdef TX_PORT_USE_BASEPRI + MRS r1, BASEPRI // Thread context returning, pickup BASEPRI + MOV r0, #0 + MSR BASEPRI, r0 // Enable interrupts + MSR BASEPRI, r1 // Restore original interrupt posture +#else + MRS r1, PRIMASK // Thread context returning, pickup PRIMASK + CPSIE i // Enable interrupts + MSR PRIMASK, r1 // Restore original interrupt posture +#endif +_isr_context + BX lr // Return to caller +// } + END diff --git a/ports_arch/ARMv7-M/threadx/ac5/src/tx_timer_interrupt.s b/ports_arch/ARMv7-M/threadx/ac5/src/tx_timer_interrupt.s new file mode 100644 index 00000000..ab23bebf --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac5/src/tx_timer_interrupt.s @@ -0,0 +1,259 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + IMPORT _tx_timer_time_slice + IMPORT _tx_timer_system_clock + IMPORT _tx_timer_current_ptr + IMPORT _tx_timer_list_start + IMPORT _tx_timer_list_end + IMPORT _tx_timer_expired_time_slice + IMPORT _tx_timer_expired + IMPORT _tx_thread_time_slice + IMPORT _tx_timer_expiration_process + IMPORT _tx_thread_preempt_disable + IMPORT _tx_thread_current_ptr + IMPORT _tx_thread_execute_ptr + + AREA ||.text||, CODE, READONLY + PRESERVE8 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_interrupt Cortex-Mx/AC5 */ +/* 6.1.10 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the hardware timer interrupt. This */ +/* processing includes incrementing the system clock and checking for */ +/* time slice and/or timer expiration. If either is found, the */ +/* expiration functions are called. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_timer_expiration_process Timer expiration processing */ +/* _tx_thread_time_slice Time slice interrupted thread */ +/* */ +/* CALLED BY */ +/* */ +/* interrupt vector */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 01-31-2022 Scott Larson Modified comment(s), added */ +/* TX_NO_TIMER support, */ +/* resulting in version 6.1.10 */ +/* */ +/**************************************************************************/ +// VOID _tx_timer_interrupt(VOID) +// { +#ifndef TX_NO_TIMER + EXPORT _tx_timer_interrupt +_tx_timer_interrupt + + /* Upon entry to this routine, it is assumed that the compiler scratch registers are available + for use. */ + + /* Increment the system clock. */ + // _tx_timer_system_clock++; + + LDR r1, =_tx_timer_system_clock // Pickup address of system clock + LDR r0, [r1, #0] // Pickup system clock + ADD r0, r0, #1 // Increment system clock + STR r0, [r1, #0] // Store new system clock + + /* Test for time-slice expiration. */ + // if (_tx_timer_time_slice) + // { + + LDR r3, =_tx_timer_time_slice // Pickup address of time-slice + LDR r2, [r3, #0] // Pickup time-slice + CBZ r2, __tx_timer_no_time_slice // Is it non-active? + // Yes, skip time-slice processing + + /* Decrement the time_slice. */ + // _tx_timer_time_slice--; + + SUB r2, r2, #1 // Decrement the time-slice + STR r2, [r3, #0] // Store new time-slice value + + /* Check for expiration. */ + // if (__tx_timer_time_slice == 0) + + CBNZ r2, __tx_timer_no_time_slice // Has it expired? + // No, skip expiration processing + + /* Set the time-slice expired flag. */ + // _tx_timer_expired_time_slice = TX_TRUE; + + LDR r3, =_tx_timer_expired_time_slice // Pickup address of expired flag + MOV r0, #1 // Build expired value + STR r0, [r3, #0] // Set time-slice expiration flag + + // } + +__tx_timer_no_time_slice + + /* Test for timer expiration. */ + // if (*_tx_timer_current_ptr) + // { + + LDR r1, =_tx_timer_current_ptr // Pickup current timer pointer address + LDR r0, [r1, #0] // Pickup current timer + LDR r2, [r0, #0] // Pickup timer list entry + CBZ r2, __tx_timer_no_timer // Is there anything in the list? + // No, just increment the timer + + /* Set expiration flag. */ + // _tx_timer_expired = TX_TRUE; + + LDR r3, =_tx_timer_expired // Pickup expiration flag address + MOV r2, #1 // Build expired value + STR r2, [r3, #0] // Set expired flag + B __tx_timer_done // Finished timer processing + + // } + // else + // { +__tx_timer_no_timer + + /* No timer expired, increment the timer pointer. */ + // _tx_timer_current_ptr++; + + ADD r0, r0, #4 // Move to next timer + + /* Check for wrap-around. */ + // if (_tx_timer_current_ptr == _tx_timer_list_end) + + LDR r3, =_tx_timer_list_end // Pickup addr of timer list end + LDR r2, [r3, #0] // Pickup list end + CMP r0, r2 // Are we at list end? + BNE __tx_timer_skip_wrap // No, skip wrap-around logic + + /* Wrap to beginning of list. */ + // _tx_timer_current_ptr = _tx_timer_list_start; + + LDR r3, =_tx_timer_list_start // Pickup addr of timer list start + LDR r0, [r3, #0] // Set current pointer to list start + +__tx_timer_skip_wrap + + STR r0, [r1, #0] // Store new current timer pointer + // } + +__tx_timer_done + + /* See if anything has expired. */ + // if ((_tx_timer_expired_time_slice) || (_tx_timer_expired)) + // { + + LDR r3, =_tx_timer_expired_time_slice // Pickup addr of expired flag + LDR r2, [r3, #0] // Pickup time-slice expired flag + CBNZ r2, __tx_something_expired // Did a time-slice expire? + // If non-zero, time-slice expired + LDR r1, =_tx_timer_expired // Pickup addr of other expired flag + LDR r0, [r1, #0] // Pickup timer expired flag + CBZ r0, __tx_timer_nothing_expired // Did a timer expire? + // No, nothing expired + +__tx_something_expired + + STMDB sp!, {r0, lr} // Save the lr register on the stack + // and save r0 just to keep 8-byte alignment + + /* Did a timer expire? */ + // if (_tx_timer_expired) + // { + + LDR r1, =_tx_timer_expired // Pickup addr of expired flag + LDR r0, [r1, #0] // Pickup timer expired flag + CBZ r0, __tx_timer_dont_activate // Check for timer expiration + // If not set, skip timer activation + + /* Process timer expiration. */ + // _tx_timer_expiration_process(); + + BL _tx_timer_expiration_process // Call the timer expiration handling routine + + // } +__tx_timer_dont_activate + + /* Did time slice expire? */ + // if (_tx_timer_expired_time_slice) + // { + + LDR r3, =_tx_timer_expired_time_slice // Pickup addr of time-slice expired + LDR r2, [r3, #0] // Pickup the actual flag + CBZ r2, __tx_timer_not_ts_expiration // See if the flag is set + // No, skip time-slice processing + + /* Time slice interrupted thread. */ + // _tx_thread_time_slice(); + + BL _tx_thread_time_slice // Call time-slice processing + LDR r0, =_tx_thread_preempt_disable // Build address of preempt disable flag + LDR r1, [r0] // Is the preempt disable flag set? + CBNZ r1, __tx_timer_skip_time_slice // Yes, skip the PendSV logic + LDR r0, =_tx_thread_current_ptr // Build current thread pointer address + LDR r1, [r0] // Pickup the current thread pointer + LDR r2, =_tx_thread_execute_ptr // Build execute thread pointer address + LDR r3, [r2] // Pickup the execute thread pointer + LDR r0, =0xE000ED04 // Build address of control register + LDR r2, =0x10000000 // Build value for PendSV bit + CMP r1, r3 // Are they the same? + BEQ __tx_timer_skip_time_slice // If the same, there was no time-slice performed + STR r2, [r0] // Not the same, issue the PendSV for preemption +__tx_timer_skip_time_slice + + // } + +__tx_timer_not_ts_expiration + + LDMIA sp!, {r0, lr} // Recover lr register (r0 is just there for + // the 8-byte stack alignment + + // } + +__tx_timer_nothing_expired + + DSB // Complete all memory access + BX lr // Return to caller +// } +#endif + ALIGN + LTORG + END diff --git a/ports_arch/ARMv7-M/threadx/ac6/example_build/sample_threadx/sample_threadx.c b/ports_arch/ARMv7-M/threadx/ac6/example_build/sample_threadx/sample_threadx.c new file mode 100644 index 00000000..597f373c --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac6/example_build/sample_threadx/sample_threadx.c @@ -0,0 +1,370 @@ +/* This is a small demo of the high-performance ThreadX kernel. It includes examples of eight + threads of different priorities, using a message queue, semaphore, mutex, event flags group, + byte pool, and block pool. */ + +#include "tx_api.h" + +#define DEMO_STACK_SIZE 1024 +#define DEMO_BYTE_POOL_SIZE 9120 +#define DEMO_BLOCK_POOL_SIZE 100 +#define DEMO_QUEUE_SIZE 100 + + +/* Define the ThreadX object control blocks... */ + +TX_THREAD thread_0; +TX_THREAD thread_1; +TX_THREAD thread_2; +TX_THREAD thread_3; +TX_THREAD thread_4; +TX_THREAD thread_5; +TX_THREAD thread_6; +TX_THREAD thread_7; +TX_QUEUE queue_0; +TX_SEMAPHORE semaphore_0; +TX_MUTEX mutex_0; +TX_EVENT_FLAGS_GROUP event_flags_0; +TX_BYTE_POOL byte_pool_0; +TX_BLOCK_POOL block_pool_0; +UCHAR memory_area[DEMO_BYTE_POOL_SIZE]; + + +/* Define the counters used in the demo application... */ + +ULONG thread_0_counter; +ULONG thread_1_counter; +ULONG thread_1_messages_sent; +ULONG thread_2_counter; +ULONG thread_2_messages_received; +ULONG thread_3_counter; +ULONG thread_4_counter; +ULONG thread_5_counter; +ULONG thread_6_counter; +ULONG thread_7_counter; + + +/* Define thread prototypes. */ + +void thread_0_entry(ULONG thread_input); +void thread_1_entry(ULONG thread_input); +void thread_2_entry(ULONG thread_input); +void thread_3_and_4_entry(ULONG thread_input); +void thread_5_entry(ULONG thread_input); +void thread_6_and_7_entry(ULONG thread_input); + + +/* Define main entry point. */ + +int main() +{ + + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); +} + + +/* Define what the initial system looks like. */ + +void tx_application_define(void *first_unused_memory) +{ + +CHAR *pointer = TX_NULL; + + + /* Create a byte memory pool from which to allocate the thread stacks. */ + tx_byte_pool_create(&byte_pool_0, "byte pool 0", memory_area, DEMO_BYTE_POOL_SIZE); + + /* Put system definition stuff in here, e.g. thread creates and other assorted + create information. */ + + /* Allocate the stack for thread 0. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create the main thread. */ + tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0, + pointer, DEMO_STACK_SIZE, + 1, 1, TX_NO_TIME_SLICE, TX_AUTO_START); + + + /* Allocate the stack for thread 1. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create threads 1 and 2. These threads pass information through a ThreadX + message queue. It is also interesting to note that these threads have a time + slice. */ + tx_thread_create(&thread_1, "thread 1", thread_1_entry, 1, + pointer, DEMO_STACK_SIZE, + 16, 16, 4, TX_AUTO_START); + + /* Allocate the stack for thread 2. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + tx_thread_create(&thread_2, "thread 2", thread_2_entry, 2, + pointer, DEMO_STACK_SIZE, + 16, 16, 4, TX_AUTO_START); + + /* Allocate the stack for thread 3. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create threads 3 and 4. These threads compete for a ThreadX counting semaphore. + An interesting thing here is that both threads share the same instruction area. */ + tx_thread_create(&thread_3, "thread 3", thread_3_and_4_entry, 3, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 4. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + tx_thread_create(&thread_4, "thread 4", thread_3_and_4_entry, 4, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 5. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create thread 5. This thread simply pends on an event flag which will be set + by thread_0. */ + tx_thread_create(&thread_5, "thread 5", thread_5_entry, 5, + pointer, DEMO_STACK_SIZE, + 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 6. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create threads 6 and 7. These threads compete for a ThreadX mutex. */ + tx_thread_create(&thread_6, "thread 6", thread_6_and_7_entry, 6, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 7. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + tx_thread_create(&thread_7, "thread 7", thread_6_and_7_entry, 7, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the message queue. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_QUEUE_SIZE*sizeof(ULONG), TX_NO_WAIT); + + /* Create the message queue shared by threads 1 and 2. */ + tx_queue_create(&queue_0, "queue 0", TX_1_ULONG, pointer, DEMO_QUEUE_SIZE*sizeof(ULONG)); + + /* Create the semaphore used by threads 3 and 4. */ + tx_semaphore_create(&semaphore_0, "semaphore 0", 1); + + /* Create the event flags group used by threads 1 and 5. */ + tx_event_flags_create(&event_flags_0, "event flags 0"); + + /* Create the mutex used by thread 6 and 7 without priority inheritance. */ + tx_mutex_create(&mutex_0, "mutex 0", TX_NO_INHERIT); + + /* Allocate the memory for a small block pool. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_BLOCK_POOL_SIZE, TX_NO_WAIT); + + /* Create a block memory pool to allocate a message buffer from. */ + tx_block_pool_create(&block_pool_0, "block pool 0", sizeof(ULONG), pointer, DEMO_BLOCK_POOL_SIZE); + + /* Allocate a block and release the block memory. */ + tx_block_allocate(&block_pool_0, (VOID **) &pointer, TX_NO_WAIT); + + /* Release the block back to the pool. */ + tx_block_release(pointer); +} + + + +/* Define the test threads. */ + +void thread_0_entry(ULONG thread_input) +{ + +UINT status; + + + /* This thread simply sits in while-forever-sleep loop. */ + while(1) + { + + /* Increment the thread counter. */ + thread_0_counter++; + + /* Sleep for 10 ticks. */ + tx_thread_sleep(10); + + /* Set event flag 0 to wakeup thread 5. */ + status = tx_event_flags_set(&event_flags_0, 0x1, TX_OR); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + } +} + + +void thread_1_entry(ULONG thread_input) +{ + +UINT status; + + + /* This thread simply sends messages to a queue shared by thread 2. */ + while(1) + { + + /* Increment the thread counter. */ + thread_1_counter++; + + /* Send message to queue 0. */ + status = tx_queue_send(&queue_0, &thread_1_messages_sent, TX_WAIT_FOREVER); + + /* Check completion status. */ + if (status != TX_SUCCESS) + break; + + /* Increment the message sent. */ + thread_1_messages_sent++; + } +} + + +void thread_2_entry(ULONG thread_input) +{ + +ULONG received_message; +UINT status; + + /* This thread retrieves messages placed on the queue by thread 1. */ + while(1) + { + + /* Increment the thread counter. */ + thread_2_counter++; + + /* Retrieve a message from the queue. */ + status = tx_queue_receive(&queue_0, &received_message, TX_WAIT_FOREVER); + + /* Check completion status and make sure the message is what we + expected. */ + if ((status != TX_SUCCESS) || (received_message != thread_2_messages_received)) + break; + + /* Otherwise, all is okay. Increment the received message count. */ + thread_2_messages_received++; + } +} + + +void thread_3_and_4_entry(ULONG thread_input) +{ + +UINT status; + + + /* This function is executed from thread 3 and thread 4. As the loop + below shows, these function compete for ownership of semaphore_0. */ + while(1) + { + + /* Increment the thread counter. */ + if (thread_input == 3) + thread_3_counter++; + else + thread_4_counter++; + + /* Get the semaphore with suspension. */ + status = tx_semaphore_get(&semaphore_0, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Sleep for 2 ticks to hold the semaphore. */ + tx_thread_sleep(2); + + /* Release the semaphore. */ + status = tx_semaphore_put(&semaphore_0); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + } +} + + +void thread_5_entry(ULONG thread_input) +{ + +UINT status; +ULONG actual_flags; + + + /* This thread simply waits for an event in a forever loop. */ + while(1) + { + + /* Increment the thread counter. */ + thread_5_counter++; + + /* Wait for event flag 0. */ + status = tx_event_flags_get(&event_flags_0, 0x1, TX_OR_CLEAR, + &actual_flags, TX_WAIT_FOREVER); + + /* Check status. */ + if ((status != TX_SUCCESS) || (actual_flags != 0x1)) + break; + } +} + + +void thread_6_and_7_entry(ULONG thread_input) +{ + +UINT status; + + + /* This function is executed from thread 6 and thread 7. As the loop + below shows, these function compete for ownership of mutex_0. */ + while(1) + { + + /* Increment the thread counter. */ + if (thread_input == 6) + thread_6_counter++; + else + thread_7_counter++; + + /* Get the mutex with suspension. */ + status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Get the mutex again with suspension. This shows + that an owning thread may retrieve the mutex it + owns multiple times. */ + status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Sleep for 2 ticks to hold the mutex. */ + tx_thread_sleep(2); + + /* Release the mutex. */ + status = tx_mutex_put(&mutex_0); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Release the mutex again. This will actually + release ownership since it was obtained twice. */ + status = tx_mutex_put(&mutex_0); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + } +} diff --git a/ports_arch/ARMv7-M/threadx/ac6/example_build/sample_threadx/tx_initialize_low_level.S b/ports_arch/ARMv7-M/threadx/ac6/example_build/sample_threadx/tx_initialize_low_level.S new file mode 100644 index 00000000..3d1922b3 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac6/example_build/sample_threadx/tx_initialize_low_level.S @@ -0,0 +1,208 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Initialize */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .global _tx_thread_system_stack_ptr + .global _tx_initialize_unused_memory +#ifndef TX_NO_TIMER + .global _tx_timer_interrupt + .global __tx_SysTickHandler // SysTick +#endif + .global __main + .global __tx_SVCallHandler + .global __tx_PendSVHandler + .global __tx_NMIHandler // NMI + .global __tx_BadHandler // HardFault + .global __tx_SVCallHandler // SVCall + .global __tx_DBGHandler // Monitor + .global __tx_PendSVHandler // PendSV + + .global __tx_IntHandler // Int 0 + +SYSTEM_CLOCK = 6000000 +SYSTICK_CYCLES = ((SYSTEM_CLOCK / 100) -1) + + .text 32 + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_initialize_low_level Cortex-Mx/AC6 */ +/* 6.1.10 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for any low-level processor */ +/* initialization, including setting up interrupt vectors, setting */ +/* up a periodic timer interrupt source, saving the system stack */ +/* pointer for use in ISR processing later, and finding the first */ +/* available RAM memory address for tx_application_define. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_initialize_kernel_enter ThreadX entry function */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 01-31-2022 Scott Larson Modified comment(s), added */ +/* TX_NO_TIMER support, */ +/* resulting in version 6.1.10 */ +/* */ +/**************************************************************************/ +// VOID _tx_initialize_low_level(VOID) +// { + .global _tx_initialize_low_level + .thumb_func +_tx_initialize_low_level: + + /* Ensure that interrupts are disabled. */ + CPSID i + + /* Set base of available memory to end of non-initialised RAM area. */ + LDR r0, =_tx_initialize_unused_memory // Build address of unused memory pointer + LDR r1, =Image$$ARM_LIB_STACKHEAP$$ZI$$Limit // Build first free address + ADD r1, r1, #4 // + STR r1, [r0] // Setup first unused memory pointer + + /* Setup Vector Table Offset Register. */ + MOV r0, #0xE000E000 // Build address of NVIC registers + LDR r1, =vector_table // Pickup address of vector table + STR r1, [r0, #0xD08] // Set vector table address + + /* Set system stack pointer from vector value. */ + LDR r0, =_tx_thread_system_stack_ptr // Build address of system stack pointer + LDR r1, =vector_table // Pickup address of vector table + LDR r1, [r1] // Pickup reset stack pointer + STR r1, [r0] // Save system stack pointer + +#ifndef TX_NO_TIMER + /* Configure SysTick. */ + MOV r0, #0xE000E000 // Build address of NVIC registers + LDR r1, =SYSTICK_CYCLES + STR r1, [r0, #0x14] // Setup SysTick Reload Value + MOV r1, #0x7 // Build SysTick Control Enable Value + STR r1, [r0, #0x10] // Setup SysTick Control +#endif + + /* Configure handler priorities. */ + LDR r1, =0x00000000 // Rsrv, UsgF, BusF, MemM + STR r1, [r0, #0xD18] // Setup System Handlers 4-7 Priority Registers + LDR r1, =0xFF000000 // SVCl, Rsrv, Rsrv, Rsrv + STR r1, [r0, #0xD1C] // Setup System Handlers 8-11 Priority Registers + // Note: SVC must be lowest priority, which is 0xFF + LDR r1, =0x40FF0000 // SysT, PnSV, Rsrv, DbgM + STR r1, [r0, #0xD20] // Setup System Handlers 12-15 Priority Registers + // Note: PnSV must be lowest priority, which is 0xFF + + /* Return to caller. */ + BX lr +// } + +/* Define shells for each of the unused vectors. */ + .global __tx_BadHandler + .thumb_func +__tx_BadHandler: + B __tx_BadHandler + +/* added to catch the hardfault */ + .global __tx_HardfaultHandler + .thumb_func +__tx_HardfaultHandler: + B __tx_HardfaultHandler + +/* added to catch the SVC */ + .global __tx_SVCallHandler + .thumb_func +__tx_SVCallHandler: + B __tx_SVCallHandler + +/* Generic interrupt handler template */ + .global __tx_IntHandler + .thumb_func +__tx_IntHandler: +// VOID InterruptHandler (VOID) +// { + PUSH {r0, lr} +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + BL _tx_execution_isr_enter // Call the ISR enter function +#endif + /* Do interrupt handler work here */ + /* BL .... */ +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + BL _tx_execution_isr_exit // Call the ISR exit function +#endif + POP {r0, lr} + BX lr +// } + +#ifndef TX_NO_TIMER +/* System Tick timer interrupt handler */ + .global __tx_SysTickHandler + .global SysTick_Handler + .thumb_func +__tx_SysTickHandler: + .thumb_func +SysTick_Handler: +// VOID SysTick_Handler (VOID) +// { + PUSH {r0, lr} +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + BL _tx_execution_isr_enter // Call the ISR enter function +#endif + BL _tx_timer_interrupt +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + BL _tx_execution_isr_exit // Call the ISR exit function +#endif + POP {r0, lr} + BX lr +// } +#endif + +/* NMI, DBG handlers */ + .global __tx_NMIHandler + .thumb_func +__tx_NMIHandler: + B __tx_NMIHandler + + .global __tx_DBGHandler + .thumb_func +__tx_DBGHandler: + B __tx_DBGHandler diff --git a/ports_arch/ARMv7-M/threadx/ac6/example_build/tx/.cproject b/ports_arch/ARMv7-M/threadx/ac6/example_build/tx/.cproject new file mode 100644 index 00000000..b7df20f1 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac6/example_build/tx/.cproject @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ports_arch/ARMv7-M/threadx/ac6/example_build/tx/.project b/ports_arch/ARMv7-M/threadx/ac6/example_build/tx/.project new file mode 100644 index 00000000..863ca5cb --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac6/example_build/tx/.project @@ -0,0 +1,48 @@ + + + tx + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + + inc_generic + 2 + $%7BPARENT-5-PROJECT_LOC%7D/common/inc + + + inc_port + 2 + $%7BPARENT-2-PROJECT_LOC%7D/inc + + + src_generic + 2 + $%7BPARENT-5-PROJECT_LOC%7D/common/src + + + src_port + 2 + $%7BPARENT-2-PROJECT_LOC%7D/src + + + diff --git a/ports_arch/ARMv7-M/threadx/ac6/readme_threadx.txt b/ports_arch/ARMv7-M/threadx/ac6/readme_threadx.txt new file mode 100644 index 00000000..d98c90cb --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac6/readme_threadx.txt @@ -0,0 +1,209 @@ + Microsoft's Azure RTOS ThreadX for ARMv7-M + (Cortex-M3, Cortex-M4, Cortex-M7) + Using ARM Compiler 6 (AC6) + + +1. Building the ThreadX run-time Library + +In order to build the ThreadX library and the ThreadX demonstration, first import +the 'tx' and 'sample_threadx' projects (located in the "example_build" directory) +into your DS workspace. + +Building the ThreadX library is easy; simply right-click the Eclipse project +"tx" and then select the "Build Project" button. You should now observe the compilation +and assembly of the ThreadX library. This project build produces the ThreadX +library file tx.a. + + +2. Demonstration System + +The ThreadX demonstration is designed to execute under the DS debugger on the +MPS2_Cortex_Mx Bare Metal simulator. + +Building the demonstration is easy; simply right-click the Eclipse project +"sample_threadx" and then select the "Build Project" button. You should now observe +the compilation and assembly of the ThreadX demonstration. This project build produces +the ThreadX library file sample_threadx.axf. Next, expand the demo ThreadX project folder +in the Project Explorer window, right-click on the 'cortex-mx_tx.launch' file, click +'Debug As', and then click 'cortex-mx_tx' from the submenu. This will cause the +debugger to load the sample_threadx.axf ELF file and run to main. You are now ready +to execute the ThreadX demonstration. + + +3. System Initialization + +The entry point in ThreadX for the Cortex-M using AC6 tools uses the standard GNU +Cortex-M reset sequence. From the reset vector the C runtime will be initialized. + +The ThreadX tx_initialize_low_level.S file is responsible for setting up +various system data structures, the vector area, and a periodic timer interrupt +source. + +In addition, _tx_initialize_low_level determines the first available +address for use by the application, which is supplied as the sole input +parameter to your application definition function, tx_application_define. + + +4. Register Usage and Stack Frames + +The following defines the saved context stack frames for context switches +that occur as a result of interrupt handling or from thread-level API calls. +All suspended threads have the same stack frame in the Cortex-M version of +ThreadX. The top of the suspended thread's stack is pointed to by +tx_thread_stack_ptr in the associated thread control block TX_THREAD. + +Non-FPU Stack Frame: + + Stack Offset Stack Contents + + 0x00 lr Interrupted lr (lr at time of PENDSV) + 0x04 r4 Software stacked GP registers + 0x08 r5 + 0x0C r6 + 0x10 r7 + 0x14 r8 + 0x18 r9 + 0x1C r10 + 0x20 r11 + 0x24 r0 Hardware stacked registers + 0x28 r1 + 0x2C r2 + 0x30 r3 + 0x34 r12 + 0x38 lr + 0x3C pc + 0x40 xPSR + +FPU Stack Frame (only interrupted thread with FPU enabled): + + Stack Offset Stack Contents + + 0x00 lr Interrupted lr (lr at time of PENDSV) + 0x04 s16 Software stacked FPU registers + 0x08 s17 + 0x0C s18 + 0x10 s19 + 0x14 s20 + 0x18 s21 + 0x1C s22 + 0x20 s23 + 0x24 s24 + 0x28 s25 + 0x2C s26 + 0x30 s27 + 0x34 s28 + 0x38 s29 + 0x3C s30 + 0x40 s31 + 0x44 r4 Software stacked registers + 0x48 r5 + 0x4C r6 + 0x50 r7 + 0x54 r8 + 0x58 r9 + 0x5C r10 + 0x60 r11 + 0x64 r0 Hardware stacked registers + 0x68 r1 + 0x6C r2 + 0x70 r3 + 0x74 r12 + 0x78 lr + 0x7C pc + 0x80 xPSR + 0x84 s0 Hardware stacked FPU registers + 0x88 s1 + 0x8C s2 + 0x90 s3 + 0x94 s4 + 0x98 s5 + 0x9C s6 + 0xA0 s7 + 0xA4 s8 + 0xA8 s9 + 0xAC s10 + 0xB0 s11 + 0xB4 s12 + 0xB8 s13 + 0xBC s14 + 0xC0 s15 + 0xC4 fpscr + + +5. Improving Performance + +The distribution version of ThreadX is built without any compiler +optimizations. This makes it easy to debug because you can trace or set +breakpoints inside of ThreadX itself. Of course, this costs some +performance. To make it run faster, you can change the ThreadX library +project to enable various compiler optimizations. + +In addition, you can eliminate the ThreadX basic API error checking by +compiling your application code with the symbol TX_DISABLE_ERROR_CHECKING +defined. + + +6. Interrupt Handling + +ThreadX provides complete and high-performance interrupt handling for Cortex-M +targets. There are a certain set of requirements that are defined in the +following sub-sections: + + +6.1 Vector Area + +The Cortex-M vectors start at the label __tx_vectors or similar. The application may modify +the vector area according to its needs. There is code in tx_initialize_low_level() that will +configure the vector base register. + + +6.2 Managed Interrupts + +A ThreadX managed interrupt is defined below. By following these conventions, the +application ISR is then allowed access to various ThreadX services from the ISR. +Here is the standard template for managed ISRs in ThreadX: + + + .global __tx_IntHandler + .thumb_func +__tx_IntHandler: +; VOID InterruptHandler (VOID) +; { + PUSH {r0, lr} + +; /* Do interrupt handler work here */ +; /* BL */ + + POP {r0, lr} + BX lr +; } + + +Note: the Cortex-M requires exception handlers to be thumb labels, this implies bit 0 set. +To accomplish this, the declaration of the label has to be preceded by the assembler directive +.thumb_func to instruct the linker to create thumb labels. The label __tx_IntHandler needs to +be inserted in the correct location in the interrupt vector table. This table is typically +located in either your runtime startup file or in the tx_initialize_low_level.S file. + + +7. FPU Support + +ThreadX for Cortex-M supports automatic ("lazy") VFP support, which means that applications threads +can simply use the VFP and ThreadX automatically maintains the VFP registers as part of the thread +context - no additional setup by the application. + + +8. Revision History + +For generic code revision information, please refer to the readme_threadx_generic.txt +file, which is included in your distribution. The following details the revision +information associated with this specific port of ThreadX: + +06-02-2021 Initial ThreadX version 6.1.7 for Cortex-M using AC6 tools. + + +Copyright(c) 1996-2021 Microsoft Corporation + + +https://azure.com/rtos + diff --git a/ports_arch/ARMv7-M/threadx/ac6/src/tx_misra.S b/ports_arch/ARMv7-M/threadx/ac6/src/tx_misra.S new file mode 100644 index 00000000..c84d8576 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac6/src/tx_misra.S @@ -0,0 +1,723 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + #define SHT_PROGBITS 0x1 + + .global __aeabi_memset + .global _tx_thread_current_ptr + .global _tx_thread_interrupt_disable + .global _tx_thread_interrupt_restore + .global _tx_thread_stack_analyze + .global _tx_thread_stack_error_handler + .global _tx_thread_system_state +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_trace_buffer_current_ptr + .global _tx_trace_buffer_end_ptr + .global _tx_trace_buffer_start_ptr + .global _tx_trace_event_enable_bits + .global _tx_trace_full_notify_function + .global _tx_trace_header_ptr +#endif + + .global _tx_misra_always_true + .global _tx_misra_block_pool_to_uchar_pointer_convert + .global _tx_misra_byte_pool_to_uchar_pointer_convert + .global _tx_misra_char_to_uchar_pointer_convert + .global _tx_misra_const_char_to_char_pointer_convert +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_entry_to_uchar_pointer_convert +#endif + .global _tx_misra_indirect_void_to_uchar_pointer_convert + .global _tx_misra_memset + .global _tx_misra_message_copy +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_object_to_uchar_pointer_convert +#endif + .global _tx_misra_pointer_to_ulong_convert + .global _tx_misra_status_get + .global _tx_misra_thread_stack_check +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_time_stamp_get +#endif + .global _tx_misra_timer_indirect_to_void_pointer_convert + .global _tx_misra_timer_pointer_add + .global _tx_misra_timer_pointer_dif +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_trace_event_insert +#endif + .global _tx_misra_uchar_pointer_add + .global _tx_misra_uchar_pointer_dif + .global _tx_misra_uchar_pointer_sub + .global _tx_misra_uchar_to_align_type_pointer_convert + .global _tx_misra_uchar_to_block_pool_pointer_convert +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_uchar_to_entry_pointer_convert + .global _tx_misra_uchar_to_header_pointer_convert +#endif + .global _tx_misra_uchar_to_indirect_byte_pool_pointer_convert + .global _tx_misra_uchar_to_indirect_uchar_pointer_convert +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_uchar_to_object_pointer_convert +#endif + .global _tx_misra_uchar_to_void_pointer_convert + .global _tx_misra_ulong_pointer_add + .global _tx_misra_ulong_pointer_dif + .global _tx_misra_ulong_pointer_sub + .global _tx_misra_ulong_to_pointer_convert + .global _tx_misra_ulong_to_thread_pointer_convert + .global _tx_misra_user_timer_pointer_get + .global _tx_misra_void_to_block_pool_pointer_convert + .global _tx_misra_void_to_byte_pool_pointer_convert + .global _tx_misra_void_to_event_flags_pointer_convert + .global _tx_misra_void_to_indirect_uchar_pointer_convert + .global _tx_misra_void_to_mutex_pointer_convert + .global _tx_misra_void_to_queue_pointer_convert + .global _tx_misra_void_to_semaphore_pointer_convert + .global _tx_misra_void_to_thread_pointer_convert + .global _tx_misra_void_to_uchar_pointer_convert + .global _tx_misra_void_to_ulong_pointer_convert + .global _tx_misra_ipsr_get + .global _tx_misra_control_get + .global _tx_misra_control_set +#ifdef __ARM_FP + .global _tx_misra_fpccr_get + .global _tx_misra_vfp_touch +#endif + + .global _tx_misra_event_flags_group_not_used + .global _tx_misra_event_flags_set_notify_not_used + .global _tx_misra_queue_not_used + .global _tx_misra_queue_send_notify_not_used + .global _tx_misra_semaphore_not_used + .global _tx_misra_semaphore_put_notify_not_used + .global _tx_misra_thread_entry_exit_notify_not_used + .global _tx_misra_thread_not_used + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_memset(VOID *ptr, UINT value, UINT size); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .align 4 + .syntax unified + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_uchar_pointer_add: + ADD R0,R0,R1 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UCHAR *_tx_misra_uchar_pointer_sub(UCHAR *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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)); */ +/** */ +/************************************************************************************************************************************/ +/************************************************************************************************************************************/ + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_ulong_pointer_add: + ADD R0,R0,R1, LSL #+2 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG *_tx_misra_ulong_pointer_sub(ULONG *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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 R2,=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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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 + + + .data +DataTable2_1: + .word _tx_trace_buffer_current_ptr + + .data +DataTable2_2: + .word _tx_trace_event_enable_bits + + .data +DataTable2_5: + .word _tx_trace_buffer_end_ptr + + .data +DataTable2_6: + .word _tx_trace_buffer_start_ptr + + .data +DataTable2_7: + .word _tx_trace_header_ptr + + .data +DataTable2_8: + .word _tx_trace_full_notify_function + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG _tx_misra_time_stamp_get(VOID); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_time_stamp_get: + MOVS R0,#+0 + BX LR // return + +#endif + + .data +DataTable2_3: + .word _tx_thread_system_state + + .data +DataTable2_4: + .word _tx_thread_current_ptr + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UINT _tx_misra_always_true(void); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_always_true: + MOVS R0,#+1 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UINT _tx_misra_status_get(UINT status); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_status_get: + MOVS R0,#+0 + BX LR // return + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** ULONG _tx_misra_ipsr_get(void); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_tx_misra_ipsr_get: + MRS R0, IPSR + BX LR // return + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** ULONG _tx_misra_control_get(void); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_tx_misra_control_get: + MRS R0, CONTROL + BX LR // return + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** void _tx_misra_control_set(ULONG value); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_tx_misra_control_set: + MSR CONTROL, R0 + BX LR // return + + +#ifdef __ARM_FP + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** ULONG _tx_misra_fpccr_get(void); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_tx_misra_vfp_touch: + vmov.f32 s0, s0 + BX LR // return + +#endif + + + .data + .word 0 diff --git a/ports_arch/ARMv7-M/threadx/ac6/src/tx_thread_context_restore.S b/ports_arch/ARMv7-M/threadx/ac6/src/tx_thread_context_restore.S new file mode 100644 index 00000000..a6ce499a --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac6/src/tx_thread_context_restore.S @@ -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 */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + .global _tx_execution_isr_exit +#endif + + .text + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_restore Cortex-Mx/AC6 */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is only needed for legacy applications and it should */ +/* not be called in any new development on a Cortex-M. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* [_tx_execution_isr_exit] Execution profiling ISR exit */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs Interrupt Service Routines */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_context_restore(VOID) +// { + .global _tx_thread_context_restore + .thumb_func +_tx_thread_context_restore: + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the ISR exit function to indicate an ISR is complete. */ + PUSH {r0, lr} // Save return address + BL _tx_execution_isr_exit // Call the ISR exit function + POP {r0, lr} // Recover return address +#endif + + BX lr +// } diff --git a/ports_arch/ARMv7-M/threadx/ac6/src/tx_thread_context_save.S b/ports_arch/ARMv7-M/threadx/ac6/src/tx_thread_context_save.S new file mode 100644 index 00000000..eb58634c --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac6/src/tx_thread_context_save.S @@ -0,0 +1,89 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .text + .align 4 + .syntax unified +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + .global _tx_execution_isr_enter +#endif +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_save Cortex-Mx/AC6 */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is only needed for legacy applications and it should */ +/* not be called in any new development on a Cortex-M. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* [_tx_execution_isr_enter] Execution profiling ISR enter */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_context_save(VOID) +// { + .global _tx_thread_context_save + .thumb_func +_tx_thread_context_save: + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the ISR enter function to indicate an ISR is starting. */ + PUSH {r0, lr} // Save return address + BL _tx_execution_isr_enter // Call the ISR enter function + POP {r0, lr} // Recover return address +#endif + + /* Context is already saved - just return. */ + + BX lr +// } diff --git a/ports_arch/ARMv7-M/threadx/ac6/src/tx_thread_interrupt_control.S b/ports_arch/ARMv7-M/threadx/ac6/src/tx_thread_interrupt_control.S new file mode 100644 index 00000000..375f7280 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac6/src/tx_thread_interrupt_control.S @@ -0,0 +1,85 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .text 32 + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_control Cortex-Mx/AC6 */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for changing the interrupt lockout */ +/* posture of the system. */ +/* */ +/* INPUT */ +/* */ +/* new_posture New interrupt lockout posture */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_interrupt_control(UINT new_posture) +// { + .global _tx_thread_interrupt_control + .thumb_func +_tx_thread_interrupt_control: +#ifdef TX_PORT_USE_BASEPRI + MRS r1, BASEPRI // Pickup current interrupt posture + MSR BASEPRI, r0 // Apply the new interrupt posture + MOV r0, r1 // Transfer old to return register +#else + MRS r1, PRIMASK // Pickup current interrupt lockout + MSR PRIMASK, r0 // Apply the new interrupt lockout + MOV r0, r1 // Transfer old to return register +#endif + BX lr // Return to caller +// } diff --git a/ports_arch/ARMv7-M/threadx/ac6/src/tx_thread_interrupt_disable.S b/ports_arch/ARMv7-M/threadx/ac6/src/tx_thread_interrupt_disable.S new file mode 100644 index 00000000..33917aa6 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac6/src/tx_thread_interrupt_disable.S @@ -0,0 +1,85 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .text 32 + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_disable Cortex-Mx/AC6 */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for disabling interrupts and returning */ +/* the previous interrupt lockout posture. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_interrupt_disable(VOID) +// { + .global _tx_thread_interrupt_disable + .thumb_func +_tx_thread_interrupt_disable: + /* Return current interrupt lockout posture. */ +#ifdef TX_PORT_USE_BASEPRI + MRS r0, BASEPRI + LDR r1, =TX_PORT_BASEPRI + MSR BASEPRI, r1 +#else + MRS r0, PRIMASK + CPSID i +#endif + BX lr +// } diff --git a/ports_arch/ARMv7-M/threadx/ac6/src/tx_thread_interrupt_restore.S b/ports_arch/ARMv7-M/threadx/ac6/src/tx_thread_interrupt_restore.S new file mode 100644 index 00000000..3f55f3b4 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac6/src/tx_thread_interrupt_restore.S @@ -0,0 +1,82 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .text 32 + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_restore Cortex-Mx/AC6 */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for restoring the previous */ +/* interrupt lockout posture. */ +/* */ +/* INPUT */ +/* */ +/* previous_posture Previous interrupt posture */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_interrupt_restore(UINT previous_posture) +// { + .global _tx_thread_interrupt_restore + .thumb_func +_tx_thread_interrupt_restore: + /* Restore previous interrupt lockout posture. */ +#ifdef TX_PORT_USE_BASEPRI + MSR BASEPRI, r0 +#else + MSR PRIMASK, r0 +#endif + BX lr +// } diff --git a/ports_arch/ARMv7-M/threadx/ac6/src/tx_thread_schedule.S b/ports_arch/ARMv7-M/threadx/ac6/src/tx_thread_schedule.S new file mode 100644 index 00000000..57c109f1 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac6/src/tx_thread_schedule.S @@ -0,0 +1,331 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .global _tx_thread_current_ptr + .global _tx_thread_execute_ptr + .global _tx_timer_time_slice +#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.1 */ +/* 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 */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 04-25-2022 Scott Larson Added BASEPRI support, */ +/* resulting in version 6.1.11 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// 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 + + /* Clear CONTROL.FPCA bit so VFP registers aren't unnecessarily stacked. */ + +#ifdef __ARM_PCS_VFP + MRS r0, CONTROL // Pickup current CONTROL register + BIC r0, r0, #4 // Clear the FPCA bit + MSR CONTROL, r0 // Setup new CONTROL register +#endif + + /* 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 +// } + + /* Generic context switching 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_PCS_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? + CBZ r1, __tx_ts_wait // No, skip to the wait processing + + /* Yes, another thread is ready for else, make the current thread the new thread. */ + + 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. */ + +__tx_ts_restore: + 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 + LDMIA r12!, {LR} // Pickup LR +#ifdef __ARM_PCS_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! + + /* 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 + STR r1, [r0] // Store it in the current 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 + + /* Re-enable interrupts and restore new thread. */ +#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_restore // Restore the thread +// } + +#ifdef __ARM_PCS_VFP + + .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 diff --git a/ports_arch/ARMv7-M/threadx/ac6/src/tx_thread_stack_build.S b/ports_arch/ARMv7-M/threadx/ac6/src/tx_thread_stack_build.S new file mode 100644 index 00000000..162eba62 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac6/src/tx_thread_stack_build.S @@ -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 */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .text + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_stack_build Cortex-Mx/AC6 */ +/* 6.2.1 */ +/* 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 control blk */ +/* function_ptr Pointer to return function */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_create Create thread service */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID)) +// { + .global _tx_thread_stack_build + .thumb_func +_tx_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 for 8-byte alignment + 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, #24] // Store initial r9 + STR r3, [r2, #28] // Store initial r10 + STR r3, [r2, #32] // Store initial r11 + + /* Hardware stack follows. */ + + STR r3, [r2, #36] // Store initial r0 + STR r3, [r2, #40] // Store initial r1 + 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 +// } diff --git a/ports_arch/ARMv7-M/threadx/ac6/src/tx_thread_system_return.S b/ports_arch/ARMv7-M/threadx/ac6/src/tx_thread_system_return.S new file mode 100644 index 00000000..756405f3 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac6/src/tx_thread_system_return.S @@ -0,0 +1,99 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .text 32 + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_system_return Cortex-Mx/AC6 */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is target processor specific. It is used to transfer */ +/* control from a thread back to the ThreadX system. Only a */ +/* minimal context is saved since the compiler assumes temp registers */ +/* are going to get slicked by a function call anyway. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_schedule Thread scheduling loop */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX components */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_system_return(VOID) +// { + .thumb_func + .global _tx_thread_system_return +_tx_thread_system_return: + + /* Return to real scheduler via PendSV. Note that this routine is often + replaced with in-line assembly in tx_port.h to improved performance. */ + + MOV r0, #0x10000000 // Load PENDSVSET bit + MOV r1, #0xE000E000 // Load NVIC base + STR r0, [r1, #0xD04] // Set PENDSVBIT in ICSR + MRS r0, IPSR // Pickup IPSR + CMP r0, #0 // Is it a thread returning? + BNE _isr_context // If ISR, skip interrupt enable +#ifdef TX_PORT_USE_BASEPRI + MRS r1, BASEPRI // Thread context returning, pickup BASEPRI + MOV r0, #0 + MSR BASEPRI, r0 // Enable interrupts + MSR BASEPRI, r1 // Restore original interrupt posture +#else + MRS r1, PRIMASK // Thread context returning, pickup PRIMASK + CPSIE i // Enable interrupts + MSR PRIMASK, r1 // Restore original interrupt posture +#endif +_isr_context: + BX lr // Return to caller +// } diff --git a/ports_arch/ARMv7-M/threadx/ac6/src/tx_timer_interrupt.S b/ports_arch/ARMv7-M/threadx/ac6/src/tx_timer_interrupt.S new file mode 100644 index 00000000..a896426d --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ac6/src/tx_timer_interrupt.S @@ -0,0 +1,261 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .global _tx_timer_time_slice + .global _tx_timer_system_clock + .global _tx_timer_current_ptr + .global _tx_timer_list_start + .global _tx_timer_list_end + .global _tx_timer_expired_time_slice + .global _tx_timer_expired + .global _tx_thread_time_slice + .global _tx_timer_expiration_process + + .text + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_interrupt Cortex-Mx/AC6 */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the hardware timer interrupt. This */ +/* processing includes incrementing the system clock and checking for */ +/* time slice and/or timer expiration. If either is found, the */ +/* expiration functions are called. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_timer_expiration_process Timer expiration processing */ +/* _tx_thread_time_slice Time slice interrupted thread */ +/* */ +/* CALLED BY */ +/* */ +/* interrupt vector */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 01-31-2022 Scott Larson Modified comment(s), added */ +/* TX_NO_TIMER support, */ +/* resulting in version 6.1.10 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_timer_interrupt(VOID) +// { +#ifndef TX_NO_TIMER + .global _tx_timer_interrupt + .thumb_func +_tx_timer_interrupt: + + /* Upon entry to this routine, it is assumed that the compiler scratch registers are available + for use. */ + + /* Increment the system clock. */ + // _tx_timer_system_clock++; + + LDR r1, =_tx_timer_system_clock // Pickup address of system clock + LDR r0, [r1, #0] // Pickup system clock + ADD r0, r0, #1 // Increment system clock + STR r0, [r1, #0] // Store new system clock + + /* Test for time-slice expiration. */ + // if (_tx_timer_time_slice) + // { + + LDR r3, =_tx_timer_time_slice // Pickup address of time-slice + LDR r2, [r3, #0] // Pickup time-slice + CBZ r2, __tx_timer_no_time_slice // Is it non-active? + // Yes, skip time-slice processing + + /* Decrement the time_slice. */ + // _tx_timer_time_slice--; + + SUB r2, r2, #1 // Decrement the time-slice + STR r2, [r3, #0] // Store new time-slice value + + /* Check for expiration. */ + // if (__tx_timer_time_slice == 0) + + CBNZ r2, __tx_timer_no_time_slice // Has it expired? + // No, skip expiration processing + + /* Set the time-slice expired flag. */ + // _tx_timer_expired_time_slice = TX_TRUE; + + LDR r3, =_tx_timer_expired_time_slice // Pickup address of expired flag + MOV r0, #1 // Build expired value + STR r0, [r3, #0] // Set time-slice expiration flag + + // } + +__tx_timer_no_time_slice: + + /* Test for timer expiration. */ + // if (*_tx_timer_current_ptr) + // { + + LDR r1, =_tx_timer_current_ptr // Pickup current timer pointer address + LDR r0, [r1, #0] // Pickup current timer + LDR r2, [r0, #0] // Pickup timer list entry + CBZ r2, __tx_timer_no_timer // Is there anything in the list? + // No, just increment the timer + + /* Set expiration flag. */ + // _tx_timer_expired = TX_TRUE; + + LDR r3, =_tx_timer_expired // Pickup expiration flag address + MOV r2, #1 // Build expired value + STR r2, [r3, #0] // Set expired flag + B __tx_timer_done // Finished timer processing + + // } + // else + // { +__tx_timer_no_timer: + + /* No timer expired, increment the timer pointer. */ + // _tx_timer_current_ptr++; + + ADD r0, r0, #4 // Move to next timer + + /* Check for wrap-around. */ + // if (_tx_timer_current_ptr == _tx_timer_list_end) + + LDR r3, =_tx_timer_list_end // Pickup addr of timer list end + LDR r2, [r3, #0] // Pickup list end + CMP r0, r2 // Are we at list end? + BNE __tx_timer_skip_wrap // No, skip wrap-around logic + + /* Wrap to beginning of list. */ + // _tx_timer_current_ptr = _tx_timer_list_start; + + LDR r3, =_tx_timer_list_start // Pickup addr of timer list start + LDR r0, [r3, #0] // Set current pointer to list start + +__tx_timer_skip_wrap: + + STR r0, [r1, #0] // Store new current timer pointer + // } + +__tx_timer_done: + + /* See if anything has expired. */ + // if ((_tx_timer_expired_time_slice) || (_tx_timer_expired)) + // { + + LDR r3, =_tx_timer_expired_time_slice // Pickup addr of expired flag + LDR r2, [r3, #0] // Pickup time-slice expired flag + CBNZ r2, __tx_something_expired // Did a time-slice expire? + // If non-zero, time-slice expired + LDR r1, =_tx_timer_expired // Pickup addr of other expired flag + LDR r0, [r1, #0] // Pickup timer expired flag + CBZ r0, __tx_timer_nothing_expired // Did a timer expire? + // No, nothing expired + +__tx_something_expired: + + STMDB sp!, {r0, lr} // Save the lr register on the stack + // and save r0 just to keep 8-byte alignment + + /* Did a timer expire? */ + // if (_tx_timer_expired) + // { + + LDR r1, =_tx_timer_expired // Pickup addr of expired flag + LDR r0, [r1, #0] // Pickup timer expired flag + CBZ r0, __tx_timer_dont_activate // Check for timer expiration + // If not set, skip timer activation + + /* Process timer expiration. */ + // _tx_timer_expiration_process(); + + BL _tx_timer_expiration_process // Call the timer expiration handling routine + + // } +__tx_timer_dont_activate: + + /* Did time slice expire? */ + // if (_tx_timer_expired_time_slice) + // { + + LDR r3, =_tx_timer_expired_time_slice // Pickup addr of time-slice expired + LDR r2, [r3, #0] // Pickup the actual flag + CBZ r2, __tx_timer_not_ts_expiration // See if the flag is set + // No, skip time-slice processing + + /* Time slice interrupted thread. */ + // _tx_thread_time_slice(); + + BL _tx_thread_time_slice // Call time-slice processing + LDR r0, =_tx_thread_preempt_disable // Build address of preempt disable flag + LDR r1, [r0] // Is the preempt disable flag set? + CBNZ r1, __tx_timer_skip_time_slice // Yes, skip the PendSV logic + LDR r0, =_tx_thread_current_ptr // Build current thread pointer address + LDR r1, [r0] // Pickup the current thread pointer + LDR r2, =_tx_thread_execute_ptr // Build execute thread pointer address + LDR r3, [r2] // Pickup the execute thread pointer + LDR r0, =0xE000ED04 // Build address of control register + LDR r2, =0x10000000 // Build value for PendSV bit + CMP r1, r3 // Are they the same? + BEQ __tx_timer_skip_time_slice // If the same, there was no time-slice performed + STR r2, [r0] // Not the same, issue the PendSV for preemption +__tx_timer_skip_time_slice: + + // } + +__tx_timer_not_ts_expiration: + + LDMIA sp!, {r0, lr} // Recover lr register (r0 is just there for + // the 8-byte stack alignment + + // } + +__tx_timer_nothing_expired: + + DSB // Complete all memory access + BX lr // Return to caller +// } +#endif diff --git a/ports_arch/ARMv7-M/threadx/ghs/example_build/sample_threadx.c b/ports_arch/ARMv7-M/threadx/ghs/example_build/sample_threadx.c new file mode 100644 index 00000000..8c61de06 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ghs/example_build/sample_threadx.c @@ -0,0 +1,369 @@ +/* This is a small demo of the high-performance ThreadX kernel. It includes examples of eight + threads of different priorities, using a message queue, semaphore, mutex, event flags group, + byte pool, and block pool. */ + +#include "tx_api.h" + +#define DEMO_STACK_SIZE 1024 +#define DEMO_BYTE_POOL_SIZE 9120 +#define DEMO_BLOCK_POOL_SIZE 100 +#define DEMO_QUEUE_SIZE 100 + + +/* Define the ThreadX object control blocks... */ + +TX_THREAD thread_0; +TX_THREAD thread_1; +TX_THREAD thread_2; +TX_THREAD thread_3; +TX_THREAD thread_4; +TX_THREAD thread_5; +TX_THREAD thread_6; +TX_THREAD thread_7; +TX_QUEUE queue_0; +TX_SEMAPHORE semaphore_0; +TX_MUTEX mutex_0; +TX_EVENT_FLAGS_GROUP event_flags_0; +TX_BYTE_POOL byte_pool_0; +TX_BLOCK_POOL block_pool_0; + + +/* Define the counters used in the demo application... */ + +ULONG thread_0_counter; +ULONG thread_1_counter; +ULONG thread_1_messages_sent; +ULONG thread_2_counter; +ULONG thread_2_messages_received; +ULONG thread_3_counter; +ULONG thread_4_counter; +ULONG thread_5_counter; +ULONG thread_6_counter; +ULONG thread_7_counter; + + +/* Define thread prototypes. */ + +void thread_0_entry(ULONG thread_input); +void thread_1_entry(ULONG thread_input); +void thread_2_entry(ULONG thread_input); +void thread_3_and_4_entry(ULONG thread_input); +void thread_5_entry(ULONG thread_input); +void thread_6_and_7_entry(ULONG thread_input); + + +/* Define main entry point. */ + +int main() +{ + + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); +} + + +/* Define what the initial system looks like. */ + +void tx_application_define(void *first_unused_memory) +{ + +CHAR *pointer = TX_NULL; + + + /* Create a byte memory pool from which to allocate the thread stacks. */ + tx_byte_pool_create(&byte_pool_0, "byte pool 0", first_unused_memory, DEMO_BYTE_POOL_SIZE); + + /* Put system definition stuff in here, e.g. thread creates and other assorted + create information. */ + + /* Allocate the stack for thread 0. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create the main thread. */ + tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0, + pointer, DEMO_STACK_SIZE, + 1, 1, TX_NO_TIME_SLICE, TX_AUTO_START); + + + /* Allocate the stack for thread 1. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create threads 1 and 2. These threads pass information through a ThreadX + message queue. It is also interesting to note that these threads have a time + slice. */ + tx_thread_create(&thread_1, "thread 1", thread_1_entry, 1, + pointer, DEMO_STACK_SIZE, + 16, 16, 4, TX_AUTO_START); + + /* Allocate the stack for thread 2. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + tx_thread_create(&thread_2, "thread 2", thread_2_entry, 2, + pointer, DEMO_STACK_SIZE, + 16, 16, 4, TX_AUTO_START); + + /* Allocate the stack for thread 3. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create threads 3 and 4. These threads compete for a ThreadX counting semaphore. + An interesting thing here is that both threads share the same instruction area. */ + tx_thread_create(&thread_3, "thread 3", thread_3_and_4_entry, 3, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 4. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + tx_thread_create(&thread_4, "thread 4", thread_3_and_4_entry, 4, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 5. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create thread 5. This thread simply pends on an event flag which will be set + by thread_0. */ + tx_thread_create(&thread_5, "thread 5", thread_5_entry, 5, + pointer, DEMO_STACK_SIZE, + 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 6. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create threads 6 and 7. These threads compete for a ThreadX mutex. */ + tx_thread_create(&thread_6, "thread 6", thread_6_and_7_entry, 6, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 7. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + tx_thread_create(&thread_7, "thread 7", thread_6_and_7_entry, 7, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the message queue. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_QUEUE_SIZE*sizeof(ULONG), TX_NO_WAIT); + + /* Create the message queue shared by threads 1 and 2. */ + tx_queue_create(&queue_0, "queue 0", TX_1_ULONG, pointer, DEMO_QUEUE_SIZE*sizeof(ULONG)); + + /* Create the semaphore used by threads 3 and 4. */ + tx_semaphore_create(&semaphore_0, "semaphore 0", 1); + + /* Create the event flags group used by threads 1 and 5. */ + tx_event_flags_create(&event_flags_0, "event flags 0"); + + /* Create the mutex used by thread 6 and 7 without priority inheritance. */ + tx_mutex_create(&mutex_0, "mutex 0", TX_NO_INHERIT); + + /* Allocate the memory for a small block pool. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_BLOCK_POOL_SIZE, TX_NO_WAIT); + + /* Create a block memory pool to allocate a message buffer from. */ + tx_block_pool_create(&block_pool_0, "block pool 0", sizeof(ULONG), pointer, DEMO_BLOCK_POOL_SIZE); + + /* Allocate a block and release the block memory. */ + tx_block_allocate(&block_pool_0, (VOID **) &pointer, TX_NO_WAIT); + + /* Release the block back to the pool. */ + tx_block_release(pointer); +} + + + +/* Define the test threads. */ + +void thread_0_entry(ULONG thread_input) +{ + +UINT status; + + + /* This thread simply sits in while-forever-sleep loop. */ + while(1) + { + + /* Increment the thread counter. */ + thread_0_counter++; + + /* Sleep for 10 ticks. */ + tx_thread_sleep(10); + + /* Set event flag 0 to wakeup thread 5. */ + status = tx_event_flags_set(&event_flags_0, 0x1, TX_OR); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + } +} + + +void thread_1_entry(ULONG thread_input) +{ + +UINT status; + + + /* This thread simply sends messages to a queue shared by thread 2. */ + while(1) + { + + /* Increment the thread counter. */ + thread_1_counter++; + + /* Send message to queue 0. */ + status = tx_queue_send(&queue_0, &thread_1_messages_sent, TX_WAIT_FOREVER); + + /* Check completion status. */ + if (status != TX_SUCCESS) + break; + + /* Increment the message sent. */ + thread_1_messages_sent++; + } +} + + +void thread_2_entry(ULONG thread_input) +{ + +ULONG received_message; +UINT status; + + /* This thread retrieves messages placed on the queue by thread 1. */ + while(1) + { + + /* Increment the thread counter. */ + thread_2_counter++; + + /* Retrieve a message from the queue. */ + status = tx_queue_receive(&queue_0, &received_message, TX_WAIT_FOREVER); + + /* Check completion status and make sure the message is what we + expected. */ + if ((status != TX_SUCCESS) || (received_message != thread_2_messages_received)) + break; + + /* Otherwise, all is okay. Increment the received message count. */ + thread_2_messages_received++; + } +} + + +void thread_3_and_4_entry(ULONG thread_input) +{ + +UINT status; + + + /* This function is executed from thread 3 and thread 4. As the loop + below shows, these function compete for ownership of semaphore_0. */ + while(1) + { + + /* Increment the thread counter. */ + if (thread_input == 3) + thread_3_counter++; + else + thread_4_counter++; + + /* Get the semaphore with suspension. */ + status = tx_semaphore_get(&semaphore_0, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Sleep for 2 ticks to hold the semaphore. */ + tx_thread_sleep(2); + + /* Release the semaphore. */ + status = tx_semaphore_put(&semaphore_0); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + } +} + + +void thread_5_entry(ULONG thread_input) +{ + +UINT status; +ULONG actual_flags; + + + /* This thread simply waits for an event in a forever loop. */ + while(1) + { + + /* Increment the thread counter. */ + thread_5_counter++; + + /* Wait for event flag 0. */ + status = tx_event_flags_get(&event_flags_0, 0x1, TX_OR_CLEAR, + &actual_flags, TX_WAIT_FOREVER); + + /* Check status. */ + if ((status != TX_SUCCESS) || (actual_flags != 0x1)) + break; + } +} + + +void thread_6_and_7_entry(ULONG thread_input) +{ + +UINT status; + + + /* This function is executed from thread 6 and thread 7. As the loop + below shows, these function compete for ownership of mutex_0. */ + while(1) + { + + /* Increment the thread counter. */ + if (thread_input == 6) + thread_6_counter++; + else + thread_7_counter++; + + /* Get the mutex with suspension. */ + status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Get the mutex again with suspension. This shows + that an owning thread may retrieve the mutex it + owns multiple times. */ + status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Sleep for 2 ticks to hold the mutex. */ + tx_thread_sleep(2); + + /* Release the mutex. */ + status = tx_mutex_put(&mutex_0); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Release the mutex again. This will actually + release ownership since it was obtained twice. */ + status = tx_mutex_put(&mutex_0); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + } +} diff --git a/ports_arch/ARMv7-M/threadx/ghs/example_build/tx_initialize_low_level.arm b/ports_arch/ARMv7-M/threadx/ghs/example_build/tx_initialize_low_level.arm new file mode 100644 index 00000000..7102a92d --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ghs/example_build/tx_initialize_low_level.arm @@ -0,0 +1,232 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Initialize */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SYSTEM_CLOCK = 6000000 + SYSTICK_CYCLES = ((SYSTEM_CLOCK / 100) -1) + + .text + .align 4 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_initialize_low_level Cortex-M7/GHS */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for any low-level processor */ +/* initialization, including setting up interrupt vectors, setting */ +/* up a periodic timer interrupt source, saving the system stack */ +/* pointer for use in ISR processing later, and finding the first */ +/* available RAM memory address for tx_application_define. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_initialize_kernel_enter ThreadX entry function */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* */ +/**************************************************************************/ +/* VOID _tx_initialize_low_level(VOID) +{ */ + .globl _tx_initialize_low_level +_tx_initialize_low_level: + + /* Disable interrupts. */ + + CPSID i ; Disable interrupts + + + /* Save the system stack pointer. */ + /* _tx_thread_system_stack_ptr = (VOID_PTR) (sp); */ + + LDR r1,=_tx_thread_system_stack_ptr ; Pickup address of system stack ptr + STR sp, [r1] ; Save system stack + + + /* Save the first available memory address. */ + /* _tx_initialize_unused_memory = (VOID_PTR) __ghsbegin_free_mem; */ + + LDR r0,=__ghsbegin_free_mem ; Pickup free memory address + LDR r2,=_tx_initialize_unused_memory ; Pickup unused memory ptr address + STR r0, [r2] ; Save first free memory address + + + /* Enable the cycle count register. */ + + LDR r0, =0xE0001000 ; Build address of DWT register + LDR r1, [r0] ; Pickup the current value + ORR r1, r1, 1 ; Set the CYCCNTENA bit + STR r1, [r0] ; Enable the cycle count register + + + /* Setup Vector Table Offset Register. */ + + MOV r0, 0xE000E000 ; Build address of NVIC registers + LDR r1, =__vectors ; Pickup address of vector table + STR r1, [r0, 0xD08] ; Set vector table address + + + /* Configure SysTick for 100Hz clock, or 16384 cycles if no reference. */ + + LDR r1, =SYSTICK_CYCLES + STR r1, [r0, 0x14] ; Setup SysTick Reload Value + MOV r1, 0x7 ; Build SysTick Control Enable Value + STR r1, [r0, 0x10] ; Setup SysTick Control + + /* Configure handler priorities. */ + + LDR r1, =0x00000000 ; Rsrv, UsgF, BusF, MemM + STR r1, [r0, 0xD18] ; Setup System Handlers 4-7 Priority Registers + + LDR r1, =0xFF000000 ; SVCl, Rsrv, Rsrv, Rsrv + STR r1, [r0, 0xD1C] ; Setup System Handlers 8-11 Priority Registers + ; Note: SVC must be lowest priority, which is 0xFF + + LDR r1, =0x40FF0000 ; SysT, PnSV, Rsrv, DbgM + STR r1, [r0, 0xD20] ; Setup System Handlers 12-15 Priority Registers + ; Note: PnSV must be lowest priority, which is 0xFF + +#ifdef __VFP__ + LDR r0, =0xE000EF34 ; Pickup FPCCR + LDR r1, [r0] ; + LDR r2, =0x3FFFFFFF ; Build mask to clear ASPEN and LSPEN + AND r1, r1, r2 ; Clear the ASPEN and LSPEN bits + STR r1, [r0] ; Update FPCCR +#endif + + /* Return to caller. */ + + BX lr ; Return to caller + + .type _tx_initialize_low_level,$function + .size _tx_initialize_low_level,.-_tx_initialize_low_level +/* } */ + + +/* Define shells for each of the interrupt vectors. */ + + .globl __tx_BadHandler +__tx_BadHandler: + B __tx_BadHandler + + .type __tx_BadHandler,$function + .size __tx_BadHandler,.-__tx_BadHandler + + + .globl __tx_IntHandler +__tx_IntHandler: + PUSH {lr} + BL _tx_thread_context_save + +#ifdef TX_ENABLE_EVENT_LOGGING + MOV r0, 0 ; Build interrupt code + BL _tx_el_interrupt ; Call interrupt event logging +#endif + +; /* Do interrupt handler work here */ +; /* .... */ + +#ifdef TX_ENABLE_EVENT_LOGGING + MOV r0, 0 ; Build interrupt code + BL _tx_el_interrupt_end ; Call interrupt event logging +#endif + + B _tx_thread_context_restore + + .type __tx_IntHandler,$function + .size __tx_IntHandler,.-__tx_IntHandler + + + .globl __tx_SysTickHandler +__tx_SysTickHandler: + PUSH {lr} + BL _tx_thread_context_save + +#ifdef TX_ENABLE_EVENT_LOGGING + MOV r0, 15 ; Build interrupt code + BL _tx_el_interrupt ; Call interrupt event logging +#endif + + BL _tx_timer_interrupt + +#ifdef TX_ENABLE_EVENT_LOGGING + MOV r0, 15 ; Build interrupt code + BL _tx_el_interrupt_end ; Call interrupt event logging +#endif + + B _tx_thread_context_restore + + .type __tx_SysTickHandler,$function + .size __tx_SysTickHandler,.-__tx_SysTickHandler + + + .globl __tx_NMIHandler +__tx_NMIHandler: + B __tx_NMIHandler + + .type __tx_NMIHandler,$function + .size __tx_NMIHandler,.-__tx_NMIHandler + + + .globl __tx_DBGHandler +__tx_DBGHandler: + B __tx_DBGHandler + + .type __tx_DBGHandler,$function + .size __tx_DBGHandler,.-__tx_DBGHandler + + + .globl __tx_SVCallHandler +__tx_SVCallHandler: + B __tx_SVCallHandler + + .type __tx_SVCallHandler,$function + .size __tx_SVCallHandler,.-__tx_SVCallHandler + + + /* Reference build options and version ID to ensure they come in. */ + +BUILD_OPTIONS: + .data.w _tx_build_options +VERSION_ID: + .data.w _tx_version_id diff --git a/ports_arch/ARMv7-M/threadx/ghs/inc/tx_el.h b/ports_arch/ARMv7-M/threadx/ghs/inc/tx_el.h new file mode 100644 index 00000000..66cc0d7c --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ghs/inc/tx_el.h @@ -0,0 +1,765 @@ +/**************************************************************************/ +/* */ +/* 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/GHS Event Log (EL) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* tx_el.h PORTABLE C/GHS */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the ThreadX event log functions for the GHS MULTI */ +/* EventAnalyzer. It is assumed that tx_api.h and tx_port.h have */ +/* already been included. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* */ +/**************************************************************************/ + +#ifndef TX_EL_H +#define TX_EL_H + + +/* Define Event Log specific data definitions. */ + +#define TX_EL_VERSION_ID 2 /* Event log version ID */ +#define TX_EL_HEADER_SIZE 24 /* Event log header size */ +#define TX_EL_TNIS 16 /* Number of thread names supported */ + /* If the application needs to */ + /* track more thread names, just */ + /* increase this number and re- */ + /* build the ThreadX library. */ +#define TX_EL_TNI_ENTRY_SIZE 44 /* Thread name entries are 44 bytes */ +#define TX_EL_TNI_NAME_SIZE 34 /* Thread name size in TNI */ +#define TX_EL_NO_MORE_TNI_ROOM 1 /* Error return from thread register*/ +#define TX_EL_NAME_NOT_FOUND 2 /* Error return from un-register */ +#define TX_EL_EVENT_SIZE 32 /* Number of bytes in each event */ +#define TX_EL_VALID_ENTRY 1 /* Valid log entry */ +#define TX_EL_INVALID_ENTRY 0 /* Invalid log entry */ + + +/* Define necessary offsets. */ + +#define TX_EL_TNI_VALID_OFFSET 34 +#define TX_EL_TNI_THREAD_ID_OFFSET 36 +#define TX_EL_TNI_THREAD_PRIORITY_OFF 40 +#define TX_EL_EVENT_TYPE_OFFSET 0 +#define TX_EL_EVENT_SUBTYPE_OFFSET 2 +#define TX_EL_EVENT_TIME_UPPER_OFFSET 4 +#define TX_EL_EVENT_TIME_LOWER_OFFSET 8 +#define TX_EL_EVENT_THREAD_OFFSET 12 +#define TX_EL_EVENT_INFO_1_OFFSET 16 +#define TX_EL_EVENT_INFO_2_OFFSET 20 +#define TX_EL_EVENT_INFO_3_OFFSET 24 +#define TX_EL_EVENT_INFO_4_OFFSET 28 + + +/* Undefine constants that might be been defined previously by tx_api.h. */ + +#undef TX_EL_INITIALIZE +#undef TX_EL_THREAD_REGISTER +#undef TX_EL_THREAD_UNREGISTER +#undef TX_EL_THREAD_STATUS_CHANGE_INSERT +#undef TX_EL_BYTE_ALLOCATE_INSERT +#undef TX_EL_BYTE_POOL_CREATE_INSERT +#undef TX_EL_BYTE_POOL_DELETE_INSERT +#undef TX_EL_BYTE_RELEASE_INSERT +#undef TX_EL_BLOCK_ALLOCATE_INSERT +#undef TX_EL_BLOCK_POOL_CREATE_INSERT +#undef TX_EL_BLOCK_POOL_DELETE_INSERT +#undef TX_EL_BLOCK_RELEASE_INSERT +#undef TX_EL_EVENT_FLAGS_CREATE_INSERT +#undef TX_EL_EVENT_FLAGS_DELETE_INSERT +#undef TX_EL_EVENT_FLAGS_GET_INSERT +#undef TX_EL_EVENT_FLAGS_SET_INSERT +#undef TX_EL_INTERRUPT_CONTROL_INSERT +#undef TX_EL_QUEUE_CREATE_INSERT +#undef TX_EL_QUEUE_DELETE_INSERT +#undef TX_EL_QUEUE_FLUSH_INSERT +#undef TX_EL_QUEUE_RECEIVE_INSERT +#undef TX_EL_QUEUE_SEND_INSERT +#undef TX_EL_SEMAPHORE_CREATE_INSERT +#undef TX_EL_SEMAPHORE_DELETE_INSERT +#undef TX_EL_SEMAPHORE_GET_INSERT +#undef TX_EL_SEMAPHORE_PUT_INSERT +#undef TX_EL_THREAD_CREATE_INSERT +#undef TX_EL_THREAD_DELETE_INSERT +#undef TX_EL_THREAD_IDENTIFY_INSERT +#undef TX_EL_THREAD_PREEMPTION_CHANGE_INSERT +#undef TX_EL_THREAD_PRIORITY_CHANGE_INSERT +#undef TX_EL_THREAD_RELINQUISH_INSERT +#undef TX_EL_THREAD_RESUME_INSERT +#undef TX_EL_THREAD_SLEEP_INSERT +#undef TX_EL_THREAD_SUSPEND_INSERT +#undef TX_EL_THREAD_TERMINATE_INSERT +#undef TX_EL_THREAD_TIME_SLICE_CHANGE_INSERT +#undef TX_EL_TIME_GET_INSERT +#undef TX_EL_TIME_SET_INSERT +#undef TX_EL_TIMER_ACTIVATE_INSERT +#undef TX_EL_TIMER_CHANGE_INSERT +#undef TX_EL_TIMER_CREATE_INSERT +#undef TX_EL_TIMER_DEACTIVATE_INSERT +#undef TX_EL_TIMER_DELETE_INSERT +#undef TX_EL_BLOCK_POOL_INFO_GET_INSERT +#undef TX_EL_BLOCK_POOL_PRIORITIZE_INSERT +#undef TX_EL_BYTE_POOL_INFO_GET_INSERT +#undef TX_EL_BYTE_POOL_PRIORITIZE_INSERT +#undef TX_EL_EVENT_FLAGS_INFO_GET_INSERT +#undef TX_EL_MUTEX_CREATE_INSERT +#undef TX_EL_MUTEX_DELETE_INSERT +#undef TX_EL_MUTEX_GET_INSERT +#undef TX_EL_MUTEX_INFO_GET_INSERT +#undef TX_EL_MUTEX_PRIORITIZE_INSERT +#undef TX_EL_MUTEX_PUT_INSERT +#undef TX_EL_QUEUE_INFO_GET_INSERT +#undef TX_EL_QUEUE_FRONT_SEND_INSERT +#undef TX_EL_QUEUE_PRIORITIZE_INSERT +#undef TX_EL_SEMAPHORE_INFO_GET_INSERT +#undef TX_EL_SEMAPHORE_PRIORITIZE_INSERT +#undef TX_EL_THREAD_INFO_GET_INSERT +#undef TX_EL_THREAD_WAIT_ABORT_INSERT +#undef TX_EL_TIMER_INFO_GET_INSERT +#undef TX_EL_BLOCK_POOL_PERFORMANCE_INFO_GET_INSERT +#undef TX_EL_BLOCK_POOL_PERFORMANCE_SYSTEM_INFO_GET_INSERT +#undef TX_EL_BYTE_POOL_PERFORMANCE_INFO_GET_INSERT +#undef TX_EL_BYTE_POOL_PERFORMANCE_SYSTEM_INFO_GET_INSERT +#undef TX_EL_EVENT_FLAGS_PERFORMANCE_INFO_GET_INSERT +#undef TX_EL_EVENT_FLAGS_PERFORMANCE_SYSTEM_INFO_GET_INSERT +#undef TX_EL_EVENT_FLAGS_SET_NOTIFY_INSERT +#undef TX_EL_MUTEX_PERFORMANCE_INFO_GET_INSERT +#undef TX_EL_MUTEX_PERFORMANCE_SYSTEM_INFO_GET_INSERT +#undef TX_EL_QUEUE_PERFORMANCE_INFO_GET_INSERT +#undef TX_EL_QUEUE_PERFORMANCE_SYSTEM_INFO_GET_INSERT +#undef TX_EL_QUEUE_SEND_NOTIFY_INSERT +#undef TX_EL_SEMAPHORE_CEILING_PUT_INSERT +#undef TX_EL_SEMAPHORE_PERFORMANCE_INFO_GET_INSERT +#undef TX_EL_SEMAPHORE_PERFORMANCE_SYSTEM_INFO_GET_INSERT +#undef TX_EL_SEMAPHORE_PUT_NOTIFY_INSERT +#undef TX_EL_THREAD_ENTRY_EXIT_NOTIFY_INSERT +#undef TX_EL_THREAD_RESET_INSERT +#undef TX_EL_THREAD_PERFORMANCE_INFO_GET_INSERT +#undef TX_EL_THREAD_PERFORMANCE_SYSTEM_INFO_GET_INSERT +#undef TX_EL_THREAD_STACK_ERROR_NOTIFY_INSERT +#undef TX_EL_TIMER_PERFORMANCE_INFO_GET_INSERT +#undef TX_EL_TIMER_PERFORMANCE_SYSTEM_INFO_GET_INSERT + + +/* Define Event Types. */ + +#define TX_EL_THREAD_CHANGE 1 +#define TX_EL_INTERRUPT 2 +#define TX_EL_THREADX_CALL 3 +#define TX_EL_USER_EVENT 4 +#define TX_EL_THREAD_STATUS_CHANGE 5 +#define TX_EL_REFRESH 6 /* Not implemented */ +#define TX_EL_TIMER 7 /* Not implemented */ +#define TX_EL_TIMESOURCE_DELTA 8 /* Not implemented */ + + +/* Define TX_EL_THREADX_CALL event sub-types. */ + +#define TX_EL_BYTE_ALLOCATE 0 +#define TX_EL_BYTE_POOL_CREATE 1 +#define TX_EL_BYTE_POOL_DELETE 2 +#define TX_EL_BYTE_RELEASE 3 +#define TX_EL_BLOCK_ALLOCATE 4 +#define TX_EL_BLOCK_POOL_CREATE 5 +#define TX_EL_BLOCK_POOL_DELETE 6 +#define TX_EL_BLOCK_RELEASE 7 +#define TX_EL_EVENT_FLAGS_CREATE 8 +#define TX_EL_EVENT_FLAGS_DELETE 9 +#define TX_EL_EVENT_FLAGS_GET 10 +#define TX_EL_EVENT_FLAGS_SET 11 +#define TX_EL_INTERRUPT_CONTROL 12 +#define TX_EL_QUEUE_CREATE 13 +#define TX_EL_QUEUE_DELETE 14 +#define TX_EL_QUEUE_FLUSH 15 +#define TX_EL_QUEUE_RECEIVE 16 +#define TX_EL_QUEUE_SEND 17 +#define TX_EL_SEMAPHORE_CREATE 18 +#define TX_EL_SEMAPHORE_DELETE 19 +#define TX_EL_SEMAPHORE_GET 20 +#define TX_EL_SEMAPHORE_PUT 21 +#define TX_EL_THREAD_CREATE 22 +#define TX_EL_THREAD_DELETE 23 +#define TX_EL_THREAD_IDENTIFY 24 +#define TX_EL_THREAD_PREEMPTION_CHANGE 25 +#define TX_EL_THREAD_PRIORITY_CHANGE 26 +#define TX_EL_THREAD_RELINQUISH 27 +#define TX_EL_THREAD_RESUME 28 +#define TX_EL_THREAD_SLEEP 29 +#define TX_EL_THREAD_SUSPEND 30 +#define TX_EL_THREAD_TERMINATE 31 +#define TX_EL_THREAD_TIME_SLICE_CHANGE 32 +#define TX_EL_TIME_GET 33 +#define TX_EL_TIME_SET 34 +#define TX_EL_TIMER_ACTIVATE 35 +#define TX_EL_TIMER_CHANGE 36 +#define TX_EL_TIMER_CREATE 37 +#define TX_EL_TIMER_DEACTIVATE 38 +#define TX_EL_TIMER_DELETE 39 +#define TX_EL_BLOCK_POOL_INFO_GET 40 +#define TX_EL_BLOCK_POOL_PRIORITIZE 41 +#define TX_EL_BYTE_POOL_INFO_GET 42 +#define TX_EL_BYTE_POOL_PRIORITIZE 43 +#define TX_EL_EVENT_FLAGS_INFO_GET 44 +#define TX_EL_MUTEX_CREATE 45 +#define TX_EL_MUTEX_DELETE 46 +#define TX_EL_MUTEX_GET 47 +#define TX_EL_MUTEX_INFO_GET 48 +#define TX_EL_MUTEX_PRIORITIZE 49 +#define TX_EL_MUTEX_PUT 50 +#define TX_EL_QUEUE_INFO_GET 51 +#define TX_EL_QUEUE_FRONT_SEND 52 +#define TX_EL_QUEUE_PRIORITIZE 53 +#define TX_EL_SEMAPHORE_INFO_GET 54 +#define TX_EL_SEMAPHORE_PRIORITIZE 55 +#define TX_EL_THREAD_INFO_GET 56 +#define TX_EL_THREAD_WAIT_ABORT 57 +#define TX_EL_TIMER_INFO_GET 58 +#define TX_EL_BLOCK_POOL_PERFORMANCE_INFO_GET 59 +#define TX_EL_BLOCK_POOL_PERFORMANCE_SYSTEM_INFO_GET 60 +#define TX_EL_BYTE_POOL_PERFORMANCE_INFO_GET 61 +#define TX_EL_BYTE_POOL_PERFORMANCE_SYSTEM_INFO_GET 62 +#define TX_EL_EVENT_FLAGS_PERFORMANCE_INFO_GET 63 +#define TX_EL_EVENT_FLAGS_PERFORMANCE_SYSTEM_INFO_GET 64 +#define TX_EL_EVENT_FLAGS_SET_NOTIFY 65 +#define TX_EL_MUTEX_PERFORMANCE_INFO_GET 66 +#define TX_EL_MUTEX_PERFORMANCE_SYSTEM_INFO_GET 67 +#define TX_EL_QUEUE_PERFORMANCE_INFO_GET 68 +#define TX_EL_QUEUE_PERFORMANCE_SYSTEM_INFO_GET 69 +#define TX_EL_QUEUE_SEND_NOTIFY 70 +#define TX_EL_SEMAPHORE_CEILING_PUT 71 +#define TX_EL_SEMAPHORE_PERFORMANCE_INFO_GET 72 +#define TX_EL_SEMAPHORE_PERFORMANCE_SYSTEM_INFO_GET 73 +#define TX_EL_SEMAPHORE_PUT_NOTIFY 74 +#define TX_EL_THREAD_ENTRY_EXIT_NOTIFY 75 +#define TX_EL_THREAD_RESET 76 +#define TX_EL_THREAD_PERFORMANCE_INFO_GET 77 +#define TX_EL_THREAD_PERFORMANCE_SYSTEM_INFO_GET 78 +#define TX_EL_THREAD_STACK_ERROR_NOTIFY 79 +#define TX_EL_TIMER_PERFORMANCE_INFO_GET 80 +#define TX_EL_TIMER_PERFORMANCE_SYSTEM_INFO_GET 81 + + +/* Define ThreadX sub-types. */ + +#define TX_EL_INTERRUPT_SUB_TYPE 1 +#define TX_EL_END_OF_INTERRUPT 3 + + +/* Define event logging filters, which may be used by the application program to + dynamically enable/disable events in run-time. */ + +#define TX_EL_FILTER_STATUS_CHANGE 0x0001 +#define TX_EL_FILTER_INTERRUPTS 0x0002 +#define TX_EL_FILTER_THREAD_CALLS 0x0004 +#define TX_EL_FILTER_TIMER_CALLS 0x0008 +#define TX_EL_FILTER_EVENT_FLAG_CALLS 0x0010 +#define TX_EL_FILTER_SEMAPHORE_CALLS 0x0020 +#define TX_EL_FILTER_QUEUE_CALLS 0x0040 +#define TX_EL_FILTER_BLOCK_CALLS 0x0080 +#define TX_EL_FILTER_BYTE_CALLS 0x0100 +#define TX_EL_FILTER_MUTEX_CALLS 0x0200 +#define TX_EL_FILTER_ALL_EVENTS 0xFFFF +#define TX_EL_ENABLE_ALL_EVENTS 0x0000 + + +/* Define filter macros that are inserted in-line with the other macros below. */ + +#ifdef TX_ENABLE_EVENT_FILTERS +#define TX_EL_NO_STATUS_EVENTS if (!(_tx_el_event_filter & TX_EL_FILTER_STATUS_CHANGE)) { +#define TX_EL_NO_INTERRUPT_EVENTS if (!(_tx_el_event_filter & TX_EL_FILTER_INTERRUPTS)) { +#define TX_EL_NO_THREAD_EVENTS if (!(_tx_el_event_filter & TX_EL_FILTER_THREAD_CALLS)) { +#define TX_EL_NO_TIMER_EVENTS if (!(_tx_el_event_filter & TX_EL_FILTER_TIMER_CALLS)) { +#define TX_EL_NO_EVENT_FLAG_EVENTS if (!(_tx_el_event_filter & TX_EL_FILTER_EVENT_FLAG_CALLS)) { +#define TX_EL_NO_SEMAPHORE_EVENTS if (!(_tx_el_event_filter & TX_EL_FILTER_SEMAPHORE_CALLS)) { +#define TX_EL_NO_QUEUE_EVENTS if (!(_tx_el_event_filter & TX_EL_FILTER_QUEUE_CALLS)) { +#define TX_EL_NO_BLOCK_EVENTS if (!(_tx_el_event_filter & TX_EL_FILTER_BLOCK_CALLS)) { +#define TX_EL_NO_BYTE_EVENTS if (!(_tx_el_event_filter & TX_EL_FILTER_BYTE_CALLS)) { +#define TX_EL_NO_MUTEX_EVENTS if (!(_tx_el_event_filter & TX_EL_FILTER_MUTEX_CALLS)) { +#define TX_EL_END_FILTER } +#else +#define TX_EL_NO_STATUS_EVENTS +#define TX_EL_NO_INTERRUPT_EVENTS +#define TX_EL_NO_THREAD_EVENTS +#define TX_EL_NO_TIMER_EVENTS +#define TX_EL_NO_EVENT_FLAG_EVENTS +#define TX_EL_NO_SEMAPHORE_EVENTS +#define TX_EL_NO_QUEUE_EVENTS +#define TX_EL_NO_BLOCK_EVENTS +#define TX_EL_NO_BYTE_EVENTS +#define TX_EL_NO_MUTEX_EVENTS +#define TX_EL_END_FILTER +#endif + +/* Define externs and constants for non-event log source modules. This is for + the in-line macros below. */ + +#ifndef TX_EL_SOURCE_CODE +extern UCHAR *_tx_el_tni_start; +extern UCHAR **_tx_el_current_event; +extern UCHAR *_tx_el_event_area_start; +extern UCHAR *_tx_el_event_area_end; +extern UINT _tx_el_maximum_events; +extern ULONG _tx_el_total_events; +extern TX_THREAD *_tx_thread_current_ptr; +extern UINT _tx_el_event_filter; +extern ULONG _tx_el_time_base_upper; +extern ULONG _tx_el_time_base_lower; + + +/* Define macros for event logging functions. */ + +#define TX_EL_THREAD_CREATE_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO4(TX_EL_THREAD_CREATE, thread_ptr, stack_start, stack_size, priority); TX_EL_END_FILTER +#define TX_EL_EVENT_FLAGS_SET_INSERT TX_EL_NO_EVENT_FLAG_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(TX_EL_EVENT_FLAGS_SET, group_ptr, flags_to_set, set_option); TX_EL_END_FILTER +#define TX_EL_THREAD_DELETE_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_THREAD_DELETE, thread_ptr); TX_EL_END_FILTER +#define TX_EL_THREAD_INFO_GET_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_THREAD_INFO_GET, thread_ptr); TX_EL_END_FILTER +#define TX_EL_THREAD_TIME_SLICE_CHANGE_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(TX_EL_THREAD_TIME_SLICE_CHANGE, thread_ptr, thread_ptr -> tx_thread_new_time_slice, new_time_slice); TX_EL_END_FILTER +#define TX_EL_THREAD_TERMINATE_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_THREAD_TERMINATE, thread_ptr); TX_EL_END_FILTER +#define TX_EL_THREAD_SLEEP_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_THREAD_SLEEP, timer_ticks); TX_EL_END_FILTER +#define TX_EL_THREAD_SUSPEND_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_THREAD_SUSPEND, thread_ptr); TX_EL_END_FILTER +#define TX_EL_THREAD_RELINQUISH_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO0(TX_EL_THREAD_RELINQUISH); TX_EL_END_FILTER +#define TX_EL_THREAD_RESUME_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_THREAD_RESUME, thread_ptr); TX_EL_END_FILTER +#define TX_EL_THREAD_PRIORITY_CHANGE_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(TX_EL_THREAD_PRIORITY_CHANGE, thread_ptr, thread_ptr -> tx_thread_priority, new_priority); TX_EL_END_FILTER +#define TX_EL_THREAD_PREEMPTION_CHANGE_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(TX_EL_THREAD_PREEMPTION_CHANGE, thread_ptr, thread_ptr -> tx_thread_preempt_threshold, new_threshold); TX_EL_END_FILTER +#define TX_EL_THREAD_WAIT_ABORT_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_THREAD_WAIT_ABORT, thread_ptr); TX_EL_END_FILTER +#define TX_EL_THREAD_ENTRY_EXIT_NOTIFY_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_THREAD_ENTRY_EXIT_NOTIFY, thread_ptr, thread_entry_exit_notify); TX_EL_END_FILTER +#define TX_EL_THREAD_RESET_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_THREAD_RESET, thread_ptr); TX_EL_END_FILTER +#define TX_EL_THREAD_PERFORMANCE_INFO_GET_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_THREAD_PERFORMANCE_INFO_GET, thread_ptr); TX_EL_END_FILTER +#define TX_EL_THREAD_PERFORMANCE_SYSTEM_INFO_GET_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO0(TX_EL_THREAD_PERFORMANCE_SYSTEM_INFO_GET); TX_EL_END_FILTER +#define TX_EL_THREAD_STACK_ERROR_NOTIFY_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_THREAD_STACK_ERROR_NOTIFY, stack_error_handler); TX_EL_END_FILTER +#define TX_EL_TIME_SET_INSERT TX_EL_NO_TIMER_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_TIME_SET, new_time); TX_EL_END_FILTER +#define TX_EL_TIME_GET_INSERT TX_EL_NO_TIMER_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_TIME_GET, _tx_timer_system_clock); TX_EL_END_FILTER +#define TX_EL_TIMER_DELETE_INSERT TX_EL_NO_TIMER_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_TIMER_DELETE, timer_ptr); TX_EL_END_FILTER +#define TX_EL_TIMER_CREATE_INSERT TX_EL_NO_TIMER_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO4(TX_EL_TIMER_CREATE, timer_ptr, initial_ticks, reschedule_ticks, auto_activate); TX_EL_END_FILTER +#define TX_EL_TIMER_CHANGE_INSERT TX_EL_NO_TIMER_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(TX_EL_TIMER_CHANGE, timer_ptr, initial_ticks, reschedule_ticks); TX_EL_END_FILTER +#define TX_EL_THREAD_IDENTIFY_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO0(TX_EL_THREAD_IDENTIFY); TX_EL_END_FILTER +#define TX_EL_TIMER_DEACTIVATE_INSERT TX_EL_NO_TIMER_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_TIMER_DEACTIVATE, timer_ptr); TX_EL_END_FILTER +#define TX_EL_TIMER_ACTIVATE_INSERT TX_EL_NO_TIMER_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_TIMER_ACTIVATE, timer_ptr); TX_EL_END_FILTER +#define TX_EL_TIMER_INFO_GET_INSERT TX_EL_NO_TIMER_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_TIMER_INFO_GET, timer_ptr); TX_EL_END_FILTER +#define TX_EL_TIMER_PERFORMANCE_INFO_GET_INSERT TX_EL_NO_TIMER_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_TIMER_PERFORMANCE_INFO_GET, timer_ptr); TX_EL_END_FILTER +#define TX_EL_TIMER_PERFORMANCE_SYSTEM_INFO_GET_INSERT TX_EL_NO_TIMER_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO0(TX_EL_TIMER_PERFORMANCE_SYSTEM_INFO_GET); TX_EL_END_FILTER +#define TX_EL_SEMAPHORE_PUT_INSERT TX_EL_NO_SEMAPHORE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_SEMAPHORE_PUT, semaphore_ptr, semaphore_ptr -> tx_semaphore_count); TX_EL_END_FILTER +#define TX_EL_SEMAPHORE_GET_INSERT TX_EL_NO_SEMAPHORE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_SEMAPHORE_GET, semaphore_ptr, semaphore_ptr -> tx_semaphore_count); TX_EL_END_FILTER +#define TX_EL_SEMAPHORE_DELETE_INSERT TX_EL_NO_SEMAPHORE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_SEMAPHORE_DELETE, semaphore_ptr); TX_EL_END_FILTER +#define TX_EL_SEMAPHORE_CREATE_INSERT TX_EL_NO_SEMAPHORE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_SEMAPHORE_CREATE, semaphore_ptr, initial_count); TX_EL_END_FILTER +#define TX_EL_SEMAPHORE_INFO_GET_INSERT TX_EL_NO_SEMAPHORE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_SEMAPHORE_INFO_GET, semaphore_ptr); TX_EL_END_FILTER +#define TX_EL_SEMAPHORE_PRIORITIZE_INSERT TX_EL_NO_SEMAPHORE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_SEMAPHORE_PRIORITIZE, semaphore_ptr); TX_EL_END_FILTER +#define TX_EL_SEMAPHORE_CEILING_PUT_INSERT TX_EL_NO_SEMAPHORE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(TX_EL_SEMAPHORE_CEILING_PUT, semaphore_ptr, semaphore_ptr -> tx_semaphore_count, ceiling); TX_EL_END_FILTER +#define TX_EL_SEMAPHORE_PERFORMANCE_INFO_GET_INSERT TX_EL_NO_SEMAPHORE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_SEMAPHORE_PERFORMANCE_INFO_GET, semaphore_ptr); TX_EL_END_FILTER +#define TX_EL_SEMAPHORE_PERFORMANCE_SYSTEM_INFO_GET_INSERT TX_EL_NO_SEMAPHORE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO0(TX_EL_SEMAPHORE_PERFORMANCE_SYSTEM_INFO_GET); TX_EL_END_FILTER +#define TX_EL_SEMAPHORE_PUT_NOTIFY_INSERT TX_EL_NO_SEMAPHORE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_SEMAPHORE_PUT_NOTIFY, semaphore_ptr, semaphore_put_notify); TX_EL_END_FILTER +#define TX_EL_QUEUE_FRONT_SEND_INSERT TX_EL_NO_QUEUE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_QUEUE_FRONT_SEND, queue_ptr, source_ptr); TX_EL_END_FILTER +#define TX_EL_QUEUE_SEND_INSERT TX_EL_NO_QUEUE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_QUEUE_SEND, queue_ptr, source_ptr); TX_EL_END_FILTER +#define TX_EL_QUEUE_RECEIVE_INSERT TX_EL_NO_QUEUE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_QUEUE_RECEIVE, queue_ptr, destination_ptr); TX_EL_END_FILTER +#define TX_EL_QUEUE_FLUSH_INSERT TX_EL_NO_QUEUE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_QUEUE_FLUSH, queue_ptr); TX_EL_END_FILTER +#define TX_EL_QUEUE_DELETE_INSERT TX_EL_NO_QUEUE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_QUEUE_DELETE, queue_ptr); TX_EL_END_FILTER +#define TX_EL_QUEUE_CREATE_INSERT TX_EL_NO_QUEUE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO4(TX_EL_QUEUE_CREATE, queue_ptr, queue_start, queue_size, message_size); TX_EL_END_FILTER +#define TX_EL_QUEUE_INFO_GET_INSERT TX_EL_NO_QUEUE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_QUEUE_INFO_GET, queue_ptr); TX_EL_END_FILTER +#define TX_EL_QUEUE_PRIORITIZE_INSERT TX_EL_NO_QUEUE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_QUEUE_PRIORITIZE, queue_ptr); TX_EL_END_FILTER +#define TX_EL_QUEUE_PERFORMANCE_INFO_GET_INSERT TX_EL_NO_QUEUE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_QUEUE_PERFORMANCE_INFO_GET, queue_ptr); TX_EL_END_FILTER +#define TX_EL_QUEUE_PERFORMANCE_SYSTEM_INFO_GET_INSERT TX_EL_NO_QUEUE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO0(TX_EL_QUEUE_PERFORMANCE_SYSTEM_INFO_GET); TX_EL_END_FILTER +#define TX_EL_QUEUE_SEND_NOTIFY_INSERT TX_EL_NO_QUEUE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_QUEUE_SEND_NOTIFY, queue_ptr, queue_send_notify); TX_EL_END_FILTER +#define TX_EL_EVENT_FLAGS_GET_INSERT TX_EL_NO_EVENT_FLAG_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(TX_EL_EVENT_FLAGS_GET, group_ptr, requested_flags, get_option); TX_EL_END_FILTER +#define TX_EL_EVENT_FLAGS_DELETE_INSERT TX_EL_NO_EVENT_FLAG_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_EVENT_FLAGS_DELETE, group_ptr); TX_EL_END_FILTER +#define TX_EL_EVENT_FLAGS_CREATE_INSERT TX_EL_NO_EVENT_FLAG_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_EVENT_FLAGS_CREATE, group_ptr); TX_EL_END_FILTER +#define TX_EL_EVENT_FLAGS_INFO_GET_INSERT TX_EL_NO_EVENT_FLAG_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_EVENT_FLAGS_INFO_GET, group_ptr); TX_EL_END_FILTER +#define TX_EL_EVENT_FLAGS_PERFORMANCE_INFO_GET_INSERT TX_EL_NO_EVENT_FLAG_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_EVENT_FLAGS_PERFORMANCE_INFO_GET, group_ptr); TX_EL_END_FILTER +#define TX_EL_EVENT_FLAGS_PERFORMANCE_SYSTEM_INFO_GET_INSERT TX_EL_NO_EVENT_FLAG_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO0(TX_EL_EVENT_FLAGS_PERFORMANCE_SYSTEM_INFO_GET); TX_EL_END_FILTER +#define TX_EL_EVENT_FLAGS_SET_NOTIFY_INSERT TX_EL_NO_EVENT_FLAG_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_EVENT_FLAGS_SET_NOTIFY, group_ptr, events_set_notify); TX_EL_END_FILTER +#define TX_EL_BYTE_RELEASE_INSERT TX_EL_NO_BYTE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_BYTE_RELEASE, pool_ptr, memory_ptr); TX_EL_END_FILTER +#define TX_EL_BYTE_POOL_DELETE_INSERT TX_EL_NO_BYTE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_BYTE_POOL_DELETE, pool_ptr); TX_EL_END_FILTER +#define TX_EL_BYTE_POOL_CREATE_INSERT TX_EL_NO_BYTE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(TX_EL_BYTE_POOL_CREATE, pool_ptr, pool_start, pool_size); TX_EL_END_FILTER +#define TX_EL_BYTE_POOL_INFO_GET_INSERT TX_EL_NO_BYTE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_BYTE_POOL_INFO_GET, pool_ptr); TX_EL_END_FILTER +#define TX_EL_BYTE_POOL_PRIORITIZE_INSERT TX_EL_NO_BYTE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_BYTE_POOL_PRIORITIZE, pool_ptr); TX_EL_END_FILTER +#define TX_EL_BYTE_ALLOCATE_INSERT TX_EL_NO_BYTE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(TX_EL_BYTE_ALLOCATE, pool_ptr, memory_ptr, memory_size); TX_EL_END_FILTER +#define TX_EL_BYTE_POOL_PERFORMANCE_INFO_GET_INSERT TX_EL_NO_BYTE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_BYTE_POOL_PERFORMANCE_INFO_GET, pool_ptr); TX_EL_END_FILTER +#define TX_EL_BYTE_POOL_PERFORMANCE_SYSTEM_INFO_GET_INSERT TX_EL_NO_BYTE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO0(TX_EL_BYTE_POOL_PERFORMANCE_SYSTEM_INFO_GET); TX_EL_END_FILTER +#define TX_EL_BLOCK_RELEASE_INSERT TX_EL_NO_BLOCK_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_BLOCK_RELEASE, pool_ptr, block_ptr); TX_EL_END_FILTER +#define TX_EL_BLOCK_POOL_DELETE_INSERT TX_EL_NO_BLOCK_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_BLOCK_POOL_DELETE, pool_ptr); TX_EL_END_FILTER +#define TX_EL_BLOCK_POOL_CREATE_INSERT TX_EL_NO_BLOCK_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO4(TX_EL_BLOCK_POOL_CREATE, pool_ptr, pool_start, pool_size, block_size); TX_EL_END_FILTER +#define TX_EL_BLOCK_POOL_INFO_GET_INSERT TX_EL_NO_BLOCK_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_BLOCK_POOL_INFO_GET, pool_ptr); TX_EL_END_FILTER +#define TX_EL_BLOCK_POOL_PRIORITIZE_INSERT TX_EL_NO_BLOCK_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_BLOCK_POOL_PRIORITIZE, pool_ptr); TX_EL_END_FILTER +#define TX_EL_BLOCK_ALLOCATE_INSERT TX_EL_NO_BLOCK_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_BLOCK_ALLOCATE, pool_ptr, block_ptr); TX_EL_END_FILTER +#define TX_EL_BLOCK_POOL_PERFORMANCE_INFO_GET_INSERT TX_EL_NO_BLOCK_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_BLOCK_POOL_PERFORMANCE_INFO_GET, pool_ptr); TX_EL_END_FILTER +#define TX_EL_BLOCK_POOL_PERFORMANCE_SYSTEM_INFO_GET_INSERT TX_EL_NO_BLOCK_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO0(TX_EL_BLOCK_POOL_PERFORMANCE_SYSTEM_INFO_GET); TX_EL_END_FILTER +#define TX_EL_MUTEX_CREATE_INSERT TX_EL_NO_MUTEX_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_MUTEX_CREATE, mutex_ptr, inherit); TX_EL_END_FILTER +#define TX_EL_MUTEX_DELETE_INSERT TX_EL_NO_MUTEX_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_MUTEX_DELETE, mutex_ptr); TX_EL_END_FILTER +#define TX_EL_MUTEX_GET_INSERT TX_EL_NO_MUTEX_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(TX_EL_MUTEX_GET, mutex_ptr, mutex_ptr -> tx_mutex_owner, mutex_ptr -> tx_mutex_ownership_count); TX_EL_END_FILTER +#define TX_EL_MUTEX_INFO_GET_INSERT TX_EL_NO_MUTEX_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_MUTEX_INFO_GET, mutex_ptr); TX_EL_END_FILTER +#define TX_EL_MUTEX_PRIORITIZE_INSERT TX_EL_NO_MUTEX_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_MUTEX_PRIORITIZE, mutex_ptr); TX_EL_END_FILTER +#define TX_EL_MUTEX_PUT_INSERT TX_EL_NO_MUTEX_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(TX_EL_MUTEX_PUT, mutex_ptr, mutex_ptr -> tx_mutex_owner, mutex_ptr -> tx_mutex_ownership_count); TX_EL_END_FILTER +#define TX_EL_MUTEX_PERFORMANCE_INFO_GET_INSERT TX_EL_NO_MUTEX_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_MUTEX_PERFORMANCE_INFO_GET, mutex_ptr); TX_EL_END_FILTER +#define TX_EL_MUTEX_PERFORMANCE_SYSTEM_INFO_GET_INSERT TX_EL_NO_MUTEX_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO0(TX_EL_MUTEX_PERFORMANCE_SYSTEM_INFO_GET); TX_EL_END_FILTER + + +#endif + + +/* Define Event Log function prototypes. */ + +VOID _tx_el_initialize(VOID); +UINT _tx_el_thread_register(TX_THREAD *thread_ptr); +UINT _tx_el_thread_unregister(TX_THREAD *thread_ptr); +VOID _tx_el_user_event_insert(UINT sub_type, ULONG info_1, ULONG info_2, + ULONG info_3, ULONG info_4); +VOID _tx_el_thread_running(TX_THREAD *thread_ptr); +VOID _tx_el_thread_preempted(TX_THREAD *thread_ptr); +VOID _tx_el_interrupt(UINT interrupt_number); +VOID _tx_el_interrupt_end(UINT interrupt_number); +VOID _tx_el_interrupt_control_call(void); +VOID _tx_el_event_log_on(void); +VOID _tx_el_event_log_off(void); +VOID _tx_el_event_filter_set(UINT filter); + + +/* Define macros that are used inside the ThreadX source code. + If event logging is disabled, these macros will be defined + as white space. */ + +#ifdef TX_ENABLE_EVENT_LOGGING +#ifndef TX_NO_EVENT_INFO +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO4(a, b, c, d, e) \ + { \ + UCHAR *entry_ptr; \ + ULONG upper_tbu; \ + entry_ptr = *_tx_el_current_event; \ + *((unsigned short *) entry_ptr) = TX_EL_THREADX_CALL; \ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = (unsigned short) a; \ + do { \ + upper_tbu = read_tbu(); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = upper_tbu; \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) =\ + (ULONG) read_tbl();\ + } while (upper_tbu != read_tbu()); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) =\ + (ULONG) _tx_thread_current_ptr;\ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_1_OFFSET)) =\ + (ULONG) b;\ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_2_OFFSET)) =\ + (ULONG) c;\ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_3_OFFSET)) =\ + (ULONG) d;\ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_4_OFFSET)) =\ + (ULONG) e;\ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE;\ + if (entry_ptr >= _tx_el_event_area_end) \ + {\ + entry_ptr = _tx_el_event_area_start;\ + }\ + *_tx_el_current_event = entry_ptr;\ + } +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(a, b, c, d) \ + { \ + UCHAR *entry_ptr; \ + ULONG upper_tbu; \ + entry_ptr = *_tx_el_current_event; \ + *((unsigned short *) entry_ptr) = TX_EL_THREADX_CALL; \ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = (unsigned short) a; \ + do { \ + upper_tbu = read_tbu(); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = upper_tbu; \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) =\ + (ULONG) read_tbl();\ + } while (upper_tbu != read_tbu()); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) =\ + (ULONG) _tx_thread_current_ptr;\ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_1_OFFSET)) =\ + (ULONG) b;\ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_2_OFFSET)) =\ + (ULONG) c;\ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_3_OFFSET)) =\ + (ULONG) d;\ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE;\ + if (entry_ptr >= _tx_el_event_area_end) \ + {\ + entry_ptr = _tx_el_event_area_start;\ + }\ + *_tx_el_current_event = entry_ptr;\ + } +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(a, b, c) \ + { \ + UCHAR *entry_ptr; \ + ULONG upper_tbu; \ + entry_ptr = *_tx_el_current_event; \ + *((unsigned short *) entry_ptr) = TX_EL_THREADX_CALL; \ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = (unsigned short) a; \ + do { \ + upper_tbu = read_tbu(); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = upper_tbu; \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) =\ + (ULONG) read_tbl();\ + } while (upper_tbu != read_tbu()); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) =\ + (ULONG) _tx_thread_current_ptr;\ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_1_OFFSET)) =\ + (ULONG) b;\ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_2_OFFSET)) =\ + (ULONG) c;\ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE;\ + if (entry_ptr >= _tx_el_event_area_end) \ + {\ + entry_ptr = _tx_el_event_area_start;\ + }\ + *_tx_el_current_event = entry_ptr;\ + } +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(a, b) \ + { \ + UCHAR *entry_ptr; \ + ULONG upper_tbu; \ + entry_ptr = *_tx_el_current_event; \ + *((unsigned short *) entry_ptr) = TX_EL_THREADX_CALL; \ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = (unsigned short) a; \ + do { \ + upper_tbu = read_tbu(); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = upper_tbu; \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) =\ + (ULONG) read_tbl();\ + } while (upper_tbu != read_tbu()); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) =\ + (ULONG) _tx_thread_current_ptr;\ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_1_OFFSET)) =\ + (ULONG) b;\ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE;\ + if (entry_ptr >= _tx_el_event_area_end) \ + {\ + entry_ptr = _tx_el_event_area_start;\ + }\ + *_tx_el_current_event = entry_ptr;\ + } +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO0(a) \ + { \ + UCHAR *entry_ptr; \ + ULONG upper_tbu; \ + entry_ptr = *_tx_el_current_event; \ + *((unsigned short *) entry_ptr) = TX_EL_THREADX_CALL; \ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = (unsigned short) a; \ + do { \ + upper_tbu = read_tbu(); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = upper_tbu; \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) =\ + (ULONG) read_tbl();\ + } while (upper_tbu != read_tbu()); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) =\ + (ULONG) _tx_thread_current_ptr;\ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE;\ + if (entry_ptr >= _tx_el_event_area_end) \ + {\ + entry_ptr = _tx_el_event_area_start;\ + }\ + *_tx_el_current_event = entry_ptr;\ + } +#define TX_EL_THREAD_STATUS_CHANGE_INSERT(a, b) \ + { \ + UCHAR *entry_ptr; \ + ULONG upper_tbu; \ + TX_EL_NO_STATUS_EVENTS \ + entry_ptr = *_tx_el_current_event; \ + *((unsigned short *) entry_ptr) = TX_EL_THREAD_STATUS_CHANGE; \ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = (unsigned short) b; \ + do { \ + upper_tbu = read_tbu(); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = upper_tbu; \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) =\ + (ULONG) read_tbl();\ + } while (upper_tbu != read_tbu()); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) =\ + (ULONG) a;\ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE;\ + if (entry_ptr >= _tx_el_event_area_end) \ + {\ + entry_ptr = _tx_el_event_area_start;\ + }\ + *_tx_el_current_event = entry_ptr;\ + TX_EL_END_FILTER \ + } +#define TX_EL_THREAD_REGISTER(a) \ + _tx_el_thread_register(a); +#define TX_EL_THREAD_UNREGISTER(a) \ + _tx_el_thread_unregister(a); +#define TX_EL_INITIALIZE _tx_el_initialize(); +#else +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO4(a, b, c, d, e) \ + { \ + UCHAR *entry_ptr; \ + ULONG upper_tbu; \ + entry_ptr = *_tx_el_current_event; \ + *((unsigned short *) entry_ptr) = TX_EL_THREADX_CALL; \ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = (unsigned short) a; \ + do { \ + upper_tbu = read_tbu(); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = upper_tbu; \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) =\ + (ULONG) read_tbl();\ + } while (upper_tbu != read_tbu()); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) =\ + (ULONG) _tx_thread_current_ptr;\ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE;\ + if (entry_ptr >= _tx_el_event_area_end) \ + {\ + entry_ptr = _tx_el_event_area_start;\ + }\ + *_tx_el_current_event = entry_ptr;\ + } +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(a, b, c, d) \ + { \ + UCHAR *entry_ptr; \ + ULONG upper_tbu; \ + entry_ptr = *_tx_el_current_event; \ + *((unsigned short *) entry_ptr) = TX_EL_THREADX_CALL; \ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = (unsigned short) a; \ + do { \ + upper_tbu = read_tbu(); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = upper_tbu; \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) =\ + (ULONG) read_tbl();\ + } while (upper_tbu != read_tbu()); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) =\ + (ULONG) _tx_thread_current_ptr;\ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE;\ + if (entry_ptr >= _tx_el_event_area_end) \ + {\ + entry_ptr = _tx_el_event_area_start;\ + }\ + *_tx_el_current_event = entry_ptr;\ + } +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(a, b, c) \ + { \ + UCHAR *entry_ptr; \ + ULONG upper_tbu; \ + entry_ptr = *_tx_el_current_event; \ + *((unsigned short *) entry_ptr) = TX_EL_THREADX_CALL; \ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = (unsigned short) a; \ + do { \ + upper_tbu = read_tbu(); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = upper_tbu; \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) =\ + (ULONG) read_tbl();\ + } while (upper_tbu != read_tbu()); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) =\ + (ULONG) _tx_thread_current_ptr;\ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE;\ + if (entry_ptr >= _tx_el_event_area_end) \ + {\ + entry_ptr = _tx_el_event_area_start;\ + }\ + *_tx_el_current_event = entry_ptr;\ + } +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(a, b) \ + { \ + UCHAR *entry_ptr; \ + ULONG upper_tbu; \ + entry_ptr = *_tx_el_current_event; \ + *((unsigned short *) entry_ptr) = TX_EL_THREADX_CALL; \ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = (unsigned short) a; \ + do { \ + upper_tbu = read_tbu(); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = upper_tbu; \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) =\ + (ULONG) read_tbl();\ + } while (upper_tbu != read_tbu()); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) =\ + (ULONG) _tx_thread_current_ptr;\ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE;\ + if (entry_ptr >= _tx_el_event_area_end) \ + {\ + entry_ptr = _tx_el_event_area_start;\ + }\ + *_tx_el_current_event = entry_ptr;\ + } +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO0(a) \ + { \ + UCHAR *entry_ptr; \ + ULONG upper_tbu; \ + entry_ptr = *_tx_el_current_event; \ + *((unsigned short *) entry_ptr) = TX_EL_THREADX_CALL; \ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = (unsigned short) a; \ + do { \ + upper_tbu = read_tbu(); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = upper_tbu; \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) =\ + (ULONG) read_tbl();\ + } while (upper_tbu != read_tbu()); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) =\ + (ULONG) _tx_thread_current_ptr;\ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE;\ + if (entry_ptr >= _tx_el_event_area_end) \ + {\ + entry_ptr = _tx_el_event_area_start;\ + }\ + *_tx_el_current_event = entry_ptr;\ + } +#define TX_EL_THREAD_STATUS_CHANGE_INSERT(a, b) \ + { \ + UCHAR *entry_ptr; \ + ULONG upper_tbu; \ + TX_EL_NO_STATUS_EVENTS \ + entry_ptr = *_tx_el_current_event; \ + *((unsigned short *) entry_ptr) = TX_EL_THREAD_STATUS_CHANGE; \ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = (unsigned short) b; \ + do { \ + upper_tbu = read_tbu(); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = upper_tbu; \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) =\ + (ULONG) read_tbl();\ + } while (upper_tbu != read_tbu()); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) =\ + (ULONG) a;\ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE;\ + if (entry_ptr >= _tx_el_event_area_end) \ + {\ + entry_ptr = _tx_el_event_area_start;\ + }\ + *_tx_el_current_event = entry_ptr;\ + TX_EL_END_FILTER \ + } +#define TX_EL_THREAD_REGISTER(a) \ + _tx_el_thread_register(a); +#define TX_EL_THREAD_UNREGISTER(a) \ + _tx_el_thread_unregister(a); +#define TX_EL_INITIALIZE _tx_el_initialize(); +#endif +#else +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO4(a, b, c, d, e) +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(a, b, c, d) +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(a, b, c) +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(a, b) +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO0(a) +#define TX_EL_THREAD_STATUS_CHANGE_INSERT(a, b) +#define TX_EL_THREAD_REGISTER(a) +#define TX_EL_THREAD_UNREGISTER(a) +#define TX_EL_INITIALIZE +#endif + +#endif + diff --git a/ports_arch/ARMv7-M/threadx/ghs/inc/tx_ghs.h b/ports_arch/ARMv7-M/threadx/ghs/inc/tx_ghs.h new file mode 100644 index 00000000..ca976916 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ghs/inc/tx_ghs.h @@ -0,0 +1,77 @@ +/* + * ThreadX C/C++ Library Support + * + * Copyright 1983-2019 Green Hills Software LLC. + * + * This program is the property of Green Hills Software LLC., + * its contents are proprietary information and no part of it + * is to be disclosed to anyone except employees of Green Hills + * Software LLC., or as agreed in writing signed by the President + * of Green Hills Software LLC. + */ + +#ifndef _TX_GHS_H_ +#define _TX_GHS_H_ + +#include +#include +#include +#include + +#if defined(__ghs) && (__GHS_VERSION_NUMBER >= 500) +extern void *__ghs_GetThreadLocalStorageItem(int specifier); + +/* Thread-local storage routines for Green Hills releases 5.x and beyond. + The following specifiers are used when calling + __ghs_GetThreadLocalStorageItem. + + If __ghs_GetThreadLocalStorageItem is customized to + return a per-thread errno value, define the preprocessor symbol + USE_THREAD_LOCAL_ERRNO in ind_errn.c. + */ + +enum __ghs_ThreadLocalStorage_specifier { + __ghs_TLS_asctime_buff, + __ghs_TLS_tmpnam_space, + __ghs_TLS_strtok_saved_pos, + __ghs_TLS_Errno, + __ghs_TLS_gmtime_temp, + __ghs_TLS___eh_globals, + __ghs_TLS_SignalHandlers +}; +#else +/* Thread-local storage routines for Green Hills releases 4.x and 3.x . */ +typedef void (*SignalHandler)(int); + +typedef struct +{ + int Errno; /* errno. */ + SignalHandler SignalHandlers[_SIGMAX]; /* signal() buffer. */ + char tmpnam_space[L_tmpnam]; /* tmpnam(NULL) buffer. */ + char asctime_buff[30]; /* . */ + char *strtok_saved_pos; /* strtok() position. */ + struct tm gmtime_temp; /* gmtime() and localtime() buffer. */ + void *__eh_globals; /* Pointer for C++ exception handling. */ +} ThreadLocalStorage; + +ThreadLocalStorage *GetThreadLocalStorage(void); +#endif + + +void __ghsLock(void); +void __ghsUnlock(void); + +int __ghs_SaveSignalContext(jmp_buf); +void __ghs_RestoreSignalContext(jmp_buf); + +/* prototypes for FILE lock routines. */ +void __ghs_flock_file(void *); +void __ghs_funlock_file(void *); +int __ghs_ftrylock_file(void *); +void __ghs_flock_create(void **); +void __ghs_flock_destroy(void *); + +/* prototype for GHS/ThreadX error shell checking. */ +void __ghs_rnerr(char *errMsg, int stackLevels, int stackTraceDisplay, void *hexVal); + +#endif /* _TX_GHS_H_ */ diff --git a/ports_arch/ARMv7-M/threadx/ghs/inc/tx_port.h b/ports_arch/ARMv7-M/threadx/ghs/inc/tx_port.h new file mode 100644 index 00000000..245f5f26 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ghs/inc/tx_port.h @@ -0,0 +1,406 @@ +/**************************************************************************/ +/* */ +/* 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.1.7 */ +/* */ +/* 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 */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* */ +/**************************************************************************/ + +#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 + + +/* Define compiler library include files. */ + +#include +#include + +#ifdef __ICCARM__ +#include /* IAR Intrinsics */ +#define __asm__ __asm /* Define to make all inline asm look similar */ +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#include +#endif +#endif /* __ICCARM__ */ + +#ifdef __ghs__ +#include +#include "tx_ghs.h" +#endif /* __ghs__ */ + + +/* 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 + + +/* 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 *((ULONG *) 0x0a800024) +#define TX_TRACE_TIME_MASK 0x0000FFFFUL + +*/ + +#ifndef TX_MISRA_ENABLE +#ifndef TX_TRACE_TIME_SOURCE +#define TX_TRACE_TIME_SOURCE *((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 + +#ifdef __ghs__ +/* Define constants for Green Hills EventAnalyzer. */ + +/* Define the number of ticks per second. This informs the EventAnalyzer what the timestamps + represent. By default, this is set to 1,000,000 i.e., one tick every microsecond. */ + +#define TX_EL_TICKS_PER_SECOND 1000000 + +/* Define the method of how to get the upper and lower 32-bits of the time stamp. By default, simply + simulate the time-stamp source with a counter. */ + +#define read_tbu() _tx_el_time_base_upper +#define read_tbl() ++_tx_el_time_base_lower +#endif /* __ghs__ */ + +/* 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 +#define TX_THREAD_EXTENSION_2 VOID * tx_thread_eh_globals; \ + int Errno; /* errno. */ \ + char * strtok_saved_pos; /* strtok() position. */ +#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_EVENT_FLAGS_GROUP_EXTENSION +#define TX_MUTEX_EXTENSION +#define TX_QUEUE_EXTENSION +#define TX_SEMAPHORE_EXTENSION +#define TX_TIMER_EXTENSION + + +/* 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. */ + +#if (__GHS_VERSION_NUMBER >= 500) +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) \ + { \ + extern void __tx_cpp_exception_init(TX_THREAD *thread_ptr); \ + __tx_cpp_exception_init(thread_ptr); \ + } +#else +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) \ + { \ + #pragma weak __cpp_exception_init \ + extern void __cpp_exception_init(void **); \ + static void (*const cpp_init_funcp)(void **) = __cpp_exception_init; \ + if (cpp_init_funcp) \ + __cpp_exception_init(&(thread_ptr -> tx_thread_eh_globals)); \ + } +#endif + +#if (__GHS_VERSION_NUMBER >= 500) +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) \ + { \ + extern void __tx_cpp_exception_cleanup(TX_THREAD *thread_ptr); \ + __tx_cpp_exception_cleanup(thread_ptr); \ + } +#else +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) \ + { \ + #pragma weak __cpp_exception_cleanup \ + extern void __cpp_exception_cleanup(void **); \ + static void (*const cpp_cleanup_funcp)(void **) = \ + __cpp_exception_cleanup; \ + if (cpp_cleanup_funcp) \ + __cpp_exception_cleanup(&(thread_ptr -> tx_thread_eh_globals)); \ + } +#endif + +#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) +#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) + + +/* 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 +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | __MRS(__IPSR)) +#endif + + +/* 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 TX_LOWEST_SET_BIT_CALCULATE(m, b) m = m & ((ULONG) (-((LONG) m))); \ + b = __CLZ32(m); \ + b = 31 - b; + +#endif + + + + +#ifdef TX_DISABLE_INLINE + +UINT _tx_thread_interrupt_disable(VOID); +VOID _tx_thread_interrupt_restore(UINT previous_posture); + +#define TX_INTERRUPT_SAVE_AREA register int interrupt_save; + +#define TX_DISABLE interrupt_save = _tx_thread_interrupt_control(TX_INT_DISABLE); + +#define TX_RESTORE _tx_thread_interrupt_control(interrupt_save); + +#else + +#define TX_INTERRUPT_SAVE_AREA register int interrupt_save; + +/* Define ThreadX interrupt lockout and restore macros using + asm macros. */ + +asm int disable_ints(void) +{ +% + MRS r0,PRIMASK + MOV r1,1 + MSR PRIMASK,r1 +%error +} + +asm void restore_ints(int a) +{ +%reg a + MSR PRIMASK,a +%mem a + LDR r0,a + MSR PRIMASK,r0 +%error +} + +#define TX_DISABLE interrupt_save = disable_ints(); + +#define TX_RESTORE restore_ints(interrupt_save); + +#endif + + +/* 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 ARMv7-M Version 6.2.1 *"; +#else +#ifdef TX_MISRA_ENABLE +extern CHAR _tx_version_id[100]; +#else +extern CHAR _tx_version_id[]; +#endif +#endif + + +#endif diff --git a/ports_arch/ARMv7-M/threadx/ghs/readme_threadx.txt b/ports_arch/ARMv7-M/threadx/ghs/readme_threadx.txt new file mode 100644 index 00000000..2f0cc0ea --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ghs/readme_threadx.txt @@ -0,0 +1,233 @@ + Microsoft's Azure RTOS ThreadX for Cortex-M7 + + Using the Green Hills Software Tools + +1. Open the ThreadX Project Workspace + +In order to build the ThreadX library and the ThreadX demonstration first load +the Azure RTOS Workspace azure_rtos_workspace.gpj, which is located inside the +"example_build" directory. + + +2. Building the ThreadX run-time Library + +Building the ThreadX library is easy; simply select the MULTI project file +tx.gpj and then select the build button. You should now observe the +compilation and assembly of the ThreadX library. This project build produces +the ThreadX library file tx.a. + + +3. Demonstration System + +The ThreadX demonstration is designed to execute under the MULTI environment +on the Green Hills Cortex-M7 simulator. The instructions that follow describe +how to get the ThreadX evaluation running under the MULTI Cortex-M7 simulation +environment. + +Building the demonstration is easy; simply select the MULTI project file +sample_threadx.gpj. At this point, select the "Project Build" button and observe +the compilation, assembly, and linkage of the ThreadX demonstration application. + +After the demonstration is built, invoke the MULTI ARM simulator by selecting +the simulator connection from within the sample_threadx.con connection file. +Once connected to the simulator, select the "Debug" button. You should now +observe the main function of sample_threadx.c. + +You are now ready to execute the ThreadX demonstration system. Select +breakpoints and data watches to observe the execution of the sample_threadx.c +application. + + +4. EventAnalyzer Demonstration + +To build a demonstration system that also logs events for the MULTI EventAnalyzer, +perform the same steps as the regular demo, except build the ThreadX library with +txe.gpj file and use the sample_threadx_el.gpj build file to build the demonstration. +The resulting image will log all system events, which can then be displayed by the +MULTI EventAnalyzer. + + +5. System Initialization + +The system entry point using the Green Hills tools is at the label _start. +This is defined within the crt0.arm file supplied by Green Hills. In addition, +this is where all static and global preset C variable initialization +processing is called from. + +After the Green Hills startup function returns, ThreadX initialization is +called. The main initialization function is _tx_initialize_low_level and +is located in the file tx_initialize_low_level.arm. This function is responsible +for setting up various system data structures, interrupt vectors, and the +periodic timer interrupt source of ThreadX. + +In addition, _tx_initialize_low_level determines where the first available +RAM memory address is located. This address is supplied to tx_application_define. + +By default, the first available RAM memory address is assumed to start at the +beginning of the ThreadX section .free_mem. If changes are made to the +sample_threadx.ld file, the .free_mem section should remain the last allocated +section in the main RAM area. The starting address of this section is passed +to tx_application_define. + + +6. Register Usage and Stack Frames + +The following defines the saved context stack frames for context switches +that occur as a result of interrupt handling or from thread-level API calls. +All suspended threads have the same stack frame in the Cortex-M7 version of +ThreadX. The top of the suspended thread's stack is pointed to by +tx_thread_stack_ptr in the associated thread control block TX_THREAD. + + +Non-FPU Stack Frame: + + Stack Offset Stack Contents + + 0x00 r4 + 0x04 r5 + 0x08 r6 + 0x0C r7 + 0x10 r8 + 0x14 r9 + 0x18 r10 + 0x1C r11 + 0x20 r0 (Hardware stack starts here!!) + 0x24 r1 + 0x28 r2 + 0x2C r3 + 0x30 r12 + 0x34 lr + 0x38 pc + 0x3C xPSR + +FPU Stack Frame (only interrupted thread with FPU enabled): + + Stack Offset Stack Contents + + 0x00 s0 + 0x04 s1 + 0x08 s2 + 0x0C s3 + 0x10 s4 + 0x14 s5 + 0x18 s6 + 0x1C s7 + 0x20 s8 + 0x24 s9 + 0x28 s10 + 0x2C s11 + 0x30 s12 + 0x34 s13 + 0x38 s14 + 0x3C s15 + 0x40 s16 + 0x44 s17 + 0x48 s18 + 0x4C s19 + 0x50 s20 + 0x54 s21 + 0x58 s22 + 0x5C s23 + 0x60 s24 + 0x64 s25 + 0x68 s26 + 0x6C s27 + 0x70 s28 + 0x74 s29 + 0x78 s30 + 0x7C s31 + 0x80 fpscr + 0x84 r4 + 0x88 r5 + 0x8C r6 + 0x90 r7 + 0x94 r8 + 0x98 r9 + 0x9C r10 (sl) + 0xA0 r11 + 0xA4 r0 (Hardware stack starts here!!) + 0xA8 r1 + 0xAC r2 + 0xB0 r3 + 0xB4 r12 + 0xB8 lr + 0xBC pc + 0xC0 xPSR + + +7. Improving Performance + +The distribution version of ThreadX is built without any compiler +optimizations. This makes it easy to debug because you can trace or set +breakpoints inside of ThreadX itself. Of course, this costs some +performance. To make ThreadX run faster, you can change the tx.gpj project +to disable debug information and enable the desired optimizations. + +In addition, you can eliminate the ThreadX basic API error checking by +compiling your application code with the symbol TX_DISABLE_ERROR_CHECKING +defined before tx_api.h is included. + + +8. Interrupt Handling + +ThreadX provides complete and high-performance interrupt handling for Cortex-M7 +targets. There are a certain set of requirements that are defined in the +following sub-sections: + + +8.1 Vector Area + +The Cortex-M7 vectors start at the label __tx_vectors. The application may modify +the vector area according to its needs. + + +8.2 Managed Interrupts + +A ThreadX managed interrupt is defined below. By following these conventions, the +application ISR is then allowed access to various ThreadX services from the ISR. +Here is the standard template for managed ISRs in ThreadX: + + + .globl __tx_IntHandler +__tx_IntHandler: + PUSH {lr} + BL _tx_thread_context_save + + /* Do interrupt handler work here */ + + B _tx_thread_context_restore + + +9. FPU Support + +By default, FPU support is disabled for each thread. If saving the context of the FPU registers +is needed, the ThreadX library should be re-built with TX_ENABLE_FPU_SUPPORT defined. In addition, +the following API call must be made from the context of the application thread - before +the FPU usage: + +void tx_thread_fpu_enable(void); + +After this API is called in the application, FPU registers will be saved/restored for this thread if it +is preempted via an interrupt. All other suspension of the this thread will not require the FPU registers +to be saved/restored. + +To disable FPU register context saving, simply call the following API: + +void tx_thread_fpu_disable(void); + + + +10. Revision History + +For generic code revision information, please refer to the readme_threadx_generic.txt +file, which is included in your distribution. The following details the revision +information associated with this specific port of ThreadX: + +05/19/2020 Initial ThreadX version of Cortex-M7/Green Hills port. + + +Copyright(c) 1996-2020 Microsoft Corporation + + +https://azure.com/rtos + diff --git a/ports_arch/ARMv7-M/threadx/ghs/src/tx_el.c b/ports_arch/ARMv7-M/threadx/ghs/src/tx_el.c new file mode 100644 index 00000000..d8f056d7 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ghs/src/tx_el.c @@ -0,0 +1,1165 @@ +/**************************************************************************/ +/* */ +/* 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/GHS Event Log (EL) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE +#define TX_EL_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_el.h" +#include "string.h" + + +/* Define global variables used to manage the event pool. */ + +UCHAR *_tx_el_tni_start; +UCHAR **_tx_el_current_event; +UCHAR *_tx_el_event_area_start; +UCHAR *_tx_el_event_area_end; +UINT _tx_el_maximum_events; +ULONG _tx_el_total_events; +UINT _tx_el_event_filter; +ULONG _tx_el_time_base_upper; +ULONG _tx_el_time_base_lower; + +extern char __ghsbegin_eventlog[]; +extern char __ghsend_eventlog[]; + +extern TX_THREAD *_tx_thread_current_ptr; +UINT _tx_thread_interrupt_control(UINT new_posture); + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_el_initialize PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates the Event Log (in the format dictated by the */ +/* GHS Event Analyzer) and sets up various information for subsequent */ +/* operation. The start and end of the Event Log is determined by the */ +/* .eventlog section in the linker control file. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* */ +/**************************************************************************/ +VOID _tx_el_initialize(VOID) +{ + +UCHAR *work_ptr; +UCHAR *read_ptr; +ULONG event_log_size; +UCHAR *end_ptr; +UINT i; + + + /* Clear total event counter. */ + _tx_el_total_events = 0; + + /* Clear event filter. */ + _tx_el_event_filter = 0; + + /* First, pickup the starting and ending address of the Event Log memory. */ + work_ptr = (unsigned char *) __ghsbegin_eventlog; + end_ptr = (unsigned char *) __ghsend_eventlog; + + /* Calculate the event log size. */ + event_log_size = end_ptr - work_ptr; + + /* Subtract off the number of bytes in the header and the TNI area. */ + event_log_size = event_log_size - (TX_EL_HEADER_SIZE + + (TX_EL_TNI_ENTRY_SIZE * TX_EL_TNIS)); + + /* Make sure the event log is evenly divisible by the event size. */ + event_log_size = (event_log_size/TX_EL_EVENT_SIZE) * TX_EL_EVENT_SIZE; + + /* Build the Event Log header. */ + + /* Setup the Event Log Version ID. */ + *((unsigned short *) work_ptr) = (unsigned short) TX_EL_VERSION_ID; + work_ptr = work_ptr + sizeof(unsigned short); + + /* Setup the TNIS (number of thread names) field. */ + *((unsigned short *) work_ptr) = (unsigned short) TX_EL_TNIS; + work_ptr = work_ptr + sizeof(unsigned short); + + /* Setup the EVPS (event pool size) field. */ + *((ULONG *) work_ptr) = event_log_size; + work_ptr = work_ptr + sizeof(ULONG); + + /* Remember the maximum number of events. */ + _tx_el_maximum_events = event_log_size/TX_EL_EVENT_SIZE; + + /* Setup max_events field. */ + *((ULONG *) work_ptr) = _tx_el_maximum_events; + work_ptr = work_ptr + sizeof(ULONG); + + /* Setup the evploc (location of event pool). */ + *((ULONG *) work_ptr) = (ULONG) (((ULONG) __ghsbegin_eventlog) + TX_EL_HEADER_SIZE + + (TX_EL_TNIS * TX_EL_TNI_ENTRY_SIZE)); + work_ptr = work_ptr + sizeof(ULONG); + + /* Save the current event pointer. */ + _tx_el_current_event = (UCHAR **) work_ptr; + + /* Setup event_ptr (pointer to oldest event) field to the start + of the event pool. */ + *_tx_el_current_event = (UCHAR *) (((ULONG) __ghsbegin_eventlog) + TX_EL_HEADER_SIZE + + (TX_EL_TNIS * TX_EL_TNI_ENTRY_SIZE)); + work_ptr = work_ptr + sizeof(ULONG); + + /* Setup tbfreq (the number of ticks in a second) field. */ + *((ULONG *) work_ptr) = TX_EL_TICKS_PER_SECOND; + work_ptr = work_ptr + sizeof(ULONG); + + /* At this point we are pointing at the Thread Name Information (TNI) array. */ + + /* Remember the start of this for future updates. */ + _tx_el_tni_start = work_ptr; + + /* Clear the entire TNI array, this is the initial setting. */ + end_ptr = work_ptr + (TX_EL_TNIS * TX_EL_TNI_ENTRY_SIZE); + memset((void *)work_ptr, 0, (TX_EL_TNIS * TX_EL_TNI_ENTRY_SIZE)); + work_ptr = end_ptr; + + /* At this point, we are pointing at the actual Event Entry area. */ + + /* Remember the start of the actual event log area. */ + _tx_el_event_area_start = work_ptr; + + /* Clear the entire Event area. */ + end_ptr = work_ptr + event_log_size; + memset((void *)work_ptr, 0, event_log_size); + work_ptr = end_ptr; + + /* Save the end pointer for later use. */ + _tx_el_event_area_end = work_ptr; + + /* Setup an entry to resolve all activities from initialization and from + an idle system. */ + work_ptr = _tx_el_tni_start; + read_ptr = (UCHAR *) "Initialization/System Idle"; + i = 0; + while ((i < TX_EL_TNI_NAME_SIZE) && (*read_ptr)) + { + + /* Copy a character of thread's name into TNI area of log. */ + *work_ptr++ = *read_ptr++; + + /* Increment the character count. */ + i++; + } + + /* Determine if a NULL needs to be inserted. */ + if (i < TX_EL_TNI_NAME_SIZE) + { + + /* Yes, insert a NULL into the event log string. */ + *work_ptr = (unsigned char) 0; + } + + /* Setup the thread ID to NULL. */ + *((ULONG *) (_tx_el_tni_start + TX_EL_TNI_THREAD_ID_OFFSET)) = (ULONG) TX_NULL; + + /* Set the valid field to indicate the entry is complete. */ + *((UCHAR *) (_tx_el_tni_start + TX_EL_TNI_VALID_OFFSET)) = (ULONG) TX_EL_VALID_ENTRY; + + /* Clear the time base global variables. */ + _tx_el_time_base_upper = 0; + _tx_el_time_base_lower = 0; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_el_thread_register PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function registers a thread in the event log for future */ +/* display purposes. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread control block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_SUCCESS Thread was placed in TNI area */ +/* TX_ERROR No more room in the TNI area */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_create ThreadX thread create function */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* */ +/**************************************************************************/ +UINT _tx_el_thread_register(TX_THREAD *thread_ptr) +{ + +UCHAR *entry_ptr; +UCHAR *work_ptr; +UCHAR *read_ptr; +UINT i; + + + /* First of all, search for a free slot in the TNI area. */ + entry_ptr = _tx_el_tni_start; + i = 0; + while (i < TX_EL_TNIS) + { + + /* Determine if this entry is available. */ + if (*(entry_ptr + TX_EL_TNI_VALID_OFFSET) == TX_EL_INVALID_ENTRY) + break; + + /* Otherwise, increment the associated pointers and indices. */ + i++; + entry_ptr = entry_ptr + TX_EL_TNI_ENTRY_SIZE; + } + + /* Check to see if there were no more valid entries. */ + if (i >= TX_EL_TNIS) + return(TX_EL_NO_MORE_TNI_ROOM); + + /* Otherwise, we have room in the TNI and a valid record. */ + + /* Setup the thread's name. */ + work_ptr = entry_ptr; + read_ptr = (UCHAR *) thread_ptr -> tx_thread_name; + i = 0; + while ((i < TX_EL_TNI_NAME_SIZE) && (*read_ptr)) + { + + /* Copy a character of thread's name into TNI area of log. */ + *work_ptr++ = *read_ptr++; + + /* Increment the character count. */ + i++; + } + + /* Determine if a NULL needs to be inserted. */ + if (i < TX_EL_TNI_NAME_SIZE) + { + + /* Yes, insert a NULL into the event log string. */ + *work_ptr = (unsigned char) 0; + } + + /* Setup the thread ID. */ + *((ULONG *) (entry_ptr + TX_EL_TNI_THREAD_ID_OFFSET)) = (ULONG) thread_ptr; + + /* Setup the thread priority. */ + *((ULONG *) (entry_ptr + TX_EL_TNI_THREAD_PRIORITY_OFF)) = (ULONG) thread_ptr -> tx_thread_priority; + + /* Set the valid field to indicate the entry is complete. */ + *((UCHAR *) (entry_ptr + TX_EL_TNI_VALID_OFFSET)) = (ULONG) TX_EL_VALID_ENTRY; + + /* Thread name has been registered. */ + return(TX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_el_thread_unregister PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function unregisters a thread in the event log for future */ +/* display purposes. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread control block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_SUCCESS Thread was placed in TNI area */ +/* TX_ERROR No more room in the TNI area */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_create ThreadX thread create function */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* */ +/**************************************************************************/ +UINT _tx_el_thread_unregister(TX_THREAD *thread_ptr) +{ + +UCHAR *entry_ptr; +UCHAR *work_ptr; +UCHAR *read_ptr; +UINT found; +UINT i, j; + + + /* First of all, search for a match in the TNI area. */ + entry_ptr = _tx_el_tni_start; + i = 0; + while (i < TX_EL_TNIS) + { + + /* Determine if this entry is a match. */ + work_ptr = entry_ptr; + read_ptr = (UCHAR *) thread_ptr -> tx_thread_name; + found = TX_TRUE; + j = 0; + do + { + + /* Determine if this character is the same. */ + if (*work_ptr != *read_ptr) + { + + /* Set found to false and fall out of the loop. */ + found = TX_FALSE; + break; + } + else if (*work_ptr == 0) + { + + /* Null terminated, just break the loop. */ + break; + } + else + { + + /* Copy a character of thread's name into TNI area of log. */ + *work_ptr++ = *read_ptr++; + } + + /* Increment the character count. */ + j++; + + } while(j < TX_EL_TNIS); + + + /* Was a match found? */ + if (found) + { + + /* Yes, mark the entry as available now. */ + *(entry_ptr + TX_EL_TNI_VALID_OFFSET) = TX_EL_INVALID_ENTRY; + + /* Get out of the loop! */ + break; + } + + /* Otherwise, increment the associated pointers and indices. */ + i++; + entry_ptr = entry_ptr + TX_EL_TNI_ENTRY_SIZE; + } + + /* Determine status to return. */ + if (found) + return(TX_SUCCESS); + else + return(TX_EL_NAME_NOT_FOUND); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_el_user_event_insert PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function inserts a user event into the event log. */ +/* If the event log is full, the oldest event is overwritten. */ +/* */ +/* INPUT */ +/* */ +/* sub_type Event subtype for kernel call */ +/* info_1 First information field */ +/* info_2 Second information field */ +/* info_3 Third information field */ +/* info_4 Fourth information field */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX services */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* */ +/**************************************************************************/ +VOID _tx_el_user_event_insert(UINT sub_type, ULONG info_1, ULONG info_2, + ULONG info_3, ULONG info_4) +{ + +TX_INTERRUPT_SAVE_AREA + +UINT upper_tb; +UCHAR *entry_ptr; + + /* Disable interrupts. */ + TX_DISABLE + + /* Increment total event counter. */ + _tx_el_total_events++; + + /* Setup working entry pointer first. */ + entry_ptr = *_tx_el_current_event; + + /* Store the event type. */ + *((unsigned short *) entry_ptr) = (unsigned short) TX_EL_USER_EVENT; + + /* Store the event subtype. */ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = + (unsigned short) sub_type; + + /* Get time stamp. */ + do + { + + /* Pickup the upper tb. */ + upper_tb = (ULONG) read_tbu(); + + /* Store the upper time stamp. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = + (ULONG) upper_tb; + + /* Store the lower time stamp. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) = + (ULONG) read_tbl(); + } while (upper_tb != (ULONG) read_tbu()); + + /* Store the current thread. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) = + (ULONG) _tx_thread_current_ptr; + + /* Store the first info field. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_1_OFFSET)) = + (ULONG) info_1; + + /* Store the second info field. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_2_OFFSET)) = + (ULONG) info_2; + + /* Store the third info field. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_3_OFFSET)) = + (ULONG) info_3; + + /* Store the fourth info field. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_4_OFFSET)) = + (ULONG) info_4; + + /* Now move the current event log pointer. */ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE; + + /* Check for a wraparound condition. */ + if (entry_ptr >= _tx_el_event_area_end) + { + + /* Yes, we have wrapped around to the end of the event area. + Start back at the top! */ + entry_ptr = _tx_el_event_area_start; + } + + /* Write the entry pointer back into the header. */ + *_tx_el_current_event = entry_ptr; + + /* Restore interrupts. */ + TX_RESTORE +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_el_thread_running PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function inserts a thread change event into the event */ +/* log, which indicates that a context switch is taking place. */ +/* If the event log is full, the oldest event is overwritten. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread being */ +/* scheduled */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_schedule ThreadX scheduler */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* */ +/**************************************************************************/ +VOID _tx_el_thread_running(TX_THREAD *thread_ptr) +{ + +UINT upper_tb; +UCHAR *entry_ptr; + + TX_EL_NO_STATUS_EVENTS + + /* Increment total event counter. */ + _tx_el_total_events++; + + /* Setup working entry pointer first. */ + entry_ptr = *_tx_el_current_event; + + /* Store the event type. */ + *((unsigned short *) entry_ptr) = (unsigned short) TX_EL_THREAD_CHANGE; + + /* Store the event subtype. */ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = + (unsigned short) 0; + + /* Get time stamp. */ + do + { + + /* Pickup the upper tb. */ + upper_tb = (ULONG) read_tbu(); + + /* Store the upper time stamp. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = + (ULONG) upper_tb; + + /* Store the lower time stamp. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) = + (ULONG) read_tbl(); + } while (upper_tb != (ULONG) read_tbu()); + + /* Store the current thread. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) = + (ULONG) thread_ptr; + + /* Now move the current event log pointer. */ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE; + + /* Check for a wraparound condition. */ + if (entry_ptr >= _tx_el_event_area_end) + { + + /* Yes, we have wrapped around to the end of the event area. + Start back at the top! */ + entry_ptr = _tx_el_event_area_start; + } + + /* Write the entry pointer back into the header. */ + *_tx_el_current_event = entry_ptr; + + TX_EL_END_FILTER +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_el_thread_preempted PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function inserts a thread preempted event into the event */ +/* log, which indicates that an interrupt occurred that made a higher */ +/* priority thread ready for execution. In this case, the previously */ +/* executing thread has an event entered to indicate it is no longer */ +/* running. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread being */ +/* scheduled */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_context_restore ThreadX context restore */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* */ +/**************************************************************************/ +VOID _tx_el_thread_preempted(TX_THREAD *thread_ptr) +{ + +UINT upper_tb; +UCHAR *entry_ptr; + + + TX_EL_NO_STATUS_EVENTS + + /* Increment total event counter. */ + _tx_el_total_events++; + + /* Setup working entry pointer first. */ + entry_ptr = *_tx_el_current_event; + + /* Store the event type. */ + *((unsigned short *) entry_ptr) = (unsigned short) TX_EL_THREAD_STATUS_CHANGE; + + /* Store the event subtype. */ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = + (unsigned short) TX_READY; + + /* Get time stamp. */ + do + { + + /* Pickup the upper tb. */ + upper_tb = (ULONG) read_tbu(); + + /* Store the upper time stamp. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = + (ULONG) upper_tb; + + /* Store the lower time stamp. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) = + (ULONG) read_tbl(); + } while (upper_tb != (ULONG) read_tbu()); + + /* Store the current thread. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) = + (ULONG) _tx_thread_current_ptr; + + /* Now move the current event log pointer. */ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE; + + /* Check for a wraparound condition. */ + if (entry_ptr >= _tx_el_event_area_end) + { + + /* Yes, we have wrapped around to the end of the event area. + Start back at the top! */ + entry_ptr = _tx_el_event_area_start; + } + + /* Write the entry pointer back into the header. */ + *_tx_el_current_event = entry_ptr; + + TX_EL_END_FILTER +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_el_interrupt PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function inserts an interrupt event into the log, which */ +/* indicates the start of interrupt processing for the specific */ +/* */ +/* INPUT */ +/* */ +/* interrupt_number Interrupt number supplied by */ +/* ISR */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* ISR processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* */ +/**************************************************************************/ +VOID _tx_el_interrupt(UINT interrupt_number) +{ + +UINT upper_tb; +UCHAR *entry_ptr; + + + TX_EL_NO_INTERRUPT_EVENTS + + /* Increment total event counter. */ + _tx_el_total_events++; + + /* Setup working entry pointer first. */ + entry_ptr = *_tx_el_current_event; + + /* Store the event type. */ + *((unsigned short *) entry_ptr) = (unsigned short) TX_EL_INTERRUPT; + + /* Store the event subtype. */ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = + (unsigned short) TX_EL_INTERRUPT_SUB_TYPE; + + /* Get time stamp. */ + do + { + + /* Pickup the upper tb. */ + upper_tb = (ULONG) read_tbu(); + + /* Store the upper time stamp. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = + (ULONG) upper_tb; + + /* Store the lower time stamp. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) = + (ULONG) read_tbl(); + } while (upper_tb != (ULONG) read_tbu()); + + /* Store the current thread. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) = + (ULONG) _tx_thread_current_ptr; + + /* Store the first info word. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_1_OFFSET)) = + (ULONG) interrupt_number; + + /* Now move the current event log pointer. */ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE; + + /* Check for a wraparound condition. */ + if (entry_ptr >= _tx_el_event_area_end) + { + + /* Yes, we have wrapped around to the end of the event area. + Start back at the top! */ + entry_ptr = _tx_el_event_area_start; + } + + /* Write the entry pointer back into the header. */ + *_tx_el_current_event = entry_ptr; + + TX_EL_END_FILTER +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_el_interrupt_end PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function inserts an interrupt end event into the log, which */ +/* indicates the end of interrupt processing for the specific */ +/* */ +/* INPUT */ +/* */ +/* interrupt_number Interrupt number supplied by */ +/* ISR */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* ISR processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* */ +/**************************************************************************/ +VOID _tx_el_interrupt_end(UINT interrupt_number) +{ + +UINT upper_tb; +UCHAR *entry_ptr; + + + TX_EL_NO_INTERRUPT_EVENTS + + /* Increment total event counter. */ + _tx_el_total_events++; + + /* Setup working entry pointer first. */ + entry_ptr = *_tx_el_current_event; + + /* Store the event type. */ + *((unsigned short *) entry_ptr) = (unsigned short) TX_EL_INTERRUPT; + + /* Store the event subtype. */ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = + (unsigned short) TX_EL_END_OF_INTERRUPT; + + /* Get time stamp. */ + do + { + + /* Pickup the upper tb. */ + upper_tb = (ULONG) read_tbu(); + + /* Store the upper time stamp. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = + (ULONG) upper_tb; + + /* Store the lower time stamp. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) = + (ULONG) read_tbl(); + } while (upper_tb != (ULONG) read_tbu()); + + /* Store the current thread. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) = + (ULONG) _tx_thread_current_ptr; + + /* Store the first info word. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_1_OFFSET)) = + (ULONG) interrupt_number; + + /* Now move the current event log pointer. */ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE; + + /* Check for a wraparound condition. */ + if (entry_ptr >= _tx_el_event_area_end) + { + + /* Yes, we have wrapped around to the end of the event area. + Start back at the top! */ + entry_ptr = _tx_el_event_area_start; + } + + /* Write the entry pointer back into the header. */ + *_tx_el_current_event = entry_ptr; + + TX_EL_END_FILTER +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_el_interrupt_control PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function remaps the tx_interrupt_control service call so that */ +/* it can be tracked in the event log. */ +/* */ +/* INPUT */ +/* */ +/* new_posture New interrupt posture */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt posture */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_interrupt_control Interrupt control service */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX services */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* */ +/**************************************************************************/ +UINT _tx_el_interrupt_control(UINT new_posture) +{ + +TX_INTERRUPT_SAVE_AREA +UINT old_posture; + + + TX_EL_NO_INTERRUPT_EVENTS + + TX_DISABLE + TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_INTERRUPT_CONTROL, _tx_thread_current_ptr, new_posture) + TX_RESTORE + + TX_EL_END_FILTER + + old_posture = _tx_thread_interrupt_control(new_posture); + return(old_posture); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_el_event_log_on PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function disables all event filters. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* */ +/**************************************************************************/ +VOID _tx_el_event_log_on(void) +{ + + /* Disable all event filters. */ + _tx_el_event_filter = TX_EL_ENABLE_ALL_EVENTS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_el_event_log_off PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets all event filters, thereby turning event */ +/* logging off. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* */ +/**************************************************************************/ +VOID _tx_el_event_log_off(void) +{ + + /* Set all event filters. */ + _tx_el_event_filter = TX_EL_FILTER_ALL_EVENTS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_el_event_log_set PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the events filters specified by the user. */ +/* */ +/* INPUT */ +/* */ +/* filter Events to filter */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* */ +/**************************************************************************/ +VOID _tx_el_event_filter_set(UINT filter) +{ + + /* Apply the user event filter. */ + _tx_el_event_filter = filter; +} + diff --git a/ports_arch/ARMv7-M/threadx/ghs/src/tx_ghs.c b/ports_arch/ARMv7-M/threadx/ghs/src/tx_ghs.c new file mode 100644 index 00000000..30b8054e --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ghs/src/tx_ghs.c @@ -0,0 +1,485 @@ +/* + * ThreadX C/C++ Library Support + * + * Copyright 1983-2019 Green Hills Software LLC. + * + * This program is the property of Green Hills Software LLC., + * its contents are proprietary information and no part of it + * is to be disclosed to anyone except employees of Green Hills + * Software LLC., or as agreed in writing signed by the President + * of Green Hills Software LLC. + */ + +#include "tx_ghs.h" +#ifndef TX_DISABLE_ERROR_CHECKING +#define TX_DISABLE_ERROR_CHECKING +#endif +#include "tx_api.h" +#include +#include + +/* Allow these routines to access the following ThreadX global variables. */ +extern ULONG _tx_thread_created_count; +extern TX_THREAD *_tx_thread_created_ptr; +extern TX_THREAD *_tx_thread_current_ptr; + +#if defined(__ghs) && (__GHS_VERSION_NUMBER >= 500) +/* Thread-local storage routines for Green Hills releases 5.x and above. */ +/* + Thread-Local (Per-Thread) Library Data Retrieval + ================================================ + + __ghs_ThreadLocalStorage_specifier defines all library data items + that the Green Hills libraries allow to be allocated per-thread. + + An implementation can choose which of these data items to allocate + for each thread. For example, an implementation may choose to + allocate an errno value for each thread, but not the strtok_saved_pos + pointer. The application could then use strtok_r instead of strtok for + correct operation. + + To add per-thread library data, define one of the + TX_THREAD_EXTENSION_* macros in tx_port.h to include the data item + or items in each thread control block TX_THREAD. + + If C++ with exceptions is being used, the __eh_globals entry must be + allocated for each thread. This is typically done by default using + TX_THREAD_EXTENSION_1 in tx_port.h. + + If __ghs_GetThreadLocalStorageItem is customized to return a + per-thread errno value, you should also: + + * Customize the System Library for your project + * Define the preprocessor symbol USE_THREAD_LOCAL_ERRNO in + src/libsys/ind_errn.c + + If you customize the System Library, you should remove ind_thrd.c + from the libsys.gpj subproject. + + */ + +/* Provide global __eh_globals value to support C++ exception handling + outside a thread context. This name also forces this module to be + included in the linked program instead of the ind_thrd.o module from + the System Library libsys.a. + */ +static void *__eh_globals; + +#pragma ghs startnomisra +void *__ghs_GetThreadLocalStorageItem(int specifier) +{ + void *ptlsitem = (void *)0; + switch (specifier) { + case (int)__ghs_TLS_Errno: + /* Set ptslsitem to the address of the per-thread errno value. + The per-thread errno value should have the type int. + + If returning a per-thread errno value, follow the steps + above. + + This item is used by numerous library functions. + */ + break; + case (int)__ghs_TLS_SignalHandlers: + /* Set ptslsitem to the address of the per-thread SignalHandlers + array. The per-thread SignalHandlers array should have the + array type as in the following declaration: + SignalHandler SignalHandlers[_SIGMAX]; + The SignalHandler type and _SIGMAX constant are defined in + ind_thrd.h. + + This item is used by the library functions signal() and + raise(). + */ + break; + case (int)__ghs_TLS_asctime_buff: + /* Set ptslsitem to the address of the per-thread asctime_buff + array. The per-thread asctime_buff array should have the + array type as in the following declaration: + char asctime_buff[30]; + + This item is used by the library functions asctime() and + ctime(). The library provides asctime_r() and ctime_r(), + inherently thread-safe versions of these functions. + */ + break; + case (int)__ghs_TLS_tmpnam_space: + /* Set ptslsitem to the address of the per-thread tmpnam_space + array. The per-thread tmpnam_space array should have the + array type as in the following declaration: + char tmpnam_space[L_tmpnam]; + The constant is defined in + + This item is used by the library function tmpnam() when + passed NULL. The library provides tmpnam_r(), an + inherently thread-safe version of tmpnam(). + */ + break; + case (int)__ghs_TLS_strtok_saved_pos: + /* Set ptslsitem to the address of the per-thread + strtok_saved_pos pointer. The per-thread strtok_saved_pos + pointer should have the type "char *". + + This item is used by the library function strtok(). + The library provides strtok_r(), an inherently thread-safe + version of strtok(). + */ + break; + case (int)__ghs_TLS_gmtime_temp: + /* Set ptslsitem to the address of the per-thread gmtime_temp + value. The per-thread gmtime_temp value should have the + type "struct tm" defined in time.h, included by indos.h. + + This item is used by the library functions gmtime() and + localtime(). The library provides gmtime_r() and + localtime_r(), inherently thread-safe versions of these + functions. + */ + break; + case (int)__ghs_TLS___eh_globals: + /* Set ptslsitem to the address of the per-thread __eh_globals + value. The per-thread __eh_globals value should have the + type "void *". + + This item is used by C++ exception handling. + */ + if (_tx_thread_current_ptr) + ptlsitem = (void *)&(_tx_thread_current_ptr->tx_thread_eh_globals); + else + /* Use the global __eh_globals pointer. */ + ptlsitem = (void *)&__eh_globals; + break; + } + return ptlsitem; +} +#pragma ghs endnomisra +#else +/* Thread-local storage routines for Green Hills releases 4.x and 3.x . */ + +/* + * ThreadX C and C++ thread-safe library support routines. + * + * This implementation merely tries to guarantee thread safety within + * individual C library calls such as malloc() and free(), but it does + * not attempt to solve the problems associated with the following + * multithreaded issues: + * + * 1. Use of errno. This can be made thread-safe by adding errno + * to TX_THREAD_PORT_EXTENSION and using that within a modified + * version of libsys/ind_errno.c. + * + * 2. Thread safety ACROSS library calls. Certain C library calls either + * return pointers to statically-allocated data structures or maintain + * state across calls. These include strtok(), asctime(), gmtime(), + * tmpnam(NULL), signal(). To make such C library routines thread-safe + * would require adding a ThreadLocalStorage struct to the thread control + * block TX_THREAD. Since relatively few applications make use of these + * library routines, the implementation provided here uses a single, global + * ThreadLocalStorage data structure rather than greatly increasing the size + * of the thread control block TX_THREAD. + * + * The ThreadX global variable _tx_thread_current_ptr points to the + * current thread's control block TX_THREAD. If a ThreadLocalStorage struct + * called tx_tls is placed in TX_THREAD, the function GetThreadLocalStorage + * should be modified to return &(_tx_thread_current_ptr->tx_tls). + */ + +static ThreadLocalStorage GlobalTLS; + +ThreadLocalStorage *GetThreadLocalStorage() +{ + return &GlobalTLS; +} +#endif + +/* + * Use a global ThreadX mutex to implement thread safety within C and C++ + * library routines. + * + */ +TX_MUTEX __ghLockMutex; + +/* + * Acquire general lock. Blocks until the lock becomes available. + * Use tx_mutex_get to implement __ghsLock + */ +void __ghsLock(void) +{ + tx_mutex_get(&__ghLockMutex, TX_WAIT_FOREVER); +} + +/* + * Release general lock + * Use tx_mutex_put to implement __ghsUnlock + */ +void __ghsUnlock(void) +{ + tx_mutex_put(&__ghLockMutex); +} + +/* ThreadX Initialization function prototype. */ +void _tx_initialize_kernel_setup(void); + +void __gh_lock_init(void) +{ + /* Initialize the low-level portions of ThreadX. */ + _tx_initialize_kernel_setup(); + + /* Create the global thread lock mutex. */ + tx_mutex_create(&__ghLockMutex, "__ghLockMutex", TX_NO_INHERIT); +} + +/* + Saving State Across setjmp() Calls + ================================== + + These routines can be used to save and restore arbitrary state + across calls to setjmp() and longjmp(). +*/ +int __ghs_SaveSignalContext(jmp_buf jmpbuf) +{ + return 0; +} + +/* Restore arbitrary state across a longjmp() */ +void __ghs_RestoreSignalContext(jmp_buf jmpbuf) +{ +} + +#if defined(__GHS_VERSION_NUMBER) && (__GHS_VERSION_NUMBER < 560) +/* + C++ Exception Handling + ====================== + + These routines allow C++ exceptions to be used in multiple threads. + The default implementation uses __ghs_GetThreadLocalStorageItem + to return a thread-specific __eh_globals pointer. + +*/ + +/* Must be called after __cpp_exception_init() is called to allocate + * and initialize the per-thread exception handling structure */ +void *__get_eh_globals(void) +{ +#if defined(__ghs) && (__GHS_VERSION_NUMBER >= 500) + return *(void **)__ghs_GetThreadLocalStorageItem(__ghs_TLS___eh_globals); +#else + if (_tx_thread_current_ptr) + + /* Return thread-specific __eh_globals pointer. */ + return _tx_thread_current_ptr->tx_thread_eh_globals; + else + /* Return the global __eh_globals pointer. */ + return GlobalTLS.__eh_globals; +#endif +} +#endif + +#if defined(__ghs) && (__GHS_VERSION_NUMBER >= 500) +#pragma weak __cpp_exception_init +extern void __cpp_exception_init(void **); +#pragma weak __cpp_exception_cleanup +extern void __cpp_exception_cleanup(void **); + +/* __tx_cpp_exception_init retrieves the eh_globals field from + thread-local storage and calls __cpp_exception_init. + */ +void __tx_cpp_exception_init(TX_THREAD *thread_ptr) { + void **peh_globals; + if(__cpp_exception_init) { + if (thread_ptr) + peh_globals = &(thread_ptr->tx_thread_eh_globals); + else + /* Use the global __eh_globals pointer. */ + peh_globals = &__eh_globals; + __cpp_exception_init(peh_globals); + } +} + +/* __tx_cpp_exception_cleanup retrieves the eh_globals field from + thread-local storage and calls __cpp_exception_cleanup. + */ +void __tx_cpp_exception_cleanup(TX_THREAD *thread_ptr) { + void **peh_globals; + if(__cpp_exception_cleanup) { + if (thread_ptr) + peh_globals = &(thread_ptr->tx_thread_eh_globals); + else + /* Use the global __eh_globals pointer. */ + peh_globals = &__eh_globals; + __cpp_exception_cleanup(peh_globals); + } +} + +/* __ghs_cpp_exception_init is called from ind_crt1.o to initialize + exceptions for the global context. + */ +void __ghs_cpp_exception_init() { + __tx_cpp_exception_init((void *)0); +} + +/* __ghs_cpp_exception_cleanup is called from ind_exit.o to clean up + exceptions for the global context. + */ +void __ghs_cpp_exception_cleanup(TX_THREAD *thread_ptr) { + __tx_cpp_exception_cleanup((void *)0); +} +#endif + + +/* + File Locks + ====================== + + These routines can be customized to implement per-file locks to allow + thread-safe I/O. + +*/ + +/* Acquire lock for FILE *addr */ +void __ghs_flock_file(void *addr) +{ + tx_mutex_get((TX_MUTEX *)addr, TX_WAIT_FOREVER); +} + +/* Release lock for FILE *addr */ +void __ghs_funlock_file(void *addr) +{ + tx_mutex_put((TX_MUTEX *)addr); +} + +/* Non blocking acquire lock for FILE *addr. May return -1 if */ +/* not implemented. Returns 0 on success and nonzero otherwise. */ +int __ghs_ftrylock_file(void *addr) +{ + return -1; +} + +/* Calls to initialize local lock data structures before they */ +/* are used. */ +void __ghs_flock_create(void **addr) +{ + *addr = (void *)(&__ghLockMutex); +} +void __ghs_flock_destroy(void *addr) {} + + +/* + * ThreadX Peak Stack Checking support routines. + * + * All of these routines are called by MULTI's ThreadX-aware debugging + * package to determine the peak stack use for one thread or for all threads. + * + * These routines are included in this file in order to guarantee that they will + * be available while debugging with MULTI. These routines are not referenced by + * any other part of the ThreadX system. + * + * _txs_thread_stack_check: return the peak stack usage for a thread. + * + * _txs_thread_stack_check_2: store the peak stack usage for all threads + * in the tx_thread_stack_size field of each thread + * control block, TX_THREAD. This routine takes + * advantage of the redundancy within the TX_THREAD + * structure since tx_thread_stack_size can be computed + * from the tx_thread_stack_start and tx_thread_stack_end + * fields of TX_THREAD. + * + * _txs_thread_stack_check_2_fixup: clean up from the _txs_thread_stack_check_2 + * call by computing the stack size for each + * thread and storing the result in the + * tx_thread_stack_size field of each thread control + * block TX_THREAD. + * + * These three routines do not support architectures such as i960 or StarCore + * where the stack grows up instead of down. + * + */ +#ifndef TX_DISABLE_STACK_CHECKING + +ULONG _txs_thread_stack_check(TX_THREAD *thread_ptr) +{ + CHAR *cp; /* Pointer inside thread's stack. */ + + /* Search through the thread's stack to find the highest address modified. */ + for ( cp = (CHAR *)thread_ptr->tx_thread_stack_start; + cp <= (CHAR *)thread_ptr->tx_thread_stack_end; ++cp ) { + + /* Check if this byte in the stack contains something other than TX_STACK_FILL. */ + if (*cp != (char)TX_STACK_FILL) { + + /* Assume cp points to the locating marking the peak stack use. + Return the number of bytes from cp up to and including the + end of the stack. */ + return (((ULONG)thread_ptr->tx_thread_stack_end) - (ULONG)cp + 1); + } + } + return thread_ptr->tx_thread_stack_size; +} + + +int _txs_thread_stack_check_2(void) { + CHAR * cp; /* Pointer inside thread's stack. */ + TX_THREAD * tp; /* Pointer to each thread. */ + + /* If no threads are created, return immediately. */ + if (!_tx_thread_created_count) + return 0; + + /* Start iterating through the threads in the system. Assume that we always + have at least one thread (the system timer thread) in the system. */ + tp = _tx_thread_created_ptr; + + do { + + /* Search through the thread's stack to find the highest address modified. */ + for ( cp = (CHAR *)tp->tx_thread_stack_start; cp <= (CHAR *)tp->tx_thread_stack_end; + ++cp ) { + + /* Check if this byte in the stack contains something other than TX_STACK_FILL. */ + if (*cp != (char)TX_STACK_FILL) { + + /* Assume cp points to the locating marking the peak stack use. + Store the number of bytes from cp up to and including the + end of the stack in the tx_thread_stack_size field. */ + tp->tx_thread_stack_size = ((ULONG)tp->tx_thread_stack_end) - (ULONG)cp + 1; + break; + } + + } + + /* Continue with the next thread. */ + tp = tp->tx_thread_created_next; + + /* Loop until we point to the first thread again. */ + } while ( tp != _tx_thread_created_ptr ); + + return 0; +} + +int _txs_thread_stack_check_2_fixup(void) { + TX_THREAD * tp; /* Pointer to each thread. */ + + /* If no threads are created, return immediately. */ + if (!_tx_thread_created_count) + return 0; + + /* Start iterating through the threads in the system. Assume that we always + have at least one thread (the system timer thread) in the system. */ + tp = _tx_thread_created_ptr; + + do { + + /* Compute the tx_thread_stack_size field by using the tx_thread_stack_end and + tx_thread_stack_start fields. */ + tp->tx_thread_stack_size = (ULONG)tp->tx_thread_stack_end-(ULONG)tp->tx_thread_stack_start+1; + + /* Continue with the next thread. */ + tp = tp->tx_thread_created_next; + + /* Loop until we point to the first thread again. */ + } while ( tp != _tx_thread_created_ptr ); + + return 0; +} + +#endif /* TX_DISABLE_STACK_CHECKING */ diff --git a/ports_arch/ARMv7-M/threadx/ghs/src/tx_ghse.c b/ports_arch/ARMv7-M/threadx/ghs/src/tx_ghse.c new file mode 100644 index 00000000..6369df77 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ghs/src/tx_ghse.c @@ -0,0 +1,49 @@ +/* + * ThreadX C++ Library Support + * + * Copyright 1983-2019 Green Hills Software LLC. + * + * This program is the property of Green Hills Software LLC., + * its contents are proprietary information and no part of it + * is to be disclosed to anyone except employees of Green Hills + * Software LLC., or as agreed in writing signed by the President + * of Green Hills Software LLC. + */ +#include "tx_ghs.h" +#ifndef TX_DISABLE_ERROR_CHECKING +#define TX_DISABLE_ERROR_CHECKING +#endif +#include "tx_api.h" + +/* + C++ Exception Handling + ====================== + + These routines allow C++ exceptions to be used in multiple threads. + The default implementation uses __ghs_GetThreadLocalStorageItem + to return a thread-specific __eh_globals pointer. + +*/ + +#if defined(__ghs) && (__GHS_VERSION_NUMBER >= 560) +#ifdef _WIN32 +/* Windows uses a different linker, so include a stub routine, never called, + to pull in __cpp_exception_init and __cpp_exception_cleanup */ +extern void __cpp_exception_init(void **); +extern void __cpp_exception_cleanup(void **); +void __tx_win32_pull_in_exceptions(void) { + __cpp_exception_init(0); + __cpp_exception_cleanup(0); +} +#else +#pragma ghs reference __cpp_exception_init +#pragma ghs reference __cpp_exception_cleanup +#endif + +/* Must be called after __cpp_exception_init() is called to allocate + * and initialize the per-thread exception handling structure */ +void *__get_eh_globals(void) +{ + return *(void **)__ghs_GetThreadLocalStorageItem(__ghs_TLS___eh_globals); +} +#endif diff --git a/ports_arch/ARMv7-M/threadx/ghs/src/tx_thread_context_restore.arm b/ports_arch/ARMv7-M/threadx/ghs/src/tx_thread_context_restore.arm new file mode 100644 index 00000000..8358c1e6 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ghs/src/tx_thread_context_restore.arm @@ -0,0 +1,78 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .align 4 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_restore Cortex-Mx/GHS */ +/* 6.1.7 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is only needed for legacy applications and it should */ +/* not be called in any new development on a Cortex-M. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* [_tx_execution_isr_exit] Execution profiling ISR exit */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs Interrupt Service Routines */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_context_restore(VOID) +// { + .globl _tx_thread_context_restore +_tx_thread_context_restore: + +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + /* Call the ISR exit function to indicate an ISR is complete. */ + PUSH {r0, lr} // Save return address + BL _tx_execution_isr_exit // Call the ISR exit function + POP {r0, lr} // Recover return address +#endif + + BX lr +// } + .type _tx_thread_context_restore,$function + .size _tx_thread_context_restore,.-_tx_thread_context_restore diff --git a/ports_arch/ARMv7-M/threadx/ghs/src/tx_thread_context_save.arm b/ports_arch/ARMv7-M/threadx/ghs/src/tx_thread_context_save.arm new file mode 100644 index 00000000..bc323ef4 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ghs/src/tx_thread_context_save.arm @@ -0,0 +1,80 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .align 4 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_save Cortex-Mx/GHS */ +/* 6.1.7 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is only needed for legacy applications and it should */ +/* not be called in any new development on a Cortex-M. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* [_tx_execution_isr_enter] Execution profiling ISR enter */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_context_save(VOID) +// { + .globl _tx_thread_context_save +_tx_thread_context_save: + +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + /* Call the ISR enter function to indicate an ISR is starting. */ + PUSH {r0, lr} // Save return address + BL _tx_execution_isr_enter // Call the ISR enter function + POP {r0, lr} // Recover return address +#endif + + /* Context is already saved - just return. */ + + BX lr +// } + .type _tx_thread_context_save,$function + .size _tx_thread_context_save,.-_tx_thread_context_save diff --git a/ports_arch/ARMv7-M/threadx/ghs/src/tx_thread_interrupt_control.arm b/ports_arch/ARMv7-M/threadx/ghs/src/tx_thread_interrupt_control.arm new file mode 100644 index 00000000..527beda7 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ghs/src/tx_thread_interrupt_control.arm @@ -0,0 +1,73 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .align 4 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_control Cortex-Mx/GHS */ +/* 6.1.7 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for changing the interrupt lockout */ +/* posture of the system. */ +/* */ +/* INPUT */ +/* */ +/* new_posture New interrupt lockout posture */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_interrupt_control(UINT new_posture) +// { + .globl _tx_thread_interrupt_control +_tx_thread_interrupt_control: + MRS r1, PRIMASK // Pickup current interrupt lockout + MSR PRIMASK, r0 // Apply the new interrupt lockout + MOV r0, r1 // Transfer old to return register + BX lr // Return to caller +// } + .type _tx_thread_interrupt_control,$function + .size _tx_thread_interrupt_control,.-_tx_thread_interrupt_control diff --git a/ports_arch/ARMv7-M/threadx/ghs/src/tx_thread_interrupt_disable.arm b/ports_arch/ARMv7-M/threadx/ghs/src/tx_thread_interrupt_disable.arm new file mode 100644 index 00000000..0ef5aa92 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ghs/src/tx_thread_interrupt_disable.arm @@ -0,0 +1,74 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .align 4 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_disable Cortex-Mx/GHS */ +/* 6.1.7 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for disabling interrupts and returning */ +/* the previous interrupt lockout posture. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_interrupt_disable(VOID) +// { + .globl _tx_thread_interrupt_disable +_tx_thread_interrupt_disable: + + /* Return current interrupt lockout posture. */ + MRS r0, PRIMASK + CPSID i + BX lr +// } + .type _tx_thread_interrupt_disable,$function + .size _tx_thread_interrupt_disable,.-_tx_thread_interrupt_disable diff --git a/ports_arch/ARMv7-M/threadx/ghs/src/tx_thread_interrupt_restore.arm b/ports_arch/ARMv7-M/threadx/ghs/src/tx_thread_interrupt_restore.arm new file mode 100644 index 00000000..96fca141 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ghs/src/tx_thread_interrupt_restore.arm @@ -0,0 +1,73 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .align 4 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_restore Cortex-Mx/GHS */ +/* 6.1.7 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for restoring the previous */ +/* interrupt lockout posture. */ +/* */ +/* INPUT */ +/* */ +/* previous_posture Previous interrupt posture */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_interrupt_restore(UINT previous_posture) +// { + .globl _tx_thread_interrupt_restore +_tx_thread_interrupt_restore: + + /* Restore previous interrupt lockout posture. */ + MSR PRIMASK, r0 + BX lr +// } + .type _tx_thread_interrupt_restore,$function + .size _tx_thread_interrupt_restore,.-_tx_thread_interrupt_restore diff --git a/ports_arch/ARMv7-M/threadx/ghs/src/tx_thread_schedule.arm b/ports_arch/ARMv7-M/threadx/ghs/src/tx_thread_schedule.arm new file mode 100644 index 00000000..6b7d5295 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ghs/src/tx_thread_schedule.arm @@ -0,0 +1,291 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .align 4 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_schedule Cortex-Mx/GHS */ +/* 6.1.7 */ +/* 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 */ +/* _tx_thread_context_restore Restore thread's context */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_schedule(VOID) +// { + .globl _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 + + /* Clear CONTROL.FPCA bit so VFP registers aren't unnecessarily stacked. */ + +#ifdef __VFP__ + MRS r0, CONTROL // Pickup current CONTROL register + BIC r0, r0, #4 // Clear the FPCA bit + MSR CONTROL, r0 // Setup new CONTROL register +#endif + + /* 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 + + .type _tx_thread_schedule,$function + .size _tx_thread_schedule,.-_tx_thread_schedule +// } + + /* Generic context switching PendSV handler. */ + + .globl PendSV_Handler + .globl __tx_PendSVHandler +PendSV_Handler: +__tx_PendSVHandler: + + /* Get current thread value and new thread pointer. */ + +__tx_ts_handler: + +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + /* Call the thread exit function to indicate the thread is no longer executing. */ + CPSID i // Disable interrupts + 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 + CPSIE i // Enable interrupts +#endif + + 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 __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 + STR.W LR, [r12, #-0x4]! // 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! */ + + CPSID i // Disable interrupts + LDR r1, [r2] // Is there another thread ready to execute? + CBZ r1, __tx_ts_wait // No, skip to the wait processing + + /* Yes, another thread is ready for else, make the current thread the new thread. */ + + STR r1, [r0] // Setup the current thread pointer to the new thread + CPSIE i // Enable interrupts + + /* Increment the thread run count. */ + +__tx_ts_restore: + 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 + +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + /* 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 + LDR.W LR, [r12], #4 // Pickup LR +#ifdef __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! + + /* 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: + CPSID i // Disable interrupts + LDR r1, [r2] // Pickup the next thread to execute pointer + STR r1, [r0] // Store it in the current 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 + + CPSIE i // Enable interrupts + 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 + + /* Re-enable interrupts and restore new thread. */ + + CPSIE i // Enable interrupts + B __tx_ts_restore // Restore the thread +// } + + .type __tx_PendSVHandler,$function + .size __tx_PendSVHandler,.-__tx_PendSVHandler + +#ifdef __VFP__ + + .globl tx_thread_fpu_enable +tx_thread_fpu_enable: + + /* Automatic VPF logic is supported, this function is present only for + backward compatibility purposes and therefore simply returns. */ + + BX LR // Return to caller + + .type tx_thread_fpu_enable,$function + .size tx_thread_fpu_enable,.-tx_thread_fpu_enable + + .global 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 + + .type tx_thread_fpu_disable,$function + .size tx_thread_fpu_disable,.-tx_thread_fpu_disable + +#endif diff --git a/ports_arch/ARMv7-M/threadx/ghs/src/tx_thread_stack_build.arm b/ports_arch/ARMv7-M/threadx/ghs/src/tx_thread_stack_build.arm new file mode 100644 index 00000000..7c2783a2 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ghs/src/tx_thread_stack_build.arm @@ -0,0 +1,133 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .align 4 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_stack_build Cortex-Mx/GHS */ +/* 6.1.7 */ +/* 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 control blk */ +/* function_ptr Pointer to return function */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_create Create thread service */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID)) +// { + .globl _tx_thread_stack_build +_tx_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 for 8-byte alignment + 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, #24] // Store initial r9 + STR r3, [r2, #28] // Store initial r10 + STR r3, [r2, #32] // Store initial r11 + + /* Hardware stack follows. */ + + STR r3, [r2, #36] // Store initial r0 + STR r3, [r2, #40] // Store initial r1 + 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 +// } + .type _tx_thread_stack_build,$function + .size _tx_thread_stack_build,.-_tx_thread_stack_build diff --git a/ports_arch/ARMv7-M/threadx/ghs/src/tx_thread_system_return.arm b/ports_arch/ARMv7-M/threadx/ghs/src/tx_thread_system_return.arm new file mode 100644 index 00000000..123d7f50 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ghs/src/tx_thread_system_return.arm @@ -0,0 +1,86 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .align 4 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_system_return Cortex-Mx/GHS */ +/* 6.1.7 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is target processor specific. It is used to transfer */ +/* control from a thread back to the ThreadX system. Only a */ +/* minimal context is saved since the compiler assumes temp registers */ +/* are going to get slicked by a function call anyway. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_schedule Thread scheduling loop */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX components */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_system_return(VOID) +// { + .globl _tx_thread_system_return +_tx_thread_system_return: + + /* Return to real scheduler via PendSV. Note that this routine is often + replaced with in-line assembly in tx_port.h to improved performance. */ + + MOV r0, #0x10000000 // Load PENDSVSET bit + MOV r1, #0xE000E000 // Load NVIC base + STR r0, [r1, #0xD04] // Set PENDSVBIT in ICSR + MRS r0, IPSR // Pickup IPSR + CMP r0, #0 // Is it a thread returning? + BNE _isr_context // If ISR, skip interrupt enable + MRS r1, PRIMASK // Thread context returning, pickup PRIMASK + CPSIE i // Enable interrupts + MSR PRIMASK, r1 // Restore original interrupt posture +_isr_context: + BX lr // Return to caller +// } + .type _tx_thread_system_return,$function + .size _tx_thread_system_return,.-_tx_thread_system_return diff --git a/ports_arch/ARMv7-M/threadx/ghs/src/tx_timer_interrupt.arm b/ports_arch/ARMv7-M/threadx/ghs/src/tx_timer_interrupt.arm new file mode 100644 index 00000000..edafb2a1 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ghs/src/tx_timer_interrupt.arm @@ -0,0 +1,241 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .align 4 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_interrupt Cortex-Mx/GHS */ +/* 6.1.7 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the hardware timer interrupt. This */ +/* processing includes incrementing the system clock and checking for */ +/* time slice and/or timer expiration. If either is found, the */ +/* expiration functions are called. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_timer_expiration_process Timer expiration processing */ +/* _tx_thread_time_slice Time slice interrupted thread */ +/* */ +/* CALLED BY */ +/* */ +/* interrupt vector */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* */ +/**************************************************************************/ +// VOID _tx_timer_interrupt(VOID) +// { + .globl _tx_timer_interrupt +_tx_timer_interrupt: + + /* Upon entry to this routine, it is assumed that the compiler scratch registers are available + for use. */ + + /* Increment the system clock. */ + // _tx_timer_system_clock++; + + LDR r1, =_tx_timer_system_clock // Pickup address of system clock + LDR r0, [r1, #0] // Pickup system clock + ADD r0, r0, #1 // Increment system clock + STR r0, [r1, #0] // Store new system clock + + /* Test for time-slice expiration. */ + // if (_tx_timer_time_slice) + // { + + LDR r3, =_tx_timer_time_slice // Pickup address of time-slice + LDR r2, [r3, #0] // Pickup time-slice + CBZ r2, __tx_timer_no_time_slice // Is it non-active? + // Yes, skip time-slice processing + + /* Decrement the time_slice. */ + // _tx_timer_time_slice--; + + SUB r2, r2, #1 // Decrement the time-slice + STR r2, [r3, #0] // Store new time-slice value + + /* Check for expiration. */ + // if (__tx_timer_time_slice == 0) + + CBNZ r2, __tx_timer_no_time_slice // Has it expired? + // No, skip expiration processing + + /* Set the time-slice expired flag. */ + // _tx_timer_expired_time_slice = TX_TRUE; + + LDR r3, =_tx_timer_expired_time_slice // Pickup address of expired flag + MOV r0, #1 // Build expired value + STR r0, [r3, #0] // Set time-slice expiration flag + + // } + +__tx_timer_no_time_slice: + + /* Test for timer expiration. */ + // if (*_tx_timer_current_ptr) + // { + + LDR r1, =_tx_timer_current_ptr // Pickup current timer pointer address + LDR r0, [r1, #0] // Pickup current timer + LDR r2, [r0, #0] // Pickup timer list entry + CBZ r2, __tx_timer_no_timer // Is there anything in the list? + // No, just increment the timer + + /* Set expiration flag. */ + // _tx_timer_expired = TX_TRUE; + + LDR r3, =_tx_timer_expired // Pickup expiration flag address + MOV r2, #1 // Build expired value + STR r2, [r3, #0] // Set expired flag + B __tx_timer_done // Finished timer processing + + // } + // else + // { +__tx_timer_no_timer: + + /* No timer expired, increment the timer pointer. */ + // _tx_timer_current_ptr++; + + ADD r0, r0, #4 // Move to next timer + + /* Check for wrap-around. */ + // if (_tx_timer_current_ptr == _tx_timer_list_end) + + LDR r3, =_tx_timer_list_end // Pickup addr of timer list end + LDR r2, [r3, #0] // Pickup list end + CMP r0, r2 // Are we at list end? + BNE __tx_timer_skip_wrap // No, skip wrap-around logic + + /* Wrap to beginning of list. */ + // _tx_timer_current_ptr = _tx_timer_list_start; + + LDR r3, =_tx_timer_list_start // Pickup addr of timer list start + LDR r0, [r3, #0] // Set current pointer to list start + +__tx_timer_skip_wrap: + + STR r0, [r1, #0] // Store new current timer pointer + // } + +__tx_timer_done: + + /* See if anything has expired. */ + // if ((_tx_timer_expired_time_slice) || (_tx_timer_expired)) + // { + + LDR r3, =_tx_timer_expired_time_slice // Pickup addr of expired flag + LDR r2, [r3, #0] // Pickup time-slice expired flag + CBNZ r2, __tx_something_expired // Did a time-slice expire? + // If non-zero, time-slice expired + LDR r1, =_tx_timer_expired // Pickup addr of other expired flag + LDR r0, [r1, #0] // Pickup timer expired flag + CBZ r0, __tx_timer_nothing_expired // Did a timer expire? + // No, nothing expired + +__tx_something_expired: + + STMDB sp!, {r0, lr} // Save the lr register on the stack + // and save r0 just to keep 8-byte alignment + + /* Did a timer expire? */ + // if (_tx_timer_expired) + // { + + LDR r1, =_tx_timer_expired // Pickup addr of expired flag + LDR r0, [r1, #0] // Pickup timer expired flag + CBZ r0, __tx_timer_dont_activate // Check for timer expiration + // If not set, skip timer activation + + /* Process timer expiration. */ + // _tx_timer_expiration_process(); + + BL _tx_timer_expiration_process // Call the timer expiration handling routine + + // } +__tx_timer_dont_activate: + + /* Did time slice expire? */ + // if (_tx_timer_expired_time_slice) + // { + + LDR r3, =_tx_timer_expired_time_slice // Pickup addr of time-slice expired + LDR r2, [r3, #0] // Pickup the actual flag + CBZ r2, __tx_timer_not_ts_expiration // See if the flag is set + // No, skip time-slice processing + + /* Time slice interrupted thread. */ + // _tx_thread_time_slice(); + + BL _tx_thread_time_slice // Call time-slice processing + LDR r0, =_tx_thread_preempt_disable // Build address of preempt disable flag + LDR r1, [r0] // Is the preempt disable flag set? + CBNZ r1, __tx_timer_skip_time_slice // Yes, skip the PendSV logic + LDR r0, =_tx_thread_current_ptr // Build current thread pointer address + LDR r1, [r0] // Pickup the current thread pointer + LDR r2, =_tx_thread_execute_ptr // Build execute thread pointer address + LDR r3, [r2] // Pickup the execute thread pointer + LDR r0, =0xE000ED04 // Build address of control register + LDR r2, =0x10000000 // Build value for PendSV bit + CMP r1, r3 // Are they the same? + BEQ __tx_timer_skip_time_slice // If the same, there was no time-slice performed + STR r2, [r0] // Not the same, issue the PendSV for preemption +__tx_timer_skip_time_slice: + + // } + +__tx_timer_not_ts_expiration: + + LDMIA sp!, {r0, lr} // Recover lr register (r0 is just there for + // the 8-byte stack alignment + + // } + +__tx_timer_nothing_expired: + + DSB // Complete all memory access + BX lr // Return to caller + +// } + .type _tx_timer_interrupt,$function + .size _tx_timer_interrupt,.-_tx_timer_interrupt diff --git a/ports_arch/ARMv7-M/threadx/ghs/src/txr_ghs.c b/ports_arch/ARMv7-M/threadx/ghs/src/txr_ghs.c new file mode 100644 index 00000000..19572e2b --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/ghs/src/txr_ghs.c @@ -0,0 +1,84 @@ +/* + * ThreadX API Runtime Error Support + * + * Copyright 1983-2019 Green Hills Software LLC. + * + * This program is the property of Green Hills Software LLC., + * its contents are proprietary information and no part of it + * is to be disclosed to anyone except employees of Green Hills + * Software LLC., or as agreed in writing signed by the President + * of Green Hills Software LLC. + */ + +/* #include "tx_ghs.h" */ +#ifndef TX_DISABLE_ERROR_CHECKING +#define TX_DISABLE_ERROR_CHECKING +#endif +#include "tx_api.h" + +/* Customized ThreadX API runtime error support routine. */ + +void _rnerr(int num, int linenum, const char*str, void*ptr, ...); + +/* __ghs_rnerr() + This is the custom runtime error checking routine. + This implementation uses the existing __rnerr() routine. + Another implementation could use the .syscall mechanism, + provided MULTI was modified to understand that. + */ +void __ghs_rnerr(char *errMsg, int stackLevels, int stackTraceDisplay, void *hexVal) { + TX_INTERRUPT_SAVE_AREA + int num; + /* + Initialize the stack levels value. + + Add 3 to account for the calls to _rnerr, __rnerr, and + __ghs_rnerr. + + If the implementation changes, calls to __ghs_rnerr + will not need to be changed. + + Zero is not permitted, so substitute 3 in that case. + */ + num = (stackLevels+3) & 0xf; + if (!num) { + num = 3; + } + /* + Shift the stack levels value to bits 12..15 and + insert the stack trace display value in bit 11. + Bits 0..10 are unused. + */ + num = (num << 12) | (stackTraceDisplay ? 0x800 : 0); + + /* This will mask all interrupts in the RTEC code, which is probably + unacceptable for many targets. */ + TX_DISABLE + _rnerr(num, -1, (const char *)hexVal, (void *)errMsg); + TX_RESTORE +} + + +/* ThreadX thread stack checking runtime support routine. */ + +extern char __ghsbegin_stack[]; +extern TX_THREAD *_tx_thread_current_ptr; + +void __stkchk(void) { + int i; + if(_tx_thread_current_ptr) + { + if((unsigned)(&i) <= + (unsigned)(_tx_thread_current_ptr -> tx_thread_stack_start)) + { + _rnerr(21, -1, 0, 0); + } + } + else + { + if((unsigned)(&i) <= (unsigned)__ghsbegin_stack) + { + _rnerr(21, -1, 0, 0); + } + } +} diff --git a/ports_arch/ARMv7-M/threadx/gnu/CMakeLists.txt b/ports_arch/ARMv7-M/threadx/gnu/CMakeLists.txt new file mode 100644 index 00000000..ab9464d2 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/gnu/CMakeLists.txt @@ -0,0 +1,18 @@ + +target_sources(${PROJECT_NAME} PRIVATE + # {{BEGIN_TARGET_SOURCES}} + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_restore.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_save.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_interrupt_control.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_interrupt_disable.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_interrupt_restore.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_schedule.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_stack_build.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_system_return.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_interrupt.S + # {{END_TARGET_SOURCES}} +) + +target_include_directories(${PROJECT_NAME} PUBLIC + ${CMAKE_CURRENT_LIST_DIR}/inc +) diff --git a/ports_arch/ARMv7-M/threadx/gnu/example_build/build_threadx.bat b/ports_arch/ARMv7-M/threadx/gnu/example_build/build_threadx.bat new file mode 100644 index 00000000..f5545692 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/gnu/example_build/build_threadx.bat @@ -0,0 +1,230 @@ +del tx.a +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb ../src/tx_thread_stack_build.S +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb ../src/tx_thread_schedule.S +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb ../src/tx_thread_system_return.S +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb ../src/tx_thread_context_save.S +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb ../src/tx_thread_context_restore.S +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb ../src/tx_thread_interrupt_control.S +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb ../src/tx_thread_interrupt_disable.S +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb ../src/tx_thread_interrupt_restore.S +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb ../src/tx_timer_interrupt.S + +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_block_allocate.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_block_pool_cleanup.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_block_pool_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_block_pool_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_block_pool_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_block_pool_initialize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_block_pool_performance_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_block_pool_performance_system_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_block_pool_prioritize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_block_release.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_byte_allocate.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_byte_pool_cleanup.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_byte_pool_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_byte_pool_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_byte_pool_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_byte_pool_initialize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_byte_pool_performance_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_byte_pool_performance_system_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_byte_pool_prioritize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_byte_pool_search.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_byte_release.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_event_flags_cleanup.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_event_flags_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_event_flags_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_event_flags_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_event_flags_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_event_flags_initialize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_event_flags_performance_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_event_flags_performance_system_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_event_flags_set.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_event_flags_set_notify.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_initialize_high_level.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_initialize_kernel_enter.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_initialize_kernel_setup.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_mutex_cleanup.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_mutex_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_mutex_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_mutex_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_mutex_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_mutex_initialize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_mutex_performance_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_mutex_performance_system_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_mutex_prioritize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_mutex_priority_change.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_mutex_put.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_queue_cleanup.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_queue_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_queue_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_queue_flush.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_queue_front_send.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_queue_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_queue_initialize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_queue_performance_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_queue_performance_system_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_queue_prioritize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_queue_receive.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_queue_send.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_queue_send_notify.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_semaphore_ceiling_put.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_semaphore_cleanup.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_semaphore_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_semaphore_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_semaphore_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_semaphore_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_semaphore_initialize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_semaphore_performance_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_semaphore_performance_system_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_semaphore_prioritize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_semaphore_put.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_semaphore_put_notify.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_entry_exit_notify.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_identify.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_initialize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_performance_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_performance_system_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_preemption_change.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_priority_change.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_relinquish.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_reset.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_resume.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_shell_entry.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_sleep.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_stack_analyze.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_stack_error_handler.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_stack_error_notify.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_suspend.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_system_preempt_check.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_system_resume.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_system_suspend.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_terminate.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_time_slice.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_time_slice_change.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_timeout.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_thread_wait_abort.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_time_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_time_set.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_timer_activate.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_timer_change.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_timer_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_timer_deactivate.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_timer_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_timer_expiration_process.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_timer_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_timer_initialize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_timer_performance_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_timer_performance_system_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_timer_system_activate.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_timer_system_deactivate.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_timer_thread_entry.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_trace_buffer_full_notify.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_trace_enable.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_trace_event_filter.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_trace_event_unfilter.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_trace_disable.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_trace_initialize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_trace_interrupt_control.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_trace_isr_enter_insert.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_trace_isr_exit_insert.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_trace_object_register.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_trace_object_unregister.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/tx_trace_user_event_insert.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_block_allocate.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_block_pool_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_block_pool_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_block_pool_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_block_pool_prioritize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_block_release.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_byte_allocate.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_byte_pool_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_byte_pool_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_byte_pool_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_byte_pool_prioritize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_byte_release.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_event_flags_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_event_flags_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_event_flags_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_event_flags_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_event_flags_set.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_event_flags_set_notify.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_mutex_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_mutex_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_mutex_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_mutex_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_mutex_prioritize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_mutex_put.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_queue_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_queue_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_queue_flush.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_queue_front_send.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_queue_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_queue_prioritize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_queue_receive.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_queue_send.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_queue_send_notify.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_semaphore_ceiling_put.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_semaphore_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_semaphore_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_semaphore_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_semaphore_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_semaphore_prioritize.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_semaphore_put.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_semaphore_put_notify.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_thread_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_thread_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_thread_entry_exit_notify.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_thread_info_get.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_thread_preemption_change.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_thread_priority_change.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_thread_relinquish.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_thread_reset.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_thread_resume.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_thread_suspend.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_thread_terminate.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_thread_time_slice_change.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_thread_wait_abort.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_timer_activate.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_timer_change.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_timer_create.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_timer_deactivate.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_timer_delete.c +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc ../../../../common/src/txe_timer_info_get.c + +arm-none-eabi-ar -r tx.a tx_thread_stack_build.o tx_thread_schedule.o tx_thread_system_return.o tx_thread_context_save.o tx_thread_context_restore.o tx_timer_interrupt.o tx_thread_interrupt_control.o +arm-none-eabi-ar -r tx.a tx_block_allocate.o tx_block_pool_cleanup.o tx_block_pool_create.o tx_block_pool_delete.o tx_block_pool_info_get.o +arm-none-eabi-ar -r tx.a tx_block_pool_initialize.o tx_block_pool_performance_info_get.o tx_block_pool_performance_system_info_get.o tx_block_pool_prioritize.o +arm-none-eabi-ar -r tx.a tx_block_release.o tx_byte_allocate.o tx_byte_pool_cleanup.o tx_byte_pool_create.o tx_byte_pool_delete.o tx_byte_pool_info_get.o +arm-none-eabi-ar -r tx.a tx_byte_pool_initialize.o tx_byte_pool_performance_info_get.o tx_byte_pool_performance_system_info_get.o tx_byte_pool_prioritize.o +arm-none-eabi-ar -r tx.a tx_byte_pool_search.o tx_byte_release.o tx_event_flags_cleanup.o tx_event_flags_create.o tx_event_flags_delete.o tx_event_flags_get.o +arm-none-eabi-ar -r tx.a tx_event_flags_info_get.o tx_event_flags_initialize.o tx_event_flags_performance_info_get.o tx_event_flags_performance_system_info_get.o +arm-none-eabi-ar -r tx.a tx_event_flags_set.o tx_event_flags_set_notify.o tx_initialize_high_level.o tx_initialize_kernel_enter.o tx_initialize_kernel_setup.o +arm-none-eabi-ar -r tx.a tx_mutex_cleanup.o tx_mutex_create.o tx_mutex_delete.o tx_mutex_get.o tx_mutex_info_get.o tx_mutex_initialize.o tx_mutex_performance_info_get.o +arm-none-eabi-ar -r tx.a tx_mutex_performance_system_info_get.o tx_mutex_prioritize.o tx_mutex_priority_change.o tx_mutex_put.o tx_queue_cleanup.o tx_queue_create.o +arm-none-eabi-ar -r tx.a tx_queue_delete.o tx_queue_flush.o tx_queue_front_send.o tx_queue_info_get.o tx_queue_initialize.o tx_queue_performance_info_get.o +arm-none-eabi-ar -r tx.a tx_queue_performance_system_info_get.o tx_queue_prioritize.o tx_queue_receive.o tx_queue_send.o tx_queue_send_notify.o tx_semaphore_ceiling_put.o +arm-none-eabi-ar -r tx.a tx_semaphore_cleanup.o tx_semaphore_create.o tx_semaphore_delete.o tx_semaphore_get.o tx_semaphore_info_get.o tx_semaphore_initialize.o +arm-none-eabi-ar -r tx.a tx_semaphore_performance_info_get.o tx_semaphore_performance_system_info_get.o tx_semaphore_prioritize.o tx_semaphore_put.o tx_semaphore_put_notify.o +arm-none-eabi-ar -r tx.a tx_thread_create.o tx_thread_delete.o tx_thread_entry_exit_notify.o tx_thread_identify.o tx_thread_info_get.o tx_thread_initialize.o +arm-none-eabi-ar -r tx.a tx_thread_performance_info_get.o tx_thread_performance_system_info_get.o tx_thread_preemption_change.o tx_thread_priority_change.o tx_thread_relinquish.o +arm-none-eabi-ar -r tx.a tx_thread_reset.o tx_thread_resume.o tx_thread_shell_entry.o tx_thread_sleep.o tx_thread_stack_analyze.o tx_thread_stack_error_handler.o +arm-none-eabi-ar -r tx.a tx_thread_stack_error_notify.o tx_thread_suspend.o tx_thread_system_preempt_check.o tx_thread_system_resume.o tx_thread_system_suspend.o +arm-none-eabi-ar -r tx.a tx_thread_terminate.o tx_thread_time_slice.o tx_thread_time_slice_change.o tx_thread_timeout.o tx_thread_wait_abort.o tx_time_get.o +arm-none-eabi-ar -r tx.a tx_time_set.o tx_timer_activate.o tx_timer_change.o tx_timer_create.o tx_timer_deactivate.o tx_timer_delete.o tx_timer_expiration_process.o +arm-none-eabi-ar -r tx.a tx_timer_info_get.o tx_timer_initialize.o tx_timer_performance_info_get.o tx_timer_performance_system_info_get.o tx_timer_system_activate.o +arm-none-eabi-ar -r tx.a tx_timer_system_deactivate.o tx_timer_thread_entry.o tx_trace_enable.o tx_trace_disable.o tx_trace_initialize.o tx_trace_interrupt_control.o +arm-none-eabi-ar -r tx.a tx_trace_isr_enter_insert.o tx_trace_isr_exit_insert.o tx_trace_object_register.o tx_trace_object_unregister.o tx_trace_user_event_insert.o +arm-none-eabi-ar -r tx.a tx_trace_buffer_full_notify.o tx_trace_event_filter.o tx_trace_event_unfilter.o +arm-none-eabi-ar -r tx.a txe_block_allocate.o txe_block_pool_create.o txe_block_pool_delete.o txe_block_pool_info_get.o txe_block_pool_prioritize.o txe_block_release.o +arm-none-eabi-ar -r tx.a txe_byte_allocate.o txe_byte_pool_create.o txe_byte_pool_delete.o txe_byte_pool_info_get.o txe_byte_pool_prioritize.o txe_byte_release.o +arm-none-eabi-ar -r tx.a txe_event_flags_create.o txe_event_flags_delete.o txe_event_flags_get.o txe_event_flags_info_get.o txe_event_flags_set.o +arm-none-eabi-ar -r tx.a txe_event_flags_set_notify.o txe_mutex_create.o txe_mutex_delete.o txe_mutex_get.o txe_mutex_info_get.o txe_mutex_prioritize.o +arm-none-eabi-ar -r tx.a txe_mutex_put.o txe_queue_create.o txe_queue_delete.o txe_queue_flush.o txe_queue_front_send.o txe_queue_info_get.o txe_queue_prioritize.o +arm-none-eabi-ar -r tx.a txe_queue_receive.o txe_queue_send.o txe_queue_send_notify.o txe_semaphore_ceiling_put.o txe_semaphore_create.o txe_semaphore_delete.o +arm-none-eabi-ar -r tx.a txe_semaphore_get.o txe_semaphore_info_get.o txe_semaphore_prioritize.o txe_semaphore_put.o txe_semaphore_put_notify.o txe_thread_create.o +arm-none-eabi-ar -r tx.a txe_thread_delete.o txe_thread_entry_exit_notify.o txe_thread_info_get.o txe_thread_preemption_change.o txe_thread_priority_change.o +arm-none-eabi-ar -r tx.a txe_thread_relinquish.o txe_thread_reset.o txe_thread_resume.o txe_thread_suspend.o txe_thread_terminate.o txe_thread_time_slice_change.o +arm-none-eabi-ar -r tx.a txe_thread_wait_abort.o txe_timer_activate.o txe_timer_change.o txe_timer_create.o txe_timer_deactivate.o txe_timer_delete.o txe_timer_info_get.o diff --git a/ports_arch/ARMv7-M/threadx/gnu/example_build/build_threadx_sample.bat b/ports_arch/ARMv7-M/threadx/gnu/example_build/build_threadx_sample.bat new file mode 100644 index 00000000..ee3f0008 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/gnu/example_build/build_threadx_sample.bat @@ -0,0 +1,5 @@ +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb cortexm4_vectors.S +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb cortexm4_crt0.S +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb tx_initialize_low_level.S +arm-none-eabi-gcc -c -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -I../../../../common/inc -I../../inc sample_threadx.c +arm-none-eabi-gcc -g -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=vfpv4 -mthumb -T sample_threadx.ld -ereset_handler -nostartfiles -o sample_threadx.out -Wl,-Map=sample_threadx.map cortexm4_vectors.o cortexm4_crt0.o tx_initialize_low_level.o sample_threadx.o tx.a diff --git a/ports_arch/ARMv7-M/threadx/gnu/example_build/cortexm4_crt0.S b/ports_arch/ARMv7-M/threadx/gnu/example_build/cortexm4_crt0.S new file mode 100644 index 00000000..4228fc11 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/gnu/example_build/cortexm4_crt0.S @@ -0,0 +1,91 @@ + .syntax unified + .section .init, "ax" + .code 16 + .align 2 + .thumb_func + + .global _start +_start: + CPSID i + ldr r1, =__stack_end__ + mov sp, r1 + + /* Copy initialised sections into RAM if required. */ + ldr r0, =__data_load_start__ + ldr r1, =__data_start__ + ldr r2, =__data_end__ + bl crt0_memory_copy + + /* Zero bss. */ + ldr r0, =__bss_start__ + ldr r1, =__bss_end__ + mov r2, #0 + bl crt0_memory_set + + /* Setup heap - not recommended for Threadx but here for compatibility reasons */ + ldr r0, = __heap_start__ + ldr r1, = __heap_end__ + sub r1, r1, r0 + mov r2, #0 + str r2, [r0] + add r0, r0, #4 + str r1, [r0] + + /* constructors in case of using C++ */ + ldr r0, =__ctors_start__ + ldr r1, =__ctors_end__ +crt0_ctor_loop: + cmp r0, r1 + beq crt0_ctor_end + ldr r2, [r0] + add r0, #4 + push {r0-r1} + blx r2 + pop {r0-r1} + b crt0_ctor_loop +crt0_ctor_end: + + /* Setup call frame for main() */ + mov r0, #0 + mov lr, r0 + mov r12, sp + +start: + /* Jump to main() */ + mov r0, #0 + mov r1, #0 + ldr r2, =main + blx r2 + /* when main returns, loop forever. */ +crt0_exit_loop: + b crt0_exit_loop + + /* Startup helper functions. */ + +crt0_memory_copy: + cmp r0, r1 + beq memory_copy_done +memory_copy_loop: + ldrb r3, [r0] + add r0, r0, #1 + strb r3, [r1] + add r1, r1, #1 + cmp r1, r2 + bne memory_copy_loop +memory_copy_done: + bx lr + +crt0_memory_set: + cmp r0, r1 + beq memory_set_done + strb r2, [r0] + add r0, r0, #1 + b crt0_memory_set +memory_set_done: + bx lr + + /* Setup attibutes of stack and heap sections so they don't take up room in the elf file */ + .section .stack, "wa", %nobits + .section .stack_process, "wa", %nobits + .section .heap, "wa", %nobits + \ No newline at end of file diff --git a/ports_arch/ARMv7-M/threadx/gnu/example_build/cortexm4_vectors.S b/ports_arch/ARMv7-M/threadx/gnu/example_build/cortexm4_vectors.S new file mode 100644 index 00000000..714944d5 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/gnu/example_build/cortexm4_vectors.S @@ -0,0 +1,77 @@ + .global reset_handler + + .global __tx_NMIHandler + .global __tx_BadHandler + .global __tx_SVCallHandler + .global __tx_DBGHandler + .global PendSV_Handler + .global __tx_SysTickHandler + .global __tx_BadHandler + + .syntax unified + .section .vectors, "ax" + .code 16 + .align 0 + .global _vectors + +_vectors: + .word __stack_end__ + .word reset_handler + .word __tx_NMIHandler + .word __tx_HardfaultHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word 0 // Reserved + .word 0 // Reserved + .word 0 // Reserved + .word 0 // Reserved + .word __tx_SVCallHandler //_SVC_Handler - used by Threadx scheduler // + .word __tx_DBGHandler + .word 0 // Reserved + .word PendSV_Handler + .word __tx_SysTickHandler // Used by Threadx timer functionality + .word __tx_BadHandler // Populate with user Interrupt handler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + + .section .init, "ax" + .thumb_func +reset_handler: + // low level hardware config, such as PLL setup goes here + b _start + + + diff --git a/ports_arch/ARMv7-M/threadx/gnu/example_build/sample_threadx.c b/ports_arch/ARMv7-M/threadx/gnu/example_build/sample_threadx.c new file mode 100644 index 00000000..597f373c --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/gnu/example_build/sample_threadx.c @@ -0,0 +1,370 @@ +/* This is a small demo of the high-performance ThreadX kernel. It includes examples of eight + threads of different priorities, using a message queue, semaphore, mutex, event flags group, + byte pool, and block pool. */ + +#include "tx_api.h" + +#define DEMO_STACK_SIZE 1024 +#define DEMO_BYTE_POOL_SIZE 9120 +#define DEMO_BLOCK_POOL_SIZE 100 +#define DEMO_QUEUE_SIZE 100 + + +/* Define the ThreadX object control blocks... */ + +TX_THREAD thread_0; +TX_THREAD thread_1; +TX_THREAD thread_2; +TX_THREAD thread_3; +TX_THREAD thread_4; +TX_THREAD thread_5; +TX_THREAD thread_6; +TX_THREAD thread_7; +TX_QUEUE queue_0; +TX_SEMAPHORE semaphore_0; +TX_MUTEX mutex_0; +TX_EVENT_FLAGS_GROUP event_flags_0; +TX_BYTE_POOL byte_pool_0; +TX_BLOCK_POOL block_pool_0; +UCHAR memory_area[DEMO_BYTE_POOL_SIZE]; + + +/* Define the counters used in the demo application... */ + +ULONG thread_0_counter; +ULONG thread_1_counter; +ULONG thread_1_messages_sent; +ULONG thread_2_counter; +ULONG thread_2_messages_received; +ULONG thread_3_counter; +ULONG thread_4_counter; +ULONG thread_5_counter; +ULONG thread_6_counter; +ULONG thread_7_counter; + + +/* Define thread prototypes. */ + +void thread_0_entry(ULONG thread_input); +void thread_1_entry(ULONG thread_input); +void thread_2_entry(ULONG thread_input); +void thread_3_and_4_entry(ULONG thread_input); +void thread_5_entry(ULONG thread_input); +void thread_6_and_7_entry(ULONG thread_input); + + +/* Define main entry point. */ + +int main() +{ + + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); +} + + +/* Define what the initial system looks like. */ + +void tx_application_define(void *first_unused_memory) +{ + +CHAR *pointer = TX_NULL; + + + /* Create a byte memory pool from which to allocate the thread stacks. */ + tx_byte_pool_create(&byte_pool_0, "byte pool 0", memory_area, DEMO_BYTE_POOL_SIZE); + + /* Put system definition stuff in here, e.g. thread creates and other assorted + create information. */ + + /* Allocate the stack for thread 0. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create the main thread. */ + tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0, + pointer, DEMO_STACK_SIZE, + 1, 1, TX_NO_TIME_SLICE, TX_AUTO_START); + + + /* Allocate the stack for thread 1. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create threads 1 and 2. These threads pass information through a ThreadX + message queue. It is also interesting to note that these threads have a time + slice. */ + tx_thread_create(&thread_1, "thread 1", thread_1_entry, 1, + pointer, DEMO_STACK_SIZE, + 16, 16, 4, TX_AUTO_START); + + /* Allocate the stack for thread 2. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + tx_thread_create(&thread_2, "thread 2", thread_2_entry, 2, + pointer, DEMO_STACK_SIZE, + 16, 16, 4, TX_AUTO_START); + + /* Allocate the stack for thread 3. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create threads 3 and 4. These threads compete for a ThreadX counting semaphore. + An interesting thing here is that both threads share the same instruction area. */ + tx_thread_create(&thread_3, "thread 3", thread_3_and_4_entry, 3, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 4. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + tx_thread_create(&thread_4, "thread 4", thread_3_and_4_entry, 4, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 5. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create thread 5. This thread simply pends on an event flag which will be set + by thread_0. */ + tx_thread_create(&thread_5, "thread 5", thread_5_entry, 5, + pointer, DEMO_STACK_SIZE, + 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 6. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create threads 6 and 7. These threads compete for a ThreadX mutex. */ + tx_thread_create(&thread_6, "thread 6", thread_6_and_7_entry, 6, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 7. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + tx_thread_create(&thread_7, "thread 7", thread_6_and_7_entry, 7, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the message queue. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_QUEUE_SIZE*sizeof(ULONG), TX_NO_WAIT); + + /* Create the message queue shared by threads 1 and 2. */ + tx_queue_create(&queue_0, "queue 0", TX_1_ULONG, pointer, DEMO_QUEUE_SIZE*sizeof(ULONG)); + + /* Create the semaphore used by threads 3 and 4. */ + tx_semaphore_create(&semaphore_0, "semaphore 0", 1); + + /* Create the event flags group used by threads 1 and 5. */ + tx_event_flags_create(&event_flags_0, "event flags 0"); + + /* Create the mutex used by thread 6 and 7 without priority inheritance. */ + tx_mutex_create(&mutex_0, "mutex 0", TX_NO_INHERIT); + + /* Allocate the memory for a small block pool. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_BLOCK_POOL_SIZE, TX_NO_WAIT); + + /* Create a block memory pool to allocate a message buffer from. */ + tx_block_pool_create(&block_pool_0, "block pool 0", sizeof(ULONG), pointer, DEMO_BLOCK_POOL_SIZE); + + /* Allocate a block and release the block memory. */ + tx_block_allocate(&block_pool_0, (VOID **) &pointer, TX_NO_WAIT); + + /* Release the block back to the pool. */ + tx_block_release(pointer); +} + + + +/* Define the test threads. */ + +void thread_0_entry(ULONG thread_input) +{ + +UINT status; + + + /* This thread simply sits in while-forever-sleep loop. */ + while(1) + { + + /* Increment the thread counter. */ + thread_0_counter++; + + /* Sleep for 10 ticks. */ + tx_thread_sleep(10); + + /* Set event flag 0 to wakeup thread 5. */ + status = tx_event_flags_set(&event_flags_0, 0x1, TX_OR); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + } +} + + +void thread_1_entry(ULONG thread_input) +{ + +UINT status; + + + /* This thread simply sends messages to a queue shared by thread 2. */ + while(1) + { + + /* Increment the thread counter. */ + thread_1_counter++; + + /* Send message to queue 0. */ + status = tx_queue_send(&queue_0, &thread_1_messages_sent, TX_WAIT_FOREVER); + + /* Check completion status. */ + if (status != TX_SUCCESS) + break; + + /* Increment the message sent. */ + thread_1_messages_sent++; + } +} + + +void thread_2_entry(ULONG thread_input) +{ + +ULONG received_message; +UINT status; + + /* This thread retrieves messages placed on the queue by thread 1. */ + while(1) + { + + /* Increment the thread counter. */ + thread_2_counter++; + + /* Retrieve a message from the queue. */ + status = tx_queue_receive(&queue_0, &received_message, TX_WAIT_FOREVER); + + /* Check completion status and make sure the message is what we + expected. */ + if ((status != TX_SUCCESS) || (received_message != thread_2_messages_received)) + break; + + /* Otherwise, all is okay. Increment the received message count. */ + thread_2_messages_received++; + } +} + + +void thread_3_and_4_entry(ULONG thread_input) +{ + +UINT status; + + + /* This function is executed from thread 3 and thread 4. As the loop + below shows, these function compete for ownership of semaphore_0. */ + while(1) + { + + /* Increment the thread counter. */ + if (thread_input == 3) + thread_3_counter++; + else + thread_4_counter++; + + /* Get the semaphore with suspension. */ + status = tx_semaphore_get(&semaphore_0, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Sleep for 2 ticks to hold the semaphore. */ + tx_thread_sleep(2); + + /* Release the semaphore. */ + status = tx_semaphore_put(&semaphore_0); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + } +} + + +void thread_5_entry(ULONG thread_input) +{ + +UINT status; +ULONG actual_flags; + + + /* This thread simply waits for an event in a forever loop. */ + while(1) + { + + /* Increment the thread counter. */ + thread_5_counter++; + + /* Wait for event flag 0. */ + status = tx_event_flags_get(&event_flags_0, 0x1, TX_OR_CLEAR, + &actual_flags, TX_WAIT_FOREVER); + + /* Check status. */ + if ((status != TX_SUCCESS) || (actual_flags != 0x1)) + break; + } +} + + +void thread_6_and_7_entry(ULONG thread_input) +{ + +UINT status; + + + /* This function is executed from thread 6 and thread 7. As the loop + below shows, these function compete for ownership of mutex_0. */ + while(1) + { + + /* Increment the thread counter. */ + if (thread_input == 6) + thread_6_counter++; + else + thread_7_counter++; + + /* Get the mutex with suspension. */ + status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Get the mutex again with suspension. This shows + that an owning thread may retrieve the mutex it + owns multiple times. */ + status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Sleep for 2 ticks to hold the mutex. */ + tx_thread_sleep(2); + + /* Release the mutex. */ + status = tx_mutex_put(&mutex_0); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Release the mutex again. This will actually + release ownership since it was obtained twice. */ + status = tx_mutex_put(&mutex_0); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + } +} diff --git a/ports_arch/ARMv7-M/threadx/gnu/example_build/sample_threadx.ld b/ports_arch/ARMv7-M/threadx/gnu/example_build/sample_threadx.ld new file mode 100644 index 00000000..c65a1346 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/gnu/example_build/sample_threadx.ld @@ -0,0 +1,125 @@ +MEMORY +{ + RAM (wx) : ORIGIN = 0x20000000, LENGTH = 0x00800000 + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00400000 +} + +__STACKSIZE__ = 1024; +__STACKSIZE_PROCESS__ = 0; +__HEAPSIZE__ = 128; + +SECTIONS +{ + .vectors : + { + KEEP(*(.vectors .vectors.*)) + } > FLASH + + .text : + { + *(.text*) + + KEEP(*(.init)) + KEEP(*(.fini)) + + /* .ctors */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + __ctors_start__ = ALIGN(4); + *(SORT(.ctors.*)) + *(.ctors) + __ctors_end__ = ALIGN(4); + + /* .dtors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + __dtors_start__ = ALIGN(4); + *(SORT(.dtors.*)) + *(.dtors) + __dtors_end__ = ALIGN(4); + + *(.rodata*) + + KEEP(*(.eh_frame*)) + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + __data_load_start__ = ALIGN (4); + + .data : AT (__data_load_start__) + { + __data_start__ = .; + + *(vtable) + *(.data*) + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + + KEEP(*(.jcr*)) + . = ALIGN(4); + /* All data end */ + + __data_end__ = .; + + } > RAM + + .bss : + { + . = ALIGN(4); + __bss_start__ = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + + } > RAM + + .heap (COPY): + { + __heap_start__ = ALIGN(4); + *(.heap) + . = ALIGN(. + __HEAPSIZE__, 4); + __heap_end__ = ALIGN(4); + } > RAM + + .stack ALIGN(4) (NOLOAD) : + { + __stack_start__ = ALIGN(4); + *(.stack) + . = ALIGN(. + __STACKSIZE__, 4); + __stack_end__ = ALIGN(4); + } > RAM + + __RAM_segment_used_end__ = .; +} diff --git a/ports_arch/ARMv7-M/threadx/gnu/example_build/tx_initialize_low_level.S b/ports_arch/ARMv7-M/threadx/gnu/example_build/tx_initialize_low_level.S new file mode 100644 index 00000000..fc987ce3 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/gnu/example_build/tx_initialize_low_level.S @@ -0,0 +1,205 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Initialize */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .global _tx_thread_system_stack_ptr + .global _tx_initialize_unused_memory + .global __RAM_segment_used_end__ + .global _tx_timer_interrupt + .global __main + .global _vectors + .global __tx_NMIHandler // NMI + .global __tx_BadHandler // HardFault + .global __tx_SVCallHandler // SVCall + .global __tx_DBGHandler // Monitor + .global __tx_PendSVHandler // PendSV + .global __tx_SysTickHandler // SysTick + .global __tx_IntHandler // Int 0 + +SYSTEM_CLOCK = 6000000 +SYSTICK_CYCLES = ((SYSTEM_CLOCK / 100) -1) + + .text 32 + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_initialize_low_level Cortex-Mx/GNU */ +/* 6.1.10 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for any low-level processor */ +/* initialization, including setting up interrupt vectors, setting */ +/* up a periodic timer interrupt source, saving the system stack */ +/* pointer for use in ISR processing later, and finding the first */ +/* available RAM memory address for tx_application_define. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_initialize_kernel_enter ThreadX entry function */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 01-31-2022 Scott Larson Modified comment(s), added */ +/* TX_NO_TIMER support, */ +/* resulting in version 6.1.10 */ +/* */ +/**************************************************************************/ +// VOID _tx_initialize_low_level(VOID) +// { + .global _tx_initialize_low_level + .thumb_func +_tx_initialize_low_level: + + /* Ensure that interrupts are disabled. */ + CPSID i + + /* Set base of available memory to end of non-initialised RAM area. */ + LDR r0, =_tx_initialize_unused_memory // Build address of unused memory pointer + LDR r1, =__RAM_segment_used_end__ // Build first free address + ADD r1, r1, #4 // + STR r1, [r0] // Setup first unused memory pointer + + /* Setup Vector Table Offset Register. */ + MOV r0, #0xE000E000 // Build address of NVIC registers + LDR r1, =_vectors // Pickup address of vector table + STR r1, [r0, #0xD08] // Set vector table address + + /* Set system stack pointer from vector value. */ + LDR r0, =_tx_thread_system_stack_ptr // Build address of system stack pointer + LDR r1, =_vectors // Pickup address of vector table + LDR r1, [r1] // Pickup reset stack pointer + STR r1, [r0] // Save system stack pointer + +#ifndef TX_NO_TIMER + /* Configure SysTick. */ + MOV r0, #0xE000E000 // Build address of NVIC registers + LDR r1, =SYSTICK_CYCLES + STR r1, [r0, #0x14] // Setup SysTick Reload Value + MOV r1, #0x7 // Build SysTick Control Enable Value + STR r1, [r0, #0x10] // Setup SysTick Control +#endif + + /* Configure handler priorities. */ + LDR r1, =0x00000000 // Rsrv, UsgF, BusF, MemM + STR r1, [r0, #0xD18] // Setup System Handlers 4-7 Priority Registers + LDR r1, =0xFF000000 // SVCl, Rsrv, Rsrv, Rsrv + STR r1, [r0, #0xD1C] // Setup System Handlers 8-11 Priority Registers + // Note: SVC must be lowest priority, which is 0xFF + LDR r1, =0x40FF0000 // SysT, PnSV, Rsrv, DbgM + STR r1, [r0, #0xD20] // Setup System Handlers 12-15 Priority Registers + // Note: PnSV must be lowest priority, which is 0xFF + + /* Return to caller. */ + BX lr +// } + +/* Define shells for each of the unused vectors. */ + .global __tx_BadHandler + .thumb_func +__tx_BadHandler: + B __tx_BadHandler + +/* added to catch the hardfault */ + .global __tx_HardfaultHandler + .thumb_func +__tx_HardfaultHandler: + B __tx_HardfaultHandler + +/* added to catch the SVC */ + .global __tx_SVCallHandler + .thumb_func +__tx_SVCallHandler: + B __tx_SVCallHandler + +/* Generic interrupt handler template */ + .global __tx_IntHandler + .thumb_func +__tx_IntHandler: +// VOID InterruptHandler (VOID) +// { + PUSH {r0, lr} +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + BL _tx_execution_isr_enter // Call the ISR enter function +#endif + /* Do interrupt handler work here */ + /* BL .... */ +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + BL _tx_execution_isr_exit // Call the ISR exit function +#endif + POP {r0, lr} + BX lr +// } + +#ifndef TX_NO_TIMER +/* System Tick timer interrupt handler */ + .global __tx_SysTickHandler + .global SysTick_Handler + .thumb_func +__tx_SysTickHandler: + .thumb_func +SysTick_Handler: +// VOID SysTick_Handler (VOID) +// { + PUSH {r0, lr} +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + BL _tx_execution_isr_enter // Call the ISR enter function +#endif + BL _tx_timer_interrupt +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + BL _tx_execution_isr_exit // Call the ISR exit function +#endif + POP {r0, lr} + BX lr +// } +#endif + +/* NMI, DBG handlers */ + .global __tx_NMIHandler + .thumb_func +__tx_NMIHandler: + B __tx_NMIHandler + + .global __tx_DBGHandler + .thumb_func +__tx_DBGHandler: + B __tx_DBGHandler diff --git a/ports_arch/ARMv7-M/threadx/gnu/readme_threadx.txt b/ports_arch/ARMv7-M/threadx/gnu/readme_threadx.txt new file mode 100644 index 00000000..d9063d65 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/gnu/readme_threadx.txt @@ -0,0 +1,209 @@ + Microsoft's Azure RTOS ThreadX for ARMv7-M + (Cortex-M3, Cortex-M4, Cortex-M7) + Using the GNU Tools + + +1. Building the ThreadX run-time Library + +Navigate to the "example_build" directory. Ensure that +you have setup your path and other environment variables necessary for the ARM +GNU compiler. At this point you may run the build_threadx.bat batch file. +This will build the ThreadX run-time environment in the "example_build" +directory. + +You should observe assembly and compilation of a series of ThreadX source +files. At the end of the batch file, they are all combined into the +run-time library file: tx.a. This file must be linked with your +application in order to use ThreadX. + + +2. Demonstration System + +The ThreadX demonstration is designed to execute on Cortex-M evaluation boards +or on a dedicated simulator. + +Building the demonstration is easy, simply execute the build_threadx_sample.bat +batch file while inside the "example_build" directory. + +You should observe the compilation of sample_threadx.c (which is the demonstration +application) and linking with tx.a. The resulting file sample_threadx.out is a binary +file that can be downloaded and executed on the a simulator, or downloaded to a board. + + +3. System Initialization + +The entry point in ThreadX for the Cortex-M using gnu tools uses the standard GNU +Cortex-M reset sequence. From the reset vector the C runtime will be initialized. + +The ThreadX tx_initialize_low_level.S file is responsible for setting up +various system data structures, the vector area, and a periodic timer interrupt +source. + +In addition, _tx_initialize_low_level determines the first available +address for use by the application, which is supplied as the sole input +parameter to your application definition function, tx_application_define. + + +4. Register Usage and Stack Frames + +The following defines the saved context stack frames for context switches +that occur as a result of interrupt handling or from thread-level API calls. +All suspended threads have the same stack frame in the Cortex-M version of +ThreadX. The top of the suspended thread's stack is pointed to by +tx_thread_stack_ptr in the associated thread control block TX_THREAD. + +Non-FPU Stack Frame: + + Stack Offset Stack Contents + + 0x00 lr Interrupted lr (lr at time of PENDSV) + 0x04 r4 Software stacked GP registers + 0x08 r5 + 0x0C r6 + 0x10 r7 + 0x14 r8 + 0x18 r9 + 0x1C r10 + 0x20 r11 + 0x24 r0 Hardware stacked registers + 0x28 r1 + 0x2C r2 + 0x30 r3 + 0x34 r12 + 0x38 lr + 0x3C pc + 0x40 xPSR + +FPU Stack Frame (only interrupted thread with FPU enabled): + + Stack Offset Stack Contents + + 0x00 lr Interrupted lr (lr at time of PENDSV) + 0x04 s16 Software stacked FPU registers + 0x08 s17 + 0x0C s18 + 0x10 s19 + 0x14 s20 + 0x18 s21 + 0x1C s22 + 0x20 s23 + 0x24 s24 + 0x28 s25 + 0x2C s26 + 0x30 s27 + 0x34 s28 + 0x38 s29 + 0x3C s30 + 0x40 s31 + 0x44 r4 Software stacked registers + 0x48 r5 + 0x4C r6 + 0x50 r7 + 0x54 r8 + 0x58 r9 + 0x5C r10 + 0x60 r11 + 0x64 r0 Hardware stacked registers + 0x68 r1 + 0x6C r2 + 0x70 r3 + 0x74 r12 + 0x78 lr + 0x7C pc + 0x80 xPSR + 0x84 s0 Hardware stacked FPU registers + 0x88 s1 + 0x8C s2 + 0x90 s3 + 0x94 s4 + 0x98 s5 + 0x9C s6 + 0xA0 s7 + 0xA4 s8 + 0xA8 s9 + 0xAC s10 + 0xB0 s11 + 0xB4 s12 + 0xB8 s13 + 0xBC s14 + 0xC0 s15 + 0xC4 fpscr + + +5. Improving Performance + +The distribution version of ThreadX is built without any compiler optimizations. +This makes it easy to debug because you can trace or set breakpoints inside of +ThreadX itself. Of course, this costs some performance. To make it run faster, +you can change the build_threadx.bat file to remove the -g option and enable +all compiler optimizations. + +In addition, you can eliminate the ThreadX basic API error checking by +compiling your application code with the symbol TX_DISABLE_ERROR_CHECKING +defined. + + +6. Interrupt Handling + +ThreadX provides complete and high-performance interrupt handling for Cortex-M +targets. There are a certain set of requirements that are defined in the +following sub-sections: + + +6.1 Vector Area + +The Cortex-M vectors start at the label __tx_vectors or similar. The application may modify +the vector area according to its needs. There is code in tx_initialize_low_level() that will +configure the vector base register. + + +6.2 Managed Interrupts + +A ThreadX managed interrupt is defined below. By following these conventions, the +application ISR is then allowed access to various ThreadX services from the ISR. +Here is the standard template for managed ISRs in ThreadX: + + + .global __tx_IntHandler + .thumb_func +__tx_IntHandler: +; VOID InterruptHandler (VOID) +; { + PUSH {r0, lr} + +; /* Do interrupt handler work here */ +; /* BL */ + + POP {r0, lr} + BX lr +; } + + +Note: the Cortex-M requires exception handlers to be thumb labels, this implies bit 0 set. +To accomplish this, the declaration of the label has to be preceded by the assembler directive +.thumb_func to instruct the linker to create thumb labels. The label __tx_IntHandler needs to +be inserted in the correct location in the interrupt vector table. This table is typically +located in either your runtime startup file or in the tx_initialize_low_level.S file. + + +7. FPU Support + +ThreadX for Cortex-M supports automatic ("lazy") VFP support, which means that applications threads +can simply use the VFP and ThreadX automatically maintains the VFP registers as part of the thread +context - no additional setup by the application. + + +8. Revision History + +For generic code revision information, please refer to the readme_threadx_generic.txt +file, which is included in your distribution. The following details the revision +information associated with this specific port of ThreadX: + +06-02-2021 Initial ThreadX version 6.1.7 for Cortex-M using GNU tools. + + +Copyright(c) 1996-2021 Microsoft Corporation + + +https://azure.com/rtos + diff --git a/ports_arch/ARMv7-M/threadx/gnu/src/tx_misra.S b/ports_arch/ARMv7-M/threadx/gnu/src/tx_misra.S new file mode 100644 index 00000000..c84d8576 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/gnu/src/tx_misra.S @@ -0,0 +1,723 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + #define SHT_PROGBITS 0x1 + + .global __aeabi_memset + .global _tx_thread_current_ptr + .global _tx_thread_interrupt_disable + .global _tx_thread_interrupt_restore + .global _tx_thread_stack_analyze + .global _tx_thread_stack_error_handler + .global _tx_thread_system_state +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_trace_buffer_current_ptr + .global _tx_trace_buffer_end_ptr + .global _tx_trace_buffer_start_ptr + .global _tx_trace_event_enable_bits + .global _tx_trace_full_notify_function + .global _tx_trace_header_ptr +#endif + + .global _tx_misra_always_true + .global _tx_misra_block_pool_to_uchar_pointer_convert + .global _tx_misra_byte_pool_to_uchar_pointer_convert + .global _tx_misra_char_to_uchar_pointer_convert + .global _tx_misra_const_char_to_char_pointer_convert +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_entry_to_uchar_pointer_convert +#endif + .global _tx_misra_indirect_void_to_uchar_pointer_convert + .global _tx_misra_memset + .global _tx_misra_message_copy +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_object_to_uchar_pointer_convert +#endif + .global _tx_misra_pointer_to_ulong_convert + .global _tx_misra_status_get + .global _tx_misra_thread_stack_check +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_time_stamp_get +#endif + .global _tx_misra_timer_indirect_to_void_pointer_convert + .global _tx_misra_timer_pointer_add + .global _tx_misra_timer_pointer_dif +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_trace_event_insert +#endif + .global _tx_misra_uchar_pointer_add + .global _tx_misra_uchar_pointer_dif + .global _tx_misra_uchar_pointer_sub + .global _tx_misra_uchar_to_align_type_pointer_convert + .global _tx_misra_uchar_to_block_pool_pointer_convert +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_uchar_to_entry_pointer_convert + .global _tx_misra_uchar_to_header_pointer_convert +#endif + .global _tx_misra_uchar_to_indirect_byte_pool_pointer_convert + .global _tx_misra_uchar_to_indirect_uchar_pointer_convert +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_uchar_to_object_pointer_convert +#endif + .global _tx_misra_uchar_to_void_pointer_convert + .global _tx_misra_ulong_pointer_add + .global _tx_misra_ulong_pointer_dif + .global _tx_misra_ulong_pointer_sub + .global _tx_misra_ulong_to_pointer_convert + .global _tx_misra_ulong_to_thread_pointer_convert + .global _tx_misra_user_timer_pointer_get + .global _tx_misra_void_to_block_pool_pointer_convert + .global _tx_misra_void_to_byte_pool_pointer_convert + .global _tx_misra_void_to_event_flags_pointer_convert + .global _tx_misra_void_to_indirect_uchar_pointer_convert + .global _tx_misra_void_to_mutex_pointer_convert + .global _tx_misra_void_to_queue_pointer_convert + .global _tx_misra_void_to_semaphore_pointer_convert + .global _tx_misra_void_to_thread_pointer_convert + .global _tx_misra_void_to_uchar_pointer_convert + .global _tx_misra_void_to_ulong_pointer_convert + .global _tx_misra_ipsr_get + .global _tx_misra_control_get + .global _tx_misra_control_set +#ifdef __ARM_FP + .global _tx_misra_fpccr_get + .global _tx_misra_vfp_touch +#endif + + .global _tx_misra_event_flags_group_not_used + .global _tx_misra_event_flags_set_notify_not_used + .global _tx_misra_queue_not_used + .global _tx_misra_queue_send_notify_not_used + .global _tx_misra_semaphore_not_used + .global _tx_misra_semaphore_put_notify_not_used + .global _tx_misra_thread_entry_exit_notify_not_used + .global _tx_misra_thread_not_used + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_memset(VOID *ptr, UINT value, UINT size); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .align 4 + .syntax unified + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_uchar_pointer_add: + ADD R0,R0,R1 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UCHAR *_tx_misra_uchar_pointer_sub(UCHAR *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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)); */ +/** */ +/************************************************************************************************************************************/ +/************************************************************************************************************************************/ + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_ulong_pointer_add: + ADD R0,R0,R1, LSL #+2 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG *_tx_misra_ulong_pointer_sub(ULONG *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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 R2,=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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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 + + + .data +DataTable2_1: + .word _tx_trace_buffer_current_ptr + + .data +DataTable2_2: + .word _tx_trace_event_enable_bits + + .data +DataTable2_5: + .word _tx_trace_buffer_end_ptr + + .data +DataTable2_6: + .word _tx_trace_buffer_start_ptr + + .data +DataTable2_7: + .word _tx_trace_header_ptr + + .data +DataTable2_8: + .word _tx_trace_full_notify_function + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG _tx_misra_time_stamp_get(VOID); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_time_stamp_get: + MOVS R0,#+0 + BX LR // return + +#endif + + .data +DataTable2_3: + .word _tx_thread_system_state + + .data +DataTable2_4: + .word _tx_thread_current_ptr + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UINT _tx_misra_always_true(void); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_always_true: + MOVS R0,#+1 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UINT _tx_misra_status_get(UINT status); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_status_get: + MOVS R0,#+0 + BX LR // return + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** ULONG _tx_misra_ipsr_get(void); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_tx_misra_ipsr_get: + MRS R0, IPSR + BX LR // return + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** ULONG _tx_misra_control_get(void); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_tx_misra_control_get: + MRS R0, CONTROL + BX LR // return + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** void _tx_misra_control_set(ULONG value); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_tx_misra_control_set: + MSR CONTROL, R0 + BX LR // return + + +#ifdef __ARM_FP + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** ULONG _tx_misra_fpccr_get(void); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_tx_misra_vfp_touch: + vmov.f32 s0, s0 + BX LR // return + +#endif + + + .data + .word 0 diff --git a/ports_arch/ARMv7-M/threadx/gnu/src/tx_thread_context_restore.S b/ports_arch/ARMv7-M/threadx/gnu/src/tx_thread_context_restore.S new file mode 100644 index 00000000..74c4f5de --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/gnu/src/tx_thread_context_restore.S @@ -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 */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + .global _tx_execution_isr_exit +#endif + + .text + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_restore Cortex-Mx/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is only needed for legacy applications and it should */ +/* not be called in any new development on a Cortex-M. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* [_tx_execution_isr_exit] Execution profiling ISR exit */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs Interrupt Service Routines */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_context_restore(VOID) +// { + .global _tx_thread_context_restore + .thumb_func +_tx_thread_context_restore: + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the ISR exit function to indicate an ISR is complete. */ + PUSH {r0, lr} // Save return address + BL _tx_execution_isr_exit // Call the ISR exit function + POP {r0, lr} // Recover return address +#endif + + BX lr +// } diff --git a/ports_arch/ARMv7-M/threadx/gnu/src/tx_thread_context_save.S b/ports_arch/ARMv7-M/threadx/gnu/src/tx_thread_context_save.S new file mode 100644 index 00000000..793810ba --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/gnu/src/tx_thread_context_save.S @@ -0,0 +1,86 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .text + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_save Cortex-Mx/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is only needed for legacy applications and it should */ +/* not be called in any new development on a Cortex-M. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* [_tx_execution_isr_enter] Execution profiling ISR enter */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_context_save(VOID) +// { + .global _tx_thread_context_save + .thumb_func +_tx_thread_context_save: + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the ISR enter function to indicate an ISR is starting. */ + PUSH {r0, lr} // Save return address + BL _tx_execution_isr_enter // Call the ISR enter function + POP {r0, lr} // Recover return address +#endif + + /* Context is already saved - just return. */ + + BX lr +// } diff --git a/ports_arch/ARMv7-M/threadx/gnu/src/tx_thread_interrupt_control.S b/ports_arch/ARMv7-M/threadx/gnu/src/tx_thread_interrupt_control.S new file mode 100644 index 00000000..adf13b13 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/gnu/src/tx_thread_interrupt_control.S @@ -0,0 +1,85 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .text 32 + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_control Cortex-Mx/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for changing the interrupt lockout */ +/* posture of the system. */ +/* */ +/* INPUT */ +/* */ +/* new_posture New interrupt lockout posture */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_interrupt_control(UINT new_posture) +// { + .global _tx_thread_interrupt_control + .thumb_func +_tx_thread_interrupt_control: +#ifdef TX_PORT_USE_BASEPRI + MRS r1, BASEPRI // Pickup current interrupt posture + MSR BASEPRI, r0 // Apply the new interrupt posture + MOV r0, r1 // Transfer old to return register +#else + MRS r1, PRIMASK // Pickup current interrupt lockout + MSR PRIMASK, r0 // Apply the new interrupt lockout + MOV r0, r1 // Transfer old to return register +#endif + BX lr // Return to caller +// } diff --git a/ports_arch/ARMv7-M/threadx/gnu/src/tx_thread_interrupt_disable.S b/ports_arch/ARMv7-M/threadx/gnu/src/tx_thread_interrupt_disable.S new file mode 100644 index 00000000..eb6c7250 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/gnu/src/tx_thread_interrupt_disable.S @@ -0,0 +1,85 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .text 32 + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_disable Cortex-Mx/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for disabling interrupts and returning */ +/* the previous interrupt lockout posture. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_interrupt_disable(VOID) +// { + .global _tx_thread_interrupt_disable + .thumb_func +_tx_thread_interrupt_disable: + /* Return current interrupt lockout posture. */ +#ifdef TX_PORT_USE_BASEPRI + MRS r0, BASEPRI + LDR r1, =TX_PORT_BASEPRI + MSR BASEPRI, r1 +#else + MRS r0, PRIMASK + CPSID i +#endif + BX lr +// } diff --git a/ports_arch/ARMv7-M/threadx/gnu/src/tx_thread_interrupt_restore.S b/ports_arch/ARMv7-M/threadx/gnu/src/tx_thread_interrupt_restore.S new file mode 100644 index 00000000..ab5b4807 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/gnu/src/tx_thread_interrupt_restore.S @@ -0,0 +1,82 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .text 32 + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_restore Cortex-Mx/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for restoring the previous */ +/* interrupt lockout posture. */ +/* */ +/* INPUT */ +/* */ +/* previous_posture Previous interrupt posture */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_interrupt_restore(UINT previous_posture) +// { + .global _tx_thread_interrupt_restore + .thumb_func +_tx_thread_interrupt_restore: + /* Restore previous interrupt lockout posture. */ +#ifdef TX_PORT_USE_BASEPRI + MSR BASEPRI, r0 +#else + MSR PRIMASK, r0 +#endif + BX lr +// } diff --git a/ports_arch/ARMv7-M/threadx/gnu/src/tx_thread_schedule.S b/ports_arch/ARMv7-M/threadx/gnu/src/tx_thread_schedule.S new file mode 100644 index 00000000..a599d9db --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/gnu/src/tx_thread_schedule.S @@ -0,0 +1,331 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .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 +#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.1 */ +/* 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 */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 01-31-2022 Scott Larson Fixed predefined macro name, */ +/* resulting in version 6.1.10 */ +/* 04-25-2022 Scott Larson Added BASEPRI support, */ +/* resulting in version 6.1.11 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// 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 + + /* Clear CONTROL.FPCA bit so VFP registers aren't unnecessarily stacked. */ + +#ifdef __ARM_FP + MRS r0, CONTROL // Pickup current CONTROL register + BIC r0, r0, #4 // Clear the FPCA bit + MSR CONTROL, r0 // Setup new CONTROL register +#endif + + /* 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 +// } + + /* Generic context switching 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? + CBZ r1, __tx_ts_wait // No, skip to the wait processing + + /* Yes, another thread is ready for else, make the current thread the new thread. */ + + 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. */ + +__tx_ts_restore: + 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 + 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! + + /* 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 + STR r1, [r0] // Store it in the current 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 + + /* Re-enable interrupts and restore new thread. */ +#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_restore // Restore the thread +// } + +#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 diff --git a/ports_arch/ARMv7-M/threadx/gnu/src/tx_thread_stack_build.S b/ports_arch/ARMv7-M/threadx/gnu/src/tx_thread_stack_build.S new file mode 100644 index 00000000..d65a483b --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/gnu/src/tx_thread_stack_build.S @@ -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 */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .text + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_stack_build Cortex-Mx/GNU */ +/* 6.2.1 */ +/* 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 control blk */ +/* function_ptr Pointer to return function */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_create Create thread service */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID)) +// { + .global _tx_thread_stack_build + .thumb_func +_tx_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 for 8-byte alignment + 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, #24] // Store initial r9 + STR r3, [r2, #28] // Store initial r10 + STR r3, [r2, #32] // Store initial r11 + + /* Hardware stack follows. */ + + STR r3, [r2, #36] // Store initial r0 + STR r3, [r2, #40] // Store initial r1 + 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 +// } diff --git a/ports_arch/ARMv7-M/threadx/gnu/src/tx_thread_system_return.S b/ports_arch/ARMv7-M/threadx/gnu/src/tx_thread_system_return.S new file mode 100644 index 00000000..759a3f8a --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/gnu/src/tx_thread_system_return.S @@ -0,0 +1,99 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .text 32 + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_system_return Cortex-Mx/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is target processor specific. It is used to transfer */ +/* control from a thread back to the ThreadX system. Only a */ +/* minimal context is saved since the compiler assumes temp registers */ +/* are going to get slicked by a function call anyway. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_schedule Thread scheduling loop */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX components */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_system_return(VOID) +// { + .thumb_func + .global _tx_thread_system_return +_tx_thread_system_return: + + /* Return to real scheduler via PendSV. Note that this routine is often + replaced with in-line assembly in tx_port.h to improved performance. */ + + MOV r0, #0x10000000 // Load PENDSVSET bit + MOV r1, #0xE000E000 // Load NVIC base + STR r0, [r1, #0xD04] // Set PENDSVBIT in ICSR + MRS r0, IPSR // Pickup IPSR + CMP r0, #0 // Is it a thread returning? + BNE _isr_context // If ISR, skip interrupt enable +#ifdef TX_PORT_USE_BASEPRI + MRS r1, BASEPRI // Thread context returning, pickup BASEPRI + MOV r0, #0 + MSR BASEPRI, r0 // Enable interrupts + MSR BASEPRI, r1 // Restore original interrupt posture +#else + MRS r1, PRIMASK // Thread context returning, pickup PRIMASK + CPSIE i // Enable interrupts + MSR PRIMASK, r1 // Restore original interrupt posture +#endif +_isr_context: + BX lr // Return to caller +// } diff --git a/ports_arch/ARMv7-M/threadx/gnu/src/tx_timer_interrupt.S b/ports_arch/ARMv7-M/threadx/gnu/src/tx_timer_interrupt.S new file mode 100644 index 00000000..3a276247 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/gnu/src/tx_timer_interrupt.S @@ -0,0 +1,261 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .global _tx_timer_time_slice + .global _tx_timer_system_clock + .global _tx_timer_current_ptr + .global _tx_timer_list_start + .global _tx_timer_list_end + .global _tx_timer_expired_time_slice + .global _tx_timer_expired + .global _tx_thread_time_slice + .global _tx_timer_expiration_process + + .text + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_interrupt Cortex-Mx/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the hardware timer interrupt. This */ +/* processing includes incrementing the system clock and checking for */ +/* time slice and/or timer expiration. If either is found, the */ +/* expiration functions are called. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_timer_expiration_process Timer expiration processing */ +/* _tx_thread_time_slice Time slice interrupted thread */ +/* */ +/* CALLED BY */ +/* */ +/* interrupt vector */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 01-31-2022 Scott Larson Modified comment(s), added */ +/* TX_NO_TIMER support, */ +/* resulting in version 6.1.10 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_timer_interrupt(VOID) +// { +#ifndef TX_NO_TIMER + .global _tx_timer_interrupt + .thumb_func +_tx_timer_interrupt: + + /* Upon entry to this routine, it is assumed that the compiler scratch registers are available + for use. */ + + /* Increment the system clock. */ + // _tx_timer_system_clock++; + + LDR r1, =_tx_timer_system_clock // Pickup address of system clock + LDR r0, [r1, #0] // Pickup system clock + ADD r0, r0, #1 // Increment system clock + STR r0, [r1, #0] // Store new system clock + + /* Test for time-slice expiration. */ + // if (_tx_timer_time_slice) + // { + + LDR r3, =_tx_timer_time_slice // Pickup address of time-slice + LDR r2, [r3, #0] // Pickup time-slice + CBZ r2, __tx_timer_no_time_slice // Is it non-active? + // Yes, skip time-slice processing + + /* Decrement the time_slice. */ + // _tx_timer_time_slice--; + + SUB r2, r2, #1 // Decrement the time-slice + STR r2, [r3, #0] // Store new time-slice value + + /* Check for expiration. */ + // if (__tx_timer_time_slice == 0) + + CBNZ r2, __tx_timer_no_time_slice // Has it expired? + // No, skip expiration processing + + /* Set the time-slice expired flag. */ + // _tx_timer_expired_time_slice = TX_TRUE; + + LDR r3, =_tx_timer_expired_time_slice // Pickup address of expired flag + MOV r0, #1 // Build expired value + STR r0, [r3, #0] // Set time-slice expiration flag + + // } + +__tx_timer_no_time_slice: + + /* Test for timer expiration. */ + // if (*_tx_timer_current_ptr) + // { + + LDR r1, =_tx_timer_current_ptr // Pickup current timer pointer address + LDR r0, [r1, #0] // Pickup current timer + LDR r2, [r0, #0] // Pickup timer list entry + CBZ r2, __tx_timer_no_timer // Is there anything in the list? + // No, just increment the timer + + /* Set expiration flag. */ + // _tx_timer_expired = TX_TRUE; + + LDR r3, =_tx_timer_expired // Pickup expiration flag address + MOV r2, #1 // Build expired value + STR r2, [r3, #0] // Set expired flag + B __tx_timer_done // Finished timer processing + + // } + // else + // { +__tx_timer_no_timer: + + /* No timer expired, increment the timer pointer. */ + // _tx_timer_current_ptr++; + + ADD r0, r0, #4 // Move to next timer + + /* Check for wrap-around. */ + // if (_tx_timer_current_ptr == _tx_timer_list_end) + + LDR r3, =_tx_timer_list_end // Pickup addr of timer list end + LDR r2, [r3, #0] // Pickup list end + CMP r0, r2 // Are we at list end? + BNE __tx_timer_skip_wrap // No, skip wrap-around logic + + /* Wrap to beginning of list. */ + // _tx_timer_current_ptr = _tx_timer_list_start; + + LDR r3, =_tx_timer_list_start // Pickup addr of timer list start + LDR r0, [r3, #0] // Set current pointer to list start + +__tx_timer_skip_wrap: + + STR r0, [r1, #0] // Store new current timer pointer + // } + +__tx_timer_done: + + /* See if anything has expired. */ + // if ((_tx_timer_expired_time_slice) || (_tx_timer_expired)) + // { + + LDR r3, =_tx_timer_expired_time_slice // Pickup addr of expired flag + LDR r2, [r3, #0] // Pickup time-slice expired flag + CBNZ r2, __tx_something_expired // Did a time-slice expire? + // If non-zero, time-slice expired + LDR r1, =_tx_timer_expired // Pickup addr of other expired flag + LDR r0, [r1, #0] // Pickup timer expired flag + CBZ r0, __tx_timer_nothing_expired // Did a timer expire? + // No, nothing expired + +__tx_something_expired: + + STMDB sp!, {r0, lr} // Save the lr register on the stack + // and save r0 just to keep 8-byte alignment + + /* Did a timer expire? */ + // if (_tx_timer_expired) + // { + + LDR r1, =_tx_timer_expired // Pickup addr of expired flag + LDR r0, [r1, #0] // Pickup timer expired flag + CBZ r0, __tx_timer_dont_activate // Check for timer expiration + // If not set, skip timer activation + + /* Process timer expiration. */ + // _tx_timer_expiration_process(); + + BL _tx_timer_expiration_process // Call the timer expiration handling routine + + // } +__tx_timer_dont_activate: + + /* Did time slice expire? */ + // if (_tx_timer_expired_time_slice) + // { + + LDR r3, =_tx_timer_expired_time_slice // Pickup addr of time-slice expired + LDR r2, [r3, #0] // Pickup the actual flag + CBZ r2, __tx_timer_not_ts_expiration // See if the flag is set + // No, skip time-slice processing + + /* Time slice interrupted thread. */ + // _tx_thread_time_slice(); + + BL _tx_thread_time_slice // Call time-slice processing + LDR r0, =_tx_thread_preempt_disable // Build address of preempt disable flag + LDR r1, [r0] // Is the preempt disable flag set? + CBNZ r1, __tx_timer_skip_time_slice // Yes, skip the PendSV logic + LDR r0, =_tx_thread_current_ptr // Build current thread pointer address + LDR r1, [r0] // Pickup the current thread pointer + LDR r2, =_tx_thread_execute_ptr // Build execute thread pointer address + LDR r3, [r2] // Pickup the execute thread pointer + LDR r0, =0xE000ED04 // Build address of control register + LDR r2, =0x10000000 // Build value for PendSV bit + CMP r1, r3 // Are they the same? + BEQ __tx_timer_skip_time_slice // If the same, there was no time-slice performed + STR r2, [r0] // Not the same, issue the PendSV for preemption +__tx_timer_skip_time_slice: + + // } + +__tx_timer_not_ts_expiration: + + LDMIA sp!, {r0, lr} // Recover lr register (r0 is just there for + // the 8-byte stack alignment + + // } + +__tx_timer_nothing_expired: + + DSB // Complete all memory access + BX lr // Return to caller +// } +#endif diff --git a/ports_arch/ARMv7-M/threadx/iar/example_build/azure_rtos.eww b/ports_arch/ARMv7-M/threadx/iar/example_build/azure_rtos.eww new file mode 100644 index 00000000..17e0d329 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/iar/example_build/azure_rtos.eww @@ -0,0 +1,13 @@ + + + + + $WS_DIR$\sample_threadx.ewp + + + $WS_DIR$\tx.ewp + + + + + diff --git a/ports_arch/ARMv7-M/threadx/iar/example_build/cstartup_M.s b/ports_arch/ARMv7-M/threadx/iar/example_build/cstartup_M.s new file mode 100644 index 00000000..8b7fbc0d --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/iar/example_build/cstartup_M.s @@ -0,0 +1,72 @@ + EXTERN __iar_program_start + PUBLIC __vector_table + + SECTION .text:CODE:REORDER(1) + + ;; Keep vector table even if it's not referenced + REQUIRE __vector_table + + THUMB + + ;; Forward declaration of sections. + SECTION CSTACK:DATA:NOROOT(3) + SECTION .intvec:CODE:NOROOT(2) + + DATA + +__vector_table + DCD sfe(CSTACK) + DCD __Reset_Vector + DCD NMI_Handler + DCD HardFault_Handler + DCD MemManage_Handler + DCD BusFault_Handler + DCD UsageFault_Handler + DCD 0 + DCD 0 + DCD 0 + DCD 0 + DCD SVC_Handler + DCD DebugMon_Handler + DCD 0 + DCD PendSV_Handler + DCD SysTick_Handler + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Default interrupt handlers. +;; + + PUBWEAK NMI_Handler + PUBWEAK HardFault_Handler + PUBWEAK MemManage_Handler + PUBWEAK BusFault_Handler + PUBWEAK UsageFault_Handler + PUBWEAK SVC_Handler + PUBWEAK DebugMon_Handler + PUBWEAK PendSV_Handler + PUBWEAK SysTick_Handler + + SECTION .text:CODE:REORDER:NOROOT(1) + THUMB +__Reset_Vector: + ; CPSID i ; Disable interrupts + B __iar_program_start + + +NMI_Handler +HardFault_Handler +MemManage_Handler +BusFault_Handler +UsageFault_Handler +SVC_Handler +DebugMon_Handler +PendSV_Handler +SysTick_Handler +Default_Handler +__default_handler + CALL_GRAPH_ROOT __default_handler, "interrupt" + NOCALL __default_handler + B __default_handler + + END diff --git a/ports_arch/ARMv7-M/threadx/iar/example_build/sample_threadx.c b/ports_arch/ARMv7-M/threadx/iar/example_build/sample_threadx.c new file mode 100644 index 00000000..60f5a3d3 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/iar/example_build/sample_threadx.c @@ -0,0 +1,389 @@ +/* This is a small demo of the high-performance ThreadX kernel. It includes examples of eight + threads of different priorities, using a message queue, semaphore, mutex, event flags group, + byte pool, and block pool. Please refer to Chapter 6 of the ThreadX User Guide for a complete + description of this demonstration. */ + +#include "tx_api.h" + +#define DEMO_STACK_SIZE 1024 +#define DEMO_BYTE_POOL_SIZE 9120 +#define DEMO_BLOCK_POOL_SIZE 100 +#define DEMO_QUEUE_SIZE 100 + + +/* Define the ThreadX object control blocks... */ + +TX_THREAD thread_0; +TX_THREAD thread_1; +TX_THREAD thread_2; +TX_THREAD thread_3; +TX_THREAD thread_4; +TX_THREAD thread_5; +TX_THREAD thread_6; +TX_THREAD thread_7; +TX_QUEUE queue_0; +TX_SEMAPHORE semaphore_0; +TX_MUTEX mutex_0; +TX_EVENT_FLAGS_GROUP event_flags_0; +TX_BYTE_POOL byte_pool_0; +TX_BLOCK_POOL block_pool_0; + + +/* Define byte pool memory. */ + +UCHAR byte_pool_memory[DEMO_BYTE_POOL_SIZE]; + + +/* Define event buffer. */ + +#ifdef TX_ENABLE_EVENT_TRACE +UCHAR trace_buffer[0x10000]; +#endif + + +/* Define the counters used in the demo application... */ + +ULONG thread_0_counter; +ULONG thread_1_counter; +ULONG thread_1_messages_sent; +ULONG thread_2_counter; +ULONG thread_2_messages_received; +ULONG thread_3_counter; +ULONG thread_4_counter; +ULONG thread_5_counter; +ULONG thread_6_counter; +ULONG thread_7_counter; + + +/* Define thread prototypes. */ + +void thread_0_entry(ULONG thread_input); +void thread_1_entry(ULONG thread_input); +void thread_2_entry(ULONG thread_input); +void thread_3_and_4_entry(ULONG thread_input); +void thread_5_entry(ULONG thread_input); +void thread_6_and_7_entry(ULONG thread_input); + + +/* Define main entry point. */ + +int main() +{ + + /* Please refer to Chapter 6 of the ThreadX User Guide for a complete + description of this demonstration. */ + + + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); +} + + +/* Define what the initial system looks like. */ + +void tx_application_define(void *first_unused_memory) +{ + +CHAR *pointer = TX_NULL; + + +#ifdef TX_ENABLE_EVENT_TRACE + tx_trace_enable(trace_buffer, sizeof(trace_buffer), 32); +#endif + + /* Create a byte memory pool from which to allocate the thread stacks. */ + tx_byte_pool_create(&byte_pool_0, "byte pool 0", byte_pool_memory, DEMO_BYTE_POOL_SIZE); + + /* Put system definition stuff in here, e.g. thread creates and other assorted + create information. */ + + /* Allocate the stack for thread 0. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create the main thread. */ + tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0, + pointer, DEMO_STACK_SIZE, + 1, 1, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 1. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create threads 1 and 2. These threads pass information through a ThreadX + message queue. It is also interesting to note that these threads have a time + slice. */ + tx_thread_create(&thread_1, "thread 1", thread_1_entry, 1, + pointer, DEMO_STACK_SIZE, + 16, 16, 4, TX_AUTO_START); + + /* Allocate the stack for thread 2. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + tx_thread_create(&thread_2, "thread 2", thread_2_entry, 2, + pointer, DEMO_STACK_SIZE, + 16, 16, 4, TX_AUTO_START); + + /* Allocate the stack for thread 3. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create threads 3 and 4. These threads compete for a ThreadX counting semaphore. + An interesting thing here is that both threads share the same instruction area. */ + tx_thread_create(&thread_3, "thread 3", thread_3_and_4_entry, 3, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 4. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + tx_thread_create(&thread_4, "thread 4", thread_3_and_4_entry, 4, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 5. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create thread 5. This thread simply pends on an event flag which will be set + by thread_0. */ + tx_thread_create(&thread_5, "thread 5", thread_5_entry, 5, + pointer, DEMO_STACK_SIZE, + 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 6. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create threads 6 and 7. These threads compete for a ThreadX mutex. */ + tx_thread_create(&thread_6, "thread 6", thread_6_and_7_entry, 6, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 7. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + tx_thread_create(&thread_7, "thread 7", thread_6_and_7_entry, 7, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the message queue. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_QUEUE_SIZE*sizeof(ULONG), TX_NO_WAIT); + + /* Create the message queue shared by threads 1 and 2. */ + tx_queue_create(&queue_0, "queue 0", TX_1_ULONG, pointer, DEMO_QUEUE_SIZE*sizeof(ULONG)); + + /* Create the semaphore used by threads 3 and 4. */ + tx_semaphore_create(&semaphore_0, "semaphore 0", 1); + + /* Create the event flags group used by threads 1 and 5. */ + tx_event_flags_create(&event_flags_0, "event flags 0"); + + /* Create the mutex used by thread 6 and 7 without priority inheritance. */ + tx_mutex_create(&mutex_0, "mutex 0", TX_NO_INHERIT); + + /* Allocate the memory for a small block pool. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_BLOCK_POOL_SIZE, TX_NO_WAIT); + + /* Create a block memory pool to allocate a message buffer from. */ + tx_block_pool_create(&block_pool_0, "block pool 0", sizeof(ULONG), pointer, DEMO_BLOCK_POOL_SIZE); + + /* Allocate a block and release the block memory. */ + tx_block_allocate(&block_pool_0, (VOID **) &pointer, TX_NO_WAIT); + + /* Release the block back to the pool. */ + tx_block_release(pointer); +} + + + +/* Define the test threads. */ + +void thread_0_entry(ULONG thread_input) +{ + +UINT status; + + + /* This thread simply sits in while-forever-sleep loop. */ + while(1) + { + + /* Increment the thread counter. */ + thread_0_counter++; + + /* Sleep for 10 ticks. */ + tx_thread_sleep(10); + + /* Set event flag 0 to wakeup thread 5. */ + status = tx_event_flags_set(&event_flags_0, 0x1, TX_OR); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + } +} + + +void thread_1_entry(ULONG thread_input) +{ + +UINT status; + + + /* This thread simply sends messages to a queue shared by thread 2. */ + while(1) + { + + /* Increment the thread counter. */ + thread_1_counter++; + + /* Send message to queue 0. */ + status = tx_queue_send(&queue_0, &thread_1_messages_sent, TX_WAIT_FOREVER); + + /* Check completion status. */ + if (status != TX_SUCCESS) + break; + + /* Increment the message sent. */ + thread_1_messages_sent++; + } +} + + +void thread_2_entry(ULONG thread_input) +{ + +ULONG received_message; +UINT status; + + /* This thread retrieves messages placed on the queue by thread 1. */ + while(1) + { + + /* Increment the thread counter. */ + thread_2_counter++; + + /* Retrieve a message from the queue. */ + status = tx_queue_receive(&queue_0, &received_message, TX_WAIT_FOREVER); + + /* Check completion status and make sure the message is what we + expected. */ + if ((status != TX_SUCCESS) || (received_message != thread_2_messages_received)) + break; + + /* Otherwise, all is okay. Increment the received message count. */ + thread_2_messages_received++; + } +} + + +void thread_3_and_4_entry(ULONG thread_input) +{ + +UINT status; + + + /* This function is executed from thread 3 and thread 4. As the loop + below shows, these function compete for ownership of semaphore_0. */ + while(1) + { + + /* Increment the thread counter. */ + if (thread_input == 3) + thread_3_counter++; + else + thread_4_counter++; + + /* Get the semaphore with suspension. */ + status = tx_semaphore_get(&semaphore_0, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Sleep for 2 ticks to hold the semaphore. */ + tx_thread_sleep(2); + + /* Release the semaphore. */ + status = tx_semaphore_put(&semaphore_0); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + } +} + + +void thread_5_entry(ULONG thread_input) +{ + +UINT status; +ULONG actual_flags; + + + /* This thread simply waits for an event in a forever loop. */ + while(1) + { + + /* Increment the thread counter. */ + thread_5_counter++; + + /* Wait for event flag 0. */ + status = tx_event_flags_get(&event_flags_0, 0x1, TX_OR_CLEAR, + &actual_flags, TX_WAIT_FOREVER); + + /* Check status. */ + if ((status != TX_SUCCESS) || (actual_flags != 0x1)) + break; + } +} + + +void thread_6_and_7_entry(ULONG thread_input) +{ + +UINT status; + + + /* This function is executed from thread 6 and thread 7. As the loop + below shows, these function compete for ownership of mutex_0. */ + while(1) + { + + /* Increment the thread counter. */ + if (thread_input == 6) + thread_6_counter++; + else + thread_7_counter++; + + /* Get the mutex with suspension. */ + status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Get the mutex again with suspension. This shows + that an owning thread may retrieve the mutex it + owns multiple times. */ + status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Sleep for 2 ticks to hold the mutex. */ + tx_thread_sleep(2); + + /* Release the mutex. */ + status = tx_mutex_put(&mutex_0); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Release the mutex again. This will actually + release ownership since it was obtained twice. */ + status = tx_mutex_put(&mutex_0); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + } +} diff --git a/ports_arch/ARMv7-M/threadx/iar/example_build/sample_threadx.ewd b/ports_arch/ARMv7-M/threadx/iar/example_build/sample_threadx.ewd new file mode 100644 index 00000000..6d7eecd6 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/iar/example_build/sample_threadx.ewd @@ -0,0 +1,2974 @@ + + + 3 + + Debug + + ARM + + 1 + + C-SPY + 2 + + 32 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ARMSIM_ID + 2 + + 1 + 1 + 1 + + + + + + + + CADI_ID + 2 + + 0 + 1 + 1 + + + + + + + + + CMSISDAP_ID + 2 + + 4 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GDBSERVER_ID + 2 + + 0 + 1 + 1 + + + + + + + + + + + IJET_ID + 2 + + 8 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + JLINK_ID + 2 + + 16 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LMIFTDI_ID + 2 + + 2 + 1 + 1 + + + + + + + + + + NULINK_ID + 2 + + 0 + 1 + 1 + + + + + + + PEMICRO_ID + 2 + + 3 + 1 + 1 + + + + + + + + STLINK_ID + 2 + + 7 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + THIRDPARTY_ID + 2 + + 0 + 1 + 1 + + + + + + + + TIFET_ID + 2 + + 1 + 1 + 1 + + + + + + + + + + + + + + + + + + + XDS100_ID + 2 + + 8 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $TOOLKIT_DIR$\plugins\rtos\CMX\CmxArmPlugin.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\CMX\CmxTinyArmPlugin.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\embOS\embOSPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\FreeRtos\FreeRtosArmPlugin.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\HWRTOSplugin\HWRTOSplugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\Mbed\MbedArmPlugin.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\Mbed\MbedArmPlugin2.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\OpenRTOS\OpenRTOSPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\RemedyRtosViewer\RemedyRtosViewer.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\SafeRTOS\SafeRTOSPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\SMX\smxAwareIarArm8b.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\SMX\smxAwareIarArm8bBE.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\ThreadX\ThreadXArmPlugin.ENU.ewplugin + 1 + + + $TOOLKIT_DIR$\plugins\rtos\TI-RTOS\tirtosplugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\uCOS-II\uCOS-II-286-KA-CSpy.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\uCOS-II\uCOS-II-KA-CSpy.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\uCOS-III\uCOS-III-KA-CSpy.ewplugin + 0 + + + $EW_DIR$\common\plugins\Orti\Orti.ENU.ewplugin + 0 + + + $EW_DIR$\common\plugins\TargetAccessServer\TargetAccessServer.ENU.ewplugin + 0 + + + $EW_DIR$\common\plugins\uCProbe\uCProbePlugin.ENU.ewplugin + 0 + + + + + Release + + ARM + + 0 + + C-SPY + 2 + + 32 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ARMSIM_ID + 2 + + 1 + 1 + 0 + + + + + + + + CADI_ID + 2 + + 0 + 1 + 0 + + + + + + + + + CMSISDAP_ID + 2 + + 4 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GDBSERVER_ID + 2 + + 0 + 1 + 0 + + + + + + + + + + + IJET_ID + 2 + + 8 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + JLINK_ID + 2 + + 16 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LMIFTDI_ID + 2 + + 2 + 1 + 0 + + + + + + + + + + NULINK_ID + 2 + + 0 + 1 + 0 + + + + + + + PEMICRO_ID + 2 + + 3 + 1 + 0 + + + + + + + + STLINK_ID + 2 + + 7 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + THIRDPARTY_ID + 2 + + 0 + 1 + 0 + + + + + + + + TIFET_ID + 2 + + 1 + 1 + 0 + + + + + + + + + + + + + + + + + + + XDS100_ID + 2 + + 8 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $TOOLKIT_DIR$\plugins\rtos\CMX\CmxArmPlugin.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\CMX\CmxTinyArmPlugin.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\embOS\embOSPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\FreeRtos\FreeRtosArmPlugin.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\HWRTOSplugin\HWRTOSplugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\Mbed\MbedArmPlugin.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\Mbed\MbedArmPlugin2.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\OpenRTOS\OpenRTOSPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\RemedyRtosViewer\RemedyRtosViewer.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\SafeRTOS\SafeRTOSPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\SMX\smxAwareIarArm8b.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\SMX\smxAwareIarArm8bBE.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\ThreadX\ThreadXArmPlugin.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\TI-RTOS\tirtosplugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\uCOS-II\uCOS-II-286-KA-CSpy.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\uCOS-II\uCOS-II-KA-CSpy.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\uCOS-III\uCOS-III-KA-CSpy.ewplugin + 0 + + + $EW_DIR$\common\plugins\Orti\Orti.ENU.ewplugin + 0 + + + $EW_DIR$\common\plugins\TargetAccessServer\TargetAccessServer.ENU.ewplugin + 0 + + + $EW_DIR$\common\plugins\uCProbe\uCProbePlugin.ENU.ewplugin + 0 + + + + diff --git a/ports_arch/ARMv7-M/threadx/iar/example_build/sample_threadx.ewp b/ports_arch/ARMv7-M/threadx/iar/example_build/sample_threadx.ewp new file mode 100644 index 00000000..20b7d7c3 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/iar/example_build/sample_threadx.ewp @@ -0,0 +1,2137 @@ + + + 3 + + Debug + + ARM + + 1 + + General + 3 + + 31 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICCARM + 2 + + 36 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AARM + 2 + + 10 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OBJCOPY + 0 + + 1 + 1 + 1 + + + + + + + + + CUSTOM + 3 + + + + 0 + + + + BICOMP + 0 + + + + BUILDACTION + 1 + + + + + + + ILINK + 0 + + 23 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IARCHIVE + 0 + + 0 + 1 + 1 + + + + + + + BILINK + 0 + + + + Coder + 0 + + + + + Release + + ARM + + 0 + + General + 3 + + 31 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICCARM + 2 + + 36 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AARM + 2 + + 10 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OBJCOPY + 0 + + 1 + 1 + 0 + + + + + + + + + CUSTOM + 3 + + + + 0 + + + + BICOMP + 0 + + + + BUILDACTION + 1 + + + + + + + ILINK + 0 + + 23 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IARCHIVE + 0 + + 0 + 1 + 0 + + + + + + + BILINK + 0 + + + + Coder + 0 + + + + + $PROJ_DIR$\cstartup_M.s + + + $PROJ_DIR$\sample_threadx.c + + + $PROJ_DIR$\Debug\Exe\tx.a + + + $PROJ_DIR$\tx_initialize_low_level.s + + diff --git a/ports_arch/ARMv7-M/threadx/iar/example_build/sample_threadx.icf b/ports_arch/ARMv7-M/threadx/iar/example_build/sample_threadx.icf new file mode 100644 index 00000000..246d387e --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/iar/example_build/sample_threadx.icf @@ -0,0 +1,42 @@ +/*###ICF### Section handled by ICF editor, don't touch! ****/ +/*-Editor annotation file-*/ +/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */ +/*-Specials-*/ +define symbol __ICFEDIT_intvec_start__ = 0x00000000; +/*-Memory Regions-*/ +define symbol __ICFEDIT_region_ROM_start__ = 0x00000000; +define symbol __ICFEDIT_region_ROM_end__ = 0x0007FFFF; +define symbol __ICFEDIT_region_RAM_start__ = 0x20000000; +define symbol __ICFEDIT_region_RAM_end__ = 0x2001FFFF; +/*-Sizes-*/ +define symbol __ICFEDIT_size_cstack__ = 0x200; +define symbol __ICFEDIT_size_heap__ = 0x200; +/**** End of ICF editor section. ###ICF###*/ + +define symbol FlashConfig_start__= 0x00000400; +define symbol FlashConfig_end__ = 0x0000040f; + +define memory mem with size = 4G; +define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to (FlashConfig_start__ - 1)] | [from (FlashConfig_end__+1) to __ICFEDIT_region_ROM_end__]; +define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__]; + +define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { }; +define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { }; + +define region FlashConfig_region = mem:[from FlashConfig_start__ to FlashConfig_end__]; + +initialize by copy { readwrite }; +initialize by copy with packing = none { section __DLIB_PERTHREAD }; // Required in a multi-threaded application +do not initialize { section .noinit }; + +place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec }; + +place in ROM_region { readonly }; +place in RAM_region { readwrite, + block CSTACK, block HEAP }; + +place in FlashConfig_region + {section FlashConfig}; + +place in RAM_region { last section FREE_MEM}; + diff --git a/ports_arch/ARMv7-M/threadx/iar/example_build/tx.ewp b/ports_arch/ARMv7-M/threadx/iar/example_build/tx.ewp new file mode 100644 index 00000000..cccb9a9a --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/iar/example_build/tx.ewp @@ -0,0 +1,2752 @@ + + + 3 + + Debug + + ARM + + 1 + + General + 3 + + 31 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICCARM + 2 + + 36 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AARM + 2 + + 10 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OBJCOPY + 0 + + 1 + 1 + 1 + + + + + + + + + CUSTOM + 3 + + + + 0 + + + + BICOMP + 0 + + + + BUILDACTION + 1 + + + + + + + ILINK + 0 + + 23 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IARCHIVE + 0 + + 0 + 1 + 1 + + + + + + + BILINK + 0 + + + + Coder + 0 + + + + + Release + + ARM + + 0 + + General + 3 + + 31 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICCARM + 2 + + 36 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AARM + 2 + + 10 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OBJCOPY + 0 + + 1 + 1 + 0 + + + + + + + + + CUSTOM + 3 + + + + 0 + + + + BICOMP + 0 + + + + BUILDACTION + 1 + + + + + + + ILINK + 0 + + 23 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IARCHIVE + 0 + + 0 + 1 + 0 + + + + + + + BILINK + 0 + + + + Coder + 0 + + + + + inc + + $PROJ_DIR$\..\..\..\..\common\inc\tx_api.h + + + $PROJ_DIR$\..\..\..\..\common\inc\tx_block_pool.h + + + $PROJ_DIR$\..\..\..\..\common\inc\tx_byte_pool.h + + + $PROJ_DIR$\..\..\..\..\common\inc\tx_event_flags.h + + + $PROJ_DIR$\..\..\..\..\common\inc\tx_initialize.h + + + $PROJ_DIR$\..\..\..\..\common\inc\tx_mutex.h + + + $PROJ_DIR$\..\inc\tx_port.h + + + $PROJ_DIR$\..\..\..\..\common\inc\tx_queue.h + + + $PROJ_DIR$\..\..\..\..\common\inc\tx_semaphore.h + + + $PROJ_DIR$\..\..\..\..\common\inc\tx_thread.h + + + $PROJ_DIR$\..\..\..\..\common\inc\tx_timer.h + + + $PROJ_DIR$\..\..\..\..\common\inc\tx_trace.h + + + $PROJ_DIR$\..\..\..\..\common\inc\tx_user.h + + + + src + + $PROJ_DIR$\..\..\..\..\common\src\tx_block_allocate.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_block_pool_cleanup.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_block_pool_create.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_block_pool_delete.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_block_pool_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_block_pool_initialize.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_block_pool_performance_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_block_pool_performance_system_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_block_pool_prioritize.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_block_release.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_byte_allocate.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_byte_pool_cleanup.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_byte_pool_create.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_byte_pool_delete.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_byte_pool_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_byte_pool_initialize.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_byte_pool_performance_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_byte_pool_performance_system_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_byte_pool_prioritize.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_byte_pool_search.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_byte_release.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_event_flags_cleanup.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_event_flags_create.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_event_flags_delete.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_event_flags_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_event_flags_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_event_flags_initialize.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_event_flags_performance_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_event_flags_performance_system_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_event_flags_set.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_event_flags_set_notify.c + + + $PROJ_DIR$\..\src\tx_iar.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_initialize_high_level.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_initialize_kernel_enter.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_initialize_kernel_setup.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_mutex_cleanup.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_mutex_create.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_mutex_delete.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_mutex_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_mutex_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_mutex_initialize.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_mutex_performance_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_mutex_performance_system_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_mutex_prioritize.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_mutex_priority_change.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_mutex_put.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_queue_cleanup.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_queue_create.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_queue_delete.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_queue_flush.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_queue_front_send.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_queue_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_queue_initialize.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_queue_performance_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_queue_performance_system_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_queue_prioritize.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_queue_receive.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_queue_send.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_queue_send_notify.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_semaphore_ceiling_put.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_semaphore_cleanup.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_semaphore_create.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_semaphore_delete.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_semaphore_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_semaphore_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_semaphore_initialize.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_semaphore_performance_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_semaphore_performance_system_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_semaphore_prioritize.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_semaphore_put.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_semaphore_put_notify.c + + + $PROJ_DIR$\..\src\tx_thread_context_restore.s + + + $PROJ_DIR$\..\src\tx_thread_context_save.s + + + $PROJ_DIR$\..\..\..\..\common\src\tx_thread_create.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_thread_delete.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_thread_entry_exit_notify.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_thread_identify.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_thread_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_thread_initialize.c + + + $PROJ_DIR$\..\src\tx_thread_interrupt_control.s + + + $PROJ_DIR$\..\src\tx_thread_interrupt_disable.s + + + $PROJ_DIR$\..\src\tx_thread_interrupt_restore.s + + + $PROJ_DIR$\..\..\..\..\common\src\tx_thread_performance_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_thread_performance_system_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_thread_preemption_change.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_thread_priority_change.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_thread_relinquish.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_thread_reset.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_thread_resume.c + + + $PROJ_DIR$\..\src\tx_thread_schedule.s + + + $PROJ_DIR$\..\..\..\..\common\src\tx_thread_shell_entry.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_thread_sleep.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_thread_stack_analyze.c + + + $PROJ_DIR$\..\src\tx_thread_stack_build.s + + + $PROJ_DIR$\..\..\..\..\common\src\tx_thread_stack_error_handler.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_thread_stack_error_notify.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_thread_suspend.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_thread_system_preempt_check.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_thread_system_resume.c + + + $PROJ_DIR$\..\src\tx_thread_system_return.s + + + $PROJ_DIR$\..\..\..\..\common\src\tx_thread_system_suspend.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_thread_terminate.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_thread_time_slice.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_thread_time_slice_change.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_thread_timeout.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_thread_wait_abort.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_time_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_time_set.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_timer_activate.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_timer_change.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_timer_create.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_timer_deactivate.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_timer_delete.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_timer_expiration_process.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_timer_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_timer_initialize.c + + + $PROJ_DIR$\..\src\tx_timer_interrupt.s + + + $PROJ_DIR$\..\..\..\..\common\src\tx_timer_performance_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_timer_performance_system_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_timer_system_activate.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_timer_system_deactivate.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_timer_thread_entry.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_trace_buffer_full_notify.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_trace_disable.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_trace_enable.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_trace_event_filter.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_trace_event_unfilter.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_trace_initialize.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_trace_interrupt_control.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_trace_isr_enter_insert.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_trace_isr_exit_insert.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_trace_object_register.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_trace_object_unregister.c + + + $PROJ_DIR$\..\..\..\..\common\src\tx_trace_user_event_insert.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_block_allocate.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_block_pool_create.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_block_pool_delete.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_block_pool_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_block_pool_prioritize.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_block_release.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_byte_allocate.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_byte_pool_create.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_byte_pool_delete.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_byte_pool_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_byte_pool_prioritize.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_byte_release.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_event_flags_create.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_event_flags_delete.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_event_flags_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_event_flags_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_event_flags_set.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_event_flags_set_notify.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_mutex_create.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_mutex_delete.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_mutex_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_mutex_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_mutex_prioritize.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_mutex_put.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_queue_create.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_queue_delete.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_queue_flush.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_queue_front_send.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_queue_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_queue_prioritize.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_queue_receive.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_queue_send.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_queue_send_notify.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_semaphore_ceiling_put.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_semaphore_create.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_semaphore_delete.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_semaphore_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_semaphore_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_semaphore_prioritize.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_semaphore_put.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_semaphore_put_notify.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_thread_create.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_thread_delete.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_thread_entry_exit_notify.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_thread_info_get.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_thread_preemption_change.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_thread_priority_change.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_thread_relinquish.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_thread_reset.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_thread_resume.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_thread_suspend.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_thread_terminate.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_thread_time_slice_change.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_thread_wait_abort.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_timer_activate.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_timer_change.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_timer_create.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_timer_deactivate.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_timer_delete.c + + + $PROJ_DIR$\..\..\..\..\common\src\txe_timer_info_get.c + + + diff --git a/ports_arch/ARMv7-M/threadx/iar/example_build/tx_initialize_low_level.s b/ports_arch/ARMv7-M/threadx/iar/example_build/tx_initialize_low_level.s new file mode 100644 index 00000000..d7d3fd9e --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/iar/example_build/tx_initialize_low_level.s @@ -0,0 +1,151 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Initialize */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + EXTERN _tx_thread_system_stack_ptr + EXTERN _tx_initialize_unused_memory + EXTERN _tx_timer_interrupt + EXTERN __vector_table + EXTERN _tx_execution_isr_enter + EXTERN _tx_execution_isr_exit + +SYSTEM_CLOCK EQU 25000000 +SYSTICK_CYCLES EQU ((SYSTEM_CLOCK / 100) -1) + + RSEG FREE_MEM:DATA + PUBLIC __tx_free_memory_start +__tx_free_memory_start + DS32 4 + + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_initialize_low_level Cortex-Mx/IAR */ +/* 6.1.10 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for any low-level processor */ +/* initialization, including setting up interrupt vectors, setting */ +/* up a periodic timer interrupt source, saving the system stack */ +/* pointer for use in ISR processing later, and finding the first */ +/* available RAM memory address for tx_application_define. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_initialize_kernel_enter ThreadX entry function */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 01-31-2022 Scott Larson Modified comment(s), added */ +/* TX_NO_TIMER support, */ +/* resulting in version 6.1.10 */ +/* */ +/**************************************************************************/ +// VOID _tx_initialize_low_level(VOID) +// { + PUBLIC _tx_initialize_low_level +_tx_initialize_low_level: + + /* Ensure that interrupts are disabled. */ + CPSID i + + /* Set base of available memory to end of non-initialised RAM area. */ + LDR r0, =__tx_free_memory_start // Get end of non-initialized RAM area + LDR r2, =_tx_initialize_unused_memory // Build address of unused memory pointer + STR r0, [r2, #0] // Save first free memory address + + /* Setup Vector Table Offset Register. */ + MOV r0, #0xE000E000 // Build address of NVIC registers + LDR r1, =__vector_table // Pickup address of vector table + STR r1, [r0, #0xD08] // Set vector table address + + /* Set system stack pointer from vector value. */ + LDR r0, =_tx_thread_system_stack_ptr // Build address of system stack pointer + LDR r1, =__vector_table // Pickup address of vector table + LDR r1, [r1] // Pickup reset stack pointer + STR r1, [r0] // Save system stack pointer + +#ifndef TX_NO_TIMER + /* Configure SysTick. */ + MOV r0, #0xE000E000 // Build address of NVIC registers + LDR r1, =SYSTICK_CYCLES + STR r1, [r0, #0x14] // Setup SysTick Reload Value + MOV r1, #0x7 // Build SysTick Control Enable Value + STR r1, [r0, #0x10] // Setup SysTick Control +#endif + + /* Configure handler priorities. */ + LDR r1, =0x00000000 // Rsrv, UsgF, BusF, MemM + STR r1, [r0, #0xD18] // Setup System Handlers 4-7 Priority Registers + LDR r1, =0xFF000000 // SVCl, Rsrv, Rsrv, Rsrv + STR r1, [r0, #0xD1C] // Setup System Handlers 8-11 Priority Registers + // Note: SVC must be lowest priority, which is 0xFF + LDR r1, =0x40FF0000 // SysT, PnSV, Rsrv, DbgM + STR r1, [r0, #0xD20] // Setup System Handlers 12-15 Priority Registers + // Note: PnSV must be lowest priority, which is 0xFF + + /* Return to caller. */ + BX lr +// } + +#ifndef TX_NO_TIMER + PUBLIC SysTick_Handler + PUBLIC __tx_SysTickHandler +__tx_SysTickHandler: +SysTick_Handler: +// VOID SysTick_Handler(VOID) +// { + + PUSH {r0, lr} +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + BL _tx_execution_isr_enter // Call the ISR enter function +#endif + BL _tx_timer_interrupt +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + BL _tx_execution_isr_exit // Call the ISR exit function +#endif + POP {r0, lr} + BX lr +// } +#endif + END diff --git a/ports_arch/ARMv7-M/threadx/iar/readme_threadx.txt b/ports_arch/ARMv7-M/threadx/iar/readme_threadx.txt new file mode 100644 index 00000000..28b54e03 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/iar/readme_threadx.txt @@ -0,0 +1,215 @@ + Microsoft's Azure RTOS ThreadX for ARMv7-M + (Cortex-M3, Cortex-M4, Cortex-M7) + Using IAR EWARM Tools + + +1. Building the ThreadX run-time Library + +Building the ThreadX library is easy. First, open the Azure RTOS workspace +azure_rtos.eww. Next, make the TX project the "active project" in the +IAR Embedded Workbench and select the "Make" button. You should observe +assembly and compilation of a series of ThreadX source files. This +results in the ThreadX run-time library file tx.a, which is needed by +the application. + + +2. Demonstration System + +The ThreadX demonstration is designed to execute under the IAR debugger under +simulation. + +Building the demonstration is easy; simply open the threadx.www workspace file, +make the sample_threadx.ewp project the "active project" in the IAR Embedded +Workbench, and select the "Make" button. + +You should observe the compilation of sample_threadx.c (which is the demonstration +application) and linking with tx.a. The resulting file sample_threadx.out is a +binary ELF file that can be downloaded and executed on the IAR Windows-based +Cortex-M simulator. + + +3. System Initialization + +The entry point in ThreadX for the Cortex-M using IAR tools is at label +__iar_program_start. This is defined within the IAR compiler's startup code. +In addition, this is where all static and global preset C variable +initialization processing takes place. + +The ThreadX tx_initialize_low_level.s file is responsible for setting up +various system data structures, and a periodic timer interrupt source. +By default, the vector area is defined at the top of cstartup_M.s, which is +a slightly modified from the base IAR file. + +The _tx_initialize_low_level function inside of tx_initialize_low_level.s +also determines the first available address for use by the application, which +is supplied as the sole input parameter to your application definition function, +tx_application_define. To accomplish this, a section is created in +tx_initialize_low_level.s called FREE_MEM, which must be located after all +other RAM sections in memory. + + +4. Register Usage and Stack Frames + +The following defines the saved context stack frames for context switches +that occur as a result of interrupt handling or from thread-level API calls. +All suspended threads have the same stack frame in the Cortex-M version of +ThreadX. The top of the suspended thread's stack is pointed to by +tx_thread_stack_ptr in the associated thread control block TX_THREAD. + +Non-FPU Stack Frame: + + Stack Offset Stack Contents + + 0x00 lr Interrupted lr (lr at time of PENDSV) + 0x04 r4 Software stacked GP registers + 0x08 r5 + 0x0C r6 + 0x10 r7 + 0x14 r8 + 0x18 r9 + 0x1C r10 + 0x20 r11 + 0x24 r0 Hardware stacked registers + 0x28 r1 + 0x2C r2 + 0x30 r3 + 0x34 r12 + 0x38 lr + 0x3C pc + 0x40 xPSR + +FPU Stack Frame (only interrupted thread with FPU enabled): + + Stack Offset Stack Contents + + 0x00 lr Interrupted lr (lr at time of PENDSV) + 0x04 s16 Software stacked FPU registers + 0x08 s17 + 0x0C s18 + 0x10 s19 + 0x14 s20 + 0x18 s21 + 0x1C s22 + 0x20 s23 + 0x24 s24 + 0x28 s25 + 0x2C s26 + 0x30 s27 + 0x34 s28 + 0x38 s29 + 0x3C s30 + 0x40 s31 + 0x44 r4 Software stacked registers + 0x48 r5 + 0x4C r6 + 0x50 r7 + 0x54 r8 + 0x58 r9 + 0x5C r10 + 0x60 r11 + 0x64 r0 Hardware stacked registers + 0x68 r1 + 0x6C r2 + 0x70 r3 + 0x74 r12 + 0x78 lr + 0x7C pc + 0x80 xPSR + 0x84 s0 Hardware stacked FPU registers + 0x88 s1 + 0x8C s2 + 0x90 s3 + 0x94 s4 + 0x98 s5 + 0x9C s6 + 0xA0 s7 + 0xA4 s8 + 0xA8 s9 + 0xAC s10 + 0xB0 s11 + 0xB4 s12 + 0xB8 s13 + 0xBC s14 + 0xC0 s15 + 0xC4 fpscr + + +5. Improving Performance + +The distribution version of ThreadX is built without any compiler +optimizations. This makes it easy to debug because you can trace or set +breakpoints inside of ThreadX itself. Of course, this costs some +performance. To make it run faster, you can change the ThreadX library +project to enable various compiler optimizations. + +In addition, you can eliminate the ThreadX basic API error checking by +compiling your application code with the symbol TX_DISABLE_ERROR_CHECKING +defined. + + +6. Interrupt Handling + +The Cortex-M vectors start at the label __vector_table and is defined in cstartup_M.s. +The application may modify the vector area according to its needs. + + +6.1 Managed Interrupts + +ISRs for Cortex-M using the IAR tools can be written completely in C (or assembly +language) without any calls to _tx_thread_context_save or _tx_thread_context_restore. +These ISRs are allowed access to the ThreadX API that is available to ISRs. + +ISRs written in C will take the form (where "your_C_isr" is an entry in the vector table): + +void your_C_isr(void) +{ + + /* ISR processing goes here, including any needed function calls. */ +} + +ISRs written in assembly language will take the form: + + PUBLIC your_assembly_isr +your_assembly_isr: + + PUSH {r0, lr} + + ; ISR processing goes here, including any needed function calls. + + POP {r0, lr} + BX lr + + +7. IAR Thread-safe Library Support + +Thread-safe support for the IAR tools is easily enabled by building the ThreadX library +and the application with TX_ENABLE_IAR_LIBRARY_SUPPORT. Also, the linker control file +should have the following line added (if not already in place): + +initialize by copy with packing = none { section __DLIB_PERTHREAD }; // Required in a multi-threaded application + +The project options "General Options -> Library Configuration" should also have the +"Enable thread support in library" box selected. + + +8. VFP Support + +ThreadX for Cortex-M supports automatic ("lazy") VFP support, which means that applications threads +can simply use the VFP and ThreadX automatically maintains the VFP registers as part of the thread +context - no additional setup by the application. + + +9. Revision History + +For generic code revision information, please refer to the readme_threadx_generic.txt +file, which is included in your distribution. The following details the revision +information associated with this specific port of ThreadX: + +06-02-2021 Initial ThreadX version 6.1.7 for Cortex-M using IAR's ARM tools. + + +Copyright(c) 1996-2021 Microsoft Corporation + + +https://azure.com/rtos + diff --git a/ports_arch/ARMv7-M/threadx/iar/src/tx_iar.c b/ports_arch/ARMv7-M/threadx/iar/src/tx_iar.c new file mode 100644 index 00000000..dd719370 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/iar/src/tx_iar.c @@ -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 is included with the following code segments: + +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#include +#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 + + +#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 is included with the following code segments: + +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#include +#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 + + +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 /* 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. */ diff --git a/ports_arch/ARMv7-M/threadx/iar/src/tx_misra.s b/ports_arch/ARMv7-M/threadx/iar/src/tx_misra.s new file mode 100644 index 00000000..ab3fef69 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/iar/src/tx_misra.s @@ -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 diff --git a/ports_arch/ARMv7-M/threadx/iar/src/tx_thread_context_restore.s b/ports_arch/ARMv7-M/threadx/iar/src/tx_thread_context_restore.s new file mode 100644 index 00000000..eaa2f9ef --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/iar/src/tx_thread_context_restore.s @@ -0,0 +1,78 @@ +/**************************************************************************/ +/* */ +/* 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_execution_isr_exit + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_restore Cortex-Mx/IAR */ +/* 6.1.7 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is only needed for legacy applications and it should */ +/* not be called in any new development on a Cortex-M. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* [_tx_execution_isr_exit] Execution profiling ISR exit */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs Interrupt Service Routines */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_context_restore(VOID) +// { + PUBLIC _tx_thread_context_restore +_tx_thread_context_restore: + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the ISR exit function to indicate an ISR is complete. */ + PUSH {r0, lr} // Save return address + BL _tx_execution_isr_exit // Call the ISR exit function + POP {r0, lr} // Recover return address +#endif + + BX lr +// } + END diff --git a/ports_arch/ARMv7-M/threadx/iar/src/tx_thread_context_save.s b/ports_arch/ARMv7-M/threadx/iar/src/tx_thread_context_save.s new file mode 100644 index 00000000..5c31541b --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/iar/src/tx_thread_context_save.s @@ -0,0 +1,80 @@ +/**************************************************************************/ +/* */ +/* 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_execution_isr_enter + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_save Cortex-Mx/IAR */ +/* 6.1.7 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is only needed for legacy applications and it should */ +/* not be called in any new development on a Cortex-M. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* [_tx_execution_isr_enter] Execution profiling ISR enter */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_context_save(VOID) +// { + PUBLIC _tx_thread_context_save +_tx_thread_context_save: + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the ISR enter function to indicate an ISR is starting. */ + PUSH {r0, lr} // Save return address + BL _tx_execution_isr_enter // Call the ISR enter function + POP {r0, lr} // Recover return address +#endif + + /* Context is already saved - just return. */ + + BX lr +// } + END diff --git a/ports_arch/ARMv7-M/threadx/iar/src/tx_thread_interrupt_control.s b/ports_arch/ARMv7-M/threadx/iar/src/tx_thread_interrupt_control.s new file mode 100644 index 00000000..ef1686e3 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/iar/src/tx_thread_interrupt_control.s @@ -0,0 +1,78 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_control Cortex-Mx/IAR */ +/* 6.1.7 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for changing the interrupt lockout */ +/* posture of the system. */ +/* */ +/* INPUT */ +/* */ +/* new_posture New interrupt lockout posture */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_interrupt_control(UINT new_posture) +// { + PUBLIC _tx_thread_interrupt_control +_tx_thread_interrupt_control: +#ifdef TX_PORT_USE_BASEPRI + MRS r1, BASEPRI // Pickup current interrupt posture + MSR BASEPRI, r0 // Apply the new interrupt posture + MOV r0, r1 // Transfer old to return register +#else + MRS r1, PRIMASK // Pickup current interrupt lockout + MSR PRIMASK, r0 // Apply the new interrupt lockout + MOV r0, r1 // Transfer old to return register +#endif + BX lr // Return to caller +// } + END diff --git a/ports_arch/ARMv7-M/threadx/iar/src/tx_thread_interrupt_disable.s b/ports_arch/ARMv7-M/threadx/iar/src/tx_thread_interrupt_disable.s new file mode 100644 index 00000000..dc845dc1 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/iar/src/tx_thread_interrupt_disable.s @@ -0,0 +1,78 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_disable Cortex-Mx/IAR */ +/* 6.1.7 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for disabling interrupts and returning */ +/* the previous interrupt lockout posture. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_interrupt_disable(VOID) +// { + PUBLIC _tx_thread_interrupt_disable +_tx_thread_interrupt_disable: + /* Return current interrupt lockout posture. */ +#ifdef TX_PORT_USE_BASEPRI + MRS r0, BASEPRI + LDR r1, =TX_PORT_BASEPRI + MSR BASEPRI, r1 +#else + MRS r0, PRIMASK + CPSID i +#endif + BX lr +// } + END diff --git a/ports_arch/ARMv7-M/threadx/iar/src/tx_thread_interrupt_restore.s b/ports_arch/ARMv7-M/threadx/iar/src/tx_thread_interrupt_restore.s new file mode 100644 index 00000000..0fb7ff30 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/iar/src/tx_thread_interrupt_restore.s @@ -0,0 +1,75 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_restore Cortex-Mx/IAR */ +/* 6.1.7 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for restoring the previous */ +/* interrupt lockout posture. */ +/* */ +/* INPUT */ +/* */ +/* previous_posture Previous interrupt posture */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_interrupt_restore(UINT previous_posture) +// { + PUBLIC _tx_thread_interrupt_restore +_tx_thread_interrupt_restore: + /* Restore previous interrupt lockout posture. */ +#ifdef TX_PORT_USE_BASEPRI + MSR BASEPRI, r0 +#else + MSR PRIMASK, r0 +#endif + BX lr +// } + END diff --git a/ports_arch/ARMv7-M/threadx/iar/src/tx_thread_schedule.s b/ports_arch/ARMv7-M/threadx/iar/src/tx_thread_schedule.s new file mode 100644 index 00000000..727ff0f1 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/iar/src/tx_thread_schedule.s @@ -0,0 +1,318 @@ +/**************************************************************************/ +/* */ +/* 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_thread_preempt_disable + EXTERN _tx_execution_thread_enter + EXTERN _tx_execution_thread_exit +#ifdef TX_LOW_POWER + EXTERN tx_low_power_enter + EXTERN tx_low_power_exit +#endif + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_schedule Cortex-Mx/IAR */ +/* 6.1.11 */ +/* 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 */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 04-25-2022 Scott Larson Added BASEPRI support, */ +/* resulting in version 6.1.11 */ +/* */ +/**************************************************************************/ +// 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 + + /* Clear CONTROL.FPCA bit so VFP registers aren't unnecessarily stacked. */ + +#ifdef __ARMVFP__ + MRS r0, CONTROL // Pickup current CONTROL register + BIC r0, r0, #4 // Clear the FPCA bit + MSR CONTROL, r0 // Setup new CONTROL register +#endif + + /* 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 +// } + + /* Generic context switching 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? + CBZ r1, __tx_ts_wait // No, skip to the wait processing + + /* Yes, another thread is ready for else, make the current thread the new thread. */ + + 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. */ + +__tx_ts_restore: + 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 + 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! + + /* 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 + STR r1, [r0] // Store it in the current 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 + + /* Re-enable interrupts and restore new thread. */ +#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_restore // Restore the thread +// } + +#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 diff --git a/ports_arch/ARMv7-M/threadx/iar/src/tx_thread_stack_build.s b/ports_arch/ARMv7-M/threadx/iar/src/tx_thread_stack_build.s new file mode 100644 index 00000000..10380569 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/iar/src/tx_thread_stack_build.s @@ -0,0 +1,132 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_stack_build Cortex-Mx/IAR */ +/* 6.1.7 */ +/* 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 control blk */ +/* function_ptr Pointer to return function */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_create Create thread service */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID)) +// { + PUBLIC _tx_thread_stack_build +_tx_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 for 8-byte alignment + 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, #24] // Store initial r9 + STR r3, [r2, #28] // Store initial r10 + STR r3, [r2, #32] // Store initial r11 + + /* Hardware stack follows. */ + + STR r3, [r2, #36] // Store initial r0 + STR r3, [r2, #40] // Store initial r1 + 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 diff --git a/ports_arch/ARMv7-M/threadx/iar/src/tx_thread_system_return.s b/ports_arch/ARMv7-M/threadx/iar/src/tx_thread_system_return.s new file mode 100644 index 00000000..313d2a40 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/iar/src/tx_thread_system_return.s @@ -0,0 +1,92 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_system_return Cortex-Mx/IAR */ +/* 6.1.7 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is target processor specific. It is used to transfer */ +/* control from a thread back to the ThreadX system. Only a */ +/* minimal context is saved since the compiler assumes temp registers */ +/* are going to get slicked by a function call anyway. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_schedule Thread scheduling loop */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX components */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_system_return(VOID) +// { + PUBLIC _tx_thread_system_return +_tx_thread_system_return: + + /* Return to real scheduler via PendSV. Note that this routine is often + replaced with in-line assembly in tx_port.h to improved performance. */ + + MOV r0, #0x10000000 // Load PENDSVSET bit + MOV r1, #0xE000E000 // Load NVIC base + STR r0, [r1, #0xD04] // Set PENDSVBIT in ICSR + MRS r0, IPSR // Pickup IPSR + CMP r0, #0 // Is it a thread returning? + BNE _isr_context // If ISR, skip interrupt enable +#ifdef TX_PORT_USE_BASEPRI + MRS r1, BASEPRI // Thread context returning, pickup BASEPRI + MOV r0, #0 + MSR BASEPRI, r0 // Enable interrupts + MSR BASEPRI, r1 // Restore original interrupt posture +#else + MRS r1, PRIMASK // Thread context returning, pickup PRIMASK + CPSIE i // Enable interrupts + MSR PRIMASK, r1 // Restore original interrupt posture +#endif +_isr_context: + BX lr // Return to caller +// } + END diff --git a/ports_arch/ARMv7-M/threadx/iar/src/tx_timer_interrupt.s b/ports_arch/ARMv7-M/threadx/iar/src/tx_timer_interrupt.s new file mode 100644 index 00000000..b7ba9981 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/iar/src/tx_timer_interrupt.s @@ -0,0 +1,257 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + EXTERN _tx_timer_time_slice + EXTERN _tx_timer_system_clock + EXTERN _tx_timer_current_ptr + EXTERN _tx_timer_list_start + EXTERN _tx_timer_list_end + EXTERN _tx_timer_expired_time_slice + EXTERN _tx_timer_expired + EXTERN _tx_thread_time_slice + EXTERN _tx_timer_expiration_process + EXTERN _tx_thread_current_ptr + EXTERN _tx_thread_execute_ptr + EXTERN _tx_thread_preempt_disable + + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_interrupt Cortex-Mx/IAR */ +/* 6.1.10 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the hardware timer interrupt. This */ +/* processing includes incrementing the system clock and checking for */ +/* time slice and/or timer expiration. If either is found, the */ +/* expiration functions are called. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_timer_expiration_process Timer expiration processing */ +/* _tx_thread_time_slice Time slice interrupted thread */ +/* */ +/* CALLED BY */ +/* */ +/* interrupt vector */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 01-31-2022 Scott Larson Modified comment(s), added */ +/* TX_NO_TIMER support, */ +/* resulting in version 6.1.10 */ +/* */ +/**************************************************************************/ +// VOID _tx_timer_interrupt(VOID) +// { +#ifndef TX_NO_TIMER + PUBLIC _tx_timer_interrupt +_tx_timer_interrupt: + + /* Upon entry to this routine, it is assumed that the compiler scratch registers are available + for use. */ + + /* Increment the system clock. */ + // _tx_timer_system_clock++; + + LDR r1, =_tx_timer_system_clock // Pickup address of system clock + LDR r0, [r1, #0] // Pickup system clock + ADD r0, r0, #1 // Increment system clock + STR r0, [r1, #0] // Store new system clock + + /* Test for time-slice expiration. */ + // if (_tx_timer_time_slice) + // { + + LDR r3, =_tx_timer_time_slice // Pickup address of time-slice + LDR r2, [r3, #0] // Pickup time-slice + CBZ r2, __tx_timer_no_time_slice // Is it non-active? + // Yes, skip time-slice processing + + /* Decrement the time_slice. */ + // _tx_timer_time_slice--; + + SUB r2, r2, #1 // Decrement the time-slice + STR r2, [r3, #0] // Store new time-slice value + + /* Check for expiration. */ + // if (__tx_timer_time_slice == 0) + + CBNZ r2, __tx_timer_no_time_slice // Has it expired? + // No, skip expiration processing + + /* Set the time-slice expired flag. */ + // _tx_timer_expired_time_slice = TX_TRUE; + + LDR r3, =_tx_timer_expired_time_slice // Pickup address of expired flag + MOV r0, #1 // Build expired value + STR r0, [r3, #0] // Set time-slice expiration flag + + // } + +__tx_timer_no_time_slice: + + /* Test for timer expiration. */ + // if (*_tx_timer_current_ptr) + // { + + LDR r1, =_tx_timer_current_ptr // Pickup current timer pointer address + LDR r0, [r1, #0] // Pickup current timer + LDR r2, [r0, #0] // Pickup timer list entry + CBZ r2, __tx_timer_no_timer // Is there anything in the list? + // No, just increment the timer + + /* Set expiration flag. */ + // _tx_timer_expired = TX_TRUE; + + LDR r3, =_tx_timer_expired // Pickup expiration flag address + MOV r2, #1 // Build expired value + STR r2, [r3, #0] // Set expired flag + B __tx_timer_done // Finished timer processing + + // } + // else + // { +__tx_timer_no_timer: + + /* No timer expired, increment the timer pointer. */ + // _tx_timer_current_ptr++; + + ADD r0, r0, #4 // Move to next timer + + /* Check for wrap-around. */ + // if (_tx_timer_current_ptr == _tx_timer_list_end) + + LDR r3, =_tx_timer_list_end // Pickup addr of timer list end + LDR r2, [r3, #0] // Pickup list end + CMP r0, r2 // Are we at list end? + BNE __tx_timer_skip_wrap // No, skip wrap-around logic + + /* Wrap to beginning of list. */ + // _tx_timer_current_ptr = _tx_timer_list_start; + + LDR r3, =_tx_timer_list_start // Pickup addr of timer list start + LDR r0, [r3, #0] // Set current pointer to list start + +__tx_timer_skip_wrap: + + STR r0, [r1, #0] // Store new current timer pointer + // } + +__tx_timer_done: + + /* See if anything has expired. */ + // if ((_tx_timer_expired_time_slice) || (_tx_timer_expired)) + // { + + LDR r3, =_tx_timer_expired_time_slice // Pickup addr of expired flag + LDR r2, [r3, #0] // Pickup time-slice expired flag + CBNZ r2, __tx_something_expired // Did a time-slice expire? + // If non-zero, time-slice expired + LDR r1, =_tx_timer_expired // Pickup addr of other expired flag + LDR r0, [r1, #0] // Pickup timer expired flag + CBZ r0, __tx_timer_nothing_expired // Did a timer expire? + // No, nothing expired + +__tx_something_expired: + + STMDB sp!, {r0, lr} // Save the lr register on the stack + // and save r0 just to keep 8-byte alignment + + /* Did a timer expire? */ + // if (_tx_timer_expired) + // { + + LDR r1, =_tx_timer_expired // Pickup addr of expired flag + LDR r0, [r1, #0] // Pickup timer expired flag + CBZ r0, __tx_timer_dont_activate // Check for timer expiration + // If not set, skip timer activation + + /* Process timer expiration. */ + // _tx_timer_expiration_process(); + + BL _tx_timer_expiration_process // Call the timer expiration handling routine + + // } +__tx_timer_dont_activate: + + /* Did time slice expire? */ + // if (_tx_timer_expired_time_slice) + // { + + LDR r3, =_tx_timer_expired_time_slice // Pickup addr of time-slice expired + LDR r2, [r3, #0] // Pickup the actual flag + CBZ r2, __tx_timer_not_ts_expiration // See if the flag is set + // No, skip time-slice processing + + /* Time slice interrupted thread. */ + // _tx_thread_time_slice(); + + BL _tx_thread_time_slice // Call time-slice processing + LDR r0, =_tx_thread_preempt_disable // Build address of preempt disable flag + LDR r1, [r0] // Is the preempt disable flag set? + CBNZ r1, __tx_timer_skip_time_slice // Yes, skip the PendSV logic + LDR r0, =_tx_thread_current_ptr // Build current thread pointer address + LDR r1, [r0] // Pickup the current thread pointer + LDR r2, =_tx_thread_execute_ptr // Build execute thread pointer address + LDR r3, [r2] // Pickup the execute thread pointer + LDR r0, =0xE000ED04 // Build address of control register + LDR r2, =0x10000000 // Build value for PendSV bit + CMP r1, r3 // Are they the same? + BEQ __tx_timer_skip_time_slice // If the same, there was no time-slice performed + STR r2, [r0] // Not the same, issue the PendSV for preemption +__tx_timer_skip_time_slice: + + // } + +__tx_timer_not_ts_expiration: + + LDMIA sp!, {r0, lr} // Recover lr register (r0 is just there for + // the 8-byte stack alignment + + // } + +__tx_timer_nothing_expired: + + DSB // Complete all memory access + BX lr // Return to caller +// } +#endif + END diff --git a/ports_arch/ARMv7-M/threadx/iar/tx_low_power.c b/ports_arch/ARMv7-M/threadx/iar/tx_low_power.c new file mode 100644 index 00000000..fc09ff50 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/iar/tx_low_power.c @@ -0,0 +1,563 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Low Power Timer Management */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_timer.h" +#include "tx_low_power.h" + + +/* Define low power global variables. */ + +/* Flag to determine if we've entered low power mode or not. */ +UINT tx_low_power_entered; + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* tx_low_power_enter PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the low power entry function. This function is */ +/* assumed to be called from the idle loop of tx_thread_schedule. It */ +/* is important to note that if an interrupt managed by ThreadX occurs */ +/* anywhere where interrupts are enabled in this function, the entire */ +/* processing of this function is discarded and the function won't be */ +/* re-entered until the idle loop in tx_thread_schedule is executed */ +/* again. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_timer_get_next Get next timer expiration */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_schedule Thread scheduling loop */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID tx_low_power_enter(VOID) +{ + +TX_INTERRUPT_SAVE_AREA +ULONG tx_low_power_next_expiration; +ULONG any_expired; + + + /* The below macro is user-defined code to determine + if low power mode is beneficial for the application. + Reasons for not entering low power mode include + the overhead associated with entering and exiting low power mode + outweighs the savings given when the next interrupt is expected. + In addition, the application might also be in a state where + responsiveness is more important than power savings. In such + situations, using a "reduced power mode" might make more sense. + In any case, if low power mode is not desired, simply return at + this point in the code. */ + #ifdef TX_LOW_POWER_USER_CHECK + TX_LOW_POWER_USER_CHECK; + #endif + + /* Disable interrupts while we prepare for low power mode. */ + TX_DISABLE + + /* At this point, we want to enter low power mode, since nothing + meaningful is going on in the system. However, in order to keep + the ThreadX timer services accurate, we must first determine the + next ThreadX timer expiration in terms of ticks. This is + accomplished via the tx_timer_get_next API. */ + any_expired = tx_timer_get_next(&tx_low_power_next_expiration); + + /* There are two possibilities: + 1: A ThreadX timer is active. tx_timer_get_next returns TX_TRUE. + Program the hardware timer source such that the next timer + interrupt is equal to: tx_low_power_next_expiration*tick_frequency. + In most applications, the tick_frequency is 10ms, but this is + completely application specific in ThreadX, typically set up + in tx_low_level_initialize. + 2: There are no ThreadX timers active. tx_timer_get_next returns TX_FALSE. + If you don't care about maintaining the ThreadX system clock, you can simply + sleep forever (until an interrupt wakes you up). + If you do want to maintain the ThreadX system clock, + program the hardware timer so you can keep track of elapsed time. */ + #ifdef TX_LOW_POWER_USER_TIMER_SETUP + TX_LOW_POWER_USER_TIMER_SETUP(any_expired, tx_low_power_next_expiration); + #endif + + + /* Set the flag indicating that low power has been entered. This + flag is checked in tx_low_power_exit to determine if the logic + used to adjust the ThreadX time is required. */ + tx_low_power_entered = TX_TRUE; + + /* Re-enable interrupts before low power mode is entered. */ + TX_RESTORE + + /* User code to enter low power mode. */ + #ifdef TX_LOW_POWER_USER_ENTER + TX_LOW_POWER_USER_ENTER; + #endif + + /* If the low power code returns, this routine returns to the + tx_thread_schedule loop. */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* tx_low_power_exit PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the low power exit function. This function must */ +/* be called from any interrupt that can wakeup the processor from */ +/* low power mode. If nothing needs to be done, this function simply */ +/* returns. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_time_increment Update the ThreadX timer */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs Front-end of Interrupt */ +/* Service Routines */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID tx_low_power_exit(VOID) +{ +ULONG tx_low_power_adjust_ticks; + + /* Determine if the interrupt occurred in low power mode. */ + if (tx_low_power_entered) + { + + /* Yes, low power mode was interrupted. */ + + /* Clear the low power entered flag. */ + tx_low_power_entered = TX_FALSE; + + /* User code to exit low power mode and reprogram the + timer to the desired interrupt frequency. */ + #ifdef TX_LOW_POWER_USER_EXIT + TX_LOW_POWER_USER_EXIT; + #endif + + /* User code to determine how many timer ticks (interrupts) that + the ThreadX time should be incremented to properly adjust + for the time in low power mode. The result is assumed to be + placed in tx_low_power_adjust_ticks. */ + #ifdef TX_LOW_POWER_USER_TIMER_ADJUST + tx_low_power_adjust_ticks = TX_LOW_POWER_USER_TIMER_ADJUST; + #else + tx_low_power_adjust_ticks = (ULONG)0; + #endif + + /* Determine if the ThreadX timer needs incrementing. */ + if (tx_low_power_adjust_ticks) + { + + /* Yes, the ThreadX time must be incremented. Call tx_time_increment + to accomplish this. */ + tx_time_increment(tx_low_power_adjust_ticks); + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* tx_timer_get_next PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function calculates the next expiration time minus 1 tick for */ +/* the currently active ThreadX timers. If no timer is active, this */ +/* routine will return a value of TX_FALSE and the next ticks value */ +/* will be set to zero. */ +/* */ +/* INPUT */ +/* */ +/* next_timer_tick_ptr Pointer to destination for next */ +/* timer expiration value */ +/* */ +/* OUTPUT */ +/* */ +/* TX_TRUE (1) At least one timer is active */ +/* TX_FALSE (0) No timers are currently active */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* tx_low_power_enter */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +/* */ +/**************************************************************************/ +ULONG tx_timer_get_next(ULONG *next_timer_tick_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +TX_TIMER_INTERNAL **timer_list_head; +TX_TIMER_INTERNAL *next_timer; +UINT i; +ULONG calculated_time; +ULONG expiration_time = (ULONG) 0xFFFFFFFF; + + + /* Disable interrupts. */ + TX_DISABLE + + /* Look at the next timer entry. */ + timer_list_head = _tx_timer_current_ptr; + + /* Loop through the timer list, looking for the first non-NULL + value to signal an active timer. */ + for (i = (UINT)0; i < TX_TIMER_ENTRIES; i++) + { + + /* Now determine if there is an active timer in this slot. */ + if (*timer_list_head) + { + + /* Setup the pointer to the expiration list. */ + next_timer = *timer_list_head; + + /* Loop through the timers active for this relative time slot (determined by i). */ + do + { + + /* Determine if the remaining time is larger than the list. */ + if (next_timer -> tx_timer_internal_remaining_ticks > TX_TIMER_ENTRIES) + { + + /* Calculate the expiration time. */ + calculated_time = next_timer -> tx_timer_internal_remaining_ticks - (TX_TIMER_ENTRIES - i); + } + else + { + + /* Calculate the expiration time, which is simply the number of entries in this case. */ + calculated_time = i; + } + + /* Determine if a new minimum expiration time is present. */ + if (expiration_time > calculated_time) + { + + /* Yes, a new minimum expiration time is present - remember it! */ + expiration_time = calculated_time; + } + + /* Move to the next entry in the timer list. */ + next_timer = next_timer -> tx_timer_internal_active_next; + + } while (next_timer != *timer_list_head); + } + + /* This timer entry is NULL, so just move to the next one. */ + timer_list_head++; + + /* Check for timer list wrap condition. */ + if (timer_list_head >= _tx_timer_list_end) + { + + /* Wrap to the beginning of the list. */ + timer_list_head = _tx_timer_list_start; + } + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Determine if an active timer was found. */ + if (expiration_time != 0xFFFFFFFF) + { + + /* Yes, an active timer was found. */ + *next_timer_tick_ptr = expiration_time; + return(TX_TRUE); + } + else + { + + /* No active timer was found. */ + *next_timer_tick_ptr = 0; + return(TX_FALSE); + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* tx_time_increment PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function increments the current time by a specified value. */ +/* The value was derived by the application by calling the */ +/* tx_timer_get_next function prior to this call, which was right */ +/* before the processor was put in sleep mode. */ +/* */ +/* INPUT */ +/* */ +/* time_increment The amount of time to catch up on */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_timer_system_activate Timer activate service */ +/* */ +/* CALLED BY */ +/* */ +/* tx_low_power_exit */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID tx_time_increment(ULONG time_increment) +{ + +TX_INTERRUPT_SAVE_AREA +UINT i; +TX_TIMER_INTERNAL **timer_list_head; +TX_TIMER_INTERNAL *next_timer; +TX_TIMER_INTERNAL *temp_list_head; + + + /* Determine if there is any time increment. */ + if (time_increment == 0) + { + + /* Nothing to do, just return. */ + return; + } + + /* Disable interrupts. */ + TX_DISABLE + + /* Adjust the system clock. */ + _tx_timer_system_clock = _tx_timer_system_clock + time_increment; + + /* Adjust the time slice variable. */ + if (_tx_timer_time_slice) + { + + /* Decrement the time-slice variable. */ + if (_tx_timer_time_slice > time_increment) + _tx_timer_time_slice = _tx_timer_time_slice - time_increment; + else + _tx_timer_time_slice = 1; + } + + /* Calculate the proper place to position the timer. */ + timer_list_head = _tx_timer_current_ptr; + + /* Setup the temporary list pointer. */ + temp_list_head = TX_NULL; + + /* Loop to pull all timers off the timer structure and put on the + the temporary list head. */ + for (i = 0; i < TX_TIMER_ENTRIES; i++) + { + + /* Determine if there is a timer list in this entry. */ + if (*timer_list_head) + { + + /* Walk the list and update all the relative times to actual times. */ + + /* Setup the pointer to the expiration list. */ + next_timer = *timer_list_head; + + /* Loop through the timers active for this relative time slot (determined by i). */ + do + { + + /* Determine if the remaining time is larger than the list. */ + if (next_timer -> tx_timer_internal_remaining_ticks > TX_TIMER_ENTRIES) + { + + /* Calculate the actual expiration time. */ + next_timer -> tx_timer_internal_remaining_ticks = + next_timer -> tx_timer_internal_remaining_ticks - (TX_TIMER_ENTRIES - i) + 1; + } + else + { + + /* Calculate the expiration time, which is simply the number of entries in this + case. */ + next_timer -> tx_timer_internal_remaining_ticks = i + 1; + } + + /* Move to the next entry in the timer list. */ + next_timer = next_timer -> tx_timer_internal_active_next; + + } while (next_timer != *timer_list_head); + + /* NULL terminate the current timer list. */ + ((*timer_list_head) -> tx_timer_internal_active_previous) -> tx_timer_internal_active_next = TX_NULL; + + /* Yes, determine if the temporary list is NULL. */ + if (temp_list_head == TX_NULL) + { + + /* First item on the list. Move the entire + linked list. */ + temp_list_head = *timer_list_head; + } + else + { + + /* No, the temp list already has timers on it. Link the next + timer list to the end. */ + (temp_list_head -> tx_timer_internal_active_previous) -> tx_timer_internal_active_next = *timer_list_head; + + /* Now update the previous to the new list's previous timer pointer. */ + temp_list_head -> tx_timer_internal_active_previous = (*timer_list_head) -> tx_timer_internal_active_previous; + } + + /* Now clear the current timer head pointer. */ + *timer_list_head = TX_NULL; + } + + /* Move to next timer entry. */ + timer_list_head++; + + /* Determine if a wrap around condition has occurred. */ + if (timer_list_head >= _tx_timer_list_end) + { + + /* Wrap from the beginning of the list. */ + timer_list_head = _tx_timer_list_start; + } + } + + /* Set the current timer pointer to the beginning of the list. */ + _tx_timer_current_ptr = _tx_timer_list_start; + + /* Loop to update and reinsert all the timers in the list. */ + while (temp_list_head) + { + + /* Pickup the next timer to update and reinsert. */ + next_timer = temp_list_head; + + /* Move the temp list head pointer to the next pointer. */ + temp_list_head = next_timer -> tx_timer_internal_active_next; + + /* Determine if the remaining time is greater than the time increment + value - this is the normal case. */ + if (next_timer -> tx_timer_internal_remaining_ticks > time_increment) + { + + /* Decrement the elapsed time. */ + next_timer -> tx_timer_internal_remaining_ticks = next_timer -> tx_timer_internal_remaining_ticks - time_increment; + } + else + { + + /* Simply set the expiration value to expire on the next tick. */ + next_timer -> tx_timer_internal_remaining_ticks = 1; + } + + /* Now clear the timer list head pointer for the timer activate function to work properly. */ + next_timer -> tx_timer_internal_list_head = TX_NULL; + + /* Now re-insert the timer into the list. */ + _tx_timer_system_activate(next_timer); + } + + /* Restore interrupts. */ + TX_RESTORE +} diff --git a/ports_arch/ARMv7-M/threadx/iar/tx_low_power.h b/ports_arch/ARMv7-M/threadx/iar/tx_low_power.h new file mode 100644 index 00000000..47b9228b --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/iar/tx_low_power.h @@ -0,0 +1,58 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Timer Management */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* tx_low_power.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines prototypes for the low-power timer additions */ +/* required for sleep mode. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef TX_LOW_POWER_H +#define TX_LOW_POWER_H + + +/* Define low-power function prototypes. */ + +VOID tx_low_power_enter(VOID); +VOID tx_low_power_exit(VOID); +VOID tx_time_increment(ULONG time_increment); +ULONG tx_timer_get_next(ULONG *next_timer_tick_ptr); + +#endif diff --git a/ports_arch/ARMv7-M/threadx/inc/tx_port.h b/ports_arch/ARMv7-M/threadx/inc/tx_port.h new file mode 100644 index 00000000..14a5f775 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx/inc/tx_port.h @@ -0,0 +1,729 @@ +/**************************************************************************/ +/* */ +/* 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.1.12 */ +/* */ +/* 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 */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 01-31-2022 Scott Larson Modified comments, updated */ +/* typedef to fix misra */ +/* violation, */ +/* fixed predefined macro, */ +/* resulting in version 6.1.10 */ +/* 04-25-2022 Scott Larson Modified comments and added */ +/* volatile to registers, */ +/* resulting in version 6.1.11 */ +/* 07-29-2022 Scott Larson Modified comments and */ +/* described BASEPRI usage, */ +/* resulting in version 6.1.12 */ +/* */ +/**************************************************************************/ + +#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 + + +/* Define compiler library include files. */ + +#include +#include + +#ifdef __ICCARM__ +#include /* IAR Intrinsics */ +#define __asm__ __asm /* Define to make all inline asm look similar */ +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#include +#endif +#endif /* __ICCARM__ */ + +#ifdef __ghs__ +#include +#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 + +#ifdef __ghs__ +/* Define constants for Green Hills EventAnalyzer. */ + +/* Define the number of ticks per second. This informs the EventAnalyzer what the timestamps + represent. By default, this is set to 1,000,000 i.e., one tick every microsecond. */ + +#define TX_EL_TICKS_PER_SECOND 1000000 + +/* Define the method of how to get the upper and lower 32-bits of the time stamp. By default, simply + simulate the time-stamp source with a counter. */ + +#define read_tbu() _tx_el_time_base_upper +#define read_tbl() ++_tx_el_time_base_lower +#endif /* __ghs__ */ + +/* 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_iar_tls_pointer; +#elif defined(__ghs__) +#define TX_THREAD_EXTENSION_2 VOID * tx_thread_eh_globals; \ + int Errno; /* errno. */ \ + char * strtok_saved_pos; /* strtok() position. */ +#else +#define TX_THREAD_EXTENSION_2 +#endif + + +#define TX_THREAD_EXTENSION_3 + + + +/* Define the port extensions of the remaining ThreadX objects. */ + +#define TX_BLOCK_POOL_EXTENSION +#define TX_BYTE_POOL_EXTENSION +#define TX_EVENT_FLAGS_GROUP_EXTENSION +#define TX_MUTEX_EXTENSION +#define TX_QUEUE_EXTENSION +#define TX_SEMAPHORE_EXTENSION +#define TX_TIMER_EXTENSION + + +/* 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) ); +#endif + + + +/* Define the interrupt disable/restore macros for each compiler. */ + +#if defined(__GNUC__) || defined(__ICCARM__) + +/*** GCC/AC6 and IAR ***/ + +__attribute__( ( always_inline ) ) static inline unsigned int __get_interrupt_posture(void) +{ +unsigned int 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(unsigned int 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(unsigned int int_posture) +{ +#ifdef TX_PORT_USE_BASEPRI + __set_basepri_value(int_posture); + //__asm__ volatile ("MSR BASEPRI,%0": : "r" (int_posture): "memory"); +#else + __asm__ volatile ("MSR PRIMASK,%0": : "r" (int_posture): "memory"); +#endif +} + +__attribute__( ( always_inline ) ) 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" : : : "memory"); +#endif + return(int_posture); +} + +__attribute__( ( always_inline ) ) static inline void _tx_thread_system_return_inline(void) +{ +unsigned int 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 diff --git a/ports_arch/ARMv7-M/threadx_modules/ac5/module_lib/src/txm_module_initialize.s b/ports_arch/ARMv7-M/threadx_modules/ac5/module_lib/src/txm_module_initialize.s new file mode 100644 index 00000000..4a721c20 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx_modules/ac5/module_lib/src/txm_module_initialize.s @@ -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 diff --git a/ports_arch/ARMv7-M/threadx_modules/ac5/module_lib/src/txm_module_thread_shell_entry.c b/ports_arch/ARMv7-M/threadx_modules/ac5/module_lib/src/txm_module_thread_shell_entry.c new file mode 100644 index 00000000..1f87ca65 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx_modules/ac5/module_lib/src/txm_module_thread_shell_entry.c @@ -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 +} diff --git a/ports_arch/ARMv7-M/threadx_modules/ac5/module_manager/src/tx_thread_schedule.s b/ports_arch/ARMv7-M/threadx_modules/ac5/module_manager/src/tx_thread_schedule.s new file mode 100644 index 00000000..6dcf71b1 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx_modules/ac5/module_manager/src/tx_thread_schedule.s @@ -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 diff --git a/ports_arch/ARMv7-M/threadx_modules/ac5/module_manager/src/txm_module_manager_thread_stack_build.s b/ports_arch/ARMv7-M/threadx_modules/ac5/module_manager/src/txm_module_manager_thread_stack_build.s new file mode 100644 index 00000000..8b32e650 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx_modules/ac5/module_manager/src/txm_module_manager_thread_stack_build.s @@ -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 diff --git a/ports_arch/ARMv7-M/threadx_modules/ac5/module_manager/src/txm_module_manager_user_mode_entry.s b/ports_arch/ARMv7-M/threadx_modules/ac5/module_manager/src/txm_module_manager_user_mode_entry.s new file mode 100644 index 00000000..753bdb8c --- /dev/null +++ b/ports_arch/ARMv7-M/threadx_modules/ac5/module_manager/src/txm_module_manager_user_mode_entry.s @@ -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 diff --git a/ports_arch/ARMv7-M/threadx_modules/ac6/module_lib/src/txm_module_initialize.S b/ports_arch/ARMv7-M/threadx_modules/ac6/module_lib/src/txm_module_initialize.S new file mode 100644 index 00000000..ed3c8661 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx_modules/ac6/module_lib/src/txm_module_initialize.S @@ -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 diff --git a/ports_arch/ARMv7-M/threadx_modules/ac6/module_lib/src/txm_module_thread_shell_entry.c b/ports_arch/ARMv7-M/threadx_modules/ac6/module_lib/src/txm_module_thread_shell_entry.c new file mode 100644 index 00000000..74139f55 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx_modules/ac6/module_lib/src/txm_module_thread_shell_entry.c @@ -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 +} diff --git a/ports_arch/ARMv7-M/threadx_modules/ac6/module_manager/src/tx_thread_schedule.S b/ports_arch/ARMv7-M/threadx_modules/ac6/module_manager/src/tx_thread_schedule.S new file mode 100644 index 00000000..0dee2fd7 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx_modules/ac6/module_manager/src/tx_thread_schedule.S @@ -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 diff --git a/ports_arch/ARMv7-M/threadx_modules/ac6/module_manager/src/txm_module_manager_thread_stack_build.S b/ports_arch/ARMv7-M/threadx_modules/ac6/module_manager/src/txm_module_manager_thread_stack_build.S new file mode 100644 index 00000000..3a3a2dcf --- /dev/null +++ b/ports_arch/ARMv7-M/threadx_modules/ac6/module_manager/src/txm_module_manager_thread_stack_build.S @@ -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 +// } diff --git a/ports_arch/ARMv7-M/threadx_modules/common/module_manager/src/txm_module_manager_alignment_adjust.c b/ports_arch/ARMv7-M/threadx_modules/common/module_manager/src/txm_module_manager_alignment_adjust.c new file mode 100644 index 00000000..e9a3b076 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx_modules/common/module_manager/src/txm_module_manager_alignment_adjust.c @@ -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 +} diff --git a/ports_arch/ARMv7-M/threadx_modules/common/module_manager/src/txm_module_manager_external_memory_enable.c b/ports_arch/ARMv7-M/threadx_modules/common/module_manager/src/txm_module_manager_external_memory_enable.c new file mode 100644 index 00000000..5d499ff5 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx_modules/common/module_manager/src/txm_module_manager_external_memory_enable.c @@ -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 +} diff --git a/ports_arch/ARMv7-M/threadx_modules/common/module_manager/src/txm_module_manager_memory_fault_handler.c b/ports_arch/ARMv7-M/threadx_modules/common/module_manager/src/txm_module_manager_memory_fault_handler.c new file mode 100644 index 00000000..1032cbd6 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx_modules/common/module_manager/src/txm_module_manager_memory_fault_handler.c @@ -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); + } +} diff --git a/ports_arch/ARMv7-M/threadx_modules/common/module_manager/src/txm_module_manager_memory_fault_notify.c b/ports_arch/ARMv7-M/threadx_modules/common/module_manager/src/txm_module_manager_memory_fault_notify.c new file mode 100644 index 00000000..65c6ca10 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx_modules/common/module_manager/src/txm_module_manager_memory_fault_notify.c @@ -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); +} diff --git a/ports_arch/ARMv7-M/threadx_modules/common/module_manager/src/txm_module_manager_mm_register_setup.c b/ports_arch/ARMv7-M/threadx_modules/common/module_manager/src/txm_module_manager_mm_register_setup.c new file mode 100644 index 00000000..a6b77473 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx_modules/common/module_manager/src/txm_module_manager_mm_register_setup.c @@ -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 diff --git a/ports_arch/ARMv7-M/threadx_modules/gnu/module_lib/src/txm_module_thread_shell_entry.c b/ports_arch/ARMv7-M/threadx_modules/gnu/module_lib/src/txm_module_thread_shell_entry.c new file mode 100644 index 00000000..bdf4b94b --- /dev/null +++ b/ports_arch/ARMv7-M/threadx_modules/gnu/module_lib/src/txm_module_thread_shell_entry.c @@ -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 +} diff --git a/ports_arch/ARMv7-M/threadx_modules/gnu/module_manager/src/tx_thread_schedule.S b/ports_arch/ARMv7-M/threadx_modules/gnu/module_manager/src/tx_thread_schedule.S new file mode 100644 index 00000000..b6aa4849 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx_modules/gnu/module_manager/src/tx_thread_schedule.S @@ -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 diff --git a/ports_arch/ARMv7-M/threadx_modules/gnu/module_manager/src/txm_module_manager_thread_stack_build.s b/ports_arch/ARMv7-M/threadx_modules/gnu/module_manager/src/txm_module_manager_thread_stack_build.s new file mode 100644 index 00000000..75c9b234 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx_modules/gnu/module_manager/src/txm_module_manager_thread_stack_build.s @@ -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 +// } diff --git a/ports_arch/ARMv7-M/threadx_modules/iar/module_lib/src/txm_module_thread_shell_entry.c b/ports_arch/ARMv7-M/threadx_modules/iar/module_lib/src/txm_module_thread_shell_entry.c new file mode 100644 index 00000000..4808f6a7 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx_modules/iar/module_lib/src/txm_module_thread_shell_entry.c @@ -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 +} diff --git a/ports_arch/ARMv7-M/threadx_modules/iar/module_manager/src/tx_iar.c b/ports_arch/ARMv7-M/threadx_modules/iar/module_manager/src/tx_iar.c new file mode 100644 index 00000000..dd719370 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx_modules/iar/module_manager/src/tx_iar.c @@ -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 is included with the following code segments: + +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#include +#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 + + +#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 is included with the following code segments: + +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#include +#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 + + +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 /* 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. */ diff --git a/ports_arch/ARMv7-M/threadx_modules/iar/module_manager/src/tx_misra.s b/ports_arch/ARMv7-M/threadx_modules/iar/module_manager/src/tx_misra.s new file mode 100644 index 00000000..ab3fef69 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx_modules/iar/module_manager/src/tx_misra.s @@ -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 diff --git a/ports_arch/ARMv7-M/threadx_modules/iar/module_manager/src/tx_thread_schedule.s b/ports_arch/ARMv7-M/threadx_modules/iar/module_manager/src/tx_thread_schedule.s new file mode 100644 index 00000000..0e47d0d2 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx_modules/iar/module_manager/src/tx_thread_schedule.s @@ -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 diff --git a/ports_arch/ARMv7-M/threadx_modules/iar/module_manager/src/txm_module_manager_thread_stack_build.s b/ports_arch/ARMv7-M/threadx_modules/iar/module_manager/src/txm_module_manager_thread_stack_build.s new file mode 100644 index 00000000..bb691440 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx_modules/iar/module_manager/src/txm_module_manager_thread_stack_build.s @@ -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 diff --git a/ports_arch/ARMv7-M/threadx_modules/inc/tx_port.h b/ports_arch/ARMv7-M/threadx_modules/inc/tx_port.h new file mode 100644 index 00000000..368b91d1 --- /dev/null +++ b/ports_arch/ARMv7-M/threadx_modules/inc/tx_port.h @@ -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 +#include + +#ifdef __ICCARM__ +#include /* IAR Intrinsics */ +#define __asm__ __asm /* Define to make all inline asm look similar */ +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#include +#endif /* TX_ENABLE_IAR_LIBRARY_SUPPORT */ +#endif /* __ICCARM__ */ + +#ifdef __ghs__ +#include +#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 diff --git a/ports_arch/ARMv7-M/threadx_modules/inc/txm_module_port.h b/ports_arch/ARMv7-M/threadx_modules/inc/txm_module_port.h new file mode 100644 index 00000000..bbddb7ab --- /dev/null +++ b/ports_arch/ARMv7-M/threadx_modules/inc/txm_module_port.h @@ -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 diff --git a/ports_arch/ARMv8-M/README.md b/ports_arch/ARMv8-M/README.md new file mode 100644 index 00000000..327f925c --- /dev/null +++ b/ports_arch/ARMv8-M/README.md @@ -0,0 +1,5 @@ +# ARMv8-M architecture ports + +The ThreadX, ThreadX SMP, ThreadX Modules and ThreadX SMP Modules ports for ARMv8 share many files in common. +To make work more efficient these files are internally tracked only once and copied over to specific ports for users. + diff --git a/ports_arch/ARMv8-M/threadx/ac6/CMakeLists.txt b/ports_arch/ARMv8-M/threadx/ac6/CMakeLists.txt new file mode 100644 index 00000000..5ad3b8e7 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/ac6/CMakeLists.txt @@ -0,0 +1,21 @@ +target_sources(${PROJECT_NAME} PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/src/txe_thread_secure_stack_allocate.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_thread_secure_stack_free.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_initialize_low_level.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_restore.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_save.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_interrupt_control.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_interrupt_disable.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_interrupt_restore.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_schedule.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_secure_stack.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_secure_stack_allocate.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_secure_stack_free.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_stack_build.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_system_return.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_interrupt.S +) + +target_include_directories(${PROJECT_NAME} PUBLIC + inc +) diff --git a/ports_arch/ARMv8-M/threadx/ac6/readme_threadx.txt b/ports_arch/ARMv8-M/threadx/ac6/readme_threadx.txt new file mode 100644 index 00000000..5821892f --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/ac6/readme_threadx.txt @@ -0,0 +1,228 @@ + Microsoft's Azure RTOS ThreadX for Cortex-Mxx + + Using the AC6 Tools in Keil uVision + +1. Import the ThreadX Projects + +In order to build the ThreadX library and the ThreadX demonstration, first open +the AzureRTOS.uvmpw workspace (located in the "example_build" directory) +into Keil. + + +2. Building the ThreadX run-time Library + +Building the ThreadX library is easy; simply set the ThreadX_Library project +as active, then then build the library. You should now observe the compilation +and assembly of the ThreadX library. This project build produces the ThreadX +library file ThreadX_Library.lib. +Files tx_thread_stack_error_handler.c and tx_thread_stack_error_notify.c +replace the common files of the same name. + +3. Demonstration System + +The ThreadX demonstration is designed to execute under the Keil debugger on the +FVP_MPS2_Cortex-Mxx_MDK simulator. + +Building the demonstration is easy; simply select the "Batch Build" button. +You should now observe the compilation and assembly of the ThreadX demonstration of +both the demo_secure_zone and demo_threadx_non-secure_zone projects. +Then click the Start/Stop Debug Session button to start the simulator and begin debugging. +You are now ready to execute the ThreadX demonstration. + + +4. System Initialization + +The entry point in ThreadX for the Cortex-Mxx using AC6 tools uses the standard AC6 +Cortex-Mxx reset sequence. From the reset vector the C runtime will be initialized. + +The ThreadX tx_initialize_low_level.s file is responsible for setting up +various system data structures, the vector area, and a periodic timer interrupt +source. + +In addition, _tx_initialize_low_level determines the first available +address for use by the application, which is supplied as the sole input +parameter to your application definition function, tx_application_define. + + +5. Register Usage and Stack Frames + +The following defines the saved context stack frames for context switches +that occur as a result of interrupt handling or from thread-level API calls. +All suspended threads have the same stack frame in the Cortex-Mxx version of +ThreadX. The top of the suspended thread's stack is pointed to by +tx_thread_stack_ptr in the associated thread control block TX_THREAD. + +Non-FPU Stack Frame: + + Stack Offset Stack Contents + + 0x00 LR Interrupted LR (LR at time of PENDSV) + 0x04 r4 Software stacked GP registers + 0x08 r5 + 0x0C r6 + 0x10 r7 + 0x14 r8 + 0x18 r9 + 0x1C r10 + 0x20 r11 + 0x24 r0 Hardware stacked registers + 0x28 r1 + 0x2C r2 + 0x30 r3 + 0x34 r12 + 0x38 lr + 0x3C pc + 0x40 xPSR + +FPU Stack Frame (only interrupted thread with FPU enabled): + + Stack Offset Stack Contents + + 0x00 LR Interrupted LR (LR at time of PENDSV) + 0x04 s16 Software stacked FPU registers + 0x08 s17 + 0x0C s18 + 0x10 s19 + 0x14 s20 + 0x18 s21 + 0x1C s22 + 0x20 s23 + 0x24 s24 + 0x28 s25 + 0x2C s26 + 0x30 s27 + 0x34 s28 + 0x38 s29 + 0x3C s30 + 0x40 s31 + 0x44 r4 Software stacked registers + 0x48 r5 + 0x4C r6 + 0x50 r7 + 0x54 r8 + 0x58 r9 + 0x5C r10 + 0x60 r11 + 0x64 r0 Hardware stacked registers + 0x68 r1 + 0x6C r2 + 0x70 r3 + 0x74 r12 + 0x78 lr + 0x7C pc + 0x80 xPSR + 0x84 s0 Hardware stacked FPU registers + 0x88 s1 + 0x8C s2 + 0x90 s3 + 0x94 s4 + 0x98 s5 + 0x9C s6 + 0xA0 s7 + 0xA4 s8 + 0xA8 s9 + 0xAC s10 + 0xB0 s11 + 0xB4 s12 + 0xB8 s13 + 0xBC s14 + 0xC0 s15 + 0xC4 fpscr + + +6. Improving Performance + +To make ThreadX and the application(s) run faster, you can enable +all compiler optimizations. + +In addition, you can eliminate the ThreadX basic API error checking by +compiling your application code with the symbol TX_DISABLE_ERROR_CHECKING +defined. + + +7. Interrupt Handling + +ThreadX provides complete and high-performance interrupt handling for Cortex-Mxx +targets. There are a certain set of requirements that are defined in the +following sub-sections: + + +7.1 Vector Area + +The Cortex-Mxx vectors start at the label __Vectors or similar. The application may modify +the vector area according to its needs. There is code in tx_initialize_low_level() that will +configure the vector base register. + + +7.2 Managed Interrupts + +ISRs can be written completely in C (or assembly language) without any calls to +_tx_thread_context_save or _tx_thread_context_restore. These ISRs are allowed access to the +ThreadX API that is available to ISRs. + +ISRs written in C will take the form (where "your_C_isr" is an entry in the vector table): + +void your_C_isr(void) +{ + + /* ISR processing goes here, including any needed function calls. */ +} + +ISRs written in assembly language will take the form: + + + .global your_assembly_isr + .thumb_func +your_assembly_isr: +; VOID your_assembly_isr(VOID) +; { + PUSH {r0, lr} +; +; /* Do interrupt handler work here */ +; /* BL */ + + POP {r0, lr} + BX lr +; } + +Note: the Cortex-Mxx requires exception handlers to be thumb labels, this implies bit 0 set. +To accomplish this, the declaration of the label has to be preceded by the assembler directive +.thumb_func to instruct the linker to create thumb labels. The label __tx_IntHandler needs to +be inserted in the correct location in the interrupt vector table. This table is typically +located in either your runtime startup file or in the tx_initialize_low_level.s file. + + +8. FPU Support + +ThreadX for Cortex-Mxx supports automatic ("lazy") VFP support, which means that applications threads +can simply use the VFP and ThreadX automatically maintains the VFP registers as part of the thread +context. + + +9. Revision History + +For generic code revision information, please refer to the readme_threadx_generic.txt +file, which is included in your distribution. The following details the revision +information associated with this specific port of ThreadX: + +06-02-2021 Release 6.1.7 changes: + tx_port.h Remove unneeded include file + tx_thread_secure_stack_initialize.S New file + tx_thread_schedule.S Added secure stack initialize to SVC hander + tx_thread_secure_stack.c Fixed stack pointer save, initialize in handler mode + +04-02-2021 Release 6.1.6 changes: + tx_port.h Updated macro definition + tx_thread_schedule.s Added low power support + +03-02-2021 The following files were changed/added for version 6.1.5: + tx_port.h Added ULONG64_DEFINED + +09-30-2020 Initial ThreadX 6.1 version for Cortex-Mxx using AC6 tools. + + +Copyright(c) 1996-2020 Microsoft Corporation + + +https://azure.com/rtos + diff --git a/ports_arch/ARMv8-M/threadx/ac6/src/tx_initialize_low_level.S b/ports_arch/ARMv8-M/threadx/ac6/src/tx_initialize_low_level.S new file mode 100644 index 00000000..cf146cc2 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/ac6/src/tx_initialize_low_level.S @@ -0,0 +1,283 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Initialize */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +SYSTEM_CLOCK = 6000000 +SYSTICK_CYCLES = ((SYSTEM_CLOCK / 100) -1) + +/* Setup the stack and heap areas. */ + +STACK_SIZE = 0x00000400 +HEAP_SIZE = 0x00000000 + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_initialize_low_level Cortex-Mxx/AC6 */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for any low-level processor */ +/* initialization, including setting up interrupt vectors, setting */ +/* up a periodic timer interrupt source, saving the system stack */ +/* pointer for use in ISR processing later, and finding the first */ +/* available RAM memory address for tx_application_define. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_initialize_kernel_enter ThreadX entry function */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_initialize_low_level(VOID) +// { + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_initialize_low_level + .thumb_func +.type _tx_initialize_low_level, function +_tx_initialize_low_level: + + /* Disable interrupts during ThreadX initialization. */ + CPSID i + + /* Set base of available memory to end of non-initialised RAM area. */ + LDR r0, =_tx_initialize_unused_memory // Build address of unused memory pointer + LDR r1, =Image$$ARM_LIB_STACK$$ZI$$Limit // Build first free address + ADD r1, r1, #4 // + STR r1, [r0] // Setup first unused memory pointer + + /* Setup Vector Table Offset Register. */ + MOV r0, #0xE000E000 // Build address of NVIC registers + LDR r1, =__Vectors // Pickup address of vector table + STR r1, [r0, #0xD08] // Set vector table address + + /* Enable the cycle count register. */ + LDR r0, =0xE0001000 // Build address of DWT register + LDR r1, [r0] // Pickup the current value + ORR r1, r1, #1 // Set the CYCCNTENA bit + STR r1, [r0] // Enable the cycle count register + + /* Set system stack pointer from vector value. */ + LDR r0, =_tx_thread_system_stack_ptr // Build address of system stack pointer + LDR r1, =__Vectors // Pickup address of vector table + LDR r1, [r1] // Pickup reset stack pointer + STR r1, [r0] // Save system stack pointer + + /* Configure SysTick. */ + MOV r0, #0xE000E000 // Build address of NVIC registers + LDR r1, =SYSTICK_CYCLES + STR r1, [r0, #0x14] // Setup SysTick Reload Value + MOV r1, #0x7 // Build SysTick Control Enable Value + STR r1, [r0, #0x10] // Setup SysTick Control + + /* Configure handler priorities. */ + LDR r1, =0x00000000 // Rsrv, UsgF, BusF, MemM + STR r1, [r0, #0xD18] // Setup System Handlers 4-7 Priority Registers + + LDR r1, =0xFF000000 // SVCl, Rsrv, Rsrv, Rsrv + STR r1, [r0, #0xD1C] // Setup System Handlers 8-11 Priority Registers + // Note: SVC must be lowest priority, which is 0xFF + + LDR r1, =0x40FF0000 // SysT, PnSV, Rsrv, DbgM + STR r1, [r0, #0xD20] // Setup System Handlers 12-15 Priority Registers + // Note: PnSV must be lowest priority, which is 0xFF + + /* Return to caller. */ + BX lr +// } + + +/* Define shells for each of the unused vectors. */ + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global __tx_BadHandler + .thumb_func +.type __tx_BadHandler, function +__tx_BadHandler: + B __tx_BadHandler + + + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global __tx_IntHandler + .thumb_func +.type __tx_IntHandler, function +__tx_IntHandler: +// VOID InterruptHandler (VOID) +// { + PUSH {r0,lr} // Save LR (and dummy r0 to maintain stack alignment) +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + BL _tx_execution_isr_enter // Call the ISR enter function +#endif + /* Do interrupt handler work here */ + /* .... */ +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + BL _tx_execution_isr_exit // Call the ISR exit function +#endif + POP {r0,lr} + BX LR +// } + + + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global SysTick_Handler + .thumb_func +.type SysTick_Handler, function +SysTick_Handler: +// VOID TimerInterruptHandler (VOID) +// { + PUSH {r0,lr} // Save LR (and dummy r0 to maintain stack alignment) +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + BL _tx_execution_isr_enter // Call the ISR enter function +#endif + BL _tx_timer_interrupt +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + BL _tx_execution_isr_exit // Call the ISR exit function +#endif + POP {r0,lr} + BX LR +// } + + + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global HardFault_Handler + .thumb_func +.type HardFault_Handler, function +HardFault_Handler: + B HardFault_Handler + + + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global UsageFault_Handler + .thumb_func +.type UsageFault_Handler, function +UsageFault_Handler: + CPSID i // Disable interrupts + // Check for stack limit fault + LDR r0, =0xE000ED28 // CFSR address + LDR r1,[r0] // Pick up CFSR + TST r1, #0x00100000 // Check for Stack Overflow +_unhandled_usage_loop: + BEQ _unhandled_usage_loop // If not stack overflow then loop + + // Handle stack overflow + STR r1, [r0] // Clear CFSR flag(s) + +#ifdef __ARM_PCS_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] // Store the value +#endif + + LDR r0, =_tx_thread_current_ptr // Build current thread pointer address + LDR r0,[r0] // Pick up current thread pointer + PUSH {r0,lr} // Save LR (and r0 to maintain stack alignment) + BL _tx_thread_stack_error_handler // Call ThreadX/user handler + POP {r0,lr} // Restore LR and dummy reg + +#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. + 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 +#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 UsageFault_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 + CPSIE i // Enable interrupts + BX lr // Return from exception + + + + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global __tx_NMIHandler + .thumb_func +.type __tx_NMIHandler, function +__tx_NMIHandler: + B __tx_NMIHandler + + + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global __tx_DBGHandler + .thumb_func +.type __tx_DBGHandler, function +__tx_DBGHandler: + B __tx_DBGHandler + + .end diff --git a/ports_arch/ARMv8-M/threadx/ac6/src/tx_misra.S b/ports_arch/ARMv8-M/threadx/ac6/src/tx_misra.S new file mode 100644 index 00000000..c84d8576 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/ac6/src/tx_misra.S @@ -0,0 +1,723 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + #define SHT_PROGBITS 0x1 + + .global __aeabi_memset + .global _tx_thread_current_ptr + .global _tx_thread_interrupt_disable + .global _tx_thread_interrupt_restore + .global _tx_thread_stack_analyze + .global _tx_thread_stack_error_handler + .global _tx_thread_system_state +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_trace_buffer_current_ptr + .global _tx_trace_buffer_end_ptr + .global _tx_trace_buffer_start_ptr + .global _tx_trace_event_enable_bits + .global _tx_trace_full_notify_function + .global _tx_trace_header_ptr +#endif + + .global _tx_misra_always_true + .global _tx_misra_block_pool_to_uchar_pointer_convert + .global _tx_misra_byte_pool_to_uchar_pointer_convert + .global _tx_misra_char_to_uchar_pointer_convert + .global _tx_misra_const_char_to_char_pointer_convert +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_entry_to_uchar_pointer_convert +#endif + .global _tx_misra_indirect_void_to_uchar_pointer_convert + .global _tx_misra_memset + .global _tx_misra_message_copy +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_object_to_uchar_pointer_convert +#endif + .global _tx_misra_pointer_to_ulong_convert + .global _tx_misra_status_get + .global _tx_misra_thread_stack_check +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_time_stamp_get +#endif + .global _tx_misra_timer_indirect_to_void_pointer_convert + .global _tx_misra_timer_pointer_add + .global _tx_misra_timer_pointer_dif +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_trace_event_insert +#endif + .global _tx_misra_uchar_pointer_add + .global _tx_misra_uchar_pointer_dif + .global _tx_misra_uchar_pointer_sub + .global _tx_misra_uchar_to_align_type_pointer_convert + .global _tx_misra_uchar_to_block_pool_pointer_convert +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_uchar_to_entry_pointer_convert + .global _tx_misra_uchar_to_header_pointer_convert +#endif + .global _tx_misra_uchar_to_indirect_byte_pool_pointer_convert + .global _tx_misra_uchar_to_indirect_uchar_pointer_convert +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_uchar_to_object_pointer_convert +#endif + .global _tx_misra_uchar_to_void_pointer_convert + .global _tx_misra_ulong_pointer_add + .global _tx_misra_ulong_pointer_dif + .global _tx_misra_ulong_pointer_sub + .global _tx_misra_ulong_to_pointer_convert + .global _tx_misra_ulong_to_thread_pointer_convert + .global _tx_misra_user_timer_pointer_get + .global _tx_misra_void_to_block_pool_pointer_convert + .global _tx_misra_void_to_byte_pool_pointer_convert + .global _tx_misra_void_to_event_flags_pointer_convert + .global _tx_misra_void_to_indirect_uchar_pointer_convert + .global _tx_misra_void_to_mutex_pointer_convert + .global _tx_misra_void_to_queue_pointer_convert + .global _tx_misra_void_to_semaphore_pointer_convert + .global _tx_misra_void_to_thread_pointer_convert + .global _tx_misra_void_to_uchar_pointer_convert + .global _tx_misra_void_to_ulong_pointer_convert + .global _tx_misra_ipsr_get + .global _tx_misra_control_get + .global _tx_misra_control_set +#ifdef __ARM_FP + .global _tx_misra_fpccr_get + .global _tx_misra_vfp_touch +#endif + + .global _tx_misra_event_flags_group_not_used + .global _tx_misra_event_flags_set_notify_not_used + .global _tx_misra_queue_not_used + .global _tx_misra_queue_send_notify_not_used + .global _tx_misra_semaphore_not_used + .global _tx_misra_semaphore_put_notify_not_used + .global _tx_misra_thread_entry_exit_notify_not_used + .global _tx_misra_thread_not_used + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_memset(VOID *ptr, UINT value, UINT size); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .align 4 + .syntax unified + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_uchar_pointer_add: + ADD R0,R0,R1 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UCHAR *_tx_misra_uchar_pointer_sub(UCHAR *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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)); */ +/** */ +/************************************************************************************************************************************/ +/************************************************************************************************************************************/ + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_ulong_pointer_add: + ADD R0,R0,R1, LSL #+2 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG *_tx_misra_ulong_pointer_sub(ULONG *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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 R2,=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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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 + + + .data +DataTable2_1: + .word _tx_trace_buffer_current_ptr + + .data +DataTable2_2: + .word _tx_trace_event_enable_bits + + .data +DataTable2_5: + .word _tx_trace_buffer_end_ptr + + .data +DataTable2_6: + .word _tx_trace_buffer_start_ptr + + .data +DataTable2_7: + .word _tx_trace_header_ptr + + .data +DataTable2_8: + .word _tx_trace_full_notify_function + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG _tx_misra_time_stamp_get(VOID); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_time_stamp_get: + MOVS R0,#+0 + BX LR // return + +#endif + + .data +DataTable2_3: + .word _tx_thread_system_state + + .data +DataTable2_4: + .word _tx_thread_current_ptr + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UINT _tx_misra_always_true(void); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_always_true: + MOVS R0,#+1 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UINT _tx_misra_status_get(UINT status); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_status_get: + MOVS R0,#+0 + BX LR // return + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** ULONG _tx_misra_ipsr_get(void); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_tx_misra_ipsr_get: + MRS R0, IPSR + BX LR // return + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** ULONG _tx_misra_control_get(void); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_tx_misra_control_get: + MRS R0, CONTROL + BX LR // return + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** void _tx_misra_control_set(ULONG value); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_tx_misra_control_set: + MSR CONTROL, R0 + BX LR // return + + +#ifdef __ARM_FP + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** ULONG _tx_misra_fpccr_get(void); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_tx_misra_vfp_touch: + vmov.f32 s0, s0 + BX LR // return + +#endif + + + .data + .word 0 diff --git a/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_context_restore.S b/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_context_restore.S new file mode 100644 index 00000000..af6570cc --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_context_restore.S @@ -0,0 +1,89 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + .global _tx_execution_isr_exit +#endif +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_restore Cortex-Mxx/AC6 */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is not needed for Cortex-M. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* [_tx_execution_isr_exit] Execution profiling ISR exit */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs Interrupt Service Routines */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_context_restore(VOID) +// { + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_thread_context_restore + .thumb_func +.type _tx_thread_context_restore, function +_tx_thread_context_restore: + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the ISR exit function to indicate an ISR is complete. */ + PUSH {r0, lr} // Save return address + BL _tx_execution_isr_exit // Call the ISR exit function + POP {r0, lr} // Recover return address +#endif + + BX lr +// } + .end diff --git a/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_context_save.S b/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_context_save.S new file mode 100644 index 00000000..a95c14f7 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_context_save.S @@ -0,0 +1,89 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + .global _tx_execution_isr_enter +#endif +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_save Cortex-Mxx/AC6 */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is not needed for Cortex-M. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* [_tx_execution_isr_enter] Execution profiling ISR enter */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_context_save(VOID) +// { + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_thread_context_save + .thumb_func +.type _tx_thread_context_save, function +_tx_thread_context_save: + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the ISR enter function to indicate an ISR is starting. */ + PUSH {r0, lr} // Save return address + BL _tx_execution_isr_enter // Call the ISR enter function + POP {r0, lr} // Recover return address +#endif + + BX lr +// } + .end diff --git a/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_interrupt_control.S b/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_interrupt_control.S new file mode 100644 index 00000000..dbb9d24b --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_interrupt_control.S @@ -0,0 +1,87 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_control Cortex-Mxx/AC6 */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for changing the interrupt lockout */ +/* posture of the system. */ +/* */ +/* INPUT */ +/* */ +/* new_posture New interrupt lockout posture */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_interrupt_control(UINT new_posture) +// { + .section .text + .balign 4 + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_thread_interrupt_control + .thumb_func +.type _tx_thread_interrupt_control, function +_tx_thread_interrupt_control: +#ifdef TX_PORT_USE_BASEPRI + MRS r1, BASEPRI // Pickup current interrupt posture + MSR BASEPRI, r0 // Apply the new interrupt posture + MOV r0, r1 // Transfer old to return register +#else + MRS r1, PRIMASK // Pickup current interrupt lockout + MSR PRIMASK, r0 // Apply the new interrupt lockout + MOV r0, r1 // Transfer old to return register +#endif + BX lr // Return to caller +// } + .end diff --git a/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_interrupt_disable.S b/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_interrupt_disable.S new file mode 100644 index 00000000..a61ec0c6 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_interrupt_disable.S @@ -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 */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_disable Cortex-Mxx/AC6 */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for disabling interrupts and returning */ +/* the previous interrupt lockout posture. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_interrupt_disable(VOID) +// { + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_thread_interrupt_disable + .thumb_func +.type _tx_thread_interrupt_disable, function +_tx_thread_interrupt_disable: + /* Return current interrupt lockout posture. */ +#ifdef TX_PORT_USE_BASEPRI + MRS r0, BASEPRI + LDR r1, =TX_PORT_BASEPRI + MSR BASEPRI, r1 +#else + MRS r0, PRIMASK + CPSID i +#endif + BX lr +// } + .end diff --git a/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_interrupt_restore.S b/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_interrupt_restore.S new file mode 100644 index 00000000..bec99cf5 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_interrupt_restore.S @@ -0,0 +1,85 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_restore Cortex-Mxx/AC6 */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for restoring the previous */ +/* interrupt lockout posture. */ +/* */ +/* INPUT */ +/* */ +/* previous_posture Previous interrupt posture */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_interrupt_restore(UINT previous_posture) +// { + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_thread_interrupt_restore + .thumb_func +.type _tx_thread_interrupt_restore, function +_tx_thread_interrupt_restore: + /* Restore previous interrupt lockout posture. */ +#ifdef TX_PORT_USE_BASEPRI + MSR BASEPRI, r0 +#else + MSR PRIMASK, r0 +#endif + BX lr +// } + .end diff --git a/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_schedule.S b/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_schedule.S new file mode 100644 index 00000000..aae38194 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_schedule.S @@ -0,0 +1,399 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + .global _tx_execution_thread_enter + .global _tx_execution_thread_exit +#endif +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_schedule Cortex-Mxx/AC6 */ +/* 6.2.1 */ +/* 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 */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 04-02-2021 Scott Larson Modified comment(s), added */ +/* low power code, */ +/* resulting in version 6.1.6 */ +/* 06-02-2021 Scott Larson Added secure stack initialize */ +/* in SVC handler, */ +/* resulting in version 6.1.7 */ +/* 04-25-2022 Scott Larson Added BASEPRI support, */ +/* resulting in version 6.1.11 */ +/* 03-08-2023 Scott Larson Added preproc FPU option, */ +/* included tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_schedule(VOID) +// { + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_thread_schedule + .thumb_func +.type _tx_thread_schedule, function +_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_PCS_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 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 +// } + + /* Generic context switching PendSV handler. */ + + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global PendSV_Handler + .thumb_func +.type PendSV_Handler, function + /* Get current thread value and new thread pointer. */ +PendSV_Handler: +__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_PCS_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 + STR r12, [r1, #8] // Save the thread stack pointer + +#if (!defined(TX_SINGLE_MODE_SECURE) && !defined(TX_SINGLE_MODE_NON_SECURE)) + // Save secure context + LDR r5, [r1,#0x90] // Load secure stack index + CBZ r5, _skip_secure_save // Skip save if there is no secure context + PUSH {r0,r1,r2,r3} // Save scratch registers + MOV r0, r1 // Move thread ptr to r0 + BL _tx_thread_secure_stack_context_save // Save secure stack + POP {r0,r1,r2,r3} // Restore secure registers +_skip_secure_save: +#endif + + /* Determine if time-slice is active. If it isn't, skip time handling processing. */ + + LDR r5, [r4] // Pickup current time-slice + 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? + CBZ r1, __tx_ts_wait // No, skip to the wait processing + + /* Yes, another thread is ready for else, make the current thread the new thread. */ + + 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. */ + +__tx_ts_restore: + 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 + +#if (!defined(TX_SINGLE_MODE_SECURE) && !defined(TX_SINGLE_MODE_NON_SECURE)) + // Restore secure context + LDR r0, [r1,#0x90] // Load secure stack index + CBZ r0, _skip_secure_restore // Skip restore if there is no secure context + PUSH {r0,r1} // Save r1 (and dummy r0) + MOV r0, r1 // Move thread ptr to r0 + BL _tx_thread_secure_stack_context_restore // Restore secure stack + POP {r0,r1} // Restore r1 (and dummy r0) +_skip_secure_restore: +#endif + + /* Restore the thread context and PSP. */ + LDR r12, [r1, #12] // Get stack start + MSR PSPLIM, r12 // Set stack limit + LDR r12, [r1, #8] // Pickup thread's stack pointer + LDMIA r12!, {LR} // Pickup LR +#ifdef __ARM_PCS_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 + + BX lr // Return to thread! + + /* 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 + STR r1, [r0] // Store it in the current 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 + + /* Re-enable interrupts and restore new thread. */ +#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_restore // Restore the thread +// } + + +#if (!defined(TX_SINGLE_MODE_SECURE) && !defined(TX_SINGLE_MODE_NON_SECURE)) + // SVC_Handler is not needed when ThreadX is running in single mode. + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global SVC_Handler + .thumb_func +.type SVC_Handler, function +SVC_Handler: + TST lr, #0x04 // Determine return stack from EXC_RETURN bit 2 + ITE EQ + MRSEQ r0, MSP // Get MSP if return stack is MSP + MRSNE r0, PSP // Get PSP if return stack is PSP + + LDR r1, [r0,#24] // Load saved PC from stack + LDRB r1, [r1,#-2] // Load SVC number + + CMP r1, #1 // Is it a secure stack allocate request? + BEQ _tx_svc_secure_alloc // Yes, go there + + CMP r1, #2 // Is it a secure stack free request? + BEQ _tx_svc_secure_free // Yes, go there + + CMP r1, #3 // Is it a secure stack init request? + BEQ _tx_svc_secure_init // Yes, go there + + // Unknown SVC argument - just return + BX lr + +_tx_svc_secure_alloc: + PUSH {r0,lr} // Save SP and EXC_RETURN + LDM r0, {r0-r3} // Load function parameters from stack + BL _tx_thread_secure_mode_stack_allocate + POP {r12,lr} // Restore SP and EXC_RETURN + STR r0,[r12] // Store function return value + BX lr +_tx_svc_secure_free: + PUSH {r0,lr} // Save SP and EXC_RETURN + LDM r0, {r0-r3} // Load function parameters from stack + BL _tx_thread_secure_mode_stack_free + POP {r12,lr} // Restore SP and EXC_RETURN + STR r0,[r12] // Store function return value + BX lr +_tx_svc_secure_init: + PUSH {r0,lr} // Save SP and EXC_RETURN + BL _tx_thread_secure_mode_stack_initialize + POP {r12,lr} // Restore SP and EXC_RETURN + BX lr +#endif // End of ifndef TX_SINGLE_MODE_SECURE, TX_SINGLE_MODE_NON_SECURE + + + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_vfp_access + .thumb_func +.type _tx_vfp_access, function +_tx_vfp_access: +#ifdef __ARM_PCS_VFP + VMOV.F32 s0, s0 // Simply access the VFP +#endif + BX lr // Return to caller +.end diff --git a/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_secure_stack.c b/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_secure_stack.c new file mode 100644 index 00000000..feb87e77 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_secure_stack.c @@ -0,0 +1,592 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +#include "tx_api.h" + +/* If TX_SINGLE_MODE_SECURE or TX_SINGLE_MODE_NON_SECURE is defined, + no secure stack functionality is needed. */ +#if !defined(TX_SINGLE_MODE_SECURE) && !defined(TX_SINGLE_MODE_NON_SECURE) + +#define TX_SOURCE_CODE + +#include "cmsis_compiler.h" /* For intrinsic functions. */ +#include "tx_secure_interface.h" /* Interface for NS code. */ + +/* Minimum size of secure stack. */ +#ifndef TX_THREAD_SECURE_STACK_MINIMUM +#define TX_THREAD_SECURE_STACK_MINIMUM 256 +#endif +/* Maximum size of secure stack. */ +#ifndef TX_THREAD_SECURE_STACK_MAXIMUM +#define TX_THREAD_SECURE_STACK_MAXIMUM 1024 +#endif + +/* 8 bytes added to stack size to "seal" stack. */ +#define TX_THREAD_STACK_SEAL_SIZE 8 +#define TX_THREAD_STACK_SEAL_VALUE 0xFEF5EDA5 + +/* max number of Secure context */ +#ifndef TX_MAX_SECURE_CONTEXTS +#define TX_MAX_SECURE_CONTEXTS 32 +#endif +#define TX_INVALID_SECURE_CONTEXT_IDX (-1) + +/* Secure stack info struct to hold stack start, stack limit, + current stack pointer, and pointer to owning thread. + This will be allocated for each thread with a secure stack. */ +typedef struct TX_THREAD_SECURE_STACK_INFO_STRUCT +{ + VOID *tx_thread_secure_stack_ptr; /* Thread's secure stack current pointer */ + VOID *tx_thread_secure_stack_start; /* Thread's secure stack start address */ + VOID *tx_thread_secure_stack_limit; /* Thread's secure stack limit */ + TX_THREAD *tx_thread_ptr; /* Keep track of thread for error handling */ + INT tx_next_free_index; /* Next free index of free secure context */ +} TX_THREAD_SECURE_STACK_INFO; + +/* Static secure contexts */ +static TX_THREAD_SECURE_STACK_INFO tx_thread_secure_context[TX_MAX_SECURE_CONTEXTS]; +/* Head of free secure context */ +static INT tx_head_free_index = 0U; + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_secure_mode_stack_initialize Cortex-Mxx/AC6 */ +/* 6.1.10 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function initializes secure mode to use PSP stack. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* status */ +/* */ +/* CALLS */ +/* */ +/* __get_CONTROL Intrinsic to get CONTROL */ +/* __set_CONTROL Intrinsic to set CONTROL */ +/* __set_PSPLIM Intrinsic to set PSP limit */ +/* __set_PSP Intrinsic to set PSP */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_initialize_kernel_enter */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 10-16-2020 Scott Larson Modified comment(s), */ +/* resulting in version 6.1.1 */ +/* 06-02-2021 Scott Larson Modified comment(s), and */ +/* changed name, execute in */ +/* handler mode, */ +/* resulting in version 6.1.7 */ +/* 01-31-2022 Himanshu Gupta Modified comments(s), updated */ +/* secure stack allocation, */ +/* resulting in version 6.1.10 */ +/* */ +/**************************************************************************/ +__attribute__((cmse_nonsecure_entry)) +UINT _tx_thread_secure_mode_stack_initialize(void) +{ +UINT status; +INT index; + + /* Make sure function is called from interrupt (threads should not call). */ + if (__get_IPSR() == 0) + { + status = TX_CALLER_ERROR; + } + else + { + /* Set secure mode to use PSP. */ + __set_CONTROL(__get_CONTROL() | 2); + + /* Set process stack pointer and stack limit to 0 to throw exception when a thread + without a secure stack calls a secure function that tries to use secure stack. */ + __set_PSPLIM(0); + __set_PSP(0); + + for (index = 0; index < TX_MAX_SECURE_CONTEXTS; index++) + { + + /* Check last index and mark next free to invalid index */ + if(index == (TX_MAX_SECURE_CONTEXTS - 1)) + { + tx_thread_secure_context[index].tx_next_free_index = TX_INVALID_SECURE_CONTEXT_IDX; + } + else + { + tx_thread_secure_context[index].tx_next_free_index = index + 1; + } + } + + status = TX_SUCCESS; + } + return status; +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_secure_mode_stack_allocate Cortex-Mxx/AC6 */ +/* 6.1.10 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function allocates a thread's secure stack. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* stack_size Size of stack to allocates */ +/* */ +/* OUTPUT */ +/* */ +/* TX_THREAD_ERROR Invalid thread pointer */ +/* TX_SIZE_ERROR Invalid stack size */ +/* TX_CALLER_ERROR Invalid caller of function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* __get_IPSR Intrinsic to get IPSR */ +/* malloc Compiler's malloc function */ +/* __set_PSPLIM Intrinsic to set PSP limit */ +/* __set_PSP Intrinsic to set PSP */ +/* __TZ_get_PSPLIM_NS Intrinsic to get NS PSP */ +/* */ +/* CALLED BY */ +/* */ +/* SVC Handler */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 10-16-2020 Scott Larson Modified comment(s), */ +/* added stack sealing, */ +/* resulting in version 6.1.1 */ +/* 01-31-2022 Himanshu Gupta Modified comments(s), updated */ +/* secure stack allocation, */ +/* resulting in version 6.1.10 */ +/* */ +/**************************************************************************/ +__attribute__((cmse_nonsecure_entry)) +UINT _tx_thread_secure_mode_stack_allocate(TX_THREAD *thread_ptr, ULONG stack_size) +{ +TX_INTERRUPT_SAVE_AREA +UINT status; +TX_THREAD_SECURE_STACK_INFO *info_ptr; +UCHAR *stack_mem; +INT secure_context_index; + + status = TX_SUCCESS; + + /* Make sure function is called from interrupt (threads should not call). */ + if (__get_IPSR() == 0) + { + status = TX_CALLER_ERROR; + } + else if (stack_size < TX_THREAD_SECURE_STACK_MINIMUM || stack_size > TX_THREAD_SECURE_STACK_MAXIMUM) + { + status = TX_SIZE_ERROR; + } + + /* Check if thread already has secure stack allocated. */ + else if (thread_ptr -> tx_thread_secure_stack_context != 0) + { + status = TX_THREAD_ERROR; + } + + else + { + TX_DISABLE + + /* Allocate free index for secure stack info. */ + if(tx_head_free_index != TX_INVALID_SECURE_CONTEXT_IDX) + { + secure_context_index = tx_head_free_index; + tx_head_free_index = tx_thread_secure_context[tx_head_free_index].tx_next_free_index; + tx_thread_secure_context[secure_context_index].tx_next_free_index = TX_INVALID_SECURE_CONTEXT_IDX; + } + else + { + secure_context_index = TX_INVALID_SECURE_CONTEXT_IDX; + } + + TX_RESTORE + + if(secure_context_index != TX_INVALID_SECURE_CONTEXT_IDX) + { + info_ptr = &tx_thread_secure_context[secure_context_index]; + + /* If stack info allocated, allocate a stack & seal. */ + stack_mem = malloc(stack_size + TX_THREAD_STACK_SEAL_SIZE); + + if(stack_mem != TX_NULL) + { + /* Secure stack has been allocated, save in the stack info struct. */ + info_ptr -> tx_thread_secure_stack_limit = stack_mem; + info_ptr -> tx_thread_secure_stack_start = stack_mem + stack_size; + info_ptr -> tx_thread_secure_stack_ptr = info_ptr -> tx_thread_secure_stack_start; + info_ptr -> tx_thread_ptr = thread_ptr; + + /* Seal bottom of stack. */ + *(ULONG*)info_ptr -> tx_thread_secure_stack_start = TX_THREAD_STACK_SEAL_VALUE; + + /* Save secure context id (i.e non-zero base index) in thread. */ + thread_ptr -> tx_thread_secure_stack_context = (VOID *)(secure_context_index + 1); + + /* Check if this thread is running by looking at its stack start and PSPLIM_NS */ + if(((ULONG) thread_ptr -> tx_thread_stack_start & 0xFFFFFFF8) == __TZ_get_PSPLIM_NS()) + { + /* If this thread is running, set Secure PSP and PSPLIM. */ + __set_PSPLIM((ULONG)(info_ptr -> tx_thread_secure_stack_limit)); + __set_PSP((ULONG)(info_ptr -> tx_thread_secure_stack_ptr)); + } + } + + else + { + TX_DISABLE + + /* Stack not allocated, free the info struct. */ + tx_thread_secure_context[secure_context_index].tx_next_free_index = tx_head_free_index; + tx_head_free_index = secure_context_index; + TX_RESTORE + + status = TX_NO_MEMORY; + } + } + + else + { + status = TX_NO_MEMORY; + } + } + + return(status); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_secure_mode_stack_free Cortex-Mxx/AC6 */ +/* 6.1.10 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function frees a thread's secure stack. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* */ +/* OUTPUT */ +/* */ +/* TX_THREAD_ERROR Invalid thread pointer */ +/* TX_CALLER_ERROR Invalid caller of function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* __get_IPSR Intrinsic to get IPSR */ +/* free Compiler's free() function */ +/* */ +/* CALLED BY */ +/* */ +/* SVC Handler */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 10-16-2020 Scott Larson Modified comment(s), */ +/* resulting in version 6.1.1 */ +/* 01-31-2022 Himanshu Gupta Modified comments(s), updated */ +/* secure stack allocation, */ +/* resulting in version 6.1.10 */ +/* */ +/**************************************************************************/ +__attribute__((cmse_nonsecure_entry)) +UINT _tx_thread_secure_mode_stack_free(TX_THREAD *thread_ptr) +{ +TX_INTERRUPT_SAVE_AREA +UINT status; +TX_THREAD_SECURE_STACK_INFO *info_ptr; +INT secure_context_index; + + status = TX_SUCCESS; + + /* Pickup stack info id from thread. */ + secure_context_index = (INT)thread_ptr -> tx_thread_secure_stack_context - 1; + + /* Make sure function is called from interrupt (threads should not call). */ + if (__get_IPSR() == 0) + { + status = TX_CALLER_ERROR; + } + + /* Check if secure context index is in valid range. */ + else if (secure_context_index < 0 || secure_context_index >= TX_MAX_SECURE_CONTEXTS) + { + status = TX_THREAD_ERROR; + } + else + { + + /* Pickup stack info from static array of secure contexts. */ + info_ptr = &tx_thread_secure_context[secure_context_index]; + + /* Check that this secure context is for this thread. */ + if (info_ptr -> tx_thread_ptr != thread_ptr) + { + status = TX_THREAD_ERROR; + } + + else + { + + /* Free secure stack. */ + free(info_ptr -> tx_thread_secure_stack_limit); + + TX_DISABLE + + /* Free info struct. */ + tx_thread_secure_context[secure_context_index].tx_next_free_index = tx_head_free_index; + tx_head_free_index = secure_context_index; + TX_RESTORE + + /* Clear secure context from thread. */ + thread_ptr -> tx_thread_secure_stack_context = 0; + } + } + + return(status); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_secure_stack_context_save Cortex-Mxx/AC6 */ +/* 6.1.10 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function saves context of the secure stack. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* __get_IPSR Intrinsic to get IPSR */ +/* __get_PSP Intrinsic to get PSP */ +/* __set_PSPLIM Intrinsic to set PSP limit */ +/* __set_PSP Intrinsic to set PSP */ +/* */ +/* CALLED BY */ +/* */ +/* PendSV Handler */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 10-16-2020 Scott Larson Modified comment(s), */ +/* resulting in version 6.1.1 */ +/* 06-02-2021 Scott Larson Fix stack pointer save, */ +/* resulting in version 6.1.7 */ +/* 01-31-2022 Himanshu Gupta Modified comments(s), updated */ +/* secure stack allocation, */ +/* resulting in version 6.1.10 */ +/* */ +/**************************************************************************/ +__attribute__((cmse_nonsecure_entry)) +void _tx_thread_secure_stack_context_save(TX_THREAD *thread_ptr) +{ +TX_THREAD_SECURE_STACK_INFO *info_ptr; +ULONG sp; +INT secure_context_index = (INT)thread_ptr -> tx_thread_secure_stack_context - 1; + + /* This function should be called from scheduler only. */ + if (__get_IPSR() == 0) + { + return; + } + + /* Check if secure context index is in valid range. */ + else if (secure_context_index < 0 || secure_context_index >= TX_MAX_SECURE_CONTEXTS) + { + return; + } + + /* Pickup the secure context pointer. */ + info_ptr = &tx_thread_secure_context[secure_context_index]; + + /* Check that this secure context is for this thread. */ + if (info_ptr -> tx_thread_ptr != thread_ptr) + { + return; + } + + /* Check that stack pointer is in range */ + sp = __get_PSP(); + if ((sp < (ULONG)info_ptr -> tx_thread_secure_stack_limit) || + (sp > (ULONG)info_ptr -> tx_thread_secure_stack_start)) + { + return; + } + + /* Save stack pointer. */ + info_ptr -> tx_thread_secure_stack_ptr = (VOID *) sp; + + /* Set process stack pointer and stack limit to 0 to throw exception when a thread + without a secure stack calls a secure function that tries to use secure stack. */ + __set_PSPLIM(0); + __set_PSP(0); + + return; +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_secure_stack_context_restore Cortex-Mxx/AC6 */ +/* 6.1.10 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function restores context of the secure stack. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* __get_IPSR Intrinsic to get IPSR */ +/* __set_PSPLIM Intrinsic to set PSP limit */ +/* __set_PSP Intrinsic to set PSP */ +/* */ +/* CALLED BY */ +/* */ +/* PendSV Handler */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 10-16-2020 Scott Larson Modified comment(s), */ +/* resulting in version 6.1.1 */ +/* 01-31-2022 Himanshu Gupta Modified comments(s), updated */ +/* secure stack allocation, */ +/* resulting in version 6.1.10 */ +/* */ +/**************************************************************************/ +__attribute__((cmse_nonsecure_entry)) +void _tx_thread_secure_stack_context_restore(TX_THREAD *thread_ptr) +{ +TX_THREAD_SECURE_STACK_INFO *info_ptr; +INT secure_context_index = (INT)thread_ptr -> tx_thread_secure_stack_context - 1; + + /* This function should be called from scheduler only. */ + if (__get_IPSR() == 0) + { + return; + } + + /* Check if secure context index is in valid range. */ + else if (secure_context_index < 0 || secure_context_index >= TX_MAX_SECURE_CONTEXTS) + { + return; + } + + /* Pickup the secure context pointer. */ + info_ptr = &tx_thread_secure_context[secure_context_index]; + + /* Check that this secure context is for this thread. */ + if (info_ptr -> tx_thread_ptr != thread_ptr) + { + return; + } + + /* Set stack pointer and limit. */ + __set_PSPLIM((ULONG)info_ptr -> tx_thread_secure_stack_limit); + __set_PSP ((ULONG)info_ptr -> tx_thread_secure_stack_ptr); + + return; +} + +#endif diff --git a/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_secure_stack_allocate.S b/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_secure_stack_allocate.S new file mode 100644 index 00000000..5c4897aa --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_secure_stack_allocate.S @@ -0,0 +1,90 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_secure_stack_allocate Cortex-Mxx/AC6 */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enters the SVC handler to allocate a secure stack. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* stack_size Size of secure stack to */ +/* allocate */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* SVC 1 */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_secure_stack_allocate(TX_THREAD *thread_ptr, ULONG stack_size) +// { + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_thread_secure_stack_allocate + .thumb_func +.type _tx_thread_secure_stack_allocate, function +_tx_thread_secure_stack_allocate: +#if !defined(TX_SINGLE_MODE_SECURE) && !defined(TX_SINGLE_MODE_NON_SECURE) + MRS r3, PRIMASK // Save interrupt mask + CPSIE i // Enable interrupts for SVC call + SVC 1 + CMP r3, #0 // If interrupts enabled, just return + BEQ _alloc_return_interrupt_enabled + CPSID i // Otherwise, disable interrupts +#else + MOV r0, #0xFF // Feature not enabled +#endif +_alloc_return_interrupt_enabled: + BX lr + .end diff --git a/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_secure_stack_free.S b/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_secure_stack_free.S new file mode 100644 index 00000000..87703b70 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_secure_stack_free.S @@ -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 */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_secure_stack_free Cortex-Mxx/AC6 */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enters the SVC handler to free a secure stack. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* SVC 2 */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_secure_stack_free(TX_THREAD *thread_ptr) +// { + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_thread_secure_stack_free + .thumb_func +.type _tx_thread_secure_stack_free, function +_tx_thread_secure_stack_free: +#if !defined(TX_SINGLE_MODE_SECURE) && !defined(TX_SINGLE_MODE_NON_SECURE) + MRS r3, PRIMASK // Save interrupt mask + CPSIE i // Enable interrupts for SVC call + SVC 2 + CMP r3, #0 // If interrupts enabled, just return + BEQ _free_return_interrupt_enabled + CPSID i // Otherwise, disable interrupts +#else + MOV r0, #0xFF // Feature not enabled +#endif +_free_return_interrupt_enabled: + BX lr + .end diff --git a/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_secure_stack_initialize.S b/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_secure_stack_initialize.S new file mode 100644 index 00000000..b44f5b9a --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_secure_stack_initialize.S @@ -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 */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_secure_stack_initialize Cortex-Mxx/AC6 */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enters the SVC handler to initialize a secure stack. */ +/* */ +/* INPUT */ +/* */ +/* none */ +/* */ +/* OUTPUT */ +/* */ +/* none */ +/* */ +/* CALLS */ +/* */ +/* SVC 3 */ +/* */ +/* CALLED BY */ +/* */ +/* TX_PORT_SPECIFIC_PRE_INITIALIZATION */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 07-29-2022 Scott Larson Modified comments and changed */ +/* secure stack initialization */ +/* macro to port-specific, */ +/* resulting in version 6.1.12 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_secure_stack_initialize(VOID) +// { + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_thread_secure_stack_initialize + .thumb_func +.type _tx_thread_secure_stack_initialize, function +_tx_thread_secure_stack_initialize: +#if !defined(TX_SINGLE_MODE_SECURE) && !defined(TX_SINGLE_MODE_NON_SECURE) + CPSIE i // Enable interrupts for SVC call + SVC 3 + CPSID i // Disable interrupts +#else + MOV r0, #0xFF // Feature not enabled +#endif + BX lr + .end diff --git a/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_stack_build.S b/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_stack_build.S new file mode 100644 index 00000000..5b94225f --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_stack_build.S @@ -0,0 +1,145 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_stack_build Cortex-Mxx/AC6 */ +/* 6.2.1 */ +/* 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 control blk */ +/* function_ptr Pointer to return function */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_create Create thread service */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID)) +// { + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_thread_stack_build + .thumb_func +.type _tx_thread_stack_build, function +_tx_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 for 8-byte alignment + SUB r2, r2, #68 // Subtract frame size +#ifdef TX_SINGLE_MODE_SECURE + LDR r3, =0xFFFFFFFD // Build initial LR value for secure mode +#else + LDR r3, =0xFFFFFFBC // Build initial LR value to return to non-secure PSP +#endif + 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, #24] // Store initial r9 + STR r3, [r2, #28] // Store initial r10 + STR r3, [r2, #32] // Store initial r11 + + /* Hardware stack follows. */ + + STR r3, [r2, #36] // Store initial r0 + STR r3, [r2, #40] // Store initial r1 + 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 diff --git a/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_system_return.S b/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_system_return.S new file mode 100644 index 00000000..0f54bd00 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/ac6/src/tx_thread_system_return.S @@ -0,0 +1,101 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_system_return Cortex-Mxx/AC6 */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is target processor specific. It is used to transfer */ +/* control from a thread back to the ThreadX system. Only a */ +/* minimal context is saved since the compiler assumes temp registers */ +/* are going to get slicked by a function call anyway. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_schedule Thread scheduling loop */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX components */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_system_return(VOID) +// { + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_thread_system_return + .thumb_func +.type _tx_thread_system_return, function +_tx_thread_system_return: + /* Return to real scheduler via PendSV. Note that this routine is often + replaced with in-line assembly in tx_port.h to improved performance. */ + + MOV r0, #0x10000000 // Load PENDSVSET bit + MOV r1, #0xE000E000 // Load NVIC base + STR r0, [r1, #0xD04] // Set PENDSVBIT in ICSR + MRS r0, IPSR // Pickup IPSR + CMP r0, #0 // Is it a thread returning? + BNE _isr_context // If ISR, skip interrupt enable +#ifdef TX_PORT_USE_BASEPRI + MRS r1, BASEPRI // Thread context returning, pickup BASEPRI + MOV r0, #0 + MSR BASEPRI, r0 // Enable interrupts + MSR BASEPRI, r1 // Restore original interrupt posture +#else + MRS r1, PRIMASK // Thread context returning, pickup PRIMASK + CPSIE i // Enable interrupts + MSR PRIMASK, r1 // Restore original interrupt posture +#endif +_isr_context: + BX lr // Return to caller +// } + .end diff --git a/ports_arch/ARMv8-M/threadx/ac6/src/tx_timer_interrupt.S b/ports_arch/ARMv8-M/threadx/ac6/src/tx_timer_interrupt.S new file mode 100644 index 00000000..8081f7a7 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/ac6/src/tx_timer_interrupt.S @@ -0,0 +1,248 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_interrupt Cortex-Mxx/AC6 */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the hardware timer interrupt. This */ +/* processing includes incrementing the system clock and checking for */ +/* time slice and/or timer expiration. If either is found, the */ +/* expiration functions are called. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_timer_expiration_process Timer expiration processing */ +/* _tx_thread_time_slice Time slice interrupted thread */ +/* */ +/* CALLED BY */ +/* */ +/* interrupt vector */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_timer_interrupt(VOID) +// { + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_timer_interrupt + .thumb_func +.type _tx_timer_interrupt, function +_tx_timer_interrupt: + + /* Upon entry to this routine, it is assumed that the compiler scratch registers are available + for use. */ + + /* Increment the system clock. */ + // _tx_timer_system_clock++; + + LDR r1, =_tx_timer_system_clock // Pickup address of system clock + LDR r0, [r1, #0] // Pickup system clock + ADD r0, r0, #1 // Increment system clock + STR r0, [r1, #0] // Store new system clock + + /* Test for time-slice expiration. */ + // if (_tx_timer_time_slice) + // { + + LDR r3, =_tx_timer_time_slice // Pickup address of time-slice + LDR r2, [r3, #0] // Pickup time-slice + CBZ r2, __tx_timer_no_time_slice // Is it non-active? + // Yes, skip time-slice processing + + /* Decrement the time_slice. */ + // _tx_timer_time_slice--; + + SUB r2, r2, #1 // Decrement the time-slice + STR r2, [r3, #0] // Store new time-slice value + + /* Check for expiration. */ + // if (__tx_timer_time_slice == 0) + + CBNZ r2, __tx_timer_no_time_slice // Has it expired? + // No, skip expiration processing + + /* Set the time-slice expired flag. */ + // _tx_timer_expired_time_slice = TX_TRUE; + + LDR r3, =_tx_timer_expired_time_slice // Pickup address of expired flag + MOV r0, #1 // Build expired value + STR r0, [r3, #0] // Set time-slice expiration flag + + // } + +__tx_timer_no_time_slice: + + /* Test for timer expiration. */ + // if (*_tx_timer_current_ptr) + // { + + LDR r1, =_tx_timer_current_ptr // Pickup current timer pointer address + LDR r0, [r1, #0] // Pickup current timer + LDR r2, [r0, #0] // Pickup timer list entry + CBZ r2, __tx_timer_no_timer // Is there anything in the list? + // No, just increment the timer + + /* Set expiration flag. */ + // _tx_timer_expired = TX_TRUE; + + LDR r3, =_tx_timer_expired // Pickup expiration flag address + MOV r2, #1 // Build expired value + STR r2, [r3, #0] // Set expired flag + B __tx_timer_done // Finished timer processing + + // } + // else + // { +__tx_timer_no_timer: + + /* No timer expired, increment the timer pointer. */ + // _tx_timer_current_ptr++; + + ADD r0, r0, #4 // Move to next timer + + /* Check for wrap-around. */ + // if (_tx_timer_current_ptr == _tx_timer_list_end) + + LDR r3, =_tx_timer_list_end // Pickup addr of timer list end + LDR r2, [r3, #0] // Pickup list end + CMP r0, r2 // Are we at list end? + BNE __tx_timer_skip_wrap // No, skip wrap-around logic + + /* Wrap to beginning of list. */ + // _tx_timer_current_ptr = _tx_timer_list_start; + + LDR r3, =_tx_timer_list_start // Pickup addr of timer list start + LDR r0, [r3, #0] // Set current pointer to list start + +__tx_timer_skip_wrap: + + STR r0, [r1, #0] // Store new current timer pointer + // } + +__tx_timer_done: + + /* See if anything has expired. */ + // if ((_tx_timer_expired_time_slice) || (_tx_timer_expired)) + // { + + LDR r3, =_tx_timer_expired_time_slice // Pickup addr of expired flag + LDR r2, [r3, #0] // Pickup time-slice expired flag + CBNZ r2, __tx_something_expired // Did a time-slice expire? + // If non-zero, time-slice expired + LDR r1, =_tx_timer_expired // Pickup addr of other expired flag + LDR r0, [r1, #0] // Pickup timer expired flag + CBZ r0, __tx_timer_nothing_expired // Did a timer expire? + // No, nothing expired + +__tx_something_expired: + + PUSH {r0, lr} // Save the lr register on the stack + // and save r0 just to keep 8-byte alignment + + /* Did a timer expire? */ + // if (_tx_timer_expired) + // { + + LDR r1, =_tx_timer_expired // Pickup addr of expired flag + LDR r0, [r1, #0] // Pickup timer expired flag + CBZ r0, __tx_timer_dont_activate // Check for timer expiration + // If not set, skip timer activation + + /* Process timer expiration. */ + // _tx_timer_expiration_process(); + + BL _tx_timer_expiration_process // Call the timer expiration handling routine + + // } +__tx_timer_dont_activate: + + /* Did time slice expire? */ + // if (_tx_timer_expired_time_slice) + // { + + LDR r3, =_tx_timer_expired_time_slice // Pickup addr of time-slice expired + LDR r2, [r3, #0] // Pickup the actual flag + CBZ r2, __tx_timer_not_ts_expiration // See if the flag is set + // No, skip time-slice processing + + /* Time slice interrupted thread. */ + // _tx_thread_time_slice(); + + BL _tx_thread_time_slice // Call time-slice processing + LDR r0, =_tx_thread_preempt_disable // Build address of preempt disable flag + LDR r1, [r0] // Is the preempt disable flag set? + CBNZ r1, __tx_timer_skip_time_slice // Yes, skip the PendSV logic + LDR r0, =_tx_thread_current_ptr // Build current thread pointer address + LDR r1, [r0] // Pickup the current thread pointer + LDR r2, =_tx_thread_execute_ptr // Build execute thread pointer address + LDR r3, [r2] // Pickup the execute thread pointer + LDR r0, =0xE000ED04 // Build address of control register + LDR r2, =0x10000000 // Build value for PendSV bit + CMP r1, r3 // Are they the same? + BEQ __tx_timer_skip_time_slice // If the same, there was no time-slice performed + STR r2, [r0] // Not the same, issue the PendSV for preemption +__tx_timer_skip_time_slice: + // } + +__tx_timer_not_ts_expiration: + + POP {r0, lr} // Recover lr register (r0 is just there for + // the 8-byte stack alignment + + // } + +__tx_timer_nothing_expired: + + DSB // Complete all memory access + BX lr // Return to caller +// } + .end diff --git a/ports_arch/ARMv8-M/threadx/ac6/src/txe_thread_secure_stack_allocate.c b/ports_arch/ARMv8-M/threadx/ac6/src/txe_thread_secure_stack_allocate.c new file mode 100644 index 00000000..caa47139 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/ac6/src/txe_thread_secure_stack_allocate.c @@ -0,0 +1,119 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_initialize.h" +#include "tx_thread.h" + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_secure_stack_allocate Cortex-Mxx */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the secure stack allocate */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* stack_size Size of secure stack to */ +/* allocate */ +/* */ +/* OUTPUT */ +/* */ +/* TX_THREAD_ERROR Invalid thread pointer */ +/* TX_CALLER_ERROR Invalid caller of function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_secure_stack_allocate Actual stack alloc function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* */ +/**************************************************************************/ +UINT _txe_thread_secure_stack_allocate(TX_THREAD *thread_ptr, ULONG stack_size) +{ +#if defined(TX_SINGLE_MODE_SECURE) || defined(TX_SINGLE_MODE_NON_SECURE) + return(TX_FEATURE_NOT_ENABLED); +#else +UINT status; + + /* Default status to success. */ + status = TX_SUCCESS; + + /* Check for an invalid thread pointer. */ + if (thread_ptr == TX_NULL) + { + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Now check for invalid thread ID. */ + else if (thread_ptr -> tx_thread_id != TX_THREAD_ID) + { + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Check for interrupt call. */ + if (TX_THREAD_GET_SYSTEM_STATE() != ((ULONG) 0)) + { + /* Is call from an interrupt and not initialization? */ + if (TX_THREAD_GET_SYSTEM_STATE() < TX_INITIALIZE_IN_PROGRESS) + { + /* Invalid caller of this function, return appropriate error code. */ + status = TX_CALLER_ERROR; + } + } + + /* Determine if everything is okay. */ + if (status == TX_SUCCESS) + { + /* Call actual secure stack allocate function. */ + status = _tx_thread_secure_stack_allocate(thread_ptr, stack_size); + } + + /* Return completion status. */ + return(status); +#endif +} diff --git a/ports_arch/ARMv8-M/threadx/ac6/src/txe_thread_secure_stack_free.c b/ports_arch/ARMv8-M/threadx/ac6/src/txe_thread_secure_stack_free.c new file mode 100644 index 00000000..0e1efcf4 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/ac6/src/txe_thread_secure_stack_free.c @@ -0,0 +1,120 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_initialize.h" +#include "tx_thread.h" + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_secure_stack_free Cortex-Mxx */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the secure stack free */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* */ +/* OUTPUT */ +/* */ +/* TX_THREAD_ERROR Invalid thread pointer */ +/* TX_CALLER_ERROR Invalid caller of function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_secure_stack_free Actual stack free function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* */ +/**************************************************************************/ +UINT _txe_thread_secure_stack_free(TX_THREAD *thread_ptr) +{ +#if defined(TX_SINGLE_MODE_SECURE) || defined(TX_SINGLE_MODE_NON_SECURE) + return(TX_FEATURE_NOT_ENABLED); +#else +UINT status; + + /* Default status to success. */ + status = TX_SUCCESS; + + /* Check for an invalid thread pointer. */ + if (thread_ptr == TX_NULL) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Now check for invalid thread ID. */ + else if (thread_ptr -> tx_thread_id != TX_THREAD_ID) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Check for interrupt call. */ + if (TX_THREAD_GET_SYSTEM_STATE() != ((ULONG) 0)) + { + /* Is call from an interrupt and not initialization? */ + if (TX_THREAD_GET_SYSTEM_STATE() < TX_INITIALIZE_IN_PROGRESS) + { + /* Invalid caller of this function, return appropriate error code. */ + status = TX_CALLER_ERROR; + } + } + + /* Determine if everything is okay. */ + if (status == TX_SUCCESS) + { + + /* Call actual secure stack allocate function. */ + status = _tx_thread_secure_stack_free(thread_ptr); + } + + /* Return completion status. */ + return(status); +#endif +} diff --git a/ports_arch/ARMv8-M/threadx/gnu/CMakeLists.txt b/ports_arch/ARMv8-M/threadx/gnu/CMakeLists.txt new file mode 100644 index 00000000..5ad3b8e7 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/gnu/CMakeLists.txt @@ -0,0 +1,21 @@ +target_sources(${PROJECT_NAME} PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/src/txe_thread_secure_stack_allocate.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_thread_secure_stack_free.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_initialize_low_level.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_restore.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_save.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_interrupt_control.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_interrupt_disable.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_interrupt_restore.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_schedule.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_secure_stack.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_secure_stack_allocate.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_secure_stack_free.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_stack_build.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_system_return.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_interrupt.S +) + +target_include_directories(${PROJECT_NAME} PUBLIC + inc +) diff --git a/ports_arch/ARMv8-M/threadx/gnu/readme_threadx.txt b/ports_arch/ARMv8-M/threadx/gnu/readme_threadx.txt new file mode 100644 index 00000000..4a6f5660 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/gnu/readme_threadx.txt @@ -0,0 +1,210 @@ + Microsoft's Azure RTOS ThreadX for Cortex-Mxx + + Using the GNU Tools + +1. Building the ThreadX run-time Library + +Import all ThreadX common and port-specific source files into a GNU project. +Configure the project to build a library rather than an executable. This +results in the ThreadX run-time library file tx.a, which is needed by +the application. +Files tx_thread_stack_error_handler.c and tx_thread_stack_error_notify.c +replace the common files of the same name. + +2. Demonstration System + +No demonstration project is provided. + + +3. System Initialization + +The entry point in ThreadX for the Cortex-Mxx using gnu tools uses the standard GNU +Cortex-Mxx reset sequence. From the reset vector the C runtime will be initialized. + +The ThreadX tx_initialize_low_level.S file is responsible for setting up +various system data structures, the vector area, and a periodic timer interrupt +source. + +In addition, _tx_initialize_low_level determines the first available +address for use by the application, which is supplied as the sole input +parameter to your application definition function, tx_application_define. + + +4. Register Usage and Stack Frames + +The following defines the saved context stack frames for context switches +that occur as a result of interrupt handling or from thread-level API calls. +All suspended threads have the same stack frame in the Cortex-Mxx version of +ThreadX. The top of the suspended thread's stack is pointed to by +tx_thread_stack_ptr in the associated thread control block TX_THREAD. + +Non-FPU Stack Frame: + + Stack Offset Stack Contents + + 0x00 LR Interrupted LR (LR at time of PENDSV) + 0x04 r4 Software stacked GP registers + 0x08 r5 + 0x0C r6 + 0x10 r7 + 0x14 r8 + 0x18 r9 + 0x1C r10 + 0x20 r11 + 0x24 r0 Hardware stacked registers + 0x28 r1 + 0x2C r2 + 0x30 r3 + 0x34 r12 + 0x38 lr + 0x3C pc + 0x40 xPSR + +FPU Stack Frame (only interrupted thread with FPU enabled): + + Stack Offset Stack Contents + + 0x00 LR Interrupted LR (LR at time of PENDSV) + 0x04 s16 Software stacked FPU registers + 0x08 s17 + 0x0C s18 + 0x10 s19 + 0x14 s20 + 0x18 s21 + 0x1C s22 + 0x20 s23 + 0x24 s24 + 0x28 s25 + 0x2C s26 + 0x30 s27 + 0x34 s28 + 0x38 s29 + 0x3C s30 + 0x40 s31 + 0x44 r4 Software stacked registers + 0x48 r5 + 0x4C r6 + 0x50 r7 + 0x54 r8 + 0x58 r9 + 0x5C r10 + 0x60 r11 + 0x64 r0 Hardware stacked registers + 0x68 r1 + 0x6C r2 + 0x70 r3 + 0x74 r12 + 0x78 lr + 0x7C pc + 0x80 xPSR + 0x84 s0 Hardware stacked FPU registers + 0x88 s1 + 0x8C s2 + 0x90 s3 + 0x94 s4 + 0x98 s5 + 0x9C s6 + 0xA0 s7 + 0xA4 s8 + 0xA8 s9 + 0xAC s10 + 0xB0 s11 + 0xB4 s12 + 0xB8 s13 + 0xBC s14 + 0xC0 s15 + 0xC4 fpscr + + +5. Improving Performance + +To make ThreadX and the application(s) run faster, you can enable +all compiler optimizations. + +In addition, you can eliminate the ThreadX basic API error checking by +compiling your application code with the symbol TX_DISABLE_ERROR_CHECKING +defined. + + +6. Interrupt Handling + +ThreadX provides complete and high-performance interrupt handling for Cortex-Mxx +targets. There are a certain set of requirements that are defined in the +following sub-sections: + + +6.1 Vector Area + +The Cortex-Mxx vectors start at the label __tx_vectors or similar. The application may modify +the vector area according to its needs. There is code in tx_initialize_low_level() that will +configure the vector base register. + + +6.2 Managed Interrupts + +ISRs can be written completely in C (or assembly language) without any calls to +_tx_thread_context_save or _tx_thread_context_restore. These ISRs are allowed access to the +ThreadX API that is available to ISRs. + +ISRs written in C will take the form (where "your_C_isr" is an entry in the vector table): + +void your_C_isr(void) +{ + + /* ISR processing goes here, including any needed function calls. */ +} + +ISRs written in assembly language will take the form: + + + .global your_assembly_isr + .thumb_func +your_assembly_isr: + PUSH {r0, lr} +; +; /* Do interrupt handler work here */ +; /* BL */ + + POP {r0, lr} + BX lr + +Note: the Cortex-Mxx requires exception handlers to be thumb labels, this implies bit 0 set. +To accomplish this, the declaration of the label has to be preceded by the assembler directive +.thumb_func to instruct the linker to create thumb labels. The label __tx_IntHandler needs to +be inserted in the correct location in the interrupt vector table. This table is typically +located in either your runtime startup file or in the tx_initialize_low_level.S file. + + +7. FPU Support + +ThreadX for Cortex-Mxx supports automatic ("lazy") VFP support, which means that applications threads +can simply use the VFP and ThreadX automatically maintains the VFP registers as part of the thread +context. + + +8. Revision History + +For generic code revision information, please refer to the readme_threadx_generic.txt +file, which is included in your distribution. The following details the revision +information associated with this specific port of ThreadX: + +06-02-2021 Release 6.1.7 changes: + tx_thread_secure_stack_initialize.S New file + tx_thread_schedule.S Added secure stack initialize to SVC hander + tx_thread_secure_stack.c Fixed stack pointer save, initialize in handler mode + +04-02-2021 Release 6.1.6 changes: + tx_port.h Updated macro definition + tx_thread_schedule.s Added low power support + +03-02-2021 The following files were changed/added for version 6.1.5: + tx_port.h Added ULONG64_DEFINED + +09-30-2020 Initial ThreadX 6.1 version for Cortex-Mxx using GNU tools. + + +Copyright(c) 1996-2020 Microsoft Corporation + + +https://azure.com/rtos + diff --git a/ports_arch/ARMv8-M/threadx/gnu/src/tx_initialize_low_level.S b/ports_arch/ARMv8-M/threadx/gnu/src/tx_initialize_low_level.S new file mode 100644 index 00000000..bb2b34cc --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/gnu/src/tx_initialize_low_level.S @@ -0,0 +1,283 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Initialize */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +SYSTEM_CLOCK = 6000000 +SYSTICK_CYCLES = ((SYSTEM_CLOCK / 100) -1) + +/* Setup the stack and heap areas. */ + +STACK_SIZE = 0x00000400 +HEAP_SIZE = 0x00000000 + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_initialize_low_level Cortex-Mxx/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for any low-level processor */ +/* initialization, including setting up interrupt vectors, setting */ +/* up a periodic timer interrupt source, saving the system stack */ +/* pointer for use in ISR processing later, and finding the first */ +/* available RAM memory address for tx_application_define. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_initialize_kernel_enter ThreadX entry function */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 01-31-2022 Scott Larson Fixed predefined macro name, */ +/* resulting in version 6.1.10 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_initialize_low_level(VOID) +// { + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_initialize_low_level + .thumb_func +.type _tx_initialize_low_level, function +_tx_initialize_low_level: + + /* Disable interrupts during ThreadX initialization. */ + CPSID i + + /* Set base of available memory to end of non-initialised RAM area. */ + LDR r0, =_tx_initialize_unused_memory // Build address of unused memory pointer + LDR r1, =__RAM_segment_used_end__ // Build first free address + ADD r1, r1, #4 // + STR r1, [r0] // Setup first unused memory pointer + + /* Setup Vector Table Offset Register. */ + MOV r0, #0xE000E000 // Build address of NVIC registers + LDR r1, =_vectors // Pickup address of vector table + STR r1, [r0, #0xD08] // Set vector table address + + /* Enable the cycle count register. */ + LDR r0, =0xE0001000 // Build address of DWT register + LDR r1, [r0] // Pickup the current value + ORR r1, r1, #1 // Set the CYCCNTENA bit + STR r1, [r0] // Enable the cycle count register + + /* Set system stack pointer from vector value. */ + LDR r0, =_tx_thread_system_stack_ptr // Build address of system stack pointer + LDR r1, =_vectors // Pickup address of vector table + LDR r1, [r1] // Pickup reset stack pointer + STR r1, [r0] // Save system stack pointer + + /* Configure SysTick. */ + MOV r0, #0xE000E000 // Build address of NVIC registers + LDR r1, =SYSTICK_CYCLES + STR r1, [r0, #0x14] // Setup SysTick Reload Value + MOV r1, #0x7 // Build SysTick Control Enable Value + STR r1, [r0, #0x10] // Setup SysTick Control + + /* Configure handler priorities. */ + LDR r1, =0x00000000 // Rsrv, UsgF, BusF, MemM + STR r1, [r0, #0xD18] // Setup System Handlers 4-7 Priority Registers + LDR r1, =0xFF000000 // SVCl, Rsrv, Rsrv, Rsrv + STR r1, [r0, #0xD1C] // Setup System Handlers 8-11 Priority Registers + // Note: SVC must be lowest priority, which is 0xFF + LDR r1, =0x40FF0000 // SysT, PnSV, Rsrv, DbgM + STR r1, [r0, #0xD20] // Setup System Handlers 12-15 Priority Registers + // Note: PnSV must be lowest priority, which is 0xFF + + /* Return to caller. */ + BX lr +// } + + +/* Define shells for each of the unused vectors. */ + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global __tx_BadHandler + .thumb_func +.type __tx_BadHandler, function +__tx_BadHandler: + B __tx_BadHandler + + + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global __tx_IntHandler + .thumb_func +.type __tx_IntHandler, function +__tx_IntHandler: +// VOID InterruptHandler (VOID) +// { + PUSH {r0,lr} // Save LR (and dummy r0 to maintain stack alignment) +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + BL _tx_execution_isr_enter // Call the ISR enter function +#endif + /* Do interrupt handler work here */ + /* .... */ +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + BL _tx_execution_isr_exit // Call the ISR exit function +#endif + POP {r0,lr} + BX lr +// } + + + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global SysTick_Handler + .thumb_func +.type SysTick_Handler, function +SysTick_Handler: +// VOID TimerInterruptHandler (VOID) +// { + PUSH {r0,lr} // Save LR (and dummy r0 to maintain stack alignment) +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + BL _tx_execution_isr_enter // Call the ISR enter function +#endif + BL _tx_timer_interrupt +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + BL _tx_execution_isr_exit // Call the ISR exit function +#endif + POP {r0,lr} + BX lr +// } + + + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global HardFault_Handler + .thumb_func +.type HardFault_Handler, function +HardFault_Handler: + B HardFault_Handler + + + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global UsageFault_Handler + .thumb_func +.type UsageFault_Handler, function +UsageFault_Handler: + CPSID i // Disable interrupts + // Check for stack limit fault + LDR r0, =0xE000ED28 // CFSR address + LDR r1,[r0] // Pick up CFSR + TST r1, #0x00100000 // Check for Stack Overflow +_unhandled_usage_loop: + BEQ _unhandled_usage_loop // If not stack overflow then loop + + // Handle stack overflow + STR r1, [r0] // Clear CFSR flag(s) + +#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] // Store the value +#endif + + LDR r0, =_tx_thread_current_ptr // Build current thread pointer address + LDR r0,[r0] // Pick up current thread pointer + PUSH {r0,lr} // Save LR (and r0 to maintain stack alignment) + BL _tx_thread_stack_error_handler // Call ThreadX/user handler + POP {r0,lr} // Restore LR and dummy reg + +#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. + 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 +#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 UsageFault_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 + CPSIE i // Enable interrupts + BX lr // Return from exception + + + + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global __tx_NMIHandler + .thumb_func +.type __tx_NMIHandler, function +__tx_NMIHandler: + B __tx_NMIHandler + + + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global __tx_DBGHandler + .thumb_func +.type __tx_DBGHandler, function +__tx_DBGHandler: + B __tx_DBGHandler + + .end diff --git a/ports_arch/ARMv8-M/threadx/gnu/src/tx_misra.S b/ports_arch/ARMv8-M/threadx/gnu/src/tx_misra.S new file mode 100644 index 00000000..c84d8576 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/gnu/src/tx_misra.S @@ -0,0 +1,723 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + #define SHT_PROGBITS 0x1 + + .global __aeabi_memset + .global _tx_thread_current_ptr + .global _tx_thread_interrupt_disable + .global _tx_thread_interrupt_restore + .global _tx_thread_stack_analyze + .global _tx_thread_stack_error_handler + .global _tx_thread_system_state +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_trace_buffer_current_ptr + .global _tx_trace_buffer_end_ptr + .global _tx_trace_buffer_start_ptr + .global _tx_trace_event_enable_bits + .global _tx_trace_full_notify_function + .global _tx_trace_header_ptr +#endif + + .global _tx_misra_always_true + .global _tx_misra_block_pool_to_uchar_pointer_convert + .global _tx_misra_byte_pool_to_uchar_pointer_convert + .global _tx_misra_char_to_uchar_pointer_convert + .global _tx_misra_const_char_to_char_pointer_convert +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_entry_to_uchar_pointer_convert +#endif + .global _tx_misra_indirect_void_to_uchar_pointer_convert + .global _tx_misra_memset + .global _tx_misra_message_copy +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_object_to_uchar_pointer_convert +#endif + .global _tx_misra_pointer_to_ulong_convert + .global _tx_misra_status_get + .global _tx_misra_thread_stack_check +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_time_stamp_get +#endif + .global _tx_misra_timer_indirect_to_void_pointer_convert + .global _tx_misra_timer_pointer_add + .global _tx_misra_timer_pointer_dif +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_trace_event_insert +#endif + .global _tx_misra_uchar_pointer_add + .global _tx_misra_uchar_pointer_dif + .global _tx_misra_uchar_pointer_sub + .global _tx_misra_uchar_to_align_type_pointer_convert + .global _tx_misra_uchar_to_block_pool_pointer_convert +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_uchar_to_entry_pointer_convert + .global _tx_misra_uchar_to_header_pointer_convert +#endif + .global _tx_misra_uchar_to_indirect_byte_pool_pointer_convert + .global _tx_misra_uchar_to_indirect_uchar_pointer_convert +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_uchar_to_object_pointer_convert +#endif + .global _tx_misra_uchar_to_void_pointer_convert + .global _tx_misra_ulong_pointer_add + .global _tx_misra_ulong_pointer_dif + .global _tx_misra_ulong_pointer_sub + .global _tx_misra_ulong_to_pointer_convert + .global _tx_misra_ulong_to_thread_pointer_convert + .global _tx_misra_user_timer_pointer_get + .global _tx_misra_void_to_block_pool_pointer_convert + .global _tx_misra_void_to_byte_pool_pointer_convert + .global _tx_misra_void_to_event_flags_pointer_convert + .global _tx_misra_void_to_indirect_uchar_pointer_convert + .global _tx_misra_void_to_mutex_pointer_convert + .global _tx_misra_void_to_queue_pointer_convert + .global _tx_misra_void_to_semaphore_pointer_convert + .global _tx_misra_void_to_thread_pointer_convert + .global _tx_misra_void_to_uchar_pointer_convert + .global _tx_misra_void_to_ulong_pointer_convert + .global _tx_misra_ipsr_get + .global _tx_misra_control_get + .global _tx_misra_control_set +#ifdef __ARM_FP + .global _tx_misra_fpccr_get + .global _tx_misra_vfp_touch +#endif + + .global _tx_misra_event_flags_group_not_used + .global _tx_misra_event_flags_set_notify_not_used + .global _tx_misra_queue_not_used + .global _tx_misra_queue_send_notify_not_used + .global _tx_misra_semaphore_not_used + .global _tx_misra_semaphore_put_notify_not_used + .global _tx_misra_thread_entry_exit_notify_not_used + .global _tx_misra_thread_not_used + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_memset(VOID *ptr, UINT value, UINT size); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .align 4 + .syntax unified + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_uchar_pointer_add: + ADD R0,R0,R1 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UCHAR *_tx_misra_uchar_pointer_sub(UCHAR *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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)); */ +/** */ +/************************************************************************************************************************************/ +/************************************************************************************************************************************/ + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_ulong_pointer_add: + ADD R0,R0,R1, LSL #+2 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG *_tx_misra_ulong_pointer_sub(ULONG *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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 R2,=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); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_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 + + + .data +DataTable2_1: + .word _tx_trace_buffer_current_ptr + + .data +DataTable2_2: + .word _tx_trace_event_enable_bits + + .data +DataTable2_5: + .word _tx_trace_buffer_end_ptr + + .data +DataTable2_6: + .word _tx_trace_buffer_start_ptr + + .data +DataTable2_7: + .word _tx_trace_header_ptr + + .data +DataTable2_8: + .word _tx_trace_full_notify_function + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG _tx_misra_time_stamp_get(VOID); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_time_stamp_get: + MOVS R0,#+0 + BX LR // return + +#endif + + .data +DataTable2_3: + .word _tx_thread_system_state + + .data +DataTable2_4: + .word _tx_thread_current_ptr + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UINT _tx_misra_always_true(void); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_always_true: + MOVS R0,#+1 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UINT _tx_misra_status_get(UINT status); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_status_get: + MOVS R0,#+0 + BX LR // return + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** ULONG _tx_misra_ipsr_get(void); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_tx_misra_ipsr_get: + MRS R0, IPSR + BX LR // return + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** ULONG _tx_misra_control_get(void); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_tx_misra_control_get: + MRS R0, CONTROL + BX LR // return + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** void _tx_misra_control_set(ULONG value); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_tx_misra_control_set: + MSR CONTROL, R0 + BX LR // return + + +#ifdef __ARM_FP + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** ULONG _tx_misra_fpccr_get(void); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_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); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_tx_misra_vfp_touch: + vmov.f32 s0, s0 + BX LR // return + +#endif + + + .data + .word 0 diff --git a/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_context_restore.S b/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_context_restore.S new file mode 100644 index 00000000..4c5de879 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_context_restore.S @@ -0,0 +1,89 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + .global _tx_execution_isr_exit +#endif +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_restore Cortex-Mxx/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is not needed for Cortex-M. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* [_tx_execution_isr_exit] Execution profiling ISR exit */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs Interrupt Service Routines */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_context_restore(VOID) +// { + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_thread_context_restore + .thumb_func +.type _tx_thread_context_restore, function +_tx_thread_context_restore: + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the ISR exit function to indicate an ISR is complete. */ + PUSH {r0, lr} // Save return address + BL _tx_execution_isr_exit // Call the ISR exit function + POP {r0, lr} // Recover return address +#endif + + BX lr +// } + .end diff --git a/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_context_save.S b/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_context_save.S new file mode 100644 index 00000000..9058a806 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_context_save.S @@ -0,0 +1,89 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + .global _tx_execution_isr_enter +#endif +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_save Cortex-Mxx/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is not needed for Cortex-M. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* [_tx_execution_isr_enter] Execution profiling ISR enter */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_context_save(VOID) +// { + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_thread_context_save + .thumb_func +.type _tx_thread_context_save, function +_tx_thread_context_save: + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the ISR enter function to indicate an ISR is starting. */ + PUSH {r0, lr} // Save return address + BL _tx_execution_isr_enter // Call the ISR enter function + POP {r0, lr} // Recover return address +#endif + + BX lr +// } + .end diff --git a/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_interrupt_control.S b/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_interrupt_control.S new file mode 100644 index 00000000..c55ce306 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_interrupt_control.S @@ -0,0 +1,87 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_control Cortex-Mxx/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for changing the interrupt lockout */ +/* posture of the system. */ +/* */ +/* INPUT */ +/* */ +/* new_posture New interrupt lockout posture */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_interrupt_control(UINT new_posture) +// { + .section .text + .balign 4 + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_thread_interrupt_control + .thumb_func +.type _tx_thread_interrupt_control, function +_tx_thread_interrupt_control: +#ifdef TX_PORT_USE_BASEPRI + MRS r1, BASEPRI // Pickup current interrupt posture + MSR BASEPRI, r0 // Apply the new interrupt posture + MOV r0, r1 // Transfer old to return register +#else + MRS r1, PRIMASK // Pickup current interrupt lockout + MSR PRIMASK, r0 // Apply the new interrupt lockout + MOV r0, r1 // Transfer old to return register +#endif + BX lr // Return to caller +// } + .end diff --git a/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_interrupt_disable.S b/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_interrupt_disable.S new file mode 100644 index 00000000..27f5894f --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_interrupt_disable.S @@ -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 */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_disable Cortex-Mxx/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for disabling interrupts and returning */ +/* the previous interrupt lockout posture. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_interrupt_disable(VOID) +// { + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_thread_interrupt_disable + .thumb_func +.type _tx_thread_interrupt_disable, function +_tx_thread_interrupt_disable: + /* Return current interrupt lockout posture. */ +#ifdef TX_PORT_USE_BASEPRI + MRS r0, BASEPRI + LDR r1, =TX_PORT_BASEPRI + MSR BASEPRI, r1 +#else + MRS r0, PRIMASK + CPSID i +#endif + BX lr +// } + .end diff --git a/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_interrupt_restore.S b/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_interrupt_restore.S new file mode 100644 index 00000000..29d5cc44 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_interrupt_restore.S @@ -0,0 +1,85 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_restore Cortex-Mxx/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for restoring the previous */ +/* interrupt lockout posture. */ +/* */ +/* INPUT */ +/* */ +/* previous_posture Previous interrupt posture */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_interrupt_restore(UINT previous_posture) +// { + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_thread_interrupt_restore + .thumb_func +.type _tx_thread_interrupt_restore, function +_tx_thread_interrupt_restore: + /* Restore previous interrupt lockout posture. */ +#ifdef TX_PORT_USE_BASEPRI + MSR BASEPRI, r0 +#else + MSR PRIMASK, r0 +#endif + BX lr +// } + .end diff --git a/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_schedule.S b/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_schedule.S new file mode 100644 index 00000000..7ae7c982 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_schedule.S @@ -0,0 +1,396 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_schedule Cortex-Mxx/GNU */ +/* 6.2.1 */ +/* 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 */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 04-02-2021 Scott Larson Modified comment(s), added */ +/* low power code, */ +/* resulting in version 6.1.6 */ +/* 06-02-2021 Scott Larson Added secure stack initialize */ +/* in SVC handler, */ +/* resulting in version 6.1.7 */ +/* 01-31-2022 Scott Larson Fixed predefined macro name, */ +/* resulting in version 6.1.10 */ +/* 04-25-2022 Scott Larson Added BASEPRI support, */ +/* resulting in version 6.1.11 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_schedule(VOID) +// { + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_thread_schedule + .thumb_func +.type _tx_thread_schedule, function +_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 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 +// } + + /* Generic context switching PendSV handler. */ + + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global PendSV_Handler + .thumb_func +.type PendSV_Handler, function + /* Get current thread value and new thread pointer. */ +PendSV_Handler: +__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 + STR r12, [r1, #8] // Save the thread stack pointer + +#if (!defined(TX_SINGLE_MODE_SECURE) && !defined(TX_SINGLE_MODE_NON_SECURE)) + // Save secure context + LDR r5, [r1,#0x90] // Load secure stack index + CBZ r5, _skip_secure_save // Skip save if there is no secure context + PUSH {r0,r1,r2,r3} // Save scratch registers + MOV r0, r1 // Move thread ptr to r0 + BL _tx_thread_secure_stack_context_save // Save secure stack + POP {r0,r1,r2,r3} // Restore secure registers +_skip_secure_save: +#endif + + /* Determine if time-slice is active. If it isn't, skip time handling processing. */ + + LDR r5, [r4] // Pickup current time-slice + 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? + CBZ r1, __tx_ts_wait // No, skip to the wait processing + + /* Yes, another thread is ready for else, make the current thread the new thread. */ + + 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. */ + +__tx_ts_restore: + 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 + +#if (!defined(TX_SINGLE_MODE_SECURE) && !defined(TX_SINGLE_MODE_NON_SECURE)) + // Restore secure context + LDR r0, [r1,#0x90] // Load secure stack index + CBZ r0, _skip_secure_restore // Skip restore if there is no secure context + PUSH {r0,r1} // Save r1 (and dummy r0) + MOV r0, r1 // Move thread ptr to r0 + BL _tx_thread_secure_stack_context_restore // Restore secure stack + POP {r0,r1} // Restore r1 (and dummy r0) +_skip_secure_restore: +#endif + + /* Restore the thread context and PSP. */ + LDR r12, [r1, #12] // Get stack start + MSR PSPLIM, r12 // Set stack limit + LDR r12, [r1, #8] // Pickup thread's stack pointer + 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 + + BX lr // Return to thread! + + /* 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 + STR r1, [r0] // Store it in the current 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 + + /* Re-enable interrupts and restore new thread. */ +#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_restore // Restore the thread +// } + + +#if (!defined(TX_SINGLE_MODE_SECURE) && !defined(TX_SINGLE_MODE_NON_SECURE)) + // SVC_Handler is not needed when ThreadX is running in single mode. + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global SVC_Handler + .thumb_func +.type SVC_Handler, function +SVC_Handler: + TST lr, #0x04 // Determine return stack from EXC_RETURN bit 2 + ITE EQ + MRSEQ r0, MSP // Get MSP if return stack is MSP + MRSNE r0, PSP // Get PSP if return stack is PSP + + LDR r1, [r0,#24] // Load saved PC from stack + LDRB r1, [r1,#-2] // Load SVC number + + CMP r1, #1 // Is it a secure stack allocate request? + BEQ _tx_svc_secure_alloc // Yes, go there + + CMP r1, #2 // Is it a secure stack free request? + BEQ _tx_svc_secure_free // Yes, go there + + CMP r1, #3 // Is it a secure stack init request? + BEQ _tx_svc_secure_init // Yes, go there + + // Unknown SVC argument - just return + BX lr + +_tx_svc_secure_alloc: + PUSH {r0,lr} // Save SP and EXC_RETURN + LDM r0, {r0-r3} // Load function parameters from stack + BL _tx_thread_secure_mode_stack_allocate + POP {r12,lr} // Restore SP and EXC_RETURN + STR r0,[r12] // Store function return value + BX lr +_tx_svc_secure_free: + PUSH {r0,lr} // Save SP and EXC_RETURN + LDM r0, {r0-r3} // Load function parameters from stack + BL _tx_thread_secure_mode_stack_free + POP {r12,lr} // Restore SP and EXC_RETURN + STR r0,[r12] // Store function return value + BX lr +_tx_svc_secure_init: + PUSH {r0,lr} // Save SP and EXC_RETURN + BL _tx_thread_secure_mode_stack_initialize + POP {r12,lr} // Restore SP and EXC_RETURN + BX lr +#endif // End of ifndef TX_SINGLE_MODE_SECURE, TX_SINGLE_MODE_NON_SECURE + + + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_vfp_access + .thumb_func +.type _tx_vfp_access, function +_tx_vfp_access: +#if TX_ENABLE_FPU_SUPPORT + VMOV.F32 s0, s0 // Simply access the VFP +#endif + BX lr // Return to caller +.end diff --git a/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_secure_stack.c b/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_secure_stack.c new file mode 100644 index 00000000..cbd30fa5 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_secure_stack.c @@ -0,0 +1,596 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +#include "tx_api.h" + +/* If TX_SINGLE_MODE_SECURE or TX_SINGLE_MODE_NON_SECURE is defined, + no secure stack functionality is needed. */ +#if !defined(TX_SINGLE_MODE_SECURE) && !defined(TX_SINGLE_MODE_NON_SECURE) + +#define TX_SOURCE_CODE + +#include "tx_secure_interface.h" /* Interface for NS code. */ + +/* Minimum size of secure stack. */ +#ifndef TX_THREAD_SECURE_STACK_MINIMUM +#define TX_THREAD_SECURE_STACK_MINIMUM 256 +#endif +/* Maximum size of secure stack. */ +#ifndef TX_THREAD_SECURE_STACK_MAXIMUM +#define TX_THREAD_SECURE_STACK_MAXIMUM 1024 +#endif + +/* 8 bytes added to stack size to "seal" stack. */ +#define TX_THREAD_STACK_SEAL_SIZE 8 +#define TX_THREAD_STACK_SEAL_VALUE 0xFEF5EDA5 + +/* max number of Secure context */ +#ifndef TX_MAX_SECURE_CONTEXTS +#define TX_MAX_SECURE_CONTEXTS 32 +#endif +#define TX_INVALID_SECURE_CONTEXT_IDX (-1) + +/* Secure stack info struct to hold stack start, stack limit, + current stack pointer, and pointer to owning thread. + This will be allocated for each thread with a secure stack. */ +typedef struct TX_THREAD_SECURE_STACK_INFO_STRUCT +{ + VOID *tx_thread_secure_stack_ptr; /* Thread's secure stack current pointer */ + VOID *tx_thread_secure_stack_start; /* Thread's secure stack start address */ + VOID *tx_thread_secure_stack_limit; /* Thread's secure stack limit */ + TX_THREAD *tx_thread_ptr; /* Keep track of thread for error handling */ + INT tx_next_free_index; /* Next free index of free secure context */ +} TX_THREAD_SECURE_STACK_INFO; + +/* Static secure contexts */ +static TX_THREAD_SECURE_STACK_INFO tx_thread_secure_context[TX_MAX_SECURE_CONTEXTS]; +/* Head of free secure context */ +static INT tx_head_free_index = 0U; + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_secure_mode_stack_initialize Cortex-Mxx/GNU */ +/* 6.1.10 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function initializes secure mode to use PSP stack. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_initialize_kernel_enter */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 10-16-2020 Scott Larson Modified comment(s), */ +/* resulting in version 6.1.1 */ +/* 06-02-2021 Scott Larson Change name, execute in */ +/* handler mode, */ +/* disable optimizations, */ +/* resulting in version 6.1.7 */ +/* 01-31-2022 Himanshu Gupta Modified comments(s), updated */ +/* secure stack allocation, */ +/* resulting in version 6.1.10 */ +/* */ +/**************************************************************************/ +__attribute__((cmse_nonsecure_entry, optimize(0))) +UINT _tx_thread_secure_mode_stack_initialize(void) +{ +UINT status; +ULONG control; +ULONG ipsr; +INT index; + + /* Make sure function is called from interrupt (threads should not call). */ + asm volatile("MRS %0, IPSR" : "=r" (ipsr)); /* Get IPSR register. */ + if (ipsr == 0) + { + status = TX_CALLER_ERROR; + } + else + { + /* Set secure mode to use PSP. */ + asm volatile("MRS %0, CONTROL" : "=r" (control)); /* Get CONTROL register. */ + control |= 2; /* Use PSP. */ + asm volatile("MSR CONTROL, %0" :: "r" (control)); /* Set CONTROL register. */ + + /* Set process stack pointer and stack limit to 0 to throw exception when a thread + without a secure stack calls a secure function that tries to use secure stack. */ + asm volatile("MSR PSPLIM, %0" :: "r" (0)); + asm volatile("MSR PSP, %0" :: "r" (0)); + + for (index = 0; index < TX_MAX_SECURE_CONTEXTS; index++) + { + + /* Check last index and mark next free to invalid index */ + if(index == (TX_MAX_SECURE_CONTEXTS - 1)) + { + tx_thread_secure_context[index].tx_next_free_index = TX_INVALID_SECURE_CONTEXT_IDX; + } + else + { + tx_thread_secure_context[index].tx_next_free_index = index + 1; + } + } + + status = TX_SUCCESS; + } + return status; +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_secure_mode_stack_allocate Cortex-Mxx/GNU */ +/* 6.1.11a */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function allocates a thread's secure stack. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* stack_size Size of stack to allocates */ +/* */ +/* OUTPUT */ +/* */ +/* TX_THREAD_ERROR Invalid thread pointer */ +/* TX_SIZE_ERROR Invalid stack size */ +/* TX_CALLER_ERROR Invalid caller of function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* malloc Compiler's malloc function */ +/* */ +/* CALLED BY */ +/* */ +/* SVC Handler */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 10-16-2020 Scott Larson Modified comment(s), */ +/* added stack sealing, */ +/* resulting in version 6.1.1 */ +/* 01-31-2022 Himanshu Gupta Modified comments(s), updated */ +/* secure stack allocation, */ +/* resulting in version 6.1.10 */ +/* 05-02-2022 Scott Larson Modified comment(s), added */ +/* TX_INTERRUPT_SAVE_AREA, */ +/* resulting in version 6.1.11a*/ +/* */ +/**************************************************************************/ +__attribute__((cmse_nonsecure_entry)) +UINT _tx_thread_secure_mode_stack_allocate(TX_THREAD *thread_ptr, ULONG stack_size) +{ +TX_INTERRUPT_SAVE_AREA +UINT status; +TX_THREAD_SECURE_STACK_INFO *info_ptr; +UCHAR *stack_mem; +ULONG ipsr; +ULONG psplim_ns; +INT secure_context_index; + + status = TX_SUCCESS; + + /* Make sure function is called from interrupt (threads should not call). */ + asm volatile("MRS %0, IPSR" : "=r" (ipsr)); /* Get IPSR register. */ + if (ipsr == 0) + { + status = TX_CALLER_ERROR; + } + else if (stack_size < TX_THREAD_SECURE_STACK_MINIMUM || stack_size > TX_THREAD_SECURE_STACK_MAXIMUM) + { + status = TX_SIZE_ERROR; + } + + /* Check if thread already has secure stack allocated. */ + else if (thread_ptr -> tx_thread_secure_stack_context != 0) + { + status = TX_THREAD_ERROR; + } + + else + { + TX_DISABLE + + /* Allocate free index for secure stack info. */ + if(tx_head_free_index != TX_INVALID_SECURE_CONTEXT_IDX) + { + secure_context_index = tx_head_free_index; + tx_head_free_index = tx_thread_secure_context[tx_head_free_index].tx_next_free_index; + tx_thread_secure_context[secure_context_index].tx_next_free_index = TX_INVALID_SECURE_CONTEXT_IDX; + } + else + { + secure_context_index = TX_INVALID_SECURE_CONTEXT_IDX; + } + + TX_RESTORE + + if(secure_context_index != TX_INVALID_SECURE_CONTEXT_IDX) + { + info_ptr = &tx_thread_secure_context[secure_context_index]; + + /* If stack info allocated, allocate a stack & seal. */ + stack_mem = malloc(stack_size + TX_THREAD_STACK_SEAL_SIZE); + + if(stack_mem != TX_NULL) + { + /* Secure stack has been allocated, save in the stack info struct. */ + info_ptr -> tx_thread_secure_stack_limit = stack_mem; + info_ptr -> tx_thread_secure_stack_start = stack_mem + stack_size; + info_ptr -> tx_thread_secure_stack_ptr = info_ptr -> tx_thread_secure_stack_start; + info_ptr -> tx_thread_ptr = thread_ptr; + + /* Seal bottom of stack. */ + *(ULONG*)info_ptr -> tx_thread_secure_stack_start = TX_THREAD_STACK_SEAL_VALUE; + + /* Save secure context id (i.e non-zero base index) in thread. */ + thread_ptr -> tx_thread_secure_stack_context = (VOID *)(secure_context_index + 1); + + /* Check if this thread is running by looking at its stack start and PSPLIM_NS */ + asm volatile("MRS %0, PSPLIM_NS" : "=r" (psplim_ns)); /* Get PSPLIM_NS register. */ + if(((ULONG) thread_ptr -> tx_thread_stack_start & 0xFFFFFFF8) == psplim_ns) + { + /* If this thread is running, set Secure PSP and PSPLIM. */ + asm volatile("MSR PSPLIM, %0" :: "r" ((ULONG)(info_ptr -> tx_thread_secure_stack_limit))); + asm volatile("MSR PSP, %0" :: "r" ((ULONG)(info_ptr -> tx_thread_secure_stack_ptr))); + } + } + + else + { + TX_DISABLE + + /* Stack not allocated, free the info struct. */ + tx_thread_secure_context[secure_context_index].tx_next_free_index = tx_head_free_index; + tx_head_free_index = secure_context_index; + TX_RESTORE + + status = TX_NO_MEMORY; + } + } + + else + { + status = TX_NO_MEMORY; + } + } + + return(status); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_secure_mode_stack_free Cortex-Mxx/GNU */ +/* 6.1.10 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function frees a thread's secure stack. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* */ +/* OUTPUT */ +/* */ +/* TX_THREAD_ERROR Invalid thread pointer */ +/* TX_CALLER_ERROR Invalid caller of function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* free Compiler's free() function */ +/* */ +/* CALLED BY */ +/* */ +/* SVC Handler */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 10-16-2020 Scott Larson Modified comment(s), */ +/* resulting in version 6.1.1 */ +/* 01-31-2022 Himanshu Gupta Modified comments(s), updated */ +/* secure stack allocation, */ +/* resulting in version 6.1.10 */ +/* */ +/**************************************************************************/ +__attribute__((cmse_nonsecure_entry)) +UINT _tx_thread_secure_mode_stack_free(TX_THREAD *thread_ptr) +{ +TX_INTERRUPT_SAVE_AREA +UINT status; +TX_THREAD_SECURE_STACK_INFO *info_ptr; +ULONG ipsr; +INT secure_context_index; + + status = TX_SUCCESS; + + /* Pickup stack info id from thread. */ + secure_context_index = (INT)thread_ptr -> tx_thread_secure_stack_context - 1; + + /* Make sure function is called from interrupt (threads should not call). */ + asm volatile("MRS %0, IPSR" : "=r" (ipsr)); /* Get IPSR register. */ + if (ipsr == 0) + { + status = TX_CALLER_ERROR; + } + + /* Check if secure context index is in valid range. */ + else if (secure_context_index < 0 || secure_context_index >= TX_MAX_SECURE_CONTEXTS) + { + status = TX_THREAD_ERROR; + } + else + { + + /* Pickup stack info from static array of secure contexts. */ + info_ptr = &tx_thread_secure_context[secure_context_index]; + + /* Check that this secure context is for this thread. */ + if (info_ptr -> tx_thread_ptr != thread_ptr) + { + status = TX_THREAD_ERROR; + } + + else + { + + /* Free secure stack. */ + free(info_ptr -> tx_thread_secure_stack_limit); + + TX_DISABLE + + /* Free info struct. */ + tx_thread_secure_context[secure_context_index].tx_next_free_index = tx_head_free_index; + tx_head_free_index = secure_context_index; + TX_RESTORE + + /* Clear secure context from thread. */ + thread_ptr -> tx_thread_secure_stack_context = 0; + } + } + + return(status); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_secure_stack_context_save Cortex-Mxx/GNU */ +/* 6.1.10 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function saves context of the secure stack. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* PendSV Handler */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 10-16-2020 Scott Larson Modified comment(s), */ +/* resulting in version 6.1.1 */ +/* 06-02-2021 Scott Larson Fix stack pointer save, */ +/* resulting in version 6.1.7 */ +/* 01-31-2022 Himanshu Gupta Modified comments(s), updated */ +/* secure stack allocation, */ +/* resulting in version 6.1.10 */ +/* */ +/**************************************************************************/ +__attribute__((cmse_nonsecure_entry)) +void _tx_thread_secure_stack_context_save(TX_THREAD *thread_ptr) +{ +TX_THREAD_SECURE_STACK_INFO *info_ptr; +ULONG sp; +ULONG ipsr; +INT secure_context_index = (INT)thread_ptr -> tx_thread_secure_stack_context - 1; + + /* This function should be called from scheduler only. */ + asm volatile("MRS %0, IPSR" : "=r" (ipsr)); /* Get IPSR register. */ + if (ipsr == 0) + { + return; + } + + /* Check if secure context index is in valid range. */ + else if (secure_context_index < 0 || secure_context_index >= TX_MAX_SECURE_CONTEXTS) + { + return; + } + + /* Pickup the secure context pointer. */ + info_ptr = &tx_thread_secure_context[secure_context_index]; + + /* Check that this secure context is for this thread. */ + if (info_ptr -> tx_thread_ptr != thread_ptr) + { + return; + } + + /* Check that stack pointer is in range */ + asm volatile("MRS %0, PSP" : "=r" (sp)); /* Get PSP register. */ + if ((sp < (ULONG)info_ptr -> tx_thread_secure_stack_limit) || + (sp > (ULONG)info_ptr -> tx_thread_secure_stack_start)) + { + return; + } + + /* Save stack pointer. */ + info_ptr -> tx_thread_secure_stack_ptr = (VOID *) sp; + + /* Set process stack pointer and stack limit to 0 to throw exception when a thread + without a secure stack calls a secure function that tries to use secure stack. */ + asm volatile("MSR PSPLIM, %0" :: "r" (0)); + asm volatile("MSR PSP, %0" :: "r" (0)); + + return; +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_secure_stack_context_restore Cortex-Mxx/GNU */ +/* 6.1.10 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function restores context of the secure stack. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* PendSV Handler */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 10-16-2020 Scott Larson Modified comment(s), */ +/* resulting in version 6.1.1 */ +/* 01-31-2022 Himanshu Gupta Modified comments(s), updated */ +/* secure stack allocation, */ +/* resulting in version 6.1.10 */ +/* */ +/**************************************************************************/ +__attribute__((cmse_nonsecure_entry)) +void _tx_thread_secure_stack_context_restore(TX_THREAD *thread_ptr) +{ +TX_THREAD_SECURE_STACK_INFO *info_ptr; +ULONG ipsr; +INT secure_context_index = (INT)thread_ptr -> tx_thread_secure_stack_context - 1; + + /* This function should be called from scheduler only. */ + asm volatile("MRS %0, IPSR" : "=r" (ipsr)); /* Get IPSR register. */ + if (ipsr == 0) + { + return; + } + + /* Check if secure context index is in valid range. */ + else if (secure_context_index < 0 || secure_context_index >= TX_MAX_SECURE_CONTEXTS) + { + return; + } + + /* Pickup the secure context pointer. */ + info_ptr = &tx_thread_secure_context[secure_context_index]; + + /* Check that this secure context is for this thread. */ + if (info_ptr -> tx_thread_ptr != thread_ptr) + { + return; + } + + /* Set stack pointer and limit. */ + asm volatile("MSR PSPLIM, %0" :: "r" ((ULONG)info_ptr -> tx_thread_secure_stack_limit)); + asm volatile("MSR PSP, %0" :: "r" ((ULONG)info_ptr -> tx_thread_secure_stack_ptr)); + + return; +} + +#endif diff --git a/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_secure_stack_allocate.S b/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_secure_stack_allocate.S new file mode 100644 index 00000000..408e7805 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_secure_stack_allocate.S @@ -0,0 +1,90 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_secure_stack_allocate Cortex-Mxx/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enters the SVC handler to allocate a secure stack. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* stack_size Size of secure stack to */ +/* allocate */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* SVC 1 */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_secure_stack_allocate(TX_THREAD *thread_ptr, ULONG stack_size) +// { + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_thread_secure_stack_allocate + .thumb_func +.type _tx_thread_secure_stack_allocate, function +_tx_thread_secure_stack_allocate: +#if !defined(TX_SINGLE_MODE_SECURE) && !defined(TX_SINGLE_MODE_NON_SECURE) + MRS r3, PRIMASK // Save interrupt mask + CPSIE i // Enable interrupts for SVC call + SVC 1 + CMP r3, #0 // If interrupts enabled, just return + BEQ _alloc_return_interrupt_enabled + CPSID i // Otherwise, disable interrupts +#else + MOV r0, #0xFF // Feature not enabled +#endif +_alloc_return_interrupt_enabled: + BX lr + .end diff --git a/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_secure_stack_free.S b/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_secure_stack_free.S new file mode 100644 index 00000000..7b33d795 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_secure_stack_free.S @@ -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 */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_secure_stack_free Cortex-Mxx/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enters the SVC handler to free a secure stack. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* SVC 2 */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_secure_stack_free(TX_THREAD *thread_ptr) +// { + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_thread_secure_stack_free + .thumb_func +.type _tx_thread_secure_stack_free, function +_tx_thread_secure_stack_free: +#if !defined(TX_SINGLE_MODE_SECURE) && !defined(TX_SINGLE_MODE_NON_SECURE) + MRS r3, PRIMASK // Save interrupt mask + CPSIE i // Enable interrupts for SVC call + SVC 2 + CMP r3, #0 // If interrupts enabled, just return + BEQ _free_return_interrupt_enabled + CPSID i // Otherwise, disable interrupts +#else + MOV r0, #0xFF // Feature not enabled +#endif +_free_return_interrupt_enabled: + BX lr + .end diff --git a/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_secure_stack_initialize.S b/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_secure_stack_initialize.S new file mode 100644 index 00000000..8566d4b2 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_secure_stack_initialize.S @@ -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 */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_secure_stack_initialize Cortex-Mxx/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enters the SVC handler to initialize a secure stack. */ +/* */ +/* INPUT */ +/* */ +/* none */ +/* */ +/* OUTPUT */ +/* */ +/* none */ +/* */ +/* CALLS */ +/* */ +/* SVC 3 */ +/* */ +/* CALLED BY */ +/* */ +/* TX_PORT_SPECIFIC_PRE_INITIALIZATION */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 07-29-2022 Scott Larson Modified comments and changed */ +/* secure stack initialization */ +/* macro to port-specific, */ +/* resulting in version 6.1.12 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_secure_stack_initialize(VOID) +// { + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_thread_secure_stack_initialize + .thumb_func +.type _tx_thread_secure_stack_initialize, function +_tx_thread_secure_stack_initialize: +#if !defined(TX_SINGLE_MODE_SECURE) && !defined(TX_SINGLE_MODE_NON_SECURE) + CPSIE i // Enable interrupts for SVC call + SVC 3 + CPSID i // Disable interrupts +#else + MOV r0, #0xFF // Feature not enabled +#endif + BX lr + .end diff --git a/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_stack_build.S b/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_stack_build.S new file mode 100644 index 00000000..5322c89b --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_stack_build.S @@ -0,0 +1,145 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_stack_build Cortex-Mxx/GNU */ +/* 6.2.1 */ +/* 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 control blk */ +/* function_ptr Pointer to return function */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_create Create thread service */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID)) +// { + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_thread_stack_build + .thumb_func +.type _tx_thread_stack_build, function +_tx_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 for 8-byte alignment + SUB r2, r2, #68 // Subtract frame size +#ifdef TX_SINGLE_MODE_SECURE + LDR r3, =0xFFFFFFFD // Build initial LR value for secure mode +#else + LDR r3, =0xFFFFFFBC // Build initial LR value to return to non-secure PSP +#endif + 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, #24] // Store initial r9 + STR r3, [r2, #28] // Store initial r10 + STR r3, [r2, #32] // Store initial r11 + + /* Hardware stack follows. */ + + STR r3, [r2, #36] // Store initial r0 + STR r3, [r2, #40] // Store initial r1 + 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 diff --git a/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_system_return.S b/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_system_return.S new file mode 100644 index 00000000..bd9c84ba --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/gnu/src/tx_thread_system_return.S @@ -0,0 +1,101 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_system_return Cortex-Mxx/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is target processor specific. It is used to transfer */ +/* control from a thread back to the ThreadX system. Only a */ +/* minimal context is saved since the compiler assumes temp registers */ +/* are going to get slicked by a function call anyway. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_schedule Thread scheduling loop */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX components */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_system_return(VOID) +// { + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_thread_system_return + .thumb_func +.type _tx_thread_system_return, function +_tx_thread_system_return: + /* Return to real scheduler via PendSV. Note that this routine is often + replaced with in-line assembly in tx_port.h to improved performance. */ + + MOV r0, #0x10000000 // Load PENDSVSET bit + MOV r1, #0xE000E000 // Load NVIC base + STR r0, [r1, #0xD04] // Set PENDSVBIT in ICSR + MRS r0, IPSR // Pickup IPSR + CMP r0, #0 // Is it a thread returning? + BNE _isr_context // If ISR, skip interrupt enable +#ifdef TX_PORT_USE_BASEPRI + MRS r1, BASEPRI // Thread context returning, pickup BASEPRI + MOV r0, #0 + MSR BASEPRI, r0 // Enable interrupts + MSR BASEPRI, r1 // Restore original interrupt posture +#else + MRS r1, PRIMASK // Thread context returning, pickup PRIMASK + CPSIE i // Enable interrupts + MSR PRIMASK, r1 // Restore original interrupt posture +#endif +_isr_context: + BX lr // Return to caller +// } + .end diff --git a/ports_arch/ARMv8-M/threadx/gnu/src/tx_timer_interrupt.S b/ports_arch/ARMv8-M/threadx/gnu/src/tx_timer_interrupt.S new file mode 100644 index 00000000..68436d86 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/gnu/src/tx_timer_interrupt.S @@ -0,0 +1,248 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_interrupt Cortex-Mxx/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the hardware timer interrupt. This */ +/* processing includes incrementing the system clock and checking for */ +/* time slice and/or timer expiration. If either is found, the */ +/* expiration functions are called. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_timer_expiration_process Timer expiration processing */ +/* _tx_thread_time_slice Time slice interrupted thread */ +/* */ +/* CALLED BY */ +/* */ +/* interrupt vector */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_timer_interrupt(VOID) +// { + .section .text + .balign 4 + .syntax unified + .eabi_attribute Tag_ABI_align_preserved, 1 + .global _tx_timer_interrupt + .thumb_func +.type _tx_timer_interrupt, function +_tx_timer_interrupt: + + /* Upon entry to this routine, it is assumed that the compiler scratch registers are available + for use. */ + + /* Increment the system clock. */ + // _tx_timer_system_clock++; + + LDR r1, =_tx_timer_system_clock // Pickup address of system clock + LDR r0, [r1, #0] // Pickup system clock + ADD r0, r0, #1 // Increment system clock + STR r0, [r1, #0] // Store new system clock + + /* Test for time-slice expiration. */ + // if (_tx_timer_time_slice) + // { + + LDR r3, =_tx_timer_time_slice // Pickup address of time-slice + LDR r2, [r3, #0] // Pickup time-slice + CBZ r2, __tx_timer_no_time_slice // Is it non-active? + // Yes, skip time-slice processing + + /* Decrement the time_slice. */ + // _tx_timer_time_slice--; + + SUB r2, r2, #1 // Decrement the time-slice + STR r2, [r3, #0] // Store new time-slice value + + /* Check for expiration. */ + // if (__tx_timer_time_slice == 0) + + CBNZ r2, __tx_timer_no_time_slice // Has it expired? + // No, skip expiration processing + + /* Set the time-slice expired flag. */ + // _tx_timer_expired_time_slice = TX_TRUE; + + LDR r3, =_tx_timer_expired_time_slice // Pickup address of expired flag + MOV r0, #1 // Build expired value + STR r0, [r3, #0] // Set time-slice expiration flag + + // } + +__tx_timer_no_time_slice: + + /* Test for timer expiration. */ + // if (*_tx_timer_current_ptr) + // { + + LDR r1, =_tx_timer_current_ptr // Pickup current timer pointer address + LDR r0, [r1, #0] // Pickup current timer + LDR r2, [r0, #0] // Pickup timer list entry + CBZ r2, __tx_timer_no_timer // Is there anything in the list? + // No, just increment the timer + + /* Set expiration flag. */ + // _tx_timer_expired = TX_TRUE; + + LDR r3, =_tx_timer_expired // Pickup expiration flag address + MOV r2, #1 // Build expired value + STR r2, [r3, #0] // Set expired flag + B __tx_timer_done // Finished timer processing + + // } + // else + // { +__tx_timer_no_timer: + + /* No timer expired, increment the timer pointer. */ + // _tx_timer_current_ptr++; + + ADD r0, r0, #4 // Move to next timer + + /* Check for wrap-around. */ + // if (_tx_timer_current_ptr == _tx_timer_list_end) + + LDR r3, =_tx_timer_list_end // Pickup addr of timer list end + LDR r2, [r3, #0] // Pickup list end + CMP r0, r2 // Are we at list end? + BNE __tx_timer_skip_wrap // No, skip wrap-around logic + + /* Wrap to beginning of list. */ + // _tx_timer_current_ptr = _tx_timer_list_start; + + LDR r3, =_tx_timer_list_start // Pickup addr of timer list start + LDR r0, [r3, #0] // Set current pointer to list start + +__tx_timer_skip_wrap: + + STR r0, [r1, #0] // Store new current timer pointer + // } + +__tx_timer_done: + + /* See if anything has expired. */ + // if ((_tx_timer_expired_time_slice) || (_tx_timer_expired)) + // { + + LDR r3, =_tx_timer_expired_time_slice // Pickup addr of expired flag + LDR r2, [r3, #0] // Pickup time-slice expired flag + CBNZ r2, __tx_something_expired // Did a time-slice expire? + // If non-zero, time-slice expired + LDR r1, =_tx_timer_expired // Pickup addr of other expired flag + LDR r0, [r1, #0] // Pickup timer expired flag + CBZ r0, __tx_timer_nothing_expired // Did a timer expire? + // No, nothing expired + +__tx_something_expired: + + PUSH {r0, lr} // Save the lr register on the stack + // and save r0 just to keep 8-byte alignment + + /* Did a timer expire? */ + // if (_tx_timer_expired) + // { + + LDR r1, =_tx_timer_expired // Pickup addr of expired flag + LDR r0, [r1, #0] // Pickup timer expired flag + CBZ r0, __tx_timer_dont_activate // Check for timer expiration + // If not set, skip timer activation + + /* Process timer expiration. */ + // _tx_timer_expiration_process(); + + BL _tx_timer_expiration_process // Call the timer expiration handling routine + + // } +__tx_timer_dont_activate: + + /* Did time slice expire? */ + // if (_tx_timer_expired_time_slice) + // { + + LDR r3, =_tx_timer_expired_time_slice // Pickup addr of time-slice expired + LDR r2, [r3, #0] // Pickup the actual flag + CBZ r2, __tx_timer_not_ts_expiration // See if the flag is set + // No, skip time-slice processing + + /* Time slice interrupted thread. */ + // _tx_thread_time_slice(); + + BL _tx_thread_time_slice // Call time-slice processing + LDR r0, =_tx_thread_preempt_disable // Build address of preempt disable flag + LDR r1, [r0] // Is the preempt disable flag set? + CBNZ r1, __tx_timer_skip_time_slice // Yes, skip the PendSV logic + LDR r0, =_tx_thread_current_ptr // Build current thread pointer address + LDR r1, [r0] // Pickup the current thread pointer + LDR r2, =_tx_thread_execute_ptr // Build execute thread pointer address + LDR r3, [r2] // Pickup the execute thread pointer + LDR r0, =0xE000ED04 // Build address of control register + LDR r2, =0x10000000 // Build value for PendSV bit + CMP r1, r3 // Are they the same? + BEQ __tx_timer_skip_time_slice // If the same, there was no time-slice performed + STR r2, [r0] // Not the same, issue the PendSV for preemption +__tx_timer_skip_time_slice: + // } + +__tx_timer_not_ts_expiration: + + POP {r0, lr} // Recover lr register (r0 is just there for + // the 8-byte stack alignment + + // } + +__tx_timer_nothing_expired: + + DSB // Complete all memory access + BX lr // Return to caller +// } + .end diff --git a/ports_arch/ARMv8-M/threadx/gnu/src/txe_thread_secure_stack_allocate.c b/ports_arch/ARMv8-M/threadx/gnu/src/txe_thread_secure_stack_allocate.c new file mode 100644 index 00000000..caa47139 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/gnu/src/txe_thread_secure_stack_allocate.c @@ -0,0 +1,119 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_initialize.h" +#include "tx_thread.h" + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_secure_stack_allocate Cortex-Mxx */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the secure stack allocate */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* stack_size Size of secure stack to */ +/* allocate */ +/* */ +/* OUTPUT */ +/* */ +/* TX_THREAD_ERROR Invalid thread pointer */ +/* TX_CALLER_ERROR Invalid caller of function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_secure_stack_allocate Actual stack alloc function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* */ +/**************************************************************************/ +UINT _txe_thread_secure_stack_allocate(TX_THREAD *thread_ptr, ULONG stack_size) +{ +#if defined(TX_SINGLE_MODE_SECURE) || defined(TX_SINGLE_MODE_NON_SECURE) + return(TX_FEATURE_NOT_ENABLED); +#else +UINT status; + + /* Default status to success. */ + status = TX_SUCCESS; + + /* Check for an invalid thread pointer. */ + if (thread_ptr == TX_NULL) + { + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Now check for invalid thread ID. */ + else if (thread_ptr -> tx_thread_id != TX_THREAD_ID) + { + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Check for interrupt call. */ + if (TX_THREAD_GET_SYSTEM_STATE() != ((ULONG) 0)) + { + /* Is call from an interrupt and not initialization? */ + if (TX_THREAD_GET_SYSTEM_STATE() < TX_INITIALIZE_IN_PROGRESS) + { + /* Invalid caller of this function, return appropriate error code. */ + status = TX_CALLER_ERROR; + } + } + + /* Determine if everything is okay. */ + if (status == TX_SUCCESS) + { + /* Call actual secure stack allocate function. */ + status = _tx_thread_secure_stack_allocate(thread_ptr, stack_size); + } + + /* Return completion status. */ + return(status); +#endif +} diff --git a/ports_arch/ARMv8-M/threadx/gnu/src/txe_thread_secure_stack_free.c b/ports_arch/ARMv8-M/threadx/gnu/src/txe_thread_secure_stack_free.c new file mode 100644 index 00000000..0e1efcf4 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/gnu/src/txe_thread_secure_stack_free.c @@ -0,0 +1,120 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_initialize.h" +#include "tx_thread.h" + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_secure_stack_free Cortex-Mxx */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the secure stack free */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* */ +/* OUTPUT */ +/* */ +/* TX_THREAD_ERROR Invalid thread pointer */ +/* TX_CALLER_ERROR Invalid caller of function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_secure_stack_free Actual stack free function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* */ +/**************************************************************************/ +UINT _txe_thread_secure_stack_free(TX_THREAD *thread_ptr) +{ +#if defined(TX_SINGLE_MODE_SECURE) || defined(TX_SINGLE_MODE_NON_SECURE) + return(TX_FEATURE_NOT_ENABLED); +#else +UINT status; + + /* Default status to success. */ + status = TX_SUCCESS; + + /* Check for an invalid thread pointer. */ + if (thread_ptr == TX_NULL) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Now check for invalid thread ID. */ + else if (thread_ptr -> tx_thread_id != TX_THREAD_ID) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Check for interrupt call. */ + if (TX_THREAD_GET_SYSTEM_STATE() != ((ULONG) 0)) + { + /* Is call from an interrupt and not initialization? */ + if (TX_THREAD_GET_SYSTEM_STATE() < TX_INITIALIZE_IN_PROGRESS) + { + /* Invalid caller of this function, return appropriate error code. */ + status = TX_CALLER_ERROR; + } + } + + /* Determine if everything is okay. */ + if (status == TX_SUCCESS) + { + + /* Call actual secure stack allocate function. */ + status = _tx_thread_secure_stack_free(thread_ptr); + } + + /* Return completion status. */ + return(status); +#endif +} diff --git a/ports_arch/ARMv8-M/threadx/iar/readme_threadx.txt b/ports_arch/ARMv8-M/threadx/iar/readme_threadx.txt new file mode 100644 index 00000000..122b41ef --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/iar/readme_threadx.txt @@ -0,0 +1,221 @@ + Microsoft's Azure RTOS ThreadX for Cortex-Mxx + + Using the IAR Tools + + +1. Building the ThreadX run-time Library + +Import all ThreadX common and port-specific source files into an IAR project. +Configure the project to build a library rather than an executable. This +results in the ThreadX run-time library file tx.a, which is needed by +the application. +Files tx_thread_stack_error_handler.c and tx_thread_stack_error_notify.c +replace the common files of the same name. + +2. Demonstration System + +No demonstration is provided because the IAR EWARM 8.50 simulator does +not simulate the Cortex-Mxx correctly. + + +3. System Initialization + +The entry point in ThreadX for the Cortex-Mxx using IAR tools is at label +__iar_program_start. This is defined within the IAR compiler's startup code. +In addition, this is where all static and global preset C variable +initialization processing takes place. + +The ThreadX tx_initialize_low_level.s file is responsible for setting up +various system data structures, and a periodic timer interrupt source. + +The _tx_initialize_low_level function inside of tx_initialize_low_level.s +also determines the first available address for use by the application, which +is supplied as the sole input parameter to your application definition function, +tx_application_define. To accomplish this, a section is created in +tx_initialize_low_level.s called FREE_MEM, which must be located after all +other RAM sections in memory. + + +4. Register Usage and Stack Frames + +The following defines the saved context stack frames for context switches +that occur as a result of interrupt handling or from thread-level API calls. +All suspended threads have the same stack frame in the Cortex-Mxx version of +ThreadX. The top of the suspended thread's stack is pointed to by +tx_thread_stack_ptr in the associated thread control block TX_THREAD. + +Non-FPU Stack Frame: + + Stack Offset Stack Contents + + 0x00 LR Interrupted LR (LR at time of PENDSV) + 0x04 r4 Software stacked GP registers + 0x08 r5 + 0x0C r6 + 0x10 r7 + 0x14 r8 + 0x18 r9 + 0x1C r10 + 0x20 r11 + 0x24 r0 Hardware stacked registers + 0x28 r1 + 0x2C r2 + 0x30 r3 + 0x34 r12 + 0x38 lr + 0x3C pc + 0x40 xPSR + +FPU Stack Frame (only interrupted thread with FPU enabled): + + Stack Offset Stack Contents + + 0x00 LR Interrupted LR (LR at time of PENDSV) + 0x04 s16 Software stacked FPU registers + 0x08 s17 + 0x0C s18 + 0x10 s19 + 0x14 s20 + 0x18 s21 + 0x1C s22 + 0x20 s23 + 0x24 s24 + 0x28 s25 + 0x2C s26 + 0x30 s27 + 0x34 s28 + 0x38 s29 + 0x3C s30 + 0x40 s31 + 0x44 r4 Software stacked registers + 0x48 r5 + 0x4C r6 + 0x50 r7 + 0x54 r8 + 0x58 r9 + 0x5C r10 + 0x60 r11 + 0x64 r0 Hardware stacked registers + 0x68 r1 + 0x6C r2 + 0x70 r3 + 0x74 r12 + 0x78 lr + 0x7C pc + 0x80 xPSR + 0x84 s0 Hardware stacked FPU registers + 0x88 s1 + 0x8C s2 + 0x90 s3 + 0x94 s4 + 0x98 s5 + 0x9C s6 + 0xA0 s7 + 0xA4 s8 + 0xA8 s9 + 0xAC s10 + 0xB0 s11 + 0xB4 s12 + 0xB8 s13 + 0xBC s14 + 0xC0 s15 + 0xC4 fpscr + + +5. Improving Performance + +To make ThreadX and the application(s) run faster, you can enable +all compiler optimizations. + +In addition, you can eliminate the ThreadX basic API error checking by +compiling your application code with the symbol TX_DISABLE_ERROR_CHECKING +defined. + + +6. Interrupt Handling + +The Cortex-Mxx vectors start at the label __vector_table and is typically defined in a +startup.s file (or similar). The application may modify the vector area according to its needs. + + +6.1 Managed Interrupts + +ISRs for Cortex-M using the IAR tools can be written completely in C (or assembly +language) without any calls to _tx_thread_context_save or _tx_thread_context_restore. +These ISRs are allowed access to the ThreadX API that is available to ISRs. + +ISRs written in C will take the form (where "your_C_isr" is an entry in the vector table): + +void your_C_isr(void) +{ + + /* ISR processing goes here, including any needed function calls. */ +} + +ISRs written in assembly language will take the form: + + PUBLIC your_assembly_isr +your_assembly_isr: + + PUSH {r0, lr} + + ; ISR processing goes here, including any needed function calls. + + POP {r0, lr} + BX lr + + +7. IAR Thread-safe Library Support + +Thread-safe support for the IAR tools is easily enabled by building the ThreadX library +and the application with TX_ENABLE_IAR_LIBRARY_SUPPORT. Also, the linker control file +should have the following line added (if not already in place): + +initialize by copy with packing = none { section __DLIB_PERTHREAD }; // Required in a multi-threaded application + + +7. IAR Thread-safe Library Support + +Thread-safe support for the IAR tools is easily enabled by building the ThreadX library +and the application with TX_ENABLE_IAR_LIBRARY_SUPPORT. Also, the linker control file +should have the following line added (if not already in place): + +initialize by copy with packing = none { section __DLIB_PERTHREAD }; // Required in a multi-threaded application + +The project options "General Options -> Library Configuration" should also have the +"Enable thread support in library" box selected. + + +8. VFP Support + +ThreadX for Cortex-Mxx supports automatic ("lazy") VFP support, which means that applications threads +can simply use the VFP and ThreadX automatically maintains the VFP registers as part of the thread +context. + + +9. Revision History + +For generic code revision information, please refer to the readme_threadx_generic.txt +file, which is included in your distribution. The following details the revision +information associated with this specific port of ThreadX: + +06-02-2021 Release 6.1.7 changes: + tx_thread_secure_stack_initialize.s New file + tx_thread_schedule.s Added secure stack initialize to SVC hander + tx_thread_secure_stack.c Fixed stack pointer save, initialize in handler mode + +04-02-2021 Release 6.1.6 changes: + tx_port.h Updated macro definition + tx_thread_schedule.s Added low power support + +03-02-2021 The following files were changed/added for version 6.1.5: + tx_port.h Added ULONG64_DEFINED + +09-30-2020 Initial ThreadX 6.1 version for Cortex-Mxx using IAR's ARM tools. + + +Copyright(c) 1996-2020 Microsoft Corporation + + +https://azure.com/rtos + diff --git a/ports_arch/ARMv8-M/threadx/iar/src/tx_iar.c b/ports_arch/ARMv8-M/threadx/iar/src/tx_iar.c new file mode 100644 index 00000000..dd719370 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/iar/src/tx_iar.c @@ -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 is included with the following code segments: + +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#include +#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 + + +#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 is included with the following code segments: + +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#include +#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 + + +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 /* 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. */ diff --git a/ports_arch/ARMv8-M/threadx/iar/src/tx_initialize_low_level.s b/ports_arch/ARMv8-M/threadx/iar/src/tx_initialize_low_level.s new file mode 100644 index 00000000..7580309e --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/iar/src/tx_initialize_low_level.s @@ -0,0 +1,237 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Initialize */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + EXTERN _tx_thread_system_stack_ptr + EXTERN _tx_initialize_unused_memory + EXTERN _tx_timer_interrupt + EXTERN __main + EXTERN __vector_table + EXTERN _tx_thread_current_ptr + EXTERN _tx_thread_stack_error_handler + +SYSTEM_CLOCK EQU 96000000 +SYSTICK_CYCLES EQU ((SYSTEM_CLOCK / 100) -1) + + RSEG FREE_MEM:DATA + PUBLIC __tx_free_memory_start +__tx_free_memory_start + DS32 4 + + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_initialize_low_level Cortex-Mxx/IAR */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for any low-level processor */ +/* initialization, including setting up interrupt vectors, setting */ +/* up a periodic timer interrupt source, saving the system stack */ +/* pointer for use in ISR processing later, and finding the first */ +/* available RAM memory address for tx_application_define. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_initialize_kernel_enter ThreadX entry function */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_initialize_low_level(VOID) +// { + PUBLIC _tx_initialize_low_level +_tx_initialize_low_level: + + /* Disable interrupts during ThreadX initialization. */ + CPSID i + + /* Set base of available memory to end of non-initialised RAM area. */ + LDR r0, =_tx_initialize_unused_memory // Build address of unused memory pointer + LDR r1, =__tx_free_memory_start // Build first free address + STR r1, [r0] // Setup first unused memory pointer + + /* Setup Vector Table Offset Register. */ + MOV r0, #0xE000E000 // Build address of NVIC registers + LDR r1, =__vector_table // Pickup address of vector table + STR r1, [r0, #0xD08] // Set vector table address + + /* Enable the cycle count register. */ +// LDR r0, =0xE0001000 // Build address of DWT register +// LDR r1, [r0] // Pickup the current value +// ORR r1, r1, #1 // Set the CYCCNTENA bit +// STR r1, [r0] // Enable the cycle count register + + /* Set system stack pointer from vector value. */ + LDR r0, =_tx_thread_system_stack_ptr // Build address of system stack pointer + LDR r1, =__vector_table // Pickup address of vector table + LDR r1, [r1] // Pickup reset stack pointer + STR r1, [r0] // Save system stack pointer + + /* Configure SysTick. */ + MOV r0, #0xE000E000 // Build address of NVIC registers + LDR r1, =SYSTICK_CYCLES + STR r1, [r0, #0x14] // Setup SysTick Reload Value + MOV r1, #0x7 // Build SysTick Control Enable Value + STR r1, [r0, #0x10] // Setup SysTick Control + + /* Configure handler priorities. */ + LDR r1, =0x00000000 // Rsrv, UsgF, BusF, MemM + STR r1, [r0, #0xD18] // Setup System Handlers 4-7 Priority Registers + LDR r1, =0xFF000000 // SVCl, Rsrv, Rsrv, Rsrv + STR r1, [r0, #0xD1C] // Setup System Handlers 8-11 Priority Registers + // Note: SVC must be lowest priority, which is 0xFF + LDR r1, =0x40FF0000 // SysT, PnSV, Rsrv, DbgM + STR r1, [r0, #0xD20] // Setup System Handlers 12-15 Priority Registers + // Note: PnSV must be lowest priority, which is 0xFF + + /* Return to caller. */ + BX lr +// } + + +/* Define shells for each of the unused vectors. */ + + PUBLIC __tx_BadHandler +__tx_BadHandler: + B __tx_BadHandler + + + PUBLIC __tx_IntHandler +__tx_IntHandler: +// VOID InterruptHandler (VOID) +// { + PUSH {r0,lr} // Save LR (and dummy r0 to maintain stack alignment) +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + BL _tx_execution_isr_enter // Call the ISR enter function +#endif + /* Do interrupt handler work here */ + /* .... */ +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + BL _tx_execution_isr_exit // Call the ISR exit function +#endif + POP {r0,lr} + BX lr +// } + + + PUBLIC __tx_SysTickHandler + PUBLIC SysTick_Handler +SysTick_Handler: +__tx_SysTickHandler: +// VOID TimerInterruptHandler (VOID) +// { + PUSH {r0,lr} // Save LR (and dummy r0 to maintain stack alignment) +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + BL _tx_execution_isr_enter // Call the ISR enter function +#endif + BL _tx_timer_interrupt +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + BL _tx_execution_isr_exit // Call the ISR exit function +#endif + POP {r0,lr} + BX lr +// } + + PUBLIC HardFault_Handler +HardFault_Handler: + B HardFault_Handler + + + PUBLIC UsageFault_Handler +UsageFault_Handler: + CPSID i // Disable interrupts + // Check for stack limit fault + LDR r0, =0xE000ED28 // CFSR address + LDR r1,[r0] // Pick up CFSR + TST r1, #0x00100000 // Check for Stack Overflow +_unhandled_usage_loop + BEQ _unhandled_usage_loop // If not stack overflow then loop + + // Handle stack overflow + STR r1, [r0] // Clear CFSR flag(s) + +#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 + + LDR r0, =_tx_thread_current_ptr // Build current thread pointer address + LDR r0,[r0] // Pick up current thread pointer + PUSH {r0,lr} // Save LR (and r0 to maintain stack alignment) + BL _tx_thread_stack_error_handler // Call ThreadX/user handler + POP {r0,lr} // Restore LR and dummy reg + +#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. + 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 +#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 UsageFault_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 + CPSIE i // Enable interrupts + BX lr // Return from exception + + + PUBLIC __tx_NMIHandler +__tx_NMIHandler: + B __tx_NMIHandler + + + PUBLIC __tx_DBGHandler +__tx_DBGHandler: + B __tx_DBGHandler + + END diff --git a/ports_arch/ARMv8-M/threadx/iar/src/tx_misra.s b/ports_arch/ARMv8-M/threadx/iar/src/tx_misra.s new file mode 100644 index 00000000..ab3fef69 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/iar/src/tx_misra.s @@ -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 diff --git a/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_context_restore.s b/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_context_restore.s new file mode 100644 index 00000000..6e4fa971 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_context_restore.s @@ -0,0 +1,77 @@ +/**************************************************************************/ +/* */ +/* 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_execution_isr_exit + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_restore Cortex-Mxx/IAR */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is not needed for Cortex-M. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* [_tx_execution_isr_exit] Execution profiling ISR exit */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs Interrupt Service Routines */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_context_restore(VOID) +// { + PUBLIC _tx_thread_context_restore +_tx_thread_context_restore: + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the ISR exit function to indicate an ISR is complete. */ + PUSH {r0, lr} // Save return address + BL _tx_execution_isr_exit // Call the ISR exit function + POP {r0, lr} // Recover return address +#endif + + BX lr +// } + END diff --git a/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_context_save.s b/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_context_save.s new file mode 100644 index 00000000..d05bf887 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_context_save.s @@ -0,0 +1,77 @@ +/**************************************************************************/ +/* */ +/* 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_execution_isr_enter + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_save Cortex-Mxx/IAR */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is not needed for Cortex-M. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* [_tx_execution_isr_enter] Execution profiling ISR enter */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_context_save(VOID) +// { + PUBLIC _tx_thread_context_save +_tx_thread_context_save: + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the ISR enter function to indicate an ISR is starting. */ + PUSH {r0, lr} // Save return address + BL _tx_execution_isr_enter // Call the ISR enter function + POP {r0, lr} // Recover return address +#endif + + BX lr +// } + END diff --git a/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_interrupt_control.s b/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_interrupt_control.s new file mode 100644 index 00000000..6f0e66a3 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_interrupt_control.s @@ -0,0 +1,78 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_control Cortex-Mxx/IAR */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for changing the interrupt lockout */ +/* posture of the system. */ +/* */ +/* INPUT */ +/* */ +/* new_posture New interrupt lockout posture */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_interrupt_control(UINT new_posture) +// { + PUBLIC _tx_thread_interrupt_control +_tx_thread_interrupt_control: +#ifdef TX_PORT_USE_BASEPRI + MRS r1, BASEPRI // Pickup current interrupt posture + MSR BASEPRI, r0 // Apply the new interrupt posture + MOV r0, r1 // Transfer old to return register +#else + MRS r1, PRIMASK // Pickup current interrupt lockout + MSR PRIMASK, r0 // Apply the new interrupt lockout + MOV r0, r1 // Transfer old to return register +#endif + BX lr // Return to caller +// } + END diff --git a/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_interrupt_disable.s b/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_interrupt_disable.s new file mode 100644 index 00000000..d2809173 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_interrupt_disable.s @@ -0,0 +1,78 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_disable Cortex-Mxx/IAR */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for disabling interrupts and returning */ +/* the previous interrupt lockout posture. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_interrupt_disable(VOID) +// { + PUBLIC _tx_thread_interrupt_disable +_tx_thread_interrupt_disable: + /* Return current interrupt lockout posture. */ +#ifdef TX_PORT_USE_BASEPRI + MRS r0, BASEPRI + LDR r1, =TX_PORT_BASEPRI + MSR BASEPRI, r1 +#else + MRS r0, PRIMASK + CPSID i +#endif + BX lr +// } + END diff --git a/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_interrupt_restore.s b/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_interrupt_restore.s new file mode 100644 index 00000000..cdc493f8 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_interrupt_restore.s @@ -0,0 +1,75 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_restore Cortex-Mxx/IAR */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for restoring the previous */ +/* interrupt lockout posture. */ +/* */ +/* INPUT */ +/* */ +/* previous_posture Previous interrupt posture */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_interrupt_restore(UINT previous_posture) +// { + PUBLIC _tx_thread_interrupt_restore +_tx_thread_interrupt_restore: + /* Restore previous interrupt lockout posture. */ +#ifdef TX_PORT_USE_BASEPRI + MSR BASEPRI, r0 +#else + MSR PRIMASK, r0 +#endif + BX lr +// } + END diff --git a/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_schedule.s b/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_schedule.s new file mode 100644 index 00000000..7bcebb6c --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_schedule.s @@ -0,0 +1,383 @@ +/**************************************************************************/ +/* */ +/* 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_thread_system_stack_ptr + EXTERN _tx_thread_preempt_disable + EXTERN _tx_execution_thread_enter + EXTERN _tx_execution_thread_exit + EXTERN _tx_thread_secure_stack_context_restore + EXTERN _tx_thread_secure_stack_context_save + EXTERN _tx_thread_secure_mode_stack_allocate + EXTERN _tx_thread_secure_mode_stack_free + EXTERN _tx_thread_secure_mode_stack_initialize +#ifdef TX_LOW_POWER + EXTERN tx_low_power_enter + EXTERN tx_low_power_exit +#endif + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_schedule Cortex-Mxx/IAR */ +/* 6.2.1 */ +/* 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 */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 04-02-2021 Scott Larson Modified comment(s), added */ +/* low power code, */ +/* resulting in version 6.1.6 */ +/* 06-02-2021 Scott Larson Added secure stack initialize */ +/* in SVC handler, */ +/* resulting in version 6.1.7 */ +/* 04-25-2022 Scott Larson Added BASEPRI support, */ +/* resulting in version 6.1.11 */ +/* 03-08-2023 Scott Larson Added preproc FPU option, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// 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 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 +// } + + /* Generic context switching PendSV handler. */ + + PUBLIC PendSV_Handler +PendSV_Handler: +__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 + STR r12, [r1, #8] // Save the thread stack pointer + +#if (!defined(TX_SINGLE_MODE_SECURE) && !defined(TX_SINGLE_MODE_NON_SECURE)) + // Save secure context + LDR r5, [r1,#0x90] // Load secure stack index + CBZ r5, _skip_secure_save // Skip save if there is no secure context + PUSH {r0,r1,r2,r3} // Save scratch registers + MOV r0, r1 // Move thread ptr to r0 + BL _tx_thread_secure_stack_context_save // Save secure stack + POP {r0,r1,r2,r3} // Restore secure registers +_skip_secure_save: +#endif + + /* Determine if time-slice is active. If it isn't, skip time handling processing. */ + + LDR r5, [r4] // Pickup current time-slice + 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? + CBZ r1, __tx_ts_wait // No, skip to the wait processing + + /* Yes, another thread is ready for else, make the current thread the new thread. */ + + 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. */ + +__tx_ts_restore: + 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 + +#if (!defined(TX_SINGLE_MODE_SECURE) && !defined(TX_SINGLE_MODE_NON_SECURE)) + // Restore secure context + LDR r0, [r1,#0x90] // Load secure stack index + CBZ r0, _skip_secure_restore // Skip restore if there is no secure context + PUSH {r0,r1} // Save r1 (and dummy r0) + MOV r0, r1 // Move thread ptr to r0 + BL _tx_thread_secure_stack_context_restore // Restore secure stack + POP {r0,r1} // Restore r1 (and dummy r0) +_skip_secure_restore: +#endif + + /* Restore the thread context and PSP. */ + LDR r12, [r1, #12] // Get stack start + MSR PSPLIM, r12 // Set stack limit + LDR r12, [r1, #8] // Pickup thread's stack pointer + 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 + + BX lr // Return to thread! + + /* 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 + STR r1, [r0] // Store it in the current 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 + + /* Re-enable interrupts and restore new thread. */ +#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_restore // Restore the thread +// } + + +#if (!defined(TX_SINGLE_MODE_SECURE) && !defined(TX_SINGLE_MODE_NON_SECURE)) + // SVC_Handler is not needed when ThreadX is running in single mode. + PUBLIC SVC_Handler +SVC_Handler: + TST lr, #0x04 // Determine return stack from EXC_RETURN bit 2 + ITE EQ + MRSEQ r0, MSP // Get MSP if return stack is MSP + MRSNE r0, PSP // Get PSP if return stack is PSP + + LDR r1, [r0,#24] // Load saved PC from stack + LDRB r1, [r1,#-2] // Load SVC number + + CMP r1, #1 // Is it a secure stack allocate request? + BEQ _tx_svc_secure_alloc // Yes, go there + + CMP r1, #2 // Is it a secure stack free request? + BEQ _tx_svc_secure_free // Yes, go there + + CMP r1, #3 // Is it a secure stack init request? + BEQ _tx_svc_secure_init // Yes, go there + + // Unknown SVC argument - just return + BX lr + +_tx_svc_secure_alloc: + PUSH {r0,lr} // Save SP and EXC_RETURN + LDM r0, {r0-r3} // Load function parameters from stack + BL _tx_thread_secure_mode_stack_allocate + POP {r12,lr} // Restore SP and EXC_RETURN + STR r0,[r12] // Store function return value + BX lr +_tx_svc_secure_free: + PUSH {r0,lr} // Save SP and EXC_RETURN + LDM r0, {r0-r3} // Load function parameters from stack + BL _tx_thread_secure_mode_stack_free + POP {r12,lr} // Restore SP and EXC_RETURN + STR r0,[r12] // Store function return value + BX lr +_tx_svc_secure_init: + PUSH {r0,lr} // Save SP and EXC_RETURN + BL _tx_thread_secure_mode_stack_initialize + POP {r12,lr} // Restore SP and EXC_RETURN + BX lr +#endif // End of ifndef TX_SINGLE_MODE_SECURE, TX_SINGLE_MODE_NON_SECURE + + + PUBLIC _tx_vfp_access +_tx_vfp_access: +#ifdef __ARMVFP__ + VMOV.F32 s0, s0 // Simply access the VFP +#endif + BX lr // Return to caller + END diff --git a/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_secure_stack.c b/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_secure_stack.c new file mode 100644 index 00000000..2a2548ff --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_secure_stack.c @@ -0,0 +1,597 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +#include "tx_api.h" + +/* If TX_SINGLE_MODE_SECURE or TX_SINGLE_MODE_NON_SECURE is defined, + no secure stack functionality is needed. */ +#if !defined(TX_SINGLE_MODE_SECURE) && !defined(TX_SINGLE_MODE_NON_SECURE) + +#define TX_SOURCE_CODE + +#include /* For intrinsic functions. */ +#include "tx_secure_interface.h" /* Interface for NS code. */ + +/* Minimum size of secure stack. */ +#ifndef TX_THREAD_SECURE_STACK_MINIMUM +#define TX_THREAD_SECURE_STACK_MINIMUM 256 +#endif +/* Maximum size of secure stack. */ +#ifndef TX_THREAD_SECURE_STACK_MAXIMUM +#define TX_THREAD_SECURE_STACK_MAXIMUM 1024 +#endif + +/* 8 bytes added to stack size to "seal" stack. */ +#define TX_THREAD_STACK_SEAL_SIZE 8 +#define TX_THREAD_STACK_SEAL_VALUE 0xFEF5EDA5 + +/* max number of Secure context */ +#ifndef TX_MAX_SECURE_CONTEXTS +#define TX_MAX_SECURE_CONTEXTS 32 +#endif +#define TX_INVALID_SECURE_CONTEXT_IDX (-1) + +/* Secure stack info struct to hold stack start, stack limit, + current stack pointer, and pointer to owning thread. + This will be allocated for each thread with a secure stack. */ +typedef struct TX_THREAD_SECURE_STACK_INFO_STRUCT +{ + VOID *tx_thread_secure_stack_ptr; /* Thread's secure stack current pointer */ + VOID *tx_thread_secure_stack_start; /* Thread's secure stack start address */ + VOID *tx_thread_secure_stack_limit; /* Thread's secure stack limit */ + TX_THREAD *tx_thread_ptr; /* Keep track of thread for error handling */ + INT tx_next_free_index; /* Next free index of free secure context */ +} TX_THREAD_SECURE_STACK_INFO; + +/* Static secure contexts */ +static TX_THREAD_SECURE_STACK_INFO tx_thread_secure_context[TX_MAX_SECURE_CONTEXTS]; +/* Head of free secure context */ +static INT tx_head_free_index = 0U; + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_secure_mode_stack_initialize Cortex-Mxx/IAR */ +/* 6.1.10 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function initializes secure mode to use PSP stack. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* status */ +/* */ +/* CALLS */ +/* */ +/* __get_CONTROL Intrinsic to get CONTROL */ +/* __set_CONTROL Intrinsic to set CONTROL */ +/* __set_PSPLIM Intrinsic to set PSP limit */ +/* __set_PSP Intrinsic to set PSP */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_initialize_kernel_enter */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 10-16-2020 Scott Larson Modified comment(s), */ +/* resulting in version 6.1.1 */ +/* 06-02-2021 Scott Larson Change name, execute in */ +/* handler mode, */ +/* resulting in version 6.1.7 */ +/* 01-31-2022 Himanshu Gupta Modified comments(s), updated */ +/* secure stack allocation, */ +/* resulting in version 6.1.10 */ +/* */ +/**************************************************************************/ +__attribute__((cmse_nonsecure_entry)) +UINT _tx_thread_secure_mode_stack_initialize(void) +{ +UINT status; +INT index; + + /* Make sure function is called from interrupt (threads should not call). */ + if (__get_IPSR() == 0) + { + status = TX_CALLER_ERROR; + } + else + { + /* Set secure mode to use PSP. */ + __set_CONTROL(__get_CONTROL() | 2); + + /* Set process stack pointer and stack limit to 0 to throw exception when a thread + without a secure stack calls a secure function that tries to use secure stack. */ + __set_PSPLIM(0); + __set_PSP(0); + + for (index = 0; index < TX_MAX_SECURE_CONTEXTS; index++) + { + + /* Check last index and mark next free to invalid index */ + if(index == (TX_MAX_SECURE_CONTEXTS - 1)) + { + tx_thread_secure_context[index].tx_next_free_index = TX_INVALID_SECURE_CONTEXT_IDX; + } + else + { + tx_thread_secure_context[index].tx_next_free_index = index + 1; + } + } + + status = TX_SUCCESS; + } + return status; +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_secure_mode_stack_allocate Cortex-Mxx/IAR */ +/* 6.1.11a */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function allocates a thread's secure stack. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* stack_size Size of stack to allocates */ +/* */ +/* OUTPUT */ +/* */ +/* TX_THREAD_ERROR Invalid thread pointer */ +/* TX_SIZE_ERROR Invalid stack size */ +/* TX_CALLER_ERROR Invalid caller of function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* __get_IPSR Intrinsic to get IPSR */ +/* malloc Compiler's malloc function */ +/* __set_PSPLIM Intrinsic to set PSP limit */ +/* __set_PSP Intrinsic to set PSP */ +/* __TZ_get_PSPLIM_NS Intrinsic to get NS PSP */ +/* */ +/* CALLED BY */ +/* */ +/* SVC Handler */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 10-16-2020 Scott Larson Modified comment(s), */ +/* added stack sealing, */ +/* resulting in version 6.1.1 */ +/* 01-31-2022 Himanshu Gupta Modified comments(s), updated */ +/* secure stack allocation, */ +/* resulting in version 6.1.10 */ +/* 05-02-2022 Scott Larson Modified comment(s), added */ +/* TX_INTERRUPT_SAVE_AREA, */ +/* resulting in version 6.1.11a*/ +/* */ +/**************************************************************************/ +__attribute__((cmse_nonsecure_entry)) +UINT _tx_thread_secure_mode_stack_allocate(TX_THREAD *thread_ptr, ULONG stack_size) +{ +TX_INTERRUPT_SAVE_AREA +UINT status; +TX_THREAD_SECURE_STACK_INFO *info_ptr; +UCHAR *stack_mem; +INT secure_context_index; + + status = TX_SUCCESS; + + /* Make sure function is called from interrupt (threads should not call). */ + if (__get_IPSR() == 0) + { + status = TX_CALLER_ERROR; + } + else if (stack_size < TX_THREAD_SECURE_STACK_MINIMUM || stack_size > TX_THREAD_SECURE_STACK_MAXIMUM) + { + status = TX_SIZE_ERROR; + } + + /* Check if thread already has secure stack allocated. */ + else if (thread_ptr -> tx_thread_secure_stack_context != 0) + { + status = TX_THREAD_ERROR; + } + + else + { + TX_DISABLE + + /* Allocate free index for secure stack info. */ + if(tx_head_free_index != TX_INVALID_SECURE_CONTEXT_IDX) + { + secure_context_index = tx_head_free_index; + tx_head_free_index = tx_thread_secure_context[tx_head_free_index].tx_next_free_index; + tx_thread_secure_context[secure_context_index].tx_next_free_index = TX_INVALID_SECURE_CONTEXT_IDX; + } + else + { + secure_context_index = TX_INVALID_SECURE_CONTEXT_IDX; + } + + TX_RESTORE + + if(secure_context_index != TX_INVALID_SECURE_CONTEXT_IDX) + { + info_ptr = &tx_thread_secure_context[secure_context_index]; + + /* If stack info allocated, allocate a stack & seal. */ + stack_mem = malloc(stack_size + TX_THREAD_STACK_SEAL_SIZE); + + if(stack_mem != TX_NULL) + { + /* Secure stack has been allocated, save in the stack info struct. */ + info_ptr -> tx_thread_secure_stack_limit = stack_mem; + info_ptr -> tx_thread_secure_stack_start = stack_mem + stack_size; + info_ptr -> tx_thread_secure_stack_ptr = info_ptr -> tx_thread_secure_stack_start; + info_ptr -> tx_thread_ptr = thread_ptr; + + /* Seal bottom of stack. */ + *(ULONG*)info_ptr -> tx_thread_secure_stack_start = TX_THREAD_STACK_SEAL_VALUE; + + /* Save secure context id (i.e non-zero base index) in thread. */ + thread_ptr -> tx_thread_secure_stack_context = (VOID *)(secure_context_index + 1); + + /* Check if this thread is running by looking at its stack start and PSPLIM_NS */ + if(((ULONG) thread_ptr -> tx_thread_stack_start & 0xFFFFFFF8) == __TZ_get_PSPLIM_NS()) + { + /* If this thread is running, set Secure PSP and PSPLIM. */ + __set_PSPLIM((ULONG)(info_ptr -> tx_thread_secure_stack_limit)); + __set_PSP((ULONG)(info_ptr -> tx_thread_secure_stack_ptr)); + } + } + + else + { + TX_DISABLE + + /* Stack not allocated, free the info struct. */ + tx_thread_secure_context[secure_context_index].tx_next_free_index = tx_head_free_index; + tx_head_free_index = secure_context_index; + TX_RESTORE + + status = TX_NO_MEMORY; + } + } + + else + { + status = TX_NO_MEMORY; + } + } + + return(status); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_secure_mode_stack_free Cortex-Mxx/IAR */ +/* 6.1.11a */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function frees a thread's secure stack. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* */ +/* OUTPUT */ +/* */ +/* TX_THREAD_ERROR Invalid thread pointer */ +/* TX_CALLER_ERROR Invalid caller of function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* __get_IPSR Intrinsic to get IPSR */ +/* free Compiler's free() function */ +/* */ +/* CALLED BY */ +/* */ +/* SVC Handler */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 10-16-2020 Scott Larson Modified comment(s), */ +/* resulting in version 6.1.1 */ +/* 01-31-2022 Himanshu Gupta Modified comments(s), updated */ +/* secure stack allocation, */ +/* resulting in version 6.1.10 */ +/* 05-02-2022 Scott Larson Modified comment(s), added */ +/* TX_INTERRUPT_SAVE_AREA, */ +/* resulting in version 6.1.11a*/ +/* */ +/**************************************************************************/ +__attribute__((cmse_nonsecure_entry)) +UINT _tx_thread_secure_mode_stack_free(TX_THREAD *thread_ptr) +{ +TX_INTERRUPT_SAVE_AREA +UINT status; +TX_THREAD_SECURE_STACK_INFO *info_ptr; +INT secure_context_index; + + status = TX_SUCCESS; + + /* Pickup stack info id from thread. */ + secure_context_index = (INT)thread_ptr -> tx_thread_secure_stack_context - 1; + + /* Make sure function is called from interrupt (threads should not call). */ + if (__get_IPSR() == 0) + { + status = TX_CALLER_ERROR; + } + + /* Check if secure context index is in valid range. */ + else if (secure_context_index < 0 || secure_context_index >= TX_MAX_SECURE_CONTEXTS) + { + status = TX_THREAD_ERROR; + } + else + { + + /* Pickup stack info from static array of secure contexts. */ + info_ptr = &tx_thread_secure_context[secure_context_index]; + + /* Check that this secure context is for this thread. */ + if (info_ptr -> tx_thread_ptr != thread_ptr) + { + status = TX_THREAD_ERROR; + } + + else + { + + /* Free secure stack. */ + free(info_ptr -> tx_thread_secure_stack_limit); + + TX_DISABLE + + /* Free info struct. */ + tx_thread_secure_context[secure_context_index].tx_next_free_index = tx_head_free_index; + tx_head_free_index = secure_context_index; + TX_RESTORE + + /* Clear secure context from thread. */ + thread_ptr -> tx_thread_secure_stack_context = 0; + } + } + + return(status); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_secure_stack_context_save Cortex-Mxx/IAR */ +/* 6.1.10 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function saves context of the secure stack. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* __get_IPSR Intrinsic to get IPSR */ +/* __get_PSP Intrinsic to get PSP */ +/* __set_PSPLIM Intrinsic to set PSP limit */ +/* __set_PSP Intrinsic to set PSP */ +/* */ +/* CALLED BY */ +/* */ +/* PendSV Handler */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 10-16-2020 Scott Larson Modified comment(s), */ +/* resulting in version 6.1.1 */ +/* 06-02-2021 Scott Larson Fix stack pointer save, */ +/* resulting in version 6.1.7 */ +/* 01-31-2022 Himanshu Gupta Modified comments(s), updated */ +/* secure stack allocation, */ +/* resulting in version 6.1.10 */ +/* */ +/**************************************************************************/ +__attribute__((cmse_nonsecure_entry)) +void _tx_thread_secure_stack_context_save(TX_THREAD *thread_ptr) +{ +TX_THREAD_SECURE_STACK_INFO *info_ptr; +ULONG sp; +INT secure_context_index = (INT)thread_ptr -> tx_thread_secure_stack_context - 1; + + /* This function should be called from scheduler only. */ + if (__get_IPSR() == 0) + { + return; + } + + /* Check if secure context index is in valid range. */ + else if (secure_context_index < 0 || secure_context_index >= TX_MAX_SECURE_CONTEXTS) + { + return; + } + + /* Pickup the secure context pointer. */ + info_ptr = &tx_thread_secure_context[secure_context_index]; + + /* Check that this secure context is for this thread. */ + if (info_ptr -> tx_thread_ptr != thread_ptr) + { + return; + } + + /* Check that stack pointer is in range */ + sp = __get_PSP(); + if ((sp < (ULONG)info_ptr -> tx_thread_secure_stack_limit) || + (sp > (ULONG)info_ptr -> tx_thread_secure_stack_start)) + { + return; + } + + /* Save stack pointer. */ + info_ptr -> tx_thread_secure_stack_ptr = (VOID *) sp; + + /* Set process stack pointer and stack limit to 0 to throw exception when a thread + without a secure stack calls a secure function that tries to use secure stack. */ + __set_PSPLIM(0); + __set_PSP(0); + + return; +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_secure_stack_context_restore Cortex-Mxx/IAR */ +/* 6.1.10 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function restores context of the secure stack. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* __get_IPSR Intrinsic to get IPSR */ +/* __set_PSPLIM Intrinsic to set PSP limit */ +/* __set_PSP Intrinsic to set PSP */ +/* */ +/* CALLED BY */ +/* */ +/* PendSV Handler */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 10-16-2020 Scott Larson Modified comment(s), */ +/* resulting in version 6.1.1 */ +/* 01-31-2022 Himanshu Gupta Modified comments(s), updated */ +/* secure stack allocation, */ +/* resulting in version 6.1.10 */ +/* */ +/**************************************************************************/ +__attribute__((cmse_nonsecure_entry)) +void _tx_thread_secure_stack_context_restore(TX_THREAD *thread_ptr) +{ +TX_THREAD_SECURE_STACK_INFO *info_ptr; +INT secure_context_index = (INT)thread_ptr -> tx_thread_secure_stack_context - 1; + + /* This function should be called from scheduler only. */ + if (__get_IPSR() == 0) + { + return; + } + + /* Check if secure context index is in valid range. */ + else if (secure_context_index < 0 || secure_context_index >= TX_MAX_SECURE_CONTEXTS) + { + return; + } + + /* Pickup the secure context pointer. */ + info_ptr = &tx_thread_secure_context[secure_context_index]; + + /* Check that this secure context is for this thread. */ + if (info_ptr -> tx_thread_ptr != thread_ptr) + { + return; + } + + /* Set stack pointer and limit. */ + __set_PSPLIM((ULONG)info_ptr -> tx_thread_secure_stack_limit); + __set_PSP ((ULONG)info_ptr -> tx_thread_secure_stack_ptr); + + return; +} + +#endif diff --git a/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_secure_stack_allocate.s b/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_secure_stack_allocate.s new file mode 100644 index 00000000..5f86bb2e --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_secure_stack_allocate.s @@ -0,0 +1,80 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_secure_stack_allocate Cortex-Mxx/IAR */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enters the SVC handler to allocate a secure stack. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* stack_size Size of secure stack to */ +/* allocate */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* SVC 1 */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_secure_stack_allocate(TX_THREAD *thread_ptr, ULONG stack_size) +// { + EXPORT _tx_thread_secure_stack_allocate +_tx_thread_secure_stack_allocate: +#if !defined(TX_SINGLE_MODE_SECURE) && !defined(TX_SINGLE_MODE_NON_SECURE) + MRS r3, PRIMASK // Save interrupt mask + CPSIE i // Enable interrupts for SVC call + SVC 1 + CMP r3, #0 // If interrupts enabled, just return + BEQ _alloc_return_interrupt_enabled + CPSID i // Otherwise, disable interrupts +#else + MOV r0, #0xFF // Feature not enabled +#endif +_alloc_return_interrupt_enabled + BX lr + END diff --git a/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_secure_stack_free.s b/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_secure_stack_free.s new file mode 100644 index 00000000..9394b62b --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_secure_stack_free.s @@ -0,0 +1,78 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_secure_stack_free Cortex-Mxx/IAR */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enters the SVC handler to free a secure stack. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* SVC 2 */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_secure_stack_free(TX_THREAD *thread_ptr) +// { + EXPORT _tx_thread_secure_stack_free +_tx_thread_secure_stack_free: +#if !defined(TX_SINGLE_MODE_SECURE) && !defined(TX_SINGLE_MODE_NON_SECURE) + MRS r3, PRIMASK // Save interrupt mask + CPSIE i // Enable interrupts for SVC call + SVC 2 + CMP r3, #0 // If interrupts enabled, just return + BEQ _free_return_interrupt_enabled + CPSID i // Otherwise, disable interrupts +#else + MOV r0, #0xFF // Feature not enabled +#endif +_free_return_interrupt_enabled + BX lr + END diff --git a/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_secure_stack_initialize.s b/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_secure_stack_initialize.s new file mode 100644 index 00000000..1c19fb50 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_secure_stack_initialize.s @@ -0,0 +1,78 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_secure_stack_initialize Cortex-Mxx/IAR */ +/* 6.1.12 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enters the SVC handler to initialize a secure stack. */ +/* */ +/* INPUT */ +/* */ +/* none */ +/* */ +/* OUTPUT */ +/* */ +/* none */ +/* */ +/* CALLS */ +/* */ +/* SVC 3 */ +/* */ +/* CALLED BY */ +/* */ +/* TX_PORT_SPECIFIC_PRE_INITIALIZATION */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 07-29-2022 Scott Larson Modified comments and changed */ +/* secure stack initialization */ +/* macro to port-specific, */ +/* resulting in version 6.1.12 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_secure_stack_initialize(VOID) +// { + EXPORT _tx_thread_secure_stack_initialize +_tx_thread_secure_stack_initialize: +#if !defined(TX_SINGLE_MODE_SECURE) && !defined(TX_SINGLE_MODE_NON_SECURE) + CPSIE i // Enable interrupts for SVC call + SVC 3 + CPSID i // Disable interrupts +#else + MOV r0, #0xFF // Feature not enabled +#endif + BX lr + END diff --git a/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_stack_build.s b/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_stack_build.s new file mode 100644 index 00000000..466afe15 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_stack_build.s @@ -0,0 +1,135 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_stack_build Cortex-Mxx/IAR */ +/* 6.1.8 */ +/* 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 control blk */ +/* function_ptr Pointer to return function */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_create Create thread service */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID)) +// { + PUBLIC _tx_thread_stack_build +_tx_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 for 8-byte alignment + SUB r2, r2, #68 // Subtract frame size +#ifdef TX_SINGLE_MODE_SECURE + LDR r3, =0xFFFFFFFD // Build initial LR value for secure mode +#else + LDR r3, =0xFFFFFFBC // Build initial LR value to return to non-secure PSP +#endif + 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, #24] // Store initial r9 + STR r3, [r2, #28] // Store initial r10 + STR r3, [r2, #32] // Store initial r11 + + /* Hardware stack follows. */ + + STR r3, [r2, #36] // Store initial r0 + STR r3, [r2, #40] // Store initial r1 + 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 diff --git a/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_system_return.s b/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_system_return.s new file mode 100644 index 00000000..0506de15 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/iar/src/tx_thread_system_return.s @@ -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 */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_system_return Cortex-Mxx/IAR */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is target processor specific. It is used to transfer */ +/* control from a thread back to the ThreadX system. Only a */ +/* minimal context is saved since the compiler assumes temp registers */ +/* are going to get slicked by a function call anyway. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_schedule Thread scheduling loop */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX components */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_system_return(VOID) +// { + PUBLIC _tx_thread_system_return +_tx_thread_system_return: + /* Return to real scheduler via PendSV. Note that this routine is often + replaced with in-line assembly in tx_port.h to improved performance. */ + + MOV r0, #0x10000000 // Load PENDSVSET bit + MOV r1, #0xE000E000 // Load NVIC base + STR r0, [r1, #0xD04] // Set PENDSVBIT in ICSR + MRS r0, IPSR // Pickup IPSR + CMP r0, #0 // Is it a thread returning? + BNE _isr_context // If ISR, skip interrupt enable +#ifdef TX_PORT_USE_BASEPRI + MRS r1, BASEPRI // Thread context returning, pickup BASEPRI + MOV r0, #0 + MSR BASEPRI, r0 // Enable interrupts + MSR BASEPRI, r1 // Restore original interrupt posture +#else + MRS r1, PRIMASK // Thread context returning, pickup PRIMASK + CPSIE i // Enable interrupts + MSR PRIMASK, r1 // Restore original interrupt posture +#endif +_isr_context: + BX lr // Return to caller +// } + END diff --git a/ports_arch/ARMv8-M/threadx/iar/src/tx_timer_interrupt.s b/ports_arch/ARMv8-M/threadx/iar/src/tx_timer_interrupt.s new file mode 100644 index 00000000..e206eba3 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/iar/src/tx_timer_interrupt.s @@ -0,0 +1,251 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + EXTERN _tx_timer_time_slice + EXTERN _tx_timer_system_clock + EXTERN _tx_timer_current_ptr + EXTERN _tx_timer_list_start + EXTERN _tx_timer_list_end + EXTERN _tx_timer_expired_time_slice + EXTERN _tx_timer_expired + EXTERN _tx_thread_time_slice + EXTERN _tx_timer_expiration_process + EXTERN _tx_thread_current_ptr + EXTERN _tx_thread_execute_ptr + EXTERN _tx_thread_preempt_disable + + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_interrupt Cortex-Mxx/IAR */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the hardware timer interrupt. This */ +/* processing includes incrementing the system clock and checking for */ +/* time slice and/or timer expiration. If either is found, the */ +/* expiration functions are called. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_timer_expiration_process Timer expiration processing */ +/* _tx_thread_time_slice Time slice interrupted thread */ +/* */ +/* CALLED BY */ +/* */ +/* interrupt vector */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_timer_interrupt(VOID) +// { + PUBLIC _tx_timer_interrupt +_tx_timer_interrupt: + + /* Upon entry to this routine, it is assumed that the compiler scratch registers are available + for use. */ + + /* Increment the system clock. */ + // _tx_timer_system_clock++; + + LDR r1, =_tx_timer_system_clock // Pickup address of system clock + LDR r0, [r1, #0] // Pickup system clock + ADD r0, r0, #1 // Increment system clock + STR r0, [r1, #0] // Store new system clock + + /* Test for time-slice expiration. */ + // if (_tx_timer_time_slice) + // { + + LDR r3, =_tx_timer_time_slice // Pickup address of time-slice + LDR r2, [r3, #0] // Pickup time-slice + CBZ r2, __tx_timer_no_time_slice // Is it non-active? + // Yes, skip time-slice processing + + /* Decrement the time_slice. */ + // _tx_timer_time_slice--; + + SUB r2, r2, #1 // Decrement the time-slice + STR r2, [r3, #0] // Store new time-slice value + + /* Check for expiration. */ + // if (__tx_timer_time_slice == 0) + + CBNZ r2, __tx_timer_no_time_slice // Has it expired? + // No, skip expiration processing + + /* Set the time-slice expired flag. */ + // _tx_timer_expired_time_slice = TX_TRUE; + + LDR r3, =_tx_timer_expired_time_slice // Pickup address of expired flag + MOV r0, #1 // Build expired value + STR r0, [r3, #0] // Set time-slice expiration flag + + // } + +__tx_timer_no_time_slice: + + /* Test for timer expiration. */ + // if (*_tx_timer_current_ptr) + // { + + LDR r1, =_tx_timer_current_ptr // Pickup current timer pointer address + LDR r0, [r1, #0] // Pickup current timer + LDR r2, [r0, #0] // Pickup timer list entry + CBZ r2, __tx_timer_no_timer // Is there anything in the list? + // No, just increment the timer + + /* Set expiration flag. */ + // _tx_timer_expired = TX_TRUE; + + LDR r3, =_tx_timer_expired // Pickup expiration flag address + MOV r2, #1 // Build expired value + STR r2, [r3, #0] // Set expired flag + B __tx_timer_done // Finished timer processing + + // } + // else + // { +__tx_timer_no_timer: + + /* No timer expired, increment the timer pointer. */ + // _tx_timer_current_ptr++; + + ADD r0, r0, #4 // Move to next timer + + /* Check for wrap-around. */ + // if (_tx_timer_current_ptr == _tx_timer_list_end) + + LDR r3, =_tx_timer_list_end // Pickup addr of timer list end + LDR r2, [r3, #0] // Pickup list end + CMP r0, r2 // Are we at list end? + BNE __tx_timer_skip_wrap // No, skip wrap-around logic + + /* Wrap to beginning of list. */ + // _tx_timer_current_ptr = _tx_timer_list_start; + + LDR r3, =_tx_timer_list_start // Pickup addr of timer list start + LDR r0, [r3, #0] // Set current pointer to list start + +__tx_timer_skip_wrap: + + STR r0, [r1, #0] // Store new current timer pointer + // } + +__tx_timer_done: + + /* See if anything has expired. */ + // if ((_tx_timer_expired_time_slice) || (_tx_timer_expired)) + // { + + LDR r3, =_tx_timer_expired_time_slice // Pickup addr of expired flag + LDR r2, [r3, #0] // Pickup time-slice expired flag + CBNZ r2, __tx_something_expired // Did a time-slice expire? + // If non-zero, time-slice expired + LDR r1, =_tx_timer_expired // Pickup addr of other expired flag + LDR r0, [r1, #0] // Pickup timer expired flag + CBZ r0, __tx_timer_nothing_expired // Did a timer expire? + // No, nothing expired + +__tx_something_expired: + + PUSH {r0, lr} // Save the lr register on the stack + // and save r0 just to keep 8-byte alignment + + /* Did a timer expire? */ + // if (_tx_timer_expired) + // { + + LDR r1, =_tx_timer_expired // Pickup addr of expired flag + LDR r0, [r1, #0] // Pickup timer expired flag + CBZ r0, __tx_timer_dont_activate // Check for timer expiration + // If not set, skip timer activation + + /* Process timer expiration. */ + // _tx_timer_expiration_process(); + + BL _tx_timer_expiration_process // Call the timer expiration handling routine + + // } +__tx_timer_dont_activate: + + /* Did time slice expire? */ + // if (_tx_timer_expired_time_slice) + // { + + LDR r3, =_tx_timer_expired_time_slice // Pickup addr of time-slice expired + LDR r2, [r3, #0] // Pickup the actual flag + CBZ r2, __tx_timer_not_ts_expiration // See if the flag is set + // No, skip time-slice processing + + /* Time slice interrupted thread. */ + // _tx_thread_time_slice(); + + BL _tx_thread_time_slice // Call time-slice processing + LDR r0, =_tx_thread_preempt_disable // Build address of preempt disable flag + LDR r1, [r0] // Is the preempt disable flag set? + CBNZ r1, __tx_timer_skip_time_slice // Yes, skip the PendSV logic + LDR r0, =_tx_thread_current_ptr // Build current thread pointer address + LDR r1, [r0] // Pickup the current thread pointer + LDR r2, =_tx_thread_execute_ptr // Build execute thread pointer address + LDR r3, [r2] // Pickup the execute thread pointer + LDR r0, =0xE000ED04 // Build address of control register + LDR r2, =0x10000000 // Build value for PendSV bit + CMP r1, r3 // Are they the same? + BEQ __tx_timer_skip_time_slice // If the same, there was no time-slice performed + STR r2, [r0] // Not the same, issue the PendSV for preemption +__tx_timer_skip_time_slice: + // } + +__tx_timer_not_ts_expiration: + + POP {r0, lr} // Recover lr register (r0 is just there for + // the 8-byte stack alignment + + // } + +__tx_timer_nothing_expired: + + DSB // Complete all memory access + BX lr // Return to caller +// } + END diff --git a/ports_arch/ARMv8-M/threadx/iar/src/txe_thread_secure_stack_allocate.c b/ports_arch/ARMv8-M/threadx/iar/src/txe_thread_secure_stack_allocate.c new file mode 100644 index 00000000..caa47139 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/iar/src/txe_thread_secure_stack_allocate.c @@ -0,0 +1,119 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_initialize.h" +#include "tx_thread.h" + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_secure_stack_allocate Cortex-Mxx */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the secure stack allocate */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* stack_size Size of secure stack to */ +/* allocate */ +/* */ +/* OUTPUT */ +/* */ +/* TX_THREAD_ERROR Invalid thread pointer */ +/* TX_CALLER_ERROR Invalid caller of function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_secure_stack_allocate Actual stack alloc function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* */ +/**************************************************************************/ +UINT _txe_thread_secure_stack_allocate(TX_THREAD *thread_ptr, ULONG stack_size) +{ +#if defined(TX_SINGLE_MODE_SECURE) || defined(TX_SINGLE_MODE_NON_SECURE) + return(TX_FEATURE_NOT_ENABLED); +#else +UINT status; + + /* Default status to success. */ + status = TX_SUCCESS; + + /* Check for an invalid thread pointer. */ + if (thread_ptr == TX_NULL) + { + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Now check for invalid thread ID. */ + else if (thread_ptr -> tx_thread_id != TX_THREAD_ID) + { + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Check for interrupt call. */ + if (TX_THREAD_GET_SYSTEM_STATE() != ((ULONG) 0)) + { + /* Is call from an interrupt and not initialization? */ + if (TX_THREAD_GET_SYSTEM_STATE() < TX_INITIALIZE_IN_PROGRESS) + { + /* Invalid caller of this function, return appropriate error code. */ + status = TX_CALLER_ERROR; + } + } + + /* Determine if everything is okay. */ + if (status == TX_SUCCESS) + { + /* Call actual secure stack allocate function. */ + status = _tx_thread_secure_stack_allocate(thread_ptr, stack_size); + } + + /* Return completion status. */ + return(status); +#endif +} diff --git a/ports_arch/ARMv8-M/threadx/iar/src/txe_thread_secure_stack_free.c b/ports_arch/ARMv8-M/threadx/iar/src/txe_thread_secure_stack_free.c new file mode 100644 index 00000000..0e1efcf4 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/iar/src/txe_thread_secure_stack_free.c @@ -0,0 +1,120 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_initialize.h" +#include "tx_thread.h" + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_secure_stack_free Cortex-Mxx */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the secure stack free */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* */ +/* OUTPUT */ +/* */ +/* TX_THREAD_ERROR Invalid thread pointer */ +/* TX_CALLER_ERROR Invalid caller of function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_secure_stack_free Actual stack free function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* */ +/**************************************************************************/ +UINT _txe_thread_secure_stack_free(TX_THREAD *thread_ptr) +{ +#if defined(TX_SINGLE_MODE_SECURE) || defined(TX_SINGLE_MODE_NON_SECURE) + return(TX_FEATURE_NOT_ENABLED); +#else +UINT status; + + /* Default status to success. */ + status = TX_SUCCESS; + + /* Check for an invalid thread pointer. */ + if (thread_ptr == TX_NULL) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Now check for invalid thread ID. */ + else if (thread_ptr -> tx_thread_id != TX_THREAD_ID) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Check for interrupt call. */ + if (TX_THREAD_GET_SYSTEM_STATE() != ((ULONG) 0)) + { + /* Is call from an interrupt and not initialization? */ + if (TX_THREAD_GET_SYSTEM_STATE() < TX_INITIALIZE_IN_PROGRESS) + { + /* Invalid caller of this function, return appropriate error code. */ + status = TX_CALLER_ERROR; + } + } + + /* Determine if everything is okay. */ + if (status == TX_SUCCESS) + { + + /* Call actual secure stack allocate function. */ + status = _tx_thread_secure_stack_free(thread_ptr); + } + + /* Return completion status. */ + return(status); +#endif +} diff --git a/ports_arch/ARMv8-M/threadx/inc/tx_port.h b/ports_arch/ARMv8-M/threadx/inc/tx_port.h new file mode 100644 index 00000000..0092254c --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/inc/tx_port.h @@ -0,0 +1,658 @@ +/**************************************************************************/ +/* */ +/* 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-Mxx */ +/* 6.2.1 */ +/* */ +/* 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-Mxx files. It unifies */ +/* the Cortex-Mxx compilers into one common file. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* 03-02-2021 Scott Larson Modified comment(s), added */ +/* ULONG64_DEFINED, */ +/* resulting in version 6.1.5 */ +/* 06-02-2021 Scott Larson Modified comment(s), removed */ +/* unneeded header file, funcs */ +/* set_control and get_control */ +/* changed to inline, */ +/* added symbol to enable */ +/* stack error handler, */ +/* resulting in version 6.1.7 */ +/* 10-15-2021 Scott Larson Modified comment(s), improved */ +/* stack check error handling, */ +/* resulting in version 6.1.9 */ +/* 01-31-2022 Scott Larson Modified comment(s), unified */ +/* this file across compilers, */ +/* fixed predefined macro, */ +/* resulting in version 6.1.10 */ +/* 04-25-2022 Scott Larson Modified comments and added */ +/* volatile to registers, */ +/* resulting in version 6.1.11 */ +/* 07-29-2022 Scott Larson Modified comments and changed */ +/* secure stack initialization */ +/* macro to port-specific, */ +/* described BASEPRI usage, */ +/* resulting in version 6.1.12 */ +/* 03-08-2023 Scott Larson Removed unneeded #include, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ + +#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 +#include + +#ifdef __ICCARM__ +#include /* IAR Intrinsics */ +#define __asm__ __asm /* Define to make all inline asm from each compiler look similar */ +#define _tx_control_get __get_CONTROL +#define _tx_control_set __set_CONTROL +#define _tx_ipsr_get __get_IPSR +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#include +#endif /* TX_ENABLE_IAR_LIBRARY_SUPPORT */ +#endif /* __ICCARM__ */ + + +/* 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 + +/* Function prototypes for this port. */ +struct TX_THREAD_STRUCT; +UINT _txe_thread_secure_stack_allocate(struct TX_THREAD_STRUCT *thread_ptr, ULONG stack_size); +UINT _txe_thread_secure_stack_free(struct TX_THREAD_STRUCT *thread_ptr); +UINT _tx_thread_secure_stack_allocate(struct TX_THREAD_STRUCT *tx_thread, ULONG stack_size); +UINT _tx_thread_secure_stack_free(struct TX_THREAD_STRUCT *tx_thread); + +/* Define the system API mappings based on the error checking + selected by the user. Note: this section is only applicable to + application source code, hence the conditional that turns off this + stuff when the include file is processed by the ThreadX source. */ + +#ifndef TX_SOURCE_CODE + + +/* Determine if error checking is desired. If so, map API functions + to the appropriate error checking front-ends. Otherwise, map API + functions to the core functions that actually perform the work. + Note: error checking is enabled by default. */ + +#ifdef TX_DISABLE_ERROR_CHECKING + +/* Services without error checking. */ + +#define tx_thread_secure_stack_allocate _tx_thread_secure_stack_allocate +#define tx_thread_secure_stack_free _tx_thread_secure_stack_free + +#else + +/* Services with error checking. */ + +#define tx_thread_secure_stack_allocate _txe_thread_secure_stack_allocate +#define tx_thread_secure_stack_free _txe_thread_secure_stack_free + +#endif /* TX_DISABLE_ERROR_CHECKING */ +#endif /* TX_SOURCE_CODE */ + +/* This port has a usage fault handler in _tx_initialize_low_level for stack exceptions. */ +#define TX_PORT_THREAD_STACK_ERROR_HANDLING + +/* 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 +/* IAR library support */ +#if !defined(TX_SINGLE_MODE_SECURE) && !defined(TX_SINGLE_MODE_NON_SECURE) +/* ThreadX in non-secure zone with calls to secure zone. */ +#define TX_THREAD_EXTENSION_2 VOID *tx_thread_secure_stack_context; \ + VOID *tx_thread_iar_tls_pointer; +#else +/* ThreadX in only one zone. */ +#define TX_THREAD_EXTENSION_2 VOID *tx_thread_iar_tls_pointer; +#endif + +#else +/* No IAR library support */ +#if !defined(TX_SINGLE_MODE_SECURE) && !defined(TX_SINGLE_MODE_NON_SECURE) +/* ThreadX in non-secure zone with calls to secure zone. */ +#define TX_THREAD_EXTENSION_2 VOID *tx_thread_secure_stack_context; +#else +/* ThreadX in only one zone. */ +#define TX_THREAD_EXTENSION_2 +#endif + +#endif /* TX_ENABLE_IAR_LIBRARY_SUPPORT */ + +#define TX_THREAD_EXTENSION_3 + + +/* Define the port extensions of the remaining ThreadX objects. */ + +#define TX_BLOCK_POOL_EXTENSION +#define TX_BYTE_POOL_EXTENSION +#define TX_EVENT_FLAGS_GROUP_EXTENSION +#define TX_MUTEX_EXTENSION +#define TX_QUEUE_EXTENSION +#define TX_SEMAPHORE_EXTENSION +#define TX_TIMER_EXTENSION + + +/* 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 +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(); + +#if !defined(TX_SINGLE_MODE_SECURE) && !defined(TX_SINGLE_MODE_NON_SECURE) +#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); \ + if(thread_ptr -> tx_thread_secure_stack_context){_tx_thread_secure_stack_free(thread_ptr);} +#else +#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); +#endif +#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION do {__iar_Initlocks();} while(0); + +#else /* No IAR library support. */ +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) +#if !defined(TX_SINGLE_MODE_SECURE) && !defined(TX_SINGLE_MODE_NON_SECURE) +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) if(thread_ptr -> tx_thread_secure_stack_context){_tx_thread_secure_stack_free(thread_ptr);} +#else +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) +#endif +#endif /* TX_ENABLE_IAR_LIBRARY_SUPPORT */ + +#if !defined(TX_SINGLE_MODE_SECURE) && !defined(TX_SINGLE_MODE_NON_SECURE) +/* Define the size of the secure stack for the timer thread and use the extension to allocate the secure stack. */ +#define TX_TIMER_THREAD_SECURE_STACK_SIZE 256 +#define TX_TIMER_INITIALIZE_EXTENSION(status) _tx_thread_secure_stack_allocate(&_tx_timer_thread, TX_TIMER_THREAD_SECURE_STACK_SIZE); +#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 */ + +#ifdef __GNUC__ /* GCC and ARM Compiler 6 */ + +__attribute__( ( always_inline ) ) static inline ULONG _tx_control_get(void) +{ +ULONG control_value; + + __asm__ volatile (" MRS %0,CONTROL ": "=r" (control_value) ); + return(control_value); +} + +__attribute__( ( always_inline ) ) static inline void _tx_control_set(ULONG control_value) +{ + __asm__ volatile (" MSR CONTROL,%0": : "r" (control_value): "memory" ); +} + +#endif /* __GNUC__ */ + +/* Touch VFP register in order to flush. Works for AC6/GCC/IAR compilers. */ +#define TX_VFP_TOUCH() __asm__ volatile ("VMOV.F32 s0, s0"); + +#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 = _tx_control_get(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + _tx_control_set(_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 = _tx_control_get(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + _tx_control_set(_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 = _tx_control_get(); \ + _tx_vfp_state = _tx_vfp_state & ((ULONG) 0x4); \ + TX_VFP_TOUCH(); \ + if (_tx_vfp_state == ((ULONG) 0)) \ + { \ + _tx_vfp_state = _tx_control_get(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + _tx_control_set(_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 + +#if defined(__GNUC__) /* GCC and AC6 */ +__attribute__( ( always_inline ) ) static inline UINT _tx_ipsr_get(void) +{ +UINT ipsr_value; + __asm__ volatile (" MRS %0,IPSR ": "=r" (ipsr_value) ); + return(ipsr_value); +} +#endif /* GCC and AC6 IPSR_get function. */ + +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | _tx_ipsr_get()) + +#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 + +#if !defined(TX_SINGLE_MODE_SECURE) && !defined(TX_SINGLE_MODE_NON_SECURE) +/* Initialize secure stacks for threads calling secure functions. */ +extern void _tx_thread_secure_stack_initialize(void); +#define TX_PORT_SPECIFIC_PRE_INITIALIZATION _tx_thread_secure_stack_initialize(); +#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(__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. */ + +__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 (_tx_ipsr_get() == 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); + +/* 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 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-Mxx Version 6.2.1 *"; +#else +#ifdef TX_MISRA_ENABLE +extern CHAR _tx_version_id[100]; +#else +extern CHAR _tx_version_id[]; +#endif +#endif + +#endif diff --git a/ports_arch/ARMv8-M/threadx/inc/tx_secure_interface.h b/ports_arch/ARMv8-M/threadx/inc/tx_secure_interface.h new file mode 100644 index 00000000..d6fba106 --- /dev/null +++ b/ports_arch/ARMv8-M/threadx/inc/tx_secure_interface.h @@ -0,0 +1,61 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* tx_secure_interface.h PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the ThreadX secure thread stack components, */ +/* including data types and external references. */ +/* It is assumed that tx_api.h and tx_port.h have already been */ +/* included. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* */ +/**************************************************************************/ + +#ifndef TX_SECURE_INTERFACE_H +#define TX_SECURE_INTERFACE_H + +/* Define internal secure thread stack function prototypes. */ + +extern UINT _tx_thread_secure_mode_stack_initialize(void); +extern UINT _tx_thread_secure_mode_stack_allocate(TX_THREAD *thread_ptr, ULONG stack_size); +extern UINT _tx_thread_secure_mode_stack_free(TX_THREAD *thread_ptr); +extern void _tx_thread_secure_stack_initialize(void); +extern void _tx_thread_secure_stack_context_save(TX_THREAD *thread_ptr); +extern void _tx_thread_secure_stack_context_restore(TX_THREAD *thread_ptr); + +#endif diff --git a/scripts/copy_armv7_m.sh b/scripts/copy_armv7_m.sh new file mode 100755 index 00000000..825979a2 --- /dev/null +++ b/scripts/copy_armv7_m.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +# There is only one tx_port.h file that covers three architectures: M3/M4/M7 and four tools: ac5/ac6/gnu/iar. +# This file is in threadx/ports/armv7-m/inc. We are going to ignore GHS for now, but I’d like to get GHS unified as well. + +set -e + +ports_folder="ports" +source_folder="ports_arch/ARMv7-M/threadx" +target_mcu="cortex_m3 cortex_m4 cortex_m7" +source_inc_folder="$source_folder/inc" +target_inc_mcu=$target_mcu +target_inc_ide="ac5 ac6 gnu iar keil" +target_inc_folder="inc" +source_src_ide="ac5 ac6 gnu iar" +target_src_mcu=$target_mcu +src_folder="src" +readme="readme_threadx.txt" +source_string="Cortex-Mx" +target_string_pre="Cortex-M" + +cd $(dirname `realpath $0`)/.. + +# Copy port files +for mcu in $target_mcu; +do + for ide in $target_inc_ide; + do + # Copy files + target=$ports_folder/$mcu/$ide/$target_inc_folder + [ -d "$target" ] || continue + echo "$source_inc_folder -> $target" + rm -rf $target + cp -rf $source_inc_folder $target + + # String replacement + mcu_string="$target_string_pre${mcu: -1}" + if [ "$ide" == "keil" ]; + then + ide_string="Keil" + mcu_ide_string="$mcu_string\/$ide_string" + else + ide_string="${ide^^}" + mcu_ide_string="$mcu_string\/$ide_string " + fi + sed -i "s/ $source_string /$mcu_ide_string/g" $target/* + sed -i "s/ThreadX $source_string /ThreadX $mcu_string\/$ide_string /g" $target/* + sed -i "s/$source_string/$mcu_string/g" $target/* + done +done +echo "" + +# Copy source files +for ide in $source_src_ide; +do + for mcu in $target_src_mcu; + do + # Copy source files + src=$source_folder/$ide/$src_folder + target=$ports_folder/$mcu/$ide/$src_folder + #[ -d "$target" ] || continue + echo "$src -> $target" + rm -rf $target + cp -rf $src $target + + # String replacement + sed -i "s/$source_string/$target_string_pre${mcu: -1}/g" $target/* + + # Copy readme files + src=$source_folder/$ide/$readme + target=$ports_folder/$mcu/$ide/$readme + #[ -f "$target" ] || continue + echo "$src -> $target" + rm -f $target + cp -f $src $target + + # String replacement + sed -i "s/$source_string/$target_string_pre${mcu: -1}/g" $target + done +done \ No newline at end of file diff --git a/scripts/copy_armv8_m.sh b/scripts/copy_armv8_m.sh new file mode 100755 index 00000000..0963ecbe --- /dev/null +++ b/scripts/copy_armv8_m.sh @@ -0,0 +1,104 @@ +#!/bin/bash + +# There are two files tx_port.h and tx_secure_interface.h that cover three architectures: M33/M55/M85 and three tools: ac6/gnu/iar. +# These files are in threadx/ports/armv8-m/inc. + +set -e + +ports_folder="ports" +source_folder="ports_arch/ARMv8-M/threadx" +target_mcu="cortex_m33 cortex_m55 cortex_m85" +source_inc_folder="$source_folder/inc" +target_inc_mcu=$target_mcu +target_inc_ide="ac6 gnu iar" +target_inc_folder="inc" +source_src_ide="ac6 gnu iar" +target_src_mcu=$target_mcu +src_folder="src" +readme="readme_threadx.txt" +cmake="CMakeLists.txt" +source_string="Cortex-Mxx" +target_string_pre="Cortex-M" + +cd $(dirname `realpath $0`)/.. + +# Copy port files +for mcu in $target_mcu; +do + for ide in $target_inc_ide; + do + # Copy files + target=$ports_folder/$mcu/$ide/$target_inc_folder + [ -d "$target" ] || mkdir -p $target + echo "$source_inc_folder -> $target" + rm -rf $target + cp -rf $source_inc_folder $target + + # String replacement + mcu_string="$target_string_pre${mcu: -2}" + if [ "$ide" == "keil" ]; + then + ide_string="Keil" + mcu_ide_string="$mcu_string\/$ide_string" + else + ide_string="${ide^^}" + mcu_ide_string="$mcu_string\/$ide_string " + fi + sed -i "s/ $source_string /$mcu_ide_string/g" $target/* + sed -i "s/ThreadX $source_string /ThreadX $mcu_string\/$ide_string /g" $target/* + sed -i "s/$source_string/$mcu_string/g" $target/* + done +done +echo "" + +# Copy source files +for ide in $source_src_ide; +do + for mcu in $target_src_mcu; + do + # Copy source files + src=$source_folder/$ide/$src_folder + target=$ports_folder/$mcu/$ide/$src_folder + #[ -d "$target" ] || continue + echo "$src -> $target" + rm -rf $target + cp -rf $src $target + + # String replacement + sed -i "s/$source_string/$target_string_pre${mcu: -2}/g" $target/* + + # Copy readme files + src=$source_folder/$ide/$readme + target=$ports_folder/$mcu/$ide/$readme + #[ -f "$target" ] || continue + echo "$src -> $target" + rm -f $target + cp -f $src $target + + # String replacement + sed -i "s/$source_string/$target_string_pre${mcu: -2}/g" $target + done +done + +# Copy CMakeLists files +for ide in $source_src_ide; +do + for mcu in $target_src_mcu; + do + # Copy CMakeList files ac6 + src=$source_folder/ac6/$cmake + target=$ports_folder/$mcu/ac6/$cmake + #[ -f "$target" ] || continue + echo "$src -> $target" + rm -f $target + cp -f $src $target + + # Copy CMakeList files gnu + src=$source_folder/gnu/$cmake + target=$ports_folder/$mcu/gnu/$cmake + #[ -f "$target" ] || continue + echo "$src -> $target" + rm -f $target + cp -f $src $target + done +done \ No newline at end of file diff --git a/scripts/copy_module_armv7_m.sh b/scripts/copy_module_armv7_m.sh new file mode 100755 index 00000000..8dbd834c --- /dev/null +++ b/scripts/copy_module_armv7_m.sh @@ -0,0 +1,64 @@ +#!/bin/bash + +# There is only one tx_port.h file that covers three architectures: M3/M4/M7 and four tools: ac5/ac6/gnu/iar. +# This file is in threadx/ports_module/armv7-m/inc. We are going to ignore GHS. + +set -e + +ports_folder="ports_arch/ARMv7-M/threadx" +ports_file_list="tx_thread_context_restore tx_thread_context_save tx_thread_interrupt_control tx_thread_interrupt_disable tx_thread_interrupt_restore tx_thread_stack_build tx_thread_system_return tx_timer_interrupt" +ports_module_folder="ports_module" +source_folder="ports_arch/ARMv7-M/threadx_modules" +target_mcu="cortex_m3 cortex_m4 cortex_m7" +source_inc_folder="$source_folder/inc" +target_inc_folder="inc" +target_ide="ac5 ac6 gnu iar" +source_common_folder="common/module_manager/src" +target_common_folder="module_manager" +source_string="Cortex-Mx" +target_string_pre="Cortex-M" + + +cd $(dirname `realpath $0`)/.. + +# Copy IDE specific files +for mcu in $target_mcu; +do + for ide in $target_ide; + do + for d in $(ls $source_folder/$ide); + do + # Copy specific files + source=$source_folder/$ide/$d + target=$ports_module_folder/$mcu/$ide/$d + echo "$source -> $target" + rm -rf $target + cp -rf $source $target + + # String replacement + find $target -type f -exec sed -i "s/$source_string/$target_string_pre${mcu: -1}/g" {} \; + done + + # copy common inc directory containing unified tx_port.h + target=$ports_module_folder/$mcu/$ide/$target_inc_folder + echo "$source_inc_folder -> $target" + cp -rf $source_inc_folder/* $target + find $target -type f -exec sed -i "s/$source_string/$target_string_pre${mcu: -1}/g" {} \; + + # Copy common files + source=$source_folder/$source_common_folder; + target=$ports_module_folder/$mcu/$ide/$target_common_folder + echo "$source -> $target" + cp -rf $source $target + + source=$ports_folder/$ide/src; + echo "$source -> $target" + for f in $ports_file_list; + do + cp $source/$f.* $target/src + done + + # String replacement + find $target -type f -exec sed -i "s/$source_string/$target_string_pre${mcu: -1}/g" {} \; + done +done \ No newline at end of file