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#ifdef TX_INCLUDE_USER_DEFINE_FILE
22#include "tx_user.h"
23#endif
24
25    .syntax unified
26#if defined(THUMB_MODE)
27    .thumb
28#else
29    .arm
30#endif
31
32    .global     _tx_thread_system_state
33    .global     _tx_thread_current_ptr
34    .global     __tx_irq_processing_return
35
36
37/* No 16-bit Thumb mode veneer code is needed for _tx_thread_context_save
38   since it will never be called 16-bit mode.  */
39
40    .text
41    .align 2
42/**************************************************************************/
43/*                                                                        */
44/*  FUNCTION                                               RELEASE        */
45/*                                                                        */
46/*    _tx_thread_context_save                              ARMv7-A        */
47/*                                                           6.4.0        */
48/*  AUTHOR                                                                */
49/*                                                                        */
50/*    William E. Lamie, Microsoft Corporation                             */
51/*                                                                        */
52/*  DESCRIPTION                                                           */
53/*                                                                        */
54/*    This function saves the context of an executing thread in the       */
55/*    beginning of interrupt processing.  The function also ensures that  */
56/*    the system stack is used upon return to the calling ISR.            */
57/*                                                                        */
58/*  INPUT                                                                 */
59/*                                                                        */
60/*    None                                                                */
61/*                                                                        */
62/*  OUTPUT                                                                */
63/*                                                                        */
64/*    None                                                                */
65/*                                                                        */
66/*  CALLS                                                                 */
67/*                                                                        */
68/*    None                                                                */
69/*                                                                        */
70/*  CALLED BY                                                             */
71/*                                                                        */
72/*    ISRs                                                                */
73/*                                                                        */
74/*  RELEASE HISTORY                                                       */
75/*                                                                        */
76/*    DATE              NAME                      DESCRIPTION             */
77/*                                                                        */
78/*  09-30-2020     William E. Lamie         Initial Version 6.1           */
79/*  10-15-2021     William E. Lamie         Modified comment(s), added    */
80/*                                            execution profile support,  */
81/*                                            resulting in version 6.1.9  */
82/*  04-25-2022     Zhen Kong                Updated comments,             */
83/*                                            resulting in version 6.1.11 */
84/*  10-31-2023     Tiejun Zhou              Modified comment(s), added    */
85/*                                            #include tx_user.h,         */
86/*                                            resulting in version 6.3.0  */
87/*  12-31-2023     Yajun Xia                Modified comment(s),          */
88/*                                            Added thumb mode support,   */
89/*                                            resulting in version 6.4.0  */
90/*                                                                        */
91/**************************************************************************/
92    .global _tx_thread_context_save
93    .type   _tx_thread_context_save,function
94_tx_thread_context_save:
95
96    /* Upon entry to this routine, it is assumed that IRQ interrupts are locked
97       out, we are in IRQ mode, and all registers are intact.  */
98
99    /* Check for a nested interrupt condition.  */
100
101    PUSH    {r0-r3}                         // Save some working registers
102#ifdef TX_ENABLE_FIQ_SUPPORT
103    CPSID   if                              // Disable FIQ interrupts
104#endif
105    LDR     r3, =_tx_thread_system_state    // Pickup address of system state variable
106    LDR     r2, [r3]                        // 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, #1                          // Increment the interrupt counter
113    STR     r2, [r3]                        // 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, #4                          // Adjust point of interrupt
120    PUSH    {r0, r10, r12, lr}              // Store other registers
121
122    /* Return to the ISR.  */
123
124    MOV     r10, #0                         // Clear stack limit
125
126#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
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    /* Otherwise, not nested, check to see if a thread was running.  */
140    ADD     r2, #1                          // Increment the interrupt counter
141    STR     r2, [r3]                        // Store it back in the variable
142    LDR     r1, =_tx_thread_current_ptr     // Pickup address of current thread ptr
143    LDR     r0, [r1]                        // Pickup current thread pointer
144    CMP     r0, #0                          // Is it NULL?
145    BEQ     __tx_thread_idle_system_save    // If so, interrupt occurred in
146                                            //   scheduling loop - nothing needs saving!
147
148    /* Save minimal context of interrupted thread.  */
149
150    MRS     r2, SPSR                        // Pickup saved SPSR
151    SUB     lr, #4                          // Adjust point of interrupt
152    PUSH    {r2, r10, r12, lr}              // Store other registers
153
154    MOV     r10, #0                         // Clear stack limit
155
156#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
157
158    /* Call the ISR enter function to indicate an ISR is executing.  */
159
160    PUSH    {lr}                            // Save ISR lr
161    BL      _tx_execution_isr_enter         // Call the ISR enter function
162    POP     {lr}                            // Recover ISR lr
163#endif
164
165    B       __tx_irq_processing_return      // Continue IRQ processing
166
167__tx_thread_idle_system_save:
168
169    /* Interrupt occurred in the scheduling loop.  */
170
171    /* Not much to do here, just adjust the stack pointer, and return to IRQ
172       processing.  */
173
174    MOV     r10, #0                         // Clear stack limit
175
176#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
177
178    /* Call the ISR enter function to indicate an ISR is executing.  */
179
180    PUSH    {lr}                            // Save ISR lr
181    BL      _tx_execution_isr_enter         // Call the ISR enter function
182    POP     {lr}                            // Recover ISR lr
183#endif
184
185    ADD     sp, #16                         // Recover saved registers
186    B       __tx_irq_processing_return      // Continue IRQ processing
187