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    .arm
26
27#ifdef TX_ENABLE_FIQ_SUPPORT
28SVC_MODE        =     0xD3               @ Disable IRQ/FIQ, SVC mode
29IRQ_MODE        =     0xD2               @ Disable IRQ/FIQ, IRQ mode
30#else
31SVC_MODE        =     0x93               @ Disable IRQ, SVC mode
32IRQ_MODE        =     0x92               @ Disable IRQ, IRQ mode
33#endif
34@
35    .global     _tx_thread_system_state
36    .global     _tx_thread_current_ptr
37    .global     _tx_thread_execute_ptr
38    .global     _tx_timer_time_slice
39    .global     _tx_thread_schedule
40    .global     _tx_thread_preempt_disable
41    .global     _tx_execution_isr_exit
42@
43@
44@/* No 16-bit Thumb mode veneer code is needed for _tx_thread_context_restore
45@   since it will never be called 16-bit mode.  */
46@
47    .arm
48    .text
49    .align 2
50@/**************************************************************************/
51@/*                                                                        */
52@/*  FUNCTION                                               RELEASE        */
53@/*                                                                        */
54@/*    _tx_thread_context_restore                          ARM11/GNU       */
55@/*                                                            6.2.1       */
56@/*  AUTHOR                                                                */
57@/*                                                                        */
58@/*    William E. Lamie, Microsoft Corporation                             */
59@/*                                                                        */
60@/*  DESCRIPTION                                                           */
61@/*                                                                        */
62@/*    This function restores the interrupt context if it is processing a  */
63@/*    nested interrupt.  If not, it returns to the interrupt thread if no */
64@/*    preemption is necessary.  Otherwise, if preemption is necessary or  */
65@/*    if no thread was running, the function returns to the scheduler.    */
66@/*                                                                        */
67@/*  INPUT                                                                 */
68@/*                                                                        */
69@/*    None                                                                */
70@/*                                                                        */
71@/*  OUTPUT                                                                */
72@/*                                                                        */
73@/*    None                                                                */
74@/*                                                                        */
75@/*  CALLS                                                                 */
76@/*                                                                        */
77@/*    _tx_thread_schedule                   Thread scheduling routine     */
78@/*                                                                        */
79@/*  CALLED BY                                                             */
80@/*                                                                        */
81@/*    ISRs                                  Interrupt Service Routines    */
82@/*                                                                        */
83@/*  RELEASE HISTORY                                                       */
84@/*                                                                        */
85@/*    DATE              NAME                      DESCRIPTION             */
86@/*                                                                        */
87@/*  09-30-2020     William E. Lamie         Initial Version 6.1           */
88@/*  03-08-2023     Cindy Deng               Modified comment(s), added    */
89@/*                                            #include tx_user.h,         */
90@/*                                            resulting in version 6.2.1  */
91@/*                                                                        */
92@/**************************************************************************/
93@VOID   _tx_thread_context_restore(VOID)
94@{
95    .global _tx_thread_context_restore
96    .type   _tx_thread_context_restore,function
97_tx_thread_context_restore:
98@
99@    /* Lockout interrupts.  */
100@
101    MOV     r0, #IRQ_MODE                   @ Build disable interrupts CPSR
102    MSR     CPSR, r0                        @ Lockout interrupts
103
104#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
105@
106@    /* Call the ISR exit function to indicate an ISR is complete.  */
107@
108    BL      _tx_execution_isr_exit          @ Call the ISR exit function
109#endif
110@
111@    /* Determine if interrupts are nested.  */
112@    if (--_tx_thread_system_state)
113@    {
114@
115    LDR     r3, =_tx_thread_system_state    @ Pickup address of system state variable
116    LDR     r2, [r3]                        @ Pickup system state
117    SUB     r2, r2, #1                      @ Decrement the counter
118    STR     r2, [r3]                        @ Store the counter
119    CMP     r2, #0                          @ Was this the first interrupt?
120    BEQ     __tx_thread_not_nested_restore  @ If so, not a nested restore
121@
122@    /* Interrupts are nested.  */
123@
124@    /* Just recover the saved registers and return to the point of
125@       interrupt.  */
126@
127    LDMIA   sp!, {r0, r10, r12, lr}         @ Recover SPSR, POI, and scratch regs
128    MSR     SPSR, r0                        @ Put SPSR back
129    LDMIA   sp!, {r0-r3}                    @ Recover r0-r3
130    MOVS    pc, lr                          @ Return to point of interrupt
131@
132@    }
133__tx_thread_not_nested_restore:
134@
135@    /* Determine if a thread was interrupted and no preemption is required.  */
136@    else if (((_tx_thread_current_ptr) && (_tx_thread_current_ptr == _tx_thread_execute_ptr))
137@               || (_tx_thread_preempt_disable))
138@    {
139@
140    LDR     r1, =_tx_thread_current_ptr     @ Pickup address of current thread ptr
141    LDR     r0, [r1]                        @ Pickup actual current thread pointer
142    CMP     r0, #0                          @ Is it NULL?
143    BEQ     __tx_thread_idle_system_restore @ Yes, idle system was interrupted
144@
145    LDR     r3, =_tx_thread_preempt_disable @ Pickup preempt disable address
146    LDR     r2, [r3]                        @ Pickup actual preempt disable flag
147    CMP     r2, #0                          @ Is it set?
148    BNE     __tx_thread_no_preempt_restore  @ Yes, don't preempt this thread
149    LDR     r3, =_tx_thread_execute_ptr     @ Pickup address of execute thread ptr
150    LDR     r2, [r3]                        @ Pickup actual execute thread pointer
151    CMP     r0, r2                          @ Is the same thread highest priority?
152    BNE     __tx_thread_preempt_restore     @ No, preemption needs to happen
153@
154@
155__tx_thread_no_preempt_restore:
156@
157@    /* Restore interrupted thread or ISR.  */
158@
159@    /* Pickup the saved stack pointer.  */
160@    tmp_ptr =  _tx_thread_current_ptr -> tx_thread_stack_ptr;
161@
162@   /* Recover the saved context and return to the point of interrupt.  */
163@
164    LDMIA   sp!, {r0, r10, r12, lr}         @ Recover SPSR, POI, and scratch regs
165    MSR     SPSR, r0                        @ Put SPSR back
166    LDMIA   sp!, {r0-r3}                    @ Recover r0-r3
167    MOVS    pc, lr                          @ Return to point of interrupt
168@
169@    }
170@    else
171@    {
172__tx_thread_preempt_restore:
173@
174    LDMIA   sp!, {r3, r10, r12, lr}         @ Recover temporarily saved registers
175    MOV     r1, lr                          @ Save lr (point of interrupt)
176    MOV     r2, #SVC_MODE                   @ Build SVC mode CPSR
177    MSR     CPSR, r2                        @ Enter SVC mode
178    STR     r1, [sp, #-4]!                  @ Save point of interrupt
179    STMDB   sp!, {r4-r12, lr}               @ Save upper half of registers
180    MOV     r4, r3                          @ Save SPSR in r4
181    MOV     r2, #IRQ_MODE                   @ Build IRQ mode CPSR
182    MSR     CPSR, r2                        @ Enter IRQ mode
183    LDMIA   sp!, {r0-r3}                    @ Recover r0-r3
184    MOV     r5, #SVC_MODE                   @ Build SVC mode CPSR
185    MSR     CPSR, r5                        @ Enter SVC mode
186    STMDB   sp!, {r0-r3}                    @ Save r0-r3 on thread's stack
187    MOV     r3, #1                          @ Build interrupt stack type
188    STMDB   sp!, {r3, r4}                   @ Save interrupt stack type and SPSR
189    LDR     r1, =_tx_thread_current_ptr     @ Pickup address of current thread ptr
190    LDR     r0, [r1]                        @ Pickup current thread pointer
191    STR     sp, [r0, #8]                    @ Save stack pointer in thread control
192                                            @   block
193@
194@    /* Save the remaining time-slice and disable it.  */
195@    if (_tx_timer_time_slice)
196@    {
197@
198    LDR     r3, =_tx_timer_time_slice       @ Pickup time-slice variable address
199    LDR     r2, [r3]                        @ Pickup time-slice
200    CMP     r2, #0                          @ Is it active?
201    BEQ     __tx_thread_dont_save_ts        @ No, don't save it
202@
203@        _tx_thread_current_ptr -> tx_thread_time_slice =  _tx_timer_time_slice;
204@        _tx_timer_time_slice =  0;
205@
206    STR     r2, [r0, #24]                   @ Save thread's time-slice
207    MOV     r2, #0                          @ Clear value
208    STR     r2, [r3]                        @ Disable global time-slice flag
209@
210@    }
211__tx_thread_dont_save_ts:
212@
213@
214@    /* Clear the current task pointer.  */
215@    _tx_thread_current_ptr =  TX_NULL;
216@
217    MOV     r0, #0                          @ NULL value
218    STR     r0, [r1]                        @ Clear current thread pointer
219@
220@    /* Return to the scheduler.  */
221@    _tx_thread_schedule();
222@
223    B       _tx_thread_schedule             @ Return to scheduler
224@    }
225@
226__tx_thread_idle_system_restore:
227@
228@    /* Just return back to the scheduler!  */
229@
230    MOV     r0, #SVC_MODE                   @ Build SVC mode CPSR
231    MSR     CPSR, r0                        @ Enter SVC mode
232    B       _tx_thread_schedule             @ Return to scheduler
233@}
234
235
236
237