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