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#ifdef TX_INCLUDE_USER_DEFINE_FILE
23#include "tx_user.h"
24#endif
25
26    .text
27    .align 3
28/**************************************************************************/
29/*                                                                        */
30/*  FUNCTION                                               RELEASE        */
31/*                                                                        */
32/*    _tx_thread_context_save                              ARMv8-A        */
33/*                                                           6.3.0        */
34/*  AUTHOR                                                                */
35/*                                                                        */
36/*    William E. Lamie, Microsoft Corporation                             */
37/*                                                                        */
38/*  DESCRIPTION                                                           */
39/*                                                                        */
40/*    This function saves the context of an executing thread in the       */
41/*    beginning of interrupt processing.  The function also ensures that  */
42/*    the system stack is used upon return to the calling ISR.            */
43/*                                                                        */
44/*  INPUT                                                                 */
45/*                                                                        */
46/*    None                                                                */
47/*                                                                        */
48/*  OUTPUT                                                                */
49/*                                                                        */
50/*    None                                                                */
51/*                                                                        */
52/*  CALLS                                                                 */
53/*                                                                        */
54/*    None                                                                */
55/*                                                                        */
56/*  CALLED BY                                                             */
57/*                                                                        */
58/*    ISRs                                                                */
59/*                                                                        */
60/*  RELEASE HISTORY                                                       */
61/*                                                                        */
62/*    DATE              NAME                      DESCRIPTION             */
63/*                                                                        */
64/*  09-30-2020     William E. Lamie         Initial Version 6.1           */
65/*  10-31-2023     Tiejun Zhou              Modified comment(s), added    */
66/*                                            #include tx_user.h,         */
67/*                                            resulting in version 6.3.0  */
68/*                                                                        */
69/**************************************************************************/
70// VOID   _tx_thread_context_save(VOID)
71// {
72    .global _tx_thread_context_save
73    .type   _tx_thread_context_save, @function
74_tx_thread_context_save:
75
76    /* Upon entry to this routine, it is assumed that IRQ/FIQ interrupts are locked
77       out, x29 (frame pointer), x30 (link register) are saved, we are in EL1,
78       and all other registers are intact.  */
79
80    /* Check for a nested interrupt condition.  */
81    // if (_tx_thread_system_state++)
82    // {
83
84    STP     x0, x1, [sp, #-16]!                 // Save x0, x1
85    STP     x2, x3, [sp, #-16]!                 // Save x2, x3
86    LDR     x3, =_tx_thread_system_state        // Pickup address of system state var
87    LDR     w2, [x3, #0]                        // Pickup system state
88    CMP     w2, #0                              // Is this the first interrupt?
89    BEQ     __tx_thread_not_nested_save         // Yes, not a nested context save
90
91    /* Nested interrupt condition.  */
92
93    ADD     w2, w2, #1                          // Increment the nested interrupt counter
94    STR     w2, [x3, #0]                        // Store it back in the variable
95
96   /* Save the rest of the scratch registers on the stack and return to the
97      calling ISR.  */
98
99    STP     x4, x5, [sp, #-16]!                 // Save x4, x5
100    STP     x6, x7, [sp, #-16]!                 // Save x6, x7
101    STP     x8, x9, [sp, #-16]!                 // Save x8, x9
102    STP     x10, x11, [sp, #-16]!               // Save x10, x11
103    STP     x12, x13, [sp, #-16]!               // Save x12, x13
104    STP     x14, x15, [sp, #-16]!               // Save x14, x15
105    STP     x16, x17, [sp, #-16]!               // Save x16, x17
106    STP     x18, x19, [sp, #-16]!               // Save x18, x19
107#ifdef EL1
108    MRS     x0, SPSR_EL1                        // Pickup SPSR
109    MRS     x1, ELR_EL1                         // Pickup ELR (point of interrupt)
110#else
111#ifdef EL2
112    MRS     x0, SPSR_EL2                        // Pickup SPSR
113    MRS     x1, ELR_EL2                         // Pickup ELR (point of interrupt)
114#else
115    MRS     x0, SPSR_EL3                        // Pickup SPSR
116    MRS     x1, ELR_EL3                         // Pickup ELR (point of interrupt)
117#endif
118#endif
119    STP     x0, x1, [sp, #-16]!                 // Save SPSR, ELR
120
121#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
122
123    /* Call the ISR enter function to indicate an ISR is executing.  */
124
125    STP     x29, x30, [sp, #-16]!               // Save x29, x30
126    BL      _tx_execution_isr_enter             // Call the ISR enter function
127    LDP     x29, x30, [sp], #16                 // Recover x29, x30
128#endif
129
130    /* Return to the ISR.  */
131
132    RET                                         // Return to ISR
133
134__tx_thread_not_nested_save:
135    // }
136
137    /* Otherwise, not nested, check to see if a thread was running.  */
138    // else if (_tx_thread_current_ptr)
139    // {
140
141    ADD     w2, w2, #1                          // Increment the interrupt counter
142    STR     w2, [x3, #0]                        // Store it back in the variable
143    LDR     x1, =_tx_thread_current_ptr         // Pickup address of current thread ptr
144    LDR     x0, [x1, #0]                        // Pickup current thread pointer
145    CMP     x0, #0                              // Is it NULL?
146    BEQ     __tx_thread_idle_system_save        // If so, interrupt occurred in
147                                                //   scheduling loop - nothing needs saving!
148
149    /* Save minimal context of interrupted thread.  */
150
151    STP     x4, x5, [sp, #-16]!                 // Save x4, x5
152    STP     x6, x7, [sp, #-16]!                 // Save x6, x7
153    STP     x8, x9, [sp, #-16]!                 // Save x8, x9
154    STP     x10, x11, [sp, #-16]!               // Save x10, x11
155    STP     x12, x13, [sp, #-16]!               // Save x12, x13
156    STP     x14, x15, [sp, #-16]!               // Save x14, x15
157    STP     x16, x17, [sp, #-16]!               // Save x16, x17
158    STP     x18, x19, [sp, #-16]!               // Save x18, x19
159#ifdef EL1
160    MRS     x4, SPSR_EL1                        // Pickup SPSR
161    MRS     x5, ELR_EL1                         // Pickup ELR (point of interrupt)
162#else
163#ifdef EL2
164    MRS     x4, SPSR_EL2                        // Pickup SPSR
165    MRS     x5, ELR_EL2                         // Pickup ELR (point of interrupt)
166#else
167    MRS     x4, SPSR_EL3                        // Pickup SPSR
168    MRS     x5, ELR_EL3                         // Pickup ELR (point of interrupt)
169#endif
170#endif
171    STP     x4, x5, [sp, #-16]!                 // Save SPSR, ELR
172
173    /* Save the current stack pointer in the thread's control block.  */
174    // _tx_thread_current_ptr -> tx_thread_stack_ptr =  sp;
175
176    MOV     x4, sp                              //
177    STR     x4, [x0, #8]                        // Save thread stack pointer
178
179    /* Switch to the system stack.  */
180    // sp =  _tx_thread_system_stack_ptr;
181
182    LDR     x3, =_tx_thread_system_stack_ptr    // Pickup address of system stack
183    LDR     x4, [x3, #0]                        // Pickup system stack pointer
184    MOV     sp, x4                              // Setup system stack pointer
185
186#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
187
188    /* Call the ISR enter function to indicate an ISR is executing.  */
189
190    STP     x29, x30, [sp, #-16]!               // Save x29, x30
191    BL      _tx_execution_isr_enter             // Call the ISR enter function
192    LDP     x29, x30, [sp], #16                 // Recover x29, x30
193#endif
194
195    RET                                         // Return to caller
196
197    // }
198    // else
199    // {
200
201__tx_thread_idle_system_save:
202
203    /* Interrupt occurred in the scheduling loop.  */
204
205    /* Not much to do here, just adjust the stack pointer, and return to IRQ
206       processing.  */
207
208#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
209
210    /* Call the ISR enter function to indicate an ISR is executing.  */
211
212    STP     x29, x30, [sp, #-16]!               // Save x29, x30
213    BL      _tx_execution_isr_enter             // Call the ISR enter function
214    LDP     x29, x30, [sp], #16                 // Recover x29, x30
215#endif
216
217    ADD     sp, sp, #48                         // Recover saved registers
218    RET                                         // Continue IRQ processing
219
220    // }
221// }
222