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