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; 33IRQ_MODE EQU 0xD2 ; IRQ mode 34SVC_MODE EQU 0xD3 ; SVC 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 42SVC_MODE_BITS EQU 0x13 ; SVC mode value 43; 44; 45 IMPORT _tx_thread_system_state 46 IMPORT _tx_thread_current_ptr 47 IMPORT _tx_thread_execute_ptr 48 IMPORT _tx_timer_time_slice 49 IMPORT _tx_thread_schedule 50 IMPORT _tx_thread_preempt_disable 51 IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY 52 IMPORT _tx_execution_isr_exit 53 ENDIF 54; 55; 56 AREA ||.text||, CODE, READONLY 57 PRESERVE8 58;/**************************************************************************/ 59;/* */ 60;/* FUNCTION RELEASE */ 61;/* */ 62;/* _tx_thread_context_restore ARM11/AC5 */ 63;/* 6.1 */ 64;/* AUTHOR */ 65;/* */ 66;/* William E. Lamie, Microsoft Corporation */ 67;/* */ 68;/* DESCRIPTION */ 69;/* */ 70;/* This function restores the interrupt context if it is processing a */ 71;/* nested interrupt. If not, it returns to the interrupt thread if no */ 72;/* preemption is necessary. Otherwise, if preemption is necessary or */ 73;/* if no thread was running, the function returns to the scheduler. */ 74;/* */ 75;/* INPUT */ 76;/* */ 77;/* None */ 78;/* */ 79;/* OUTPUT */ 80;/* */ 81;/* None */ 82;/* */ 83;/* CALLS */ 84;/* */ 85;/* _tx_thread_schedule Thread scheduling routine */ 86;/* */ 87;/* CALLED BY */ 88;/* */ 89;/* ISRs Interrupt Service Routines */ 90;/* */ 91;/* RELEASE HISTORY */ 92;/* */ 93;/* DATE NAME DESCRIPTION */ 94;/* */ 95;/* 09-30-2020 William E. Lamie Initial Version 6.1 */ 96;/* */ 97;/**************************************************************************/ 98;VOID _tx_thread_context_restore(VOID) 99;{ 100 EXPORT _tx_thread_context_restore 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 IF :DEF: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 END 246 247