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;
22;
23;#define TX_SOURCE_CODE
24;
25;
26;/* Include necessary system files.  */
27;
28;#include "tx_api.h"
29;#include "tx_thread.h"
30;
31;
32    IMPORT      _tx_thread_system_state
33    IMPORT      _tx_thread_current_ptr
34    IMPORT      __tx_fiq_processing_return
35    IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY
36    IMPORT      _tx_execution_isr_enter
37    ENDIF
38;
39;
40        AREA ||.text||, CODE, READONLY
41        PRESERVE8
42;/**************************************************************************/
43;/*                                                                        */
44;/*  FUNCTION                                               RELEASE        */
45;/*                                                                        */
46;/*    _tx_thread_fiq_context_save                         ARM11/AC5       */
47;/*                                                            6.1         */
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;/*                                                                        */
80;/**************************************************************************/
81; VOID   _tx_thread_fiq_context_save(VOID)
82;{
83    EXPORT  _tx_thread_fiq_context_save
84_tx_thread_fiq_context_save
85;
86;    /* Upon entry to this routine, it is assumed that IRQ interrupts are locked
87;       out, we are in IRQ mode, and all registers are intact.  */
88;
89;    /* Check for a nested interrupt condition.  */
90;    if (_tx_thread_system_state++)
91;    {
92;
93    STMDB   sp!, {r0-r3}                        ; Save some working registers
94    LDR     r3, =_tx_thread_system_state        ; Pickup address of system state var
95    LDR     r2, [r3]                            ; Pickup system state
96    CMP     r2, #0                              ; Is this the first interrupt?
97    BEQ     __tx_thread_fiq_not_nested_save     ; Yes, not a nested context save
98;
99;    /* Nested interrupt condition.  */
100;
101    ADD     r2, r2, #1                          ; Increment the interrupt counter
102    STR     r2, [r3]                            ; Store it back in the variable
103;
104;    /* Save the rest of the scratch registers on the stack and return to the
105;       calling ISR.  */
106;
107    MRS     r0, SPSR                            ; Pickup saved SPSR
108    SUB     lr, lr, #4                          ; Adjust point of interrupt
109    STMDB   sp!, {r0, r10, r12, lr}             ; Store other registers
110;
111;    /* Return to the ISR.  */
112;
113    MOV     r10, #0                             ; Clear stack limit
114
115    IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY
116;
117;    /* Call the ISR enter function to indicate an ISR is executing.  */
118;
119    PUSH    {lr}                                ; Save ISR lr
120    BL      _tx_execution_isr_enter             ; Call the ISR enter function
121    POP     {lr}                                ; Recover ISR lr
122    ENDIF
123
124    B       __tx_fiq_processing_return          ; Continue FIQ processing
125;
126__tx_thread_fiq_not_nested_save
127;    }
128;
129;    /* Otherwise, not nested, check to see if a thread was running.  */
130;    else if (_tx_thread_current_ptr)
131;    {
132;
133    ADD     r2, r2, #1                          ; Increment the interrupt counter
134    STR     r2, [r3]                            ; Store it back in the variable
135    LDR     r1, =_tx_thread_current_ptr         ; Pickup address of current thread ptr
136    LDR     r0, [r1]                            ; Pickup current thread pointer
137    CMP     r0, #0                              ; Is it NULL?
138    BEQ     __tx_thread_fiq_idle_system_save    ; If so, interrupt occurred in
139;                                               ;   scheduling loop - nothing needs saving!
140;
141;    /* Save minimal context of interrupted thread.  */
142;
143    MRS     r2, SPSR                            ; Pickup saved SPSR
144    SUB     lr, lr, #4                          ; Adjust point of interrupt
145    STMDB   sp!, {r2, lr}                       ; Store other registers, Note that we don't
146;                                               ;   need to save sl and ip since FIQ has
147;                                               ;   copies of these registers.  Nested
148;                                               ;   interrupt processing does need to save
149;                                               ;   these registers.
150;
151;    /* Save the current stack pointer in the thread's control block.  */
152;    _tx_thread_current_ptr -> tx_thread_stack_ptr =  sp;
153;
154;    /* Switch to the system stack.  */
155;    sp =  _tx_thread_system_stack_ptr;
156;
157    MOV     r10, #0                             ; Clear stack limit
158
159    IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY
160;
161;    /* Call the ISR enter function to indicate an ISR is executing.  */
162;
163    PUSH    {lr}                                ; Save ISR lr
164    BL      _tx_execution_isr_enter             ; Call the ISR enter function
165    POP     {lr}                                ; Recover ISR lr
166    ENDIF
167
168    B       __tx_fiq_processing_return          ; Continue FIQ processing
169;
170;   }
171;   else
172;   {
173;
174__tx_thread_fiq_idle_system_save
175;
176;    /* Interrupt occurred in the scheduling loop.  */
177;
178    IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY
179;
180;    /* Call the ISR enter function to indicate an ISR is executing.  */
181;
182    PUSH    {lr}                                ; Save ISR lr
183    BL      _tx_execution_isr_enter             ; Call the ISR enter function
184    POP     {lr}                                ; Recover ISR lr
185    ENDIF
186;
187;    /* Not much to do here, save the current SPSR and LR for possible
188;       use in IRQ interrupted in idle system conditions, and return to
189;       FIQ interrupt processing.  */
190;
191    MRS     r0, SPSR                            ; Pickup saved SPSR
192    SUB     lr, lr, #4                          ; Adjust point of interrupt
193    STMDB   sp!, {r0, lr}                       ; Store other registers that will get used
194;                                               ;   or stripped off the stack in context
195;                                               ;   restore
196    B       __tx_fiq_processing_return          ; Continue FIQ processing
197;
198;    }
199;}
200;
201    END
202
203