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