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; 31; 32 IF :DEF:TX_ENABLE_FIQ_SUPPORT 33DISABLE_INTS EQU 0xC0 ; IRQ & FIQ interrupts disabled 34 ELSE 35DISABLE_INTS EQU 0x80 ; IRQ interrupts disabled 36 ENDIF 37 38 IMPORT _tx_thread_system_state 39 IMPORT _tx_thread_current_ptr 40 IMPORT __tx_irq_processing_return 41 IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY 42 IMPORT _tx_execution_isr_enter 43 ENDIF 44; 45; 46 AREA ||.text||, CODE, READONLY 47 PRESERVE8 48;/**************************************************************************/ 49;/* */ 50;/* FUNCTION RELEASE */ 51;/* */ 52;/* _tx_thread_context_save ARM11/AC5 */ 53;/* 6.1 */ 54;/* AUTHOR */ 55;/* */ 56;/* William E. Lamie, Microsoft Corporation */ 57;/* */ 58;/* DESCRIPTION */ 59;/* */ 60;/* This function saves the context of an executing thread in the */ 61;/* beginning of interrupt processing. The function also ensures that */ 62;/* the system stack is used upon return to the calling ISR. */ 63;/* */ 64;/* INPUT */ 65;/* */ 66;/* None */ 67;/* */ 68;/* OUTPUT */ 69;/* */ 70;/* None */ 71;/* */ 72;/* CALLS */ 73;/* */ 74;/* None */ 75;/* */ 76;/* CALLED BY */ 77;/* */ 78;/* ISRs */ 79;/* */ 80;/* RELEASE HISTORY */ 81;/* */ 82;/* DATE NAME DESCRIPTION */ 83;/* */ 84;/* 09-30-2020 William E. Lamie Initial Version 6.1 */ 85;/* */ 86;/**************************************************************************/ 87;VOID _tx_thread_context_save(VOID) 88;{ 89 EXPORT _tx_thread_context_save 90_tx_thread_context_save 91; 92; /* Upon entry to this routine, it is assumed that IRQ interrupts are locked 93; out, we are in IRQ mode, and all registers are intact. */ 94; 95; /* Check for a nested interrupt condition. */ 96; if (_tx_thread_system_state++) 97; { 98; 99 STMDB sp!, {r0-r3} ; Save some working registers 100 IF :DEF:TX_ENABLE_FIQ_SUPPORT 101 MRS r0, CPSR ; Pickup the CPSR 102 ORR r0, r0, #DISABLE_INTS ; Build disable interrupt CPSR 103 MSR CPSR_cxsf, r0 ; Disable interrupts 104 ENDIF 105 LDR r3, =_tx_thread_system_state ; Pickup address of system state var 106 LDR r2, [r3, #0] ; Pickup system state 107 CMP r2, #0 ; Is this the first interrupt? 108 BEQ __tx_thread_not_nested_save ; Yes, not a nested context save 109; 110; /* Nested interrupt condition. */ 111; 112 ADD r2, r2, #1 ; Increment the interrupt counter 113 STR r2, [r3, #0] ; Store it back in the variable 114; 115; /* Save the rest of the scratch registers on the stack and return to the 116; calling ISR. */ 117; 118 MRS r0, SPSR ; Pickup saved SPSR 119 SUB lr, lr, #4 ; Adjust point of interrupt 120 STMDB sp!, {r0, r10, r12, lr} ; Store other registers 121; 122; /* Return to the ISR. */ 123; 124 MOV r10, #0 ; Clear stack limit 125 126 IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY 127; 128; /* Call the ISR enter function to indicate an ISR is executing. */ 129; 130 PUSH {lr} ; Save ISR lr 131 BL _tx_execution_isr_enter ; Call the ISR enter function 132 POP {lr} ; Recover ISR lr 133 ENDIF 134 135 B __tx_irq_processing_return ; Continue IRQ processing 136; 137__tx_thread_not_nested_save 138; } 139; 140; /* Otherwise, not nested, check to see if a thread was running. */ 141; else if (_tx_thread_current_ptr) 142; { 143; 144 ADD r2, r2, #1 ; Increment the interrupt counter 145 STR r2, [r3, #0] ; Store it back in the variable 146 LDR r1, =_tx_thread_current_ptr ; Pickup address of current thread ptr 147 LDR r0, [r1, #0] ; Pickup current thread pointer 148 CMP r0, #0 ; Is it NULL? 149 BEQ __tx_thread_idle_system_save ; If so, interrupt occurred in 150 ; scheduling loop - nothing needs saving! 151; 152; /* Save minimal context of interrupted thread. */ 153; 154 MRS r2, SPSR ; Pickup saved SPSR 155 SUB lr, lr, #4 ; Adjust point of interrupt 156 STMDB sp!, {r2, r10, r12, lr} ; Store other registers 157; 158; /* Save the current stack pointer in the thread's control block. */ 159; _tx_thread_current_ptr -> tx_thread_stack_ptr = sp; 160; 161; /* Switch to the system stack. */ 162; sp = _tx_thread_system_stack_ptr; 163; 164 MOV r10, #0 ; Clear stack limit 165 166 IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY 167; 168; /* Call the ISR enter function to indicate an ISR is executing. */ 169; 170 PUSH {lr} ; Save ISR lr 171 BL _tx_execution_isr_enter ; Call the ISR enter function 172 POP {lr} ; Recover ISR lr 173 ENDIF 174 175 B __tx_irq_processing_return ; Continue IRQ processing 176; 177; } 178; else 179; { 180; 181__tx_thread_idle_system_save 182; 183; /* Interrupt occurred in the scheduling loop. */ 184; 185; /* Not much to do here, just adjust the stack pointer, and return to IRQ 186; processing. */ 187; 188 MOV r10, #0 ; Clear stack limit 189 190 IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY 191; 192; /* Call the ISR enter function to indicate an ISR is executing. */ 193; 194 PUSH {lr} ; Save ISR lr 195 BL _tx_execution_isr_enter ; Call the ISR enter function 196 POP {lr} ; Recover ISR lr 197 ENDIF 198 199 ADD sp, sp, #16 ; Recover saved registers 200 B __tx_irq_processing_return ; Continue IRQ processing 201; 202; } 203;} 204; 205 END 206 207