1;/**************************************************************************/
2;/*                                                                        */
3;/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
4;/*                                                                        */
5;/*       This software is licensed under the Microsoft Software License   */
6;/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
7;/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
8;/*       and in the root directory of this software.                      */
9;/*                                                                        */
10;/**************************************************************************/
11;
12;
13;/**************************************************************************/
14;/**************************************************************************/
15;/**                                                                       */
16;/** ThreadX Component                                                     */
17;/**                                                                       */
18;/**   Thread                                                              */
19;/**                                                                       */
20;/**************************************************************************/
21;/**************************************************************************/
22;
23;
24;#define TX_SOURCE_CODE
25;
26;
27;/* Include necessary system files.  */
28;
29;#include "tx_api.h"
30;#include "tx_thread.h"
31;#include "tx_timer.h"
32;
33SVC_MODE        DEFINE  0xD3                    ; SVC mode
34IRQ_MODE        DEFINE  0xD2                    ; IRQ mode
35#ifdef TX_ENABLE_FIQ_SUPPORT
36DISABLE_INTS    DEFINE  0xC0                    ; Disable IRQ interrupts
37#else
38DISABLE_INTS    DEFINE  0x80                    ; Disable IRQ interrupts
39#endif
40MODE_MASK       DEFINE  0x1F                    ; Mode mask
41THUMB_MASK      DEFINE  0x20                    ; Thumb bit mask
42SVC_MODE_BITS   DEFINE  0x13                    ; SVC mode value
43
44;
45    EXTERN      _tx_thread_system_state
46    EXTERN      _tx_thread_current_ptr
47    EXTERN      _tx_thread_execute_ptr
48    EXTERN      _tx_timer_time_slice
49    EXTERN      _tx_thread_schedule
50    EXTERN      _tx_thread_preempt_disable
51    EXTERN      _tx_execution_isr_exit
52;
53;
54;/**************************************************************************/
55;/*                                                                        */
56;/*  FUNCTION                                               RELEASE        */
57;/*                                                                        */
58;/*    _tx_thread_context_restore                           ARM9/IAR       */
59;/*                                                           6.1          */
60;/*  AUTHOR                                                                */
61;/*                                                                        */
62;/*    William E. Lamie, Microsoft Corporation                             */
63;/*                                                                        */
64;/*  DESCRIPTION                                                           */
65;/*                                                                        */
66;/*    This function restores the interrupt context if it is processing a  */
67;/*    nested interrupt.  If not, it returns to the interrupt thread if no */
68;/*    preemption is necessary.  Otherwise, if preemption is necessary or  */
69;/*    if no thread was running, the function returns to the scheduler.    */
70;/*                                                                        */
71;/*  INPUT                                                                 */
72;/*                                                                        */
73;/*    None                                                                */
74;/*                                                                        */
75;/*  OUTPUT                                                                */
76;/*                                                                        */
77;/*    None                                                                */
78;/*                                                                        */
79;/*  CALLS                                                                 */
80;/*                                                                        */
81;/*    _tx_thread_schedule                   Thread scheduling routine     */
82;/*                                                                        */
83;/*  CALLED BY                                                             */
84;/*                                                                        */
85;/*    ISRs                                  Interrupt Service Routines    */
86;/*                                                                        */
87;/*  RELEASE HISTORY                                                       */
88;/*                                                                        */
89;/*    DATE              NAME                      DESCRIPTION             */
90;/*                                                                        */
91;/*  09-30-2020     William E. Lamie         Initial Version 6.1           */
92;/*                                                                        */
93;/**************************************************************************/
94;VOID   _tx_thread_context_restore(VOID)
95;{
96    RSEG    .text:CODE:NOROOT(2)
97    PUBLIC  _tx_thread_context_restore
98    CODE32
99_tx_thread_context_restore
100;
101;    /* Lockout interrupts.  */
102;
103    MRS     r3, CPSR                            ; Pickup current CPSR
104    ORR     r0, r3, #DISABLE_INTS               ; Build interrupt disable value
105    MSR     CPSR_cxsf, r0                       ; Lockout interrupts
106
107#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
108;
109;    /* Call the ISR exit function to indicate an ISR is complete.  */
110;
111    BL      _tx_execution_isr_exit              ; Call the ISR exit function
112#endif
113;
114;    /* Determine if interrupts are nested.  */
115;    if (--_tx_thread_system_state)
116;    {
117;
118    LDR     r3, =_tx_thread_system_state        ; Pickup address of system state var
119    LDR     r2, [r3, #0]                        ; Pickup system state
120    SUB     r2, r2, #1                          ; Decrement the counter
121    STR     r2, [r3, #0]                        ; Store the counter
122    CMP     r2, #0                              ; Was this the first interrupt?
123    BEQ     __tx_thread_not_nested_restore      ; If so, not a nested restore
124;
125;    /* Interrupts are nested.  */
126;
127;    /* Just recover the saved registers and return to the point of
128;       interrupt.  */
129;
130    LDMIA   sp!, {r0, r10, r12, lr}             ; Recover SPSR, POI, and scratch regs
131    MSR     SPSR_cxsf, r0                       ; Put SPSR back
132    LDMIA   sp!, {r0-r3}                        ; Recover r0-r3
133    MOVS    pc, lr                              ; Return to point of interrupt
134;
135;    }
136__tx_thread_not_nested_restore
137;
138;    /* Determine if a thread was interrupted and no preemption is required.  */
139;    else if (((_tx_thread_current_ptr) && (_tx_thread_current_ptr == _tx_thread_execute_ptr))
140;               || (_tx_thread_preempt_disable))
141;    {
142;
143    LDR     r1, =_tx_thread_current_ptr         ; Pickup address of current thread ptr
144    LDR     r0, [r1, #0]                        ; Pickup actual current thread pointer
145    CMP     r0, #0                              ; Is it NULL?
146    BEQ     __tx_thread_idle_system_restore     ; Yes, idle system was interrupted
147;
148    LDR     r3, =_tx_thread_preempt_disable     ; Pickup preempt disable address
149    LDR     r2, [r3, #0]                        ; Pickup actual preempt disable flag
150    CMP     r2, #0                              ; Is it set?
151    BNE     __tx_thread_no_preempt_restore      ; Yes, don't preempt this thread
152    LDR     r3, =_tx_thread_execute_ptr         ; Pickup address of execute thread ptr
153    LDR     r2, [r3, #0]                        ; Pickup actual execute thread pointer
154    CMP     r0, r2                              ; Is the same thread highest priority?
155    BNE     __tx_thread_preempt_restore         ; No, preemption needs to happen
156;
157;
158__tx_thread_no_preempt_restore
159;
160;    /* Restore interrupted thread or ISR.  */
161;
162;    /* Pickup the saved stack pointer.  */
163;    tmp_ptr =  _tx_thread_current_ptr -> tx_thread_stack_ptr;
164;
165;   /* Recover the saved context and return to the point of interrupt.  */
166;
167    LDMIA   sp!, {r0, r10, r12, lr}             ; Recover SPSR, POI, and scratch regs
168    MSR     SPSR_cxsf, r0                       ; Put SPSR back
169    LDMIA   sp!, {r0-r3}                        ; Recover r0-r3
170    MOVS    pc, lr                              ; Return to point of interrupt
171;
172;    }
173;    else
174;    {
175__tx_thread_preempt_restore
176;
177    LDMIA   sp!, {r3, r10, r12, lr}             ; Recover temporarily saved registers
178    MOV     r1, lr                              ; Save lr (point of interrupt)
179    MOV     r2, #SVC_MODE                       ; Build SVC mode CPSR
180    MSR     CPSR_c, r2                          ; Enter SVC mode
181    STR     r1, [sp, #-4]!                      ; Save point of interrupt
182    STMDB   sp!, {r4-r12, lr}                   ; Save upper half of registers
183    MOV     r4, r3                              ; Save SPSR in r4
184    MOV     r2, #IRQ_MODE                       ; Build IRQ mode CPSR
185    MSR     CPSR_c, r2                          ; Enter IRQ mode
186    LDMIA   sp!, {r0-r3}                        ; Recover r0-r3
187    MOV     r5, #SVC_MODE                       ; Build SVC mode CPSR
188    MSR     CPSR_c, r5                          ; Enter SVC mode
189    STMDB   sp!, {r0-r3}                        ; Save r0-r3 on thread's stack
190    MOV     r3, #1                              ; Build interrupt stack type
191    STMDB   sp!, {r3, r4}                       ; Save interrupt stack type and SPSR
192    LDR     r1, =_tx_thread_current_ptr         ; Pickup address of current thread ptr
193    LDR     r0, [r1, #0]                        ; Pickup current thread pointer
194    STR     sp, [r0, #8]                        ; Save stack pointer in thread control
195                                                ;   block
196    BIC     r4, r4, #THUMB_MASK                 ; Clear the Thumb bit of CPSR
197    ORR     r3, r4, #DISABLE_INTS               ; Or-in interrupt lockout bit(s)
198    MSR     CPSR_cxsf, r3                       ; Lockout interrupts
199;
200;    /* Save the remaining time-slice and disable it.  */
201;    if (_tx_timer_time_slice)
202;    {
203;
204    LDR     r3, =_tx_timer_time_slice           ; Pickup time-slice variable address
205    LDR     r2, [r3, #0]                        ; Pickup time-slice
206    CMP     r2, #0                              ; Is it active?
207    BEQ     __tx_thread_dont_save_ts            ; No, don't save it
208;
209;        _tx_thread_current_ptr -> tx_thread_time_slice =  _tx_timer_time_slice;
210;        _tx_timer_time_slice =  0;
211;
212    STR     r2, [r0, #24]                       ; Save thread's time-slice
213    MOV     r2, #0                              ; Clear value
214    STR     r2, [r3, #0]                        ; Disable global time-slice flag
215;
216;    }
217__tx_thread_dont_save_ts
218;
219;
220;    /* Clear the current task pointer.  */
221;    _tx_thread_current_ptr =  TX_NULL;
222;
223    MOV     r0, #0                              ; NULL value
224    STR     r0, [r1, #0]                        ; Clear current thread pointer
225;
226;    /* Return to the scheduler.  */
227;    _tx_thread_schedule();
228;
229    B       _tx_thread_schedule                 ; Return to scheduler
230;    }
231;
232__tx_thread_idle_system_restore
233;
234;    /* Just return back to the scheduler!  */
235;
236    MRS     r3, CPSR                            ; Pickup current CPSR
237    BIC     r3, r3, #MODE_MASK                  ; Clear the mode portion of the CPSR
238    ORR     r3, r3, #SVC_MODE_BITS              ; Or-in new interrupt lockout bit
239    MSR     CPSR_cxsf, r3                       ; Lockout interrupts
240    B       _tx_thread_schedule                 ; Return to scheduler
241;}
242;
243;
244    END
245
246