1@/*************************************************************************** 2@ * Copyright (c) 2024 Microsoft Corporation 3@ * 4@ * This program and the accompanying materials are made available under the 5@ * terms of the MIT License which is available at 6@ * https://opensource.org/licenses/MIT. 7@ * 8@ * SPDX-License-Identifier: MIT 9@ **************************************************************************/ 10@ 11@ 12@/**************************************************************************/ 13@/**************************************************************************/ 14@/** */ 15@/** ThreadX Component */ 16@/** */ 17@/** Thread */ 18@/** */ 19@/**************************************************************************/ 20@/**************************************************************************/ 21#ifdef TX_INCLUDE_USER_DEFINE_FILE 22#include "tx_user.h" 23#endif 24 25 .arm 26 27#ifdef TX_ENABLE_FIQ_SUPPORT 28SVC_MODE = 0xD3 @ Disable IRQ/FIQ, SVC mode 29IRQ_MODE = 0xD2 @ Disable IRQ/FIQ, IRQ mode 30#else 31SVC_MODE = 0x93 @ Disable IRQ, SVC mode 32IRQ_MODE = 0x92 @ Disable IRQ, IRQ mode 33#endif 34@ 35 .global _tx_thread_system_state 36 .global _tx_thread_current_ptr 37 .global _tx_thread_execute_ptr 38 .global _tx_timer_time_slice 39 .global _tx_thread_schedule 40 .global _tx_thread_preempt_disable 41 .global _tx_execution_isr_exit 42@ 43@ 44@/* No 16-bit Thumb mode veneer code is needed for _tx_thread_context_restore 45@ since it will never be called 16-bit mode. */ 46@ 47 .arm 48 .text 49 .align 2 50@/**************************************************************************/ 51@/* */ 52@/* FUNCTION RELEASE */ 53@/* */ 54@/* _tx_thread_context_restore ARM11/GNU */ 55@/* 6.2.1 */ 56@/* AUTHOR */ 57@/* */ 58@/* William E. Lamie, Microsoft Corporation */ 59@/* */ 60@/* DESCRIPTION */ 61@/* */ 62@/* This function restores the interrupt context if it is processing a */ 63@/* nested interrupt. If not, it returns to the interrupt thread if no */ 64@/* preemption is necessary. Otherwise, if preemption is necessary or */ 65@/* if no thread was running, the function returns to the scheduler. */ 66@/* */ 67@/* INPUT */ 68@/* */ 69@/* None */ 70@/* */ 71@/* OUTPUT */ 72@/* */ 73@/* None */ 74@/* */ 75@/* CALLS */ 76@/* */ 77@/* _tx_thread_schedule Thread scheduling routine */ 78@/* */ 79@/* CALLED BY */ 80@/* */ 81@/* ISRs Interrupt Service Routines */ 82@/* */ 83@/* RELEASE HISTORY */ 84@/* */ 85@/* DATE NAME DESCRIPTION */ 86@/* */ 87@/* 09-30-2020 William E. Lamie Initial Version 6.1 */ 88@/* 03-08-2023 Cindy Deng Modified comment(s), added */ 89@/* #include tx_user.h, */ 90@/* resulting in version 6.2.1 */ 91@/* */ 92@/**************************************************************************/ 93@VOID _tx_thread_context_restore(VOID) 94@{ 95 .global _tx_thread_context_restore 96 .type _tx_thread_context_restore,function 97_tx_thread_context_restore: 98@ 99@ /* Lockout interrupts. */ 100@ 101 MOV r0, #IRQ_MODE @ Build disable interrupts CPSR 102 MSR CPSR, r0 @ Lockout interrupts 103 104#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY 105@ 106@ /* Call the ISR exit function to indicate an ISR is complete. */ 107@ 108 BL _tx_execution_isr_exit @ Call the ISR exit function 109#endif 110@ 111@ /* Determine if interrupts are nested. */ 112@ if (--_tx_thread_system_state) 113@ { 114@ 115 LDR r3, =_tx_thread_system_state @ Pickup address of system state variable 116 LDR r2, [r3] @ Pickup system state 117 SUB r2, r2, #1 @ Decrement the counter 118 STR r2, [r3] @ Store the counter 119 CMP r2, #0 @ Was this the first interrupt? 120 BEQ __tx_thread_not_nested_restore @ If so, not a nested restore 121@ 122@ /* Interrupts are nested. */ 123@ 124@ /* Just recover the saved registers and return to the point of 125@ interrupt. */ 126@ 127 LDMIA sp!, {r0, r10, r12, lr} @ Recover SPSR, POI, and scratch regs 128 MSR SPSR, r0 @ Put SPSR back 129 LDMIA sp!, {r0-r3} @ Recover r0-r3 130 MOVS pc, lr @ Return to point of interrupt 131@ 132@ } 133__tx_thread_not_nested_restore: 134@ 135@ /* Determine if a thread was interrupted and no preemption is required. */ 136@ else if (((_tx_thread_current_ptr) && (_tx_thread_current_ptr == _tx_thread_execute_ptr)) 137@ || (_tx_thread_preempt_disable)) 138@ { 139@ 140 LDR r1, =_tx_thread_current_ptr @ Pickup address of current thread ptr 141 LDR r0, [r1] @ Pickup actual current thread pointer 142 CMP r0, #0 @ Is it NULL? 143 BEQ __tx_thread_idle_system_restore @ Yes, idle system was interrupted 144@ 145 LDR r3, =_tx_thread_preempt_disable @ Pickup preempt disable address 146 LDR r2, [r3] @ Pickup actual preempt disable flag 147 CMP r2, #0 @ Is it set? 148 BNE __tx_thread_no_preempt_restore @ Yes, don't preempt this thread 149 LDR r3, =_tx_thread_execute_ptr @ Pickup address of execute thread ptr 150 LDR r2, [r3] @ Pickup actual execute thread pointer 151 CMP r0, r2 @ Is the same thread highest priority? 152 BNE __tx_thread_preempt_restore @ No, preemption needs to happen 153@ 154@ 155__tx_thread_no_preempt_restore: 156@ 157@ /* Restore interrupted thread or ISR. */ 158@ 159@ /* Pickup the saved stack pointer. */ 160@ tmp_ptr = _tx_thread_current_ptr -> tx_thread_stack_ptr; 161@ 162@ /* Recover the saved context and return to the point of interrupt. */ 163@ 164 LDMIA sp!, {r0, r10, r12, lr} @ Recover SPSR, POI, and scratch regs 165 MSR SPSR, r0 @ Put SPSR back 166 LDMIA sp!, {r0-r3} @ Recover r0-r3 167 MOVS pc, lr @ Return to point of interrupt 168@ 169@ } 170@ else 171@ { 172__tx_thread_preempt_restore: 173@ 174 LDMIA sp!, {r3, r10, r12, lr} @ Recover temporarily saved registers 175 MOV r1, lr @ Save lr (point of interrupt) 176 MOV r2, #SVC_MODE @ Build SVC mode CPSR 177 MSR CPSR, r2 @ Enter SVC mode 178 STR r1, [sp, #-4]! @ Save point of interrupt 179 STMDB sp!, {r4-r12, lr} @ Save upper half of registers 180 MOV r4, r3 @ Save SPSR in r4 181 MOV r2, #IRQ_MODE @ Build IRQ mode CPSR 182 MSR CPSR, r2 @ Enter IRQ mode 183 LDMIA sp!, {r0-r3} @ Recover r0-r3 184 MOV r5, #SVC_MODE @ Build SVC mode CPSR 185 MSR CPSR, r5 @ Enter SVC mode 186 STMDB sp!, {r0-r3} @ Save r0-r3 on thread's stack 187 MOV r3, #1 @ Build interrupt stack type 188 STMDB sp!, {r3, r4} @ Save interrupt stack type and SPSR 189 LDR r1, =_tx_thread_current_ptr @ Pickup address of current thread ptr 190 LDR r0, [r1] @ Pickup current thread pointer 191 STR sp, [r0, #8] @ Save stack pointer in thread control 192 @ block 193@ 194@ /* Save the remaining time-slice and disable it. */ 195@ if (_tx_timer_time_slice) 196@ { 197@ 198 LDR r3, =_tx_timer_time_slice @ Pickup time-slice variable address 199 LDR r2, [r3] @ Pickup time-slice 200 CMP r2, #0 @ Is it active? 201 BEQ __tx_thread_dont_save_ts @ No, don't save it 202@ 203@ _tx_thread_current_ptr -> tx_thread_time_slice = _tx_timer_time_slice; 204@ _tx_timer_time_slice = 0; 205@ 206 STR r2, [r0, #24] @ Save thread's time-slice 207 MOV r2, #0 @ Clear value 208 STR r2, [r3] @ Disable global time-slice flag 209@ 210@ } 211__tx_thread_dont_save_ts: 212@ 213@ 214@ /* Clear the current task pointer. */ 215@ _tx_thread_current_ptr = TX_NULL; 216@ 217 MOV r0, #0 @ NULL value 218 STR r0, [r1] @ Clear current thread pointer 219@ 220@ /* Return to the scheduler. */ 221@ _tx_thread_schedule(); 222@ 223 B _tx_thread_schedule @ Return to scheduler 224@ } 225@ 226__tx_thread_idle_system_restore: 227@ 228@ /* Just return back to the scheduler! */ 229@ 230 MOV r0, #SVC_MODE @ Build SVC mode CPSR 231 MSR CPSR, r0 @ Enter SVC mode 232 B _tx_thread_schedule @ Return to scheduler 233@} 234 235 236 237