;/*************************************************************************** ; * Copyright (c) 2024 Microsoft Corporation ; * ; * This program and the accompanying materials are made available under the ; * terms of the MIT License which is available at ; * https://opensource.org/licenses/MIT. ; * ; * SPDX-License-Identifier: MIT ; **************************************************************************/ ; ; ;/**************************************************************************/ ;/**************************************************************************/ ;/** */ ;/** ThreadX Component */ ;/** */ ;/** Thread */ ;/** */ ;/**************************************************************************/ ;/**************************************************************************/ ; ; ;#define TX_SOURCE_CODE ; ; ;/* Include necessary system files. */ ; ;#include "tx_api.h" ;#include "tx_thread.h" ; ; IF :DEF:TX_ENABLE_FIQ_SUPPORT DISABLE_INTS EQU 0xC0 ; IRQ & FIQ interrupts disabled ELSE DISABLE_INTS EQU 0x80 ; IRQ interrupts disabled ENDIF IMPORT _tx_thread_system_state IMPORT _tx_thread_current_ptr IMPORT __tx_irq_processing_return IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY IMPORT _tx_execution_isr_enter ENDIF ; ; AREA ||.text||, CODE, READONLY PRESERVE8 ;/**************************************************************************/ ;/* */ ;/* FUNCTION RELEASE */ ;/* */ ;/* _tx_thread_context_save ARM11/AC5 */ ;/* 6.1 */ ;/* AUTHOR */ ;/* */ ;/* William E. Lamie, Microsoft Corporation */ ;/* */ ;/* DESCRIPTION */ ;/* */ ;/* This function saves the context of an executing thread in the */ ;/* beginning of interrupt processing. The function also ensures that */ ;/* the system stack is used upon return to the calling ISR. */ ;/* */ ;/* INPUT */ ;/* */ ;/* None */ ;/* */ ;/* OUTPUT */ ;/* */ ;/* None */ ;/* */ ;/* CALLS */ ;/* */ ;/* None */ ;/* */ ;/* CALLED BY */ ;/* */ ;/* ISRs */ ;/* */ ;/* RELEASE HISTORY */ ;/* */ ;/* DATE NAME DESCRIPTION */ ;/* */ ;/* 09-30-2020 William E. Lamie Initial Version 6.1 */ ;/* */ ;/**************************************************************************/ ;VOID _tx_thread_context_save(VOID) ;{ EXPORT _tx_thread_context_save _tx_thread_context_save ; ; /* Upon entry to this routine, it is assumed that IRQ interrupts are locked ; out, we are in IRQ mode, and all registers are intact. */ ; ; /* Check for a nested interrupt condition. */ ; if (_tx_thread_system_state++) ; { ; STMDB sp!, {r0-r3} ; Save some working registers IF :DEF:TX_ENABLE_FIQ_SUPPORT MRS r0, CPSR ; Pickup the CPSR ORR r0, r0, #DISABLE_INTS ; Build disable interrupt CPSR MSR CPSR_cxsf, r0 ; Disable interrupts ENDIF LDR r3, =_tx_thread_system_state ; Pickup address of system state var LDR r2, [r3, #0] ; Pickup system state CMP r2, #0 ; Is this the first interrupt? BEQ __tx_thread_not_nested_save ; Yes, not a nested context save ; ; /* Nested interrupt condition. */ ; ADD r2, r2, #1 ; Increment the interrupt counter STR r2, [r3, #0] ; Store it back in the variable ; ; /* Save the rest of the scratch registers on the stack and return to the ; calling ISR. */ ; MRS r0, SPSR ; Pickup saved SPSR SUB lr, lr, #4 ; Adjust point of interrupt STMDB sp!, {r0, r10, r12, lr} ; Store other registers ; ; /* Return to the ISR. */ ; MOV r10, #0 ; Clear stack limit IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY ; ; /* Call the ISR enter function to indicate an ISR is executing. */ ; PUSH {lr} ; Save ISR lr BL _tx_execution_isr_enter ; Call the ISR enter function POP {lr} ; Recover ISR lr ENDIF B __tx_irq_processing_return ; Continue IRQ processing ; __tx_thread_not_nested_save ; } ; ; /* Otherwise, not nested, check to see if a thread was running. */ ; else if (_tx_thread_current_ptr) ; { ; ADD r2, r2, #1 ; Increment the interrupt counter STR r2, [r3, #0] ; Store it back in the variable LDR r1, =_tx_thread_current_ptr ; Pickup address of current thread ptr LDR r0, [r1, #0] ; Pickup current thread pointer CMP r0, #0 ; Is it NULL? BEQ __tx_thread_idle_system_save ; If so, interrupt occurred in ; scheduling loop - nothing needs saving! ; ; /* Save minimal context of interrupted thread. */ ; MRS r2, SPSR ; Pickup saved SPSR SUB lr, lr, #4 ; Adjust point of interrupt STMDB sp!, {r2, r10, r12, lr} ; Store other registers ; ; /* Save the current stack pointer in the thread's control block. */ ; _tx_thread_current_ptr -> tx_thread_stack_ptr = sp; ; ; /* Switch to the system stack. */ ; sp = _tx_thread_system_stack_ptr; ; MOV r10, #0 ; Clear stack limit IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY ; ; /* Call the ISR enter function to indicate an ISR is executing. */ ; PUSH {lr} ; Save ISR lr BL _tx_execution_isr_enter ; Call the ISR enter function POP {lr} ; Recover ISR lr ENDIF B __tx_irq_processing_return ; Continue IRQ processing ; ; } ; else ; { ; __tx_thread_idle_system_save ; ; /* Interrupt occurred in the scheduling loop. */ ; ; /* Not much to do here, just adjust the stack pointer, and return to IRQ ; processing. */ ; MOV r10, #0 ; Clear stack limit IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY ; ; /* Call the ISR enter function to indicate an ISR is executing. */ ; PUSH {lr} ; Save ISR lr BL _tx_execution_isr_enter ; Call the ISR enter function POP {lr} ; Recover ISR lr ENDIF ADD sp, sp, #16 ; Recover saved registers B __tx_irq_processing_return ; Continue IRQ processing ; ; } ;} ; END