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