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