summaryrefslogtreecommitdiff
path: root/ports_arch/ARMv8-A/threadx/common/src/tx_thread_context_save.S
blob: c23951557c187871a8c876b67e41b152ac1ea401 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
/***************************************************************************
 * Copyright (c) 2024 Microsoft Corporation
 * Copyright (c) 2026-present Eclipse ThreadX contributors
 *
 * 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                                                              */
/**                                                                       */
/**************************************************************************/
/**************************************************************************/
#ifdef TX_INCLUDE_USER_DEFINE_FILE
#include "tx_user.h"
#endif

    .text
    .align 3
/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _tx_thread_context_save                              ARMv8-A        */
/*                                                           6.3.0        */
/*  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                                                                */
/*                                                                        */
/**************************************************************************/
// VOID   _tx_thread_context_save(VOID)
// {
    .global _tx_thread_context_save
    .type   _tx_thread_context_save, @function
_tx_thread_context_save:

    /* Upon entry to this routine, it is assumed that IRQ/FIQ interrupts are locked
       out, x29 (frame pointer), x30 (link register) are saved, we are in EL1,
       and all other registers are intact.  */

    /* Check for a nested interrupt condition.  */
    // if (_tx_thread_system_state++)
    // {

    STP     x0, x1, [sp, #-16]!                 // Save x0, x1
    STP     x2, x3, [sp, #-16]!                 // Save x2, x3
    LDR     x3, =_tx_thread_system_state        // Pickup address of system state var
    LDR     w2, [x3, #0]                        // Pickup system state
    CMP     w2, #0                              // Is this the first interrupt?
    BEQ     __tx_thread_not_nested_save         // Yes, not a nested context save

    /* Nested interrupt condition.  */

    ADD     w2, w2, #1                          // Increment the nested interrupt counter
    STR     w2, [x3, #0]                        // Store it back in the variable

   /* Save the rest of the scratch registers on the stack and return to the
      calling ISR.  */

    STP     x4, x5, [sp, #-16]!                 // Save x4, x5
    STP     x6, x7, [sp, #-16]!                 // Save x6, x7
    STP     x8, x9, [sp, #-16]!                 // Save x8, x9
    STP     x10, x11, [sp, #-16]!               // Save x10, x11
    STP     x12, x13, [sp, #-16]!               // Save x12, x13
    STP     x14, x15, [sp, #-16]!               // Save x14, x15
    STP     x16, x17, [sp, #-16]!               // Save x16, x17
    STP     x18, x19, [sp, #-16]!               // Save x18, x19
#ifdef EL1
    MRS     x0, SPSR_EL1                        // Pickup SPSR
    MRS     x1, ELR_EL1                         // Pickup ELR (point of interrupt)
#else
#ifdef EL2
    MRS     x0, SPSR_EL2                        // Pickup SPSR
    MRS     x1, ELR_EL2                         // Pickup ELR (point of interrupt)
#else
    MRS     x0, SPSR_EL3                        // Pickup SPSR
    MRS     x1, ELR_EL3                         // Pickup ELR (point of interrupt)
#endif
#endif
    STP     x0, x1, [sp, #-16]!                 // Save SPSR, ELR

#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))

    /* Call the ISR enter function to indicate an ISR is executing.  */

    STP     x29, x30, [sp, #-16]!               // Save x29, x30
    BL      _tx_execution_isr_enter             // Call the ISR enter function
    LDP     x29, x30, [sp], #16                 // Recover x29, x30
#endif

    /* Return to the ISR.  */

    RET                                         // Return to ISR

__tx_thread_not_nested_save:
    // }

    /* Otherwise, not nested, check to see if a thread was running.  */
    // else if (_tx_thread_current_ptr)
    // {

    ADD     w2, w2, #1                          // Increment the interrupt counter
    STR     w2, [x3, #0]                        // Store it back in the variable
    LDR     x1, =_tx_thread_current_ptr         // Pickup address of current thread ptr
    LDR     x0, [x1, #0]                        // Pickup current thread pointer
    CMP     x0, #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.  */

    STP     x4, x5, [sp, #-16]!                 // Save x4, x5
    STP     x6, x7, [sp, #-16]!                 // Save x6, x7
    STP     x8, x9, [sp, #-16]!                 // Save x8, x9
    STP     x10, x11, [sp, #-16]!               // Save x10, x11
    STP     x12, x13, [sp, #-16]!               // Save x12, x13
    STP     x14, x15, [sp, #-16]!               // Save x14, x15
    STP     x16, x17, [sp, #-16]!               // Save x16, x17
    STP     x18, x19, [sp, #-16]!               // Save x18, x19
#ifdef EL1
    MRS     x4, SPSR_EL1                        // Pickup SPSR
    MRS     x5, ELR_EL1                         // Pickup ELR (point of interrupt)
#else
#ifdef EL2
    MRS     x4, SPSR_EL2                        // Pickup SPSR
    MRS     x5, ELR_EL2                         // Pickup ELR (point of interrupt)
#else
    MRS     x4, SPSR_EL3                        // Pickup SPSR
    MRS     x5, ELR_EL3                         // Pickup ELR (point of interrupt)
#endif
#endif
    STP     x4, x5, [sp, #-16]!                 // Save SPSR, ELR

    /* Save the current stack pointer in the thread's control block.  */
    // _tx_thread_current_ptr -> tx_thread_stack_ptr =  sp;

    MOV     x4, sp                              //
    STR     x4, [x0, #8]                        // Save thread stack pointer

    /* Switch to the system stack.  */
    // sp =  _tx_thread_system_stack_ptr;

    LDR     x3, =_tx_thread_system_stack_ptr    // Pickup address of system stack
    LDR     x4, [x3, #0]                        // Pickup system stack pointer
    MOV     sp, x4                              // Setup system stack pointer

#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY

    /* Call the ISR enter function to indicate an ISR is executing.  */

    STP     x29, x30, [sp, #-16]!               // Save x29, x30
    BL      _tx_execution_isr_enter             // Call the ISR enter function
    LDP     x29, x30, [sp], #16                 // Recover x29, x30
#endif

    RET                                         // Return to caller

    // }
    // 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.  */

#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))

    /* Call the ISR enter function to indicate an ISR is executing.  */

    STP     x29, x30, [sp, #-16]!               // Save x29, x30
    BL      _tx_execution_isr_enter             // Call the ISR enter function
    LDP     x29, x30, [sp], #16                 // Recover x29, x30
#endif

    ADD     sp, sp, #48                         // Recover saved registers
    RET                                         // Continue IRQ processing

    // }
// }