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;/** ThreadX Component                                                     */
15;/**                                                                       */
16;/**   Thread                                                              */
17;/**                                                                       */
18;/**************************************************************************/
19;/**************************************************************************/
20#ifdef TX_INCLUDE_USER_DEFINE_FILE
21#include "tx_user.h"
22#endif
23
24    .equ    BTA, 0x412
25    .equ    KSTACK_TOP,     0x264
26    .equ    KSTACK_BASE,    0x265
27    .equ    STATUS32_SC,    0x4000
28
29;/**************************************************************************/
30;/*                                                                        */
31;/*  FUNCTION                                               RELEASE        */
32;/*                                                                        */
33;/*    _tx_thread_context_save                         ARCv2_EM/MetaWare   */
34;/*                                                           6.2.1        */
35;/*  AUTHOR                                                                */
36;/*                                                                        */
37;/*    William E. Lamie, Microsoft Corporation                             */
38;/*                                                                        */
39;/*  DESCRIPTION                                                           */
40;/*                                                                        */
41;/*    This function saves the context of an executing thread in the       */
42;/*    beginning of interrupt processing.  The function also ensures that  */
43;/*    the system stack is used upon return to the calling ISR.            */
44;/*                                                                        */
45;/*  INPUT                                                                 */
46;/*                                                                        */
47;/*    None                                                                */
48;/*                                                                        */
49;/*  OUTPUT                                                                */
50;/*                                                                        */
51;/*    None                                                                */
52;/*                                                                        */
53;/*  CALLS                                                                 */
54;/*                                                                        */
55;/*    None                                                                */
56;/*                                                                        */
57;/*  CALLED BY                                                             */
58;/*                                                                        */
59;/*    ISRs                                                                */
60;/*                                                                        */
61;/*  RELEASE HISTORY                                                       */
62;/*                                                                        */
63;/*    DATE              NAME                      DESCRIPTION             */
64;/*                                                                        */
65;/*  09-30-2020     William E. Lamie         Initial Version 6.1           */
66;/*  04-02-2021     Andres Mlinar            Modified comment(s), and      */
67;/*                                            r25/r30 are caller saved,   */
68;/*                                            resulting in version 6.1.6  */
69;/*  03-08-2023     Cindy Deng               Modified comment(s), added    */
70;/*                                            #include tx_user.h,         */
71;/*                                            resulting in version 6.2.1  */
72;/*                                                                        */
73;/**************************************************************************/
74;VOID   _tx_thread_context_save(VOID)
75;{
76    .global _tx_thread_context_save
77    .type   _tx_thread_context_save, @function
78_tx_thread_context_save:
79;
80;    /* Upon entry to this routine, it is assumed that an interrupt stack frame
81;       has already been allocated, and the interrupted blink register is already saved.  */
82;
83    clri                                                ; Disable interrupts
84    st      r1, [sp, 128]                               ; Save r1
85    st      r0, [sp, 132]                               ; Save r0
86;
87;    /* Check for a nested interrupt condition.  */
88;    if (_tx_thread_system_state++)
89;    {
90;
91    ld      r0, [gp, _tx_thread_system_state@sda]       ; Pickup system state
92    st      r3, [sp, 120]                               ; Save r3
93    st      r2, [sp, 124]                               ; Save r2
94    breq    r0, 0, __tx_thread_not_nested_save          ; If 0, we are not in a nested
95                                                        ;   condition
96;
97;    /* Nested interrupt condition.  */
98;
99    add     r0, r0, 1                                   ; Increment the nested interrupt count
100    st      r0, [gp, _tx_thread_system_state@sda]       ; Update system state
101;
102;   /* Save the rest of the scratch registers on the stack and return to the
103;      calling ISR.  */
104;
105__tx_thread_nested_save:                                ; Label is for special nested interrupt case from idle system save below
106    st      r30, [sp, 136]                              ; Save r30
107    st      r25, [sp, 32]                               ; Save r25
108    st      r12, [sp, 84]                               ; Save r12
109    st      r11, [sp, 88]                               ; Save r11
110    st      r10, [sp, 92]                               ; Save r10
111    st      r9,  [sp, 96]                               ; Save r9
112    st      r8,  [sp, 100]                              ; Save r8
113    st      r7,  [sp, 104]                              ; Save r7
114    st      r6,  [sp, 108]                              ; Save r6
115    st      r5,  [sp, 112]                              ; Save r5
116    st      r4,  [sp, 116]                              ; Save r4
117    lr      r10, [LP_START]                             ; Pickup LP_START
118    lr      r9,  [LP_END]                               ; Pickup LP_END
119    st      LP_COUNT, [sp, 12]                          ; Save LP_COUNT
120    st      r10, [sp, 4]                                ; Save LP_START
121    st      r9,  [sp, 8]                                ; Save LP_END
122    .ifdef   TX_ENABLE_ACC
123    st      r58, [sp, 140]                              ; Save r58
124    st      r59, [sp, 144]                              ; Save r59
125    .endif
126    lr      r0,  [BTA]                                  ; Pickup BTA
127    st      r0,  [sp, 156]                              ; Save BTA
128
129;
130;    /* Return to the ISR.  */
131;
132    .ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
133;
134;    /* Call the ISR enter function to indicate an ISR is executing.  */
135;
136    sub     sp, sp, 32                                  ; Allocating some space on the stack
137    st      blink, [sp, 16]                             ; Save blink
138    bl.d    _tx_execution_isr_enter                     ; Call the ISR enter function
139    nop                                                 ; Delay slot
140    ld      blink, [sp, 16]                             ; Recover blink
141    add     sp, sp, 32                                  ; Recover the stack space
142    .endif
143;
144
145    j.d     [blink]                                     ; Return to Level 1 ISR
146    st      ilink, [sp, 20]                             ; Save ilink
147;
148__tx_thread_not_nested_save:
149;    }
150;
151;    /* Otherwise, not nested, check to see if a thread was running.  */
152;    else if (_tx_thread_current_ptr)
153;    {
154;
155    add     r0, r0, 1                                   ; Increment the nested interrupt count
156    st      r0, [gp, _tx_thread_system_state@sda]       ; Update system state
157    ld      r1, [gp, _tx_thread_current_ptr@sda]        ; Pickup current thread pointer
158    st      r30, [sp, 136]                              ; Save r30
159    st      r25, [sp, 32]                               ; Save r25
160    st      r12, [sp, 84]                               ; Save r12
161    st      r11, [sp, 88]                               ; Save r11
162    breq    r1, 0, __tx_thread_idle_system_save         ; If no thread is running, idle system was
163                                                        ;   interrupted.
164;
165;    /* Save minimal context of interrupted thread.  */
166;
167    st      r10, [sp, 92]                               ; Save r10
168    st      r9,  [sp, 96]                               ; Save r9
169    st      r8,  [sp, 100]                              ; Save r8
170    st      r7,  [sp, 104]                              ; Save r7
171    st      r6,  [sp, 108]                              ; Save r6
172    st      r5,  [sp, 112]                              ; Save r5
173    st      r4,  [sp, 116]                              ; Save r4
174    lr      r10, [LP_START]                             ; Pickup LP_START
175    lr      r9,  [LP_END]                               ; Pickup LP_END
176    st      LP_COUNT, [sp, 12]                          ; Save LP_COUNT
177    st      r10, [sp, 4]                                ; Save LP_START
178    st      r9,  [sp, 8]                                ; Save LP_END
179    st      ilink, [sp, 20]                             ; Save ilink
180    .ifdef   TX_ENABLE_ACC
181    st      r58, [sp, 140]                              ; Save r58
182    st      r59, [sp, 144]                              ; Save r59
183    .endif
184    lr      r0,  [BTA]                                  ; Pickup BTA
185    st      r0,  [sp, 156]                              ; Save BTA
186;
187;    /* Save the current stack pointer in the thread's control block.  */
188;    _tx_thread_current_ptr -> tx_thread_stack_ptr =  sp;
189;
190    st      sp, [r1, 8]                                 ; Save thread's stack pointer
191
192    .ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
193;
194;    /* Call the ISR enter function to indicate an ISR is executing.  */
195;
196    sub     sp, sp, 32                                  ; Allocating some space on the stack
197    st      blink, [sp, 16]                             ; Save blink
198    bl.d    _tx_execution_isr_enter                     ; Call the ISR enter function
199    nop                                                 ; Delay slot
200    ld      blink, [sp, 16]                             ; Recover blink
201    add     sp, sp, 32                                  ; Recover the stack space
202    .endif
203
204    .ifdef  TX_ENABLE_HW_STACK_CHECKING
205    lr      r2, [status32]                              ; Pickup current STATUS32
206    and     r2, r2, ~STATUS32_SC                        ; Clear the hardware stack checking enable bit (SC)
207    kflag   r2                                          ; Disable hardware stack checking
208    mov     r1, _tx_system_stack_top_address            ; Pickup top of system stack (lowest memory address)
209    sr      r1, [KSTACK_TOP]                            ; Setup KSTACK_TOP
210    mov     r1, _tx_system_stack_base_address           ; Pickup base of system stack (highest memory address)
211    sr      r1, [KSTACK_BASE]                           ; Setup KSTACK_BASE
212    ld      sp, [gp, _tx_thread_system_stack_ptr@sda]   ; Switch to system stack
213    or      r2, r2, STATUS32_SC                         ; Or in hardware stack checking enable bit (SC)
214    j_s.d   [blink]                                     ; Return to calling ISR
215    kflag   r2                                          ; Enable hardware stack checking
216    .else
217;
218;    /* Switch to the system stack.  */
219;    sp =  _tx_thread_system_stack_ptr;
220;
221    j_s.d   [blink]                                     ; Return to calling ISR
222    ld      sp, [gp, _tx_thread_system_stack_ptr@sda]   ; Switch to system stack
223    .endif
224;
225;    }
226;    else
227;    {
228;
229__tx_thread_idle_system_save:
230;
231;    /* Interrupt occurred in the scheduling loop.  */
232;
233    .ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
234;
235;    /* Call the ISR enter function to indicate an ISR is executing.  */
236;
237    sub     sp, sp, 32                                  ; Allocating some space on the stack
238    st      blink, [sp, 16]                             ; Save blink
239    bl.d    _tx_execution_isr_enter                     ; Call the ISR enter function
240    nop                                                 ; Delay slot
241    ld      blink, [sp, 16]                             ; Recover blink
242    add     sp, sp, 32                                  ; Recover the stack space
243    .endif
244;
245;     /* See if we have a special nesting condition.  This happens when the higher priority
246;        interrupt occurs before the nested interrupt logic is valid.  */
247;
248    lr      r0, [AUX_IRQ_ACT]                           ; Pickup the interrupt active register
249    neg     r1, r0                                      ; Negate
250    and     r1, r0, r1                                  ; See if there are any other interrupts present
251    breq    r0, r1, __tx_thread_not_nested
252    j __tx_thread_nested_save                           ; If more interrupts, go into the nested interrupt save logic
253__tx_thread_not_nested:
254;
255;    /* Not much to do here, just adjust the stack pointer, and return to
256;       ISR processing.  */
257;
258    j_s.d   [blink]                                     ; Return to ISR
259    add     sp, sp, 160                                 ; Recover stack space
260;
261;    }
262;}
263    .end
264