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