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