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