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 25SVC_MODE = 0xD3 @ SVC mode 26FIQ_MODE = 0xD1 @ FIQ mode 27DISABLE_INTS = 0xC0 @ Disable IRQ/FIQ interrupts 28MODE_MASK = 0x1F @ Mode mask 29THUMB_MASK = 0x20 @ Thumb bit mask 30IRQ_MODE_BITS = 0x12 @ IRQ mode bits 31SVC_MODE_BITS = 0x13 @ SVC mode value 32@ 33@ 34 .global _tx_thread_system_state 35 .global _tx_thread_current_ptr 36 .global _tx_thread_system_stack_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_fiq_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_fiq_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 fiq interrupt context when 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@/* FIQ ISR 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_fiq_context_restore(VOID) 94@{ 95 .global _tx_thread_fiq_context_restore 96 .type _tx_thread_fiq_context_restore,function 97_tx_thread_fiq_context_restore: 98@ 99@ /* Lockout interrupts. */ 100@ 101 MRS r3, CPSR @ Pickup current CPSR 102 ORR r0, r3, #DISABLE_INTS @ Build interrupt disable value 103 MSR CPSR_cxsf, r0 @ Lockout interrupts 104 105#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY 106@ 107@ /* Call the ISR exit function to indicate an ISR is complete. */ 108@ 109 BL _tx_execution_isr_exit @ Call the ISR exit function 110#endif 111@ 112@ /* Determine if interrupts are nested. */ 113@ if (--_tx_thread_system_state) 114@ { 115@ 116 LDR r3, =_tx_thread_system_state @ Pickup address of system state variable 117 LDR r2, [r3] @ Pickup system state 118 SUB r2, r2, #1 @ Decrement the counter 119 STR r2, [r3] @ Store the counter 120 CMP r2, #0 @ Was this the first interrupt? 121 BEQ __tx_thread_fiq_not_nested_restore @ If so, not a nested restore 122@ 123@ /* Interrupts are nested. */ 124@ 125@ /* Just recover the saved registers and return to the point of 126@ interrupt. */ 127@ 128 LDMIA sp!, {r0, r10, r12, lr} @ Recover SPSR, POI, and scratch regs 129 MSR SPSR_cxsf, r0 @ Put SPSR back 130 LDMIA sp!, {r0-r3} @ Recover r0-r3 131 MOVS pc, lr @ Return to point of interrupt 132@ 133@ } 134__tx_thread_fiq_not_nested_restore: 135@ 136@ /* Determine if a thread was interrupted and no preemption is required. */ 137@ else if (((_tx_thread_current_ptr) && (_tx_thread_current_ptr == _tx_thread_execute_ptr)) 138@ || (_tx_thread_preempt_disable)) 139@ { 140@ 141 LDR r1, [sp] @ Pickup the saved SPSR 142 MOV r2, #MODE_MASK @ Build mask to isolate the interrupted mode 143 AND r1, r1, r2 @ Isolate mode bits 144 CMP r1, #IRQ_MODE_BITS @ Was an interrupt taken in IRQ mode before we 145 @ got to context save? */ 146 BEQ __tx_thread_fiq_no_preempt_restore @ Yes, just go back to point of interrupt 147 148 149 LDR r1, =_tx_thread_current_ptr @ Pickup address of current thread ptr 150 LDR r0, [r1] @ Pickup actual current thread pointer 151 CMP r0, #0 @ Is it NULL? 152 BEQ __tx_thread_fiq_idle_system_restore @ Yes, idle system was interrupted 153 154 LDR r3, =_tx_thread_preempt_disable @ Pickup preempt disable address 155 LDR r2, [r3] @ Pickup actual preempt disable flag 156 CMP r2, #0 @ Is it set? 157 BNE __tx_thread_fiq_no_preempt_restore @ Yes, don't preempt this thread 158 LDR r3, =_tx_thread_execute_ptr @ Pickup address of execute thread ptr 159 LDR r2, [r3] @ Pickup actual execute thread pointer 160 CMP r0, r2 @ Is the same thread highest priority? 161 BNE __tx_thread_fiq_preempt_restore @ No, preemption needs to happen 162 163 164__tx_thread_fiq_no_preempt_restore: 165@ 166@ /* Restore interrupted thread or ISR. */ 167@ 168@ /* Pickup the saved stack pointer. */ 169@ tmp_ptr = _tx_thread_current_ptr -> tx_thread_stack_ptr; 170@ 171@ /* Recover the saved context and return to the point of interrupt. */ 172@ 173 LDMIA sp!, {r0, lr} @ Recover SPSR, POI, and scratch regs 174 MSR SPSR_cxsf, r0 @ Put SPSR back 175 LDMIA sp!, {r0-r3} @ Recover r0-r3 176 MOVS pc, lr @ Return to point of interrupt 177@ 178@ } 179@ else 180@ { 181__tx_thread_fiq_preempt_restore: 182@ 183 LDMIA sp!, {r3, lr} @ Recover temporarily saved registers 184 MOV r1, lr @ Save lr (point of interrupt) 185 MOV r2, #SVC_MODE @ Build SVC mode CPSR 186 MSR CPSR_cxsf, r2 @ Enter SVC mode 187 STR r1, [sp, #-4]! @ Save point of interrupt 188 STMDB sp!, {r4-r12, lr} @ Save upper half of registers 189 MOV r4, r3 @ Save SPSR in r4 190 MOV r2, #FIQ_MODE @ Build FIQ mode CPSR 191 MSR CPSR_cxsf, r2 @ Reenter FIQ mode 192 LDMIA sp!, {r0-r3} @ Recover r0-r3 193 MOV r5, #SVC_MODE @ Build SVC mode CPSR 194 MSR CPSR_cxsf, r5 @ Enter SVC mode 195 STMDB sp!, {r0-r3} @ Save r0-r3 on thread's stack 196 MOV r3, #1 @ Build interrupt stack type 197 STMDB sp!, {r3, r4} @ Save interrupt stack type and SPSR 198 LDR r1, =_tx_thread_current_ptr @ Pickup address of current thread ptr 199 LDR r0, [r1] @ Pickup current thread pointer 200 STR sp, [r0, #8] @ Save stack pointer in thread control 201 @ block */ 202 BIC r4, r4, #THUMB_MASK @ Clear the Thumb bit of CPSR 203 ORR r3, r4, #DISABLE_INTS @ Or-in interrupt lockout bit(s) 204 MSR CPSR_cxsf, r3 @ Lockout interrupts 205@ 206@ /* Save the remaining time-slice and disable it. */ 207@ if (_tx_timer_time_slice) 208@ { 209@ 210 LDR r3, =_tx_timer_time_slice @ Pickup time-slice variable address 211 LDR r2, [r3] @ Pickup time-slice 212 CMP r2, #0 @ Is it active? 213 BEQ __tx_thread_fiq_dont_save_ts @ No, don't save it 214@ 215@ _tx_thread_current_ptr -> tx_thread_time_slice = _tx_timer_time_slice; 216@ _tx_timer_time_slice = 0; 217@ 218 STR r2, [r0, #24] @ Save thread's time-slice 219 MOV r2, #0 @ Clear value 220 STR r2, [r3] @ Disable global time-slice flag 221@ 222@ } 223__tx_thread_fiq_dont_save_ts: 224@ 225@ 226@ /* Clear the current task pointer. */ 227@ _tx_thread_current_ptr = TX_NULL; 228@ 229 MOV r0, #0 @ NULL value 230 STR r0, [r1] @ Clear current thread pointer 231@ 232@ /* Return to the scheduler. */ 233@ _tx_thread_schedule(); 234@ 235 B _tx_thread_schedule @ Return to scheduler 236@ } 237@ 238__tx_thread_fiq_idle_system_restore: 239@ 240@ /* Just return back to the scheduler! */ 241@ 242 ADD sp, sp, #24 @ Recover FIQ stack space 243 MRS r3, CPSR @ Pickup current CPSR 244 BIC r3, r3, #MODE_MASK @ Clear the mode portion of the CPSR 245 ORR r3, r3, #SVC_MODE_BITS @ Or-in new interrupt lockout bit 246 MSR CPSR_cxsf, r3 @ Lockout interrupts 247 B _tx_thread_schedule @ Return to scheduler 248@ 249@} 250 251