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