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