From 37f48fa83c0d55428ca58c98ce36d314356d5e14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= Date: Wed, 9 Sep 2026 10:29:51 -0400 Subject: [PATCH] Removed FIFO queueing from the ARMv7-A SMP ports so an ISR can no longer deadlock waiting for protection (#707) The Cortex-A5, A7 and A9 SMP ports guarded the inter-core protection with a FIFO wait list: a core that could not take the lock added itself to a queue, incremented _tx_thread_smp_protect_wait_counts[core], and only the core at the head of the queue was allowed to acquire. Two parts of that scheme require the waiting core to be interruptible. _tx_thread_smp_unprotect() refuses to release the protection while the releasing core's own wait count is non-zero, and a queued core is taken back out of the list by _tx_thread_context_restore() when it is preempted. Neither can happen on a core that is spinning inside an ISR with interrupts already masked, because the spin loop restores the caller's interrupt posture rather than enabling interrupts. The core stays in the list forever and the system deadlocks with cores stuck in the wait loop. This is the deadlock Microsoft removed from the ARMv8-A SMP ports in 6.1.11, by dropping the wait list and using a plain LDAXR/STXR spinlock. The same removal was announced for the ARMv7-A ports at the time but was never made, so those three ports have carried the deadlock ever since. The FIFO queueing is now removed from the ARMv7-A SMP ports as well. _tx_thread_smp_protect() becomes an LDREX/STREX spinlock that releases interrupts between attempts, matching the sequence already used by the Cortex-R8 SMP port; _tx_thread_smp_unprotect() no longer consults the wait counts; and _tx_thread_context_restore() no longer has to unqueue a preempted core. The now unreferenced wait list macro headers are deleted. Verified by assembling all three GNU ports with arm-none-eabi-gcc for cortex-a5, cortex-a7 and cortex-a9, with and without TX_ENABLE_FIQ_SUPPORT, TX_ENABLE_WFE and TX_MPCORE_DEBUG_ENABLE, and by reading back the disassembly of the new protect sequence. The port consistency checks pass. Fixes #219 Assisted-by: Copilot (Opus 5) --- .../ac5/src/tx_thread_context_restore.s | 80 +---- .../ac5/src/tx_thread_smp_protect.s | 308 ++++------------- ...x_thread_smp_protection_wait_list_macros.h | 314 ------------------ .../ac5/src/tx_thread_smp_unprotect.s | 7 +- .../gnu/src/tx_thread_context_restore.S | 80 +---- .../gnu/src/tx_thread_smp_protect.S | 308 ++++------------- ...x_thread_smp_protection_wait_list_macros.h | 309 ----------------- .../gnu/src/tx_thread_smp_unprotect.S | 7 +- .../ac5/src/tx_thread_context_restore.s | 79 +---- .../ac5/src/tx_thread_smp_protect.s | 306 ++++------------- ...x_thread_smp_protection_wait_list_macros.h | 312 ----------------- .../ac5/src/tx_thread_smp_unprotect.s | 7 +- .../gnu/src/tx_thread_context_restore.S | 79 +---- .../gnu/src/tx_thread_smp_protect.S | 305 ++++------------- ...x_thread_smp_protection_wait_list_macros.h | 308 ----------------- .../gnu/src/tx_thread_smp_unprotect.S | 7 +- .../ac5/src/tx_thread_context_restore.s | 80 +---- .../ac5/src/tx_thread_smp_protect.s | 306 ++++------------- ...x_thread_smp_protection_wait_list_macros.h | 314 ------------------ .../ac5/src/tx_thread_smp_unprotect.s | 7 +- .../gnu/src/tx_thread_context_restore.S | 80 +---- .../gnu/src/tx_thread_smp_protect.S | 306 ++++------------- ...x_thread_smp_protection_wait_list_macros.h | 309 ----------------- .../gnu/src/tx_thread_smp_unprotect.S | 7 +- 24 files changed, 400 insertions(+), 3825 deletions(-) delete mode 100644 ports_smp/cortex_a5_smp/ac5/src/tx_thread_smp_protection_wait_list_macros.h delete mode 100644 ports_smp/cortex_a5_smp/gnu/src/tx_thread_smp_protection_wait_list_macros.h delete mode 100644 ports_smp/cortex_a7_smp/ac5/src/tx_thread_smp_protection_wait_list_macros.h delete mode 100644 ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_protection_wait_list_macros.h delete mode 100644 ports_smp/cortex_a9_smp/ac5/src/tx_thread_smp_protection_wait_list_macros.h delete mode 100644 ports_smp/cortex_a9_smp/gnu/src/tx_thread_smp_protection_wait_list_macros.h diff --git a/ports_smp/cortex_a5_smp/ac5/src/tx_thread_context_restore.s b/ports_smp/cortex_a5_smp/ac5/src/tx_thread_context_restore.s index 21d63d05..c639983b 100644 --- a/ports_smp/cortex_a5_smp/ac5/src/tx_thread_context_restore.s +++ b/ports_smp/cortex_a5_smp/ac5/src/tx_thread_context_restore.s @@ -1,5 +1,6 @@ ;/*************************************************************************** ; * Copyright (c) 2024 Microsoft Corporation +; * Copyright (c) 2026 Eclipse ThreadX contributors ; * ; * This program and the accompanying materials are made available under the ; * terms of the MIT License which is available at @@ -7,6 +8,7 @@ ; * ; * SPDX-License-Identifier: MIT ; **************************************************************************/ +; Some portions generated by Copilot (Opus 5). ; ; ;/**************************************************************************/ @@ -29,8 +31,6 @@ ;#include "tx_thread.h" ;#include "tx_timer.h" ; -;/* Include macros for modifying the wait list. */ -#include "tx_thread_smp_protection_wait_list_macros.h" IF :DEF:TX_ENABLE_FIQ_SUPPORT DISABLE_INTS EQU 0xC0 ; Disable IRQ & FIQ interrupts @@ -51,11 +51,6 @@ SVC_MODE EQU 0x93 ; SVC mode IMPORT _tx_thread_preempt_disable IMPORT _tx_timer_interrupt_active IMPORT _tx_thread_smp_protection - IMPORT _tx_thread_smp_protect_wait_counts - IMPORT _tx_thread_smp_protect_wait_list - IMPORT _tx_thread_smp_protect_wait_list_lock_protect_in_force - IMPORT _tx_thread_smp_protect_wait_list_tail - IMPORT _tx_thread_smp_protect_wait_list_size IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY IMPORT _tx_execution_isr_exit ENDIF @@ -196,77 +191,6 @@ __tx_thread_no_preempt_restore ; { ; __tx_thread_preempt_restore -; -; /* Was the thread being preempted waiting for the lock? */ -; if (_tx_thread_smp_protect_wait_counts[this_core] != 0) -; { -; - LDR r1, =_tx_thread_smp_protect_wait_counts ; Load waiting count list - LDR r2, [r1, r10, LSL #2] ; Load waiting value for this core - CMP r2, #0 - BEQ _nobody_waiting_for_lock ; Is the core waiting for the lock? -; -; /* Do we not have the lock? This means the ISR never got the inter-core lock. */ -; if (_tx_thread_smp_protection.tx_thread_smp_protect_owned != this_core) -; { -; - LDR r1, =_tx_thread_smp_protection ; Load address of protection structure - LDR r2, [r1, #8] ; Pickup the owning core - CMP r10, r2 ; Compare our core to the owning core - BEQ _this_core_has_lock ; Do we have the lock? -; -; /* We don't have the lock. This core should be in the list. Remove it. */ -; _tx_thread_smp_protect_wait_list_remove(this_core); -; - MOV r0, r10 ; Move the core ID to r0 for the macro -macro_call0 _tx_thread_smp_protect_wait_list_remove ; Call macro to remove core from the list - B _nobody_waiting_for_lock ; Leave -; -; } -; else -; { -; /* We have the lock. This means the ISR got the inter-core lock, but -; never released it because it saw that there was someone waiting. -; Note this core is not in the list. */ -; -_this_core_has_lock -; -; /* We're no longer waiting. Note that this should be zero since this happens during thread preemption. */ -; _tx_thread_smp_protect_wait_counts[core]--; -; - LDR r1, =_tx_thread_smp_protect_wait_counts ; Load waiting count list - LDR r2, [r1, r10, LSL #2] ; Load waiting value for this core - SUB r2, r2, #1 ; Decrement waiting value. Should be zero now - STR r2, [r1, r10, LSL #2] ; Store new waiting value -; -; /* Now release the inter-core lock. */ -; -; /* Set protected core as invalid. */ -; _tx_thread_smp_protection.tx_thread_smp_protect_core = 0xFFFFFFFF; -; - LDR r1, =_tx_thread_smp_protection ; Load address of protection structure - MOV r2, #0xFFFFFFFF ; Build invalid value - STR r2, [r1, #8] ; Mark the protected core as invalid - DMB ; Ensure that accesses to shared resource have completed -; -; /* Release protection. */ -; _tx_thread_smp_protection.tx_thread_smp_protect_in_force = 0; -; - MOV r2, #0 ; Build release protection value - STR r2, [r1, #0] ; Release the protection - DSB ISH ; To ensure update of the protection occurs before other CPUs awake -; -; /* Wake up waiting processors. Note interrupts are already enabled. */ -; - IF :DEF:TX_ENABLE_WFE - SEV ; Send event to other CPUs - ENDIF -; -; } -; } -; - -_nobody_waiting_for_lock LDMIA sp!, {r3, r10, r12, lr} ; Recover temporarily saved registers MOV r1, lr ; Save lr (point of interrupt) diff --git a/ports_smp/cortex_a5_smp/ac5/src/tx_thread_smp_protect.s b/ports_smp/cortex_a5_smp/ac5/src/tx_thread_smp_protect.s index a7419c10..a1bb8b2f 100644 --- a/ports_smp/cortex_a5_smp/ac5/src/tx_thread_smp_protect.s +++ b/ports_smp/cortex_a5_smp/ac5/src/tx_thread_smp_protect.s @@ -1,5 +1,6 @@ ;/*************************************************************************** ; * Copyright (c) 2024 Microsoft Corporation +; * Copyright (c) 2026 Eclipse ThreadX contributors ; * ; * This program and the accompanying materials are made available under the ; * terms of the MIT License which is available at @@ -7,6 +8,7 @@ ; * ; * SPDX-License-Identifier: MIT ; **************************************************************************/ +; Some portions generated by Copilot (Opus 5). ; ; ;/**************************************************************************/ @@ -31,17 +33,9 @@ ; ; -;/* Include macros for modifying the wait list. */ -#include "tx_thread_smp_protection_wait_list_macros.h" IMPORT _tx_thread_current_ptr IMPORT _tx_thread_smp_protection - IMPORT _tx_thread_smp_protect_wait_counts - IMPORT _tx_thread_smp_protect_wait_list - IMPORT _tx_thread_smp_protect_wait_list_lock_protect_in_force - IMPORT _tx_thread_smp_protect_wait_list_head - IMPORT _tx_thread_smp_protect_wait_list_tail - IMPORT _tx_thread_smp_protect_wait_list_size AREA ||.text||, CODE, READONLY PRESERVE8 @@ -80,12 +74,12 @@ ;/**************************************************************************/ EXPORT _tx_thread_smp_protect _tx_thread_smp_protect - - PUSH {r4-r6} ; Save registers we'll be using +;VOID _tx_thread_smp_protect(VOID) +;{ ; ; /* Disable interrupts so we don't get preempted. */ ; - MRS r0, CPSR ; Pickup current CPSR + MRS r3, CPSR ; Pickup current CPSR IF :DEF:TX_ENABLE_FIQ_SUPPORT CPSID if ; Disable IRQ and FIQ interrupts @@ -93,266 +87,93 @@ _tx_thread_smp_protect CPSID i ; Disable IRQ interrupts ENDIF ; +; /* Pickup the CPU ID. */ +; + MRC p15, 0, r2, c0, c0, 5 ; Read CPU ID register + AND r2, r2, #0x03 ; Mask off, leaving the CPU ID field +; ; /* Do we already have protection? */ ; if (this_core == _tx_thread_smp_protection.tx_thread_smp_protect_core) ; { ; - MRC p15, 0, r1, c0, c0, 5 ; Read CPU ID register - AND r1, r1, #0x03 ; Mask off, leaving the CPU ID field - LDR r2, =_tx_thread_smp_protection ; Build address to protection structure - LDR r3, [r2, #8] ; Pickup the owning core - CMP r1, r3 ; Is it not this core? - BNE _protection_not_owned ; No, the protection is not already owned + LDR r0, =_tx_thread_smp_protection ; Build address to protection structure + LDR r1, [r0, #8] ; Pickup the owning core + CMP r1, r2 ; Is it this core? + BEQ _owned ; Yes, the protection is already owned ; -; /* We already have protection. */ -; -; /* Increment the protection count. */ -; _tx_thread_smp_protection.tx_thread_smp_protect_count++; -; - LDR r3, [r2, #12] ; Pickup ownership count - ADD r3, r3, #1 ; Increment ownership count - STR r3, [r2, #12] ; Store ownership count - DMB - - B _return - -_protection_not_owned +; } ; ; /* Is the lock available? */ ; if (_tx_thread_smp_protection.tx_thread_smp_protect_in_force == 0) ; { ; - LDREX r3, [r2, #0] ; Pickup the protection flag - CMP r3, #0 - BNE _start_waiting ; No, protection not available + LDREX r1, [r0] ; Pickup the protection flag + CMP r1, #0 ; Is it available? + BEQ _get_protection ; Yes, attempt to get the protection ; -; /* Is the list empty? */ -; if (_tx_thread_smp_protect_wait_list_head == _tx_thread_smp_protect_wait_list_tail) -; { +; } ; - LDR r3, =_tx_thread_smp_protect_wait_list_head - LDR r3, [r3] - LDR r4, =_tx_thread_smp_protect_wait_list_tail - LDR r4, [r4] - CMP r3, r4 - BNE _list_not_empty +; /* The protection is held elsewhere. Restore interrupts so this core can be +; preempted while it waits, then try the whole sequence again. */ +; + MSR CPSR_c, r3 ; Restore CPSR + IF :DEF:TX_ENABLE_WFE + WFE ; Go into standby + ENDIF + B _tx_thread_smp_protect ; On waking, restart the protection attempt + +_get_protection ; ; /* Try to get the lock. */ ; if (write_exclusive(&_tx_thread_smp_protection.tx_thread_smp_protect_in_force, 1) == SUCCESS) ; { ; - MOV r3, #1 ; Build lock value - STREX r4, r3, [r2, #0] ; Attempt to get the protection - CMP r4, #0 - BNE _start_waiting ; Did it fail? + MOV r1, #1 ; Build lock value + STREX r2, r1, [r0] ; Attempt to get the protection + CMP r2, #0 ; Check whether the store succeeded (0 = success) + BEQ _got_protection ; Yes, we have the protection ; -; /* We got the lock! */ -; _tx_thread_smp_protect_lock_got(); +; } ; - DMB ; Ensure write to protection finishes -macro_call0 _tx_thread_smp_protect_lock_got ; Call the lock got function +; /* Another core beat us to it. Restore interrupts and try again. */ +; + MSR CPSR_c, r3 ; Restore CPSR + B _tx_thread_smp_protect ; Try the whole process again - B _return +_got_protection +; +; /* Got the lock. Record the owning core. */ +; _tx_thread_smp_protection.tx_thread_smp_protect_core = this_core; +; + DMB ; Ensure the protection write completes before it is used + MRC p15, 0, r2, c0, c0, 5 ; Read CPU ID register + AND r2, r2, #0x03 ; Mask off, leaving the CPU ID field + STR r2, [r0, #8] ; Save the owning core -_list_not_empty -; -; /* Are we at the front of the list? */ -; if (this_core == _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_head]) -; { -; - LDR r3, =_tx_thread_smp_protect_wait_list_head ; Get the address of the head - LDR r3, [r3] ; Get the value of the head - LDR r4, =_tx_thread_smp_protect_wait_list ; Get the address of the list - LDR r4, [r4, r3, LSL #2] ; Get the value at the head index + IF :DEF:TX_MPCORE_DEBUG_ENABLE + LSL r2, r2, #2 ; Build offset to array indexes + LDR r1, =_tx_thread_current_ptr ; Pickup start of the current thread array + ADD r1, r1, r2 ; Build index into the current thread array + LDR r2, [r1] ; Pickup current thread for this core + STR r2, [r0, #4] ; Save current thread pointer + STR LR, [r0, #16] ; Save caller's return address + STR r3, [r0, #20] ; Save CPSR + ENDIF - CMP r1, r4 - BNE _start_waiting +_owned ; -; /* Is the lock still available? */ -; if (_tx_thread_smp_protection.tx_thread_smp_protect_in_force == 0) -; { +; /* Increment the protection count. */ +; _tx_thread_smp_protection.tx_thread_smp_protect_count++; ; - LDR r3, [r2, #0] ; Pickup the protection flag - CMP r3, #0 - BNE _start_waiting ; No, protection not available -; -; /* Get the lock. */ -; _tx_thread_smp_protection.tx_thread_smp_protect_in_force = 1; -; - MOV r3, #1 ; Build lock value - STR r3, [r2, #0] ; Store lock value + LDR r1, [r0, #12] ; Pickup ownership count + ADD r1, r1, #1 ; Increment ownership count + STR r1, [r0, #12] ; Store new ownership count DMB ; -; -; /* Got the lock. */ -; _tx_thread_smp_protect_lock_got(); -; -macro_call1 _tx_thread_smp_protect_lock_got -; -; /* Remove this core from the wait list. */ -; _tx_thread_smp_protect_remove_from_front_of_list(); -; -macro_call2 _tx_thread_smp_protect_remove_from_front_of_list - B _return - -_start_waiting + MOV r0, r3 ; Return the previous CPSR ; -; /* For one reason or another, we didn't get the lock. */ +;} ; -; /* Increment wait count. */ -; _tx_thread_smp_protect_wait_counts[this_core]++; -; - LDR r3, =_tx_thread_smp_protect_wait_counts ; Load wait list counts - LDR r4, [r3, r1, LSL #2] ; Load waiting value for this core - ADD r4, r4, #1 ; Increment wait value - STR r4, [r3, r1, LSL #2] ; Store new wait value -; -; /* Have we not added ourselves to the list yet? */ -; if (_tx_thread_smp_protect_wait_counts[this_core] == 1) -; { -; - CMP r4, #1 - BNE _already_in_list0 ; Is this core already waiting? -; -; /* Add ourselves to the list. */ -; _tx_thread_smp_protect_wait_list_add(this_core); -; -macro_call3 _tx_thread_smp_protect_wait_list_add ; Call macro to add ourselves to the list -; -; } -; -_already_in_list0 -; -; /* Restore interrupts. */ -; - MSR CPSR_c, r0 ; Restore CPSR - IF :DEF:TX_ENABLE_WFE - WFE ; Go into standby - ENDIF -; -; /* We do this until we have the lock. */ -; while (1) -; { -; -_try_to_get_lock -; -; /* Disable interrupts so we don't get preempted. */ -; - IF :DEF:TX_ENABLE_FIQ_SUPPORT - CPSID if ; Disable IRQ and FIQ interrupts - ELSE - CPSID i ; Disable IRQ interrupts - ENDIF - - MRC p15, 0, r1, c0, c0, 5 ; Read CPU ID register - AND r1, r1, #0x03 ; Mask off, leaving the CPU ID field -; -; /* Do we already have protection? */ -; if (this_core == _tx_thread_smp_protection.tx_thread_smp_protect_core) -; { -; - LDR r3, [r2, #8] ; Pickup the owning core - CMP r3, r1 ; Is it this core? - BEQ _got_lock_after_waiting ; Yes, the protection is already owned. This means - ; an ISR preempted us and got protection -; -; } -; -; /* Are we at the front of the list? */ -; if (this_core == _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_head]) -; { -; - LDR r3, =_tx_thread_smp_protect_wait_list_head ; Get the address of the head - LDR r3, [r3] ; Get the value of the head - LDR r4, =_tx_thread_smp_protect_wait_list ; Get the address of the list - LDR r4, [r4, r3, LSL #2] ; Get the value at the head index - - CMP r1, r4 - BNE _did_not_get_lock -; -; /* Is the lock still available? */ -; if (_tx_thread_smp_protection.tx_thread_smp_protect_in_force == 0) -; { -; - LDR r3, [r2, #0] ; Pickup the protection flag - CMP r3, #0 - BNE _did_not_get_lock ; No, protection not available -; -; /* Get the lock. */ -; _tx_thread_smp_protection.tx_thread_smp_protect_in_force = 1; -; - MOV r3, #1 ; Build lock value - STR r3, [r2, #0] ; Store lock value - DMB ; -; -; /* Got the lock. */ -; _tx_thread_smp_protect_lock_got(); -; -macro_call4 _tx_thread_smp_protect_lock_got -; -; /* Remove this core from the wait list. */ -; _tx_thread_smp_protect_remove_from_front_of_list(); -; -macro_call5 _tx_thread_smp_protect_remove_from_front_of_list - - B _got_lock_after_waiting - -_did_not_get_lock -; -; /* For one reason or another, we didn't get the lock. */ -; -; /* Were we removed from the list? This can happen if we're a thread -; and we got preempted. */ -; if (_tx_thread_smp_protect_wait_counts[this_core] == 0) -; { -; - LDR r3, =_tx_thread_smp_protect_wait_counts ; Load wait list counts - LDR r4, [r3, r1, LSL #2] ; Load waiting value for this core - CMP r4, #0 - BNE _already_in_list1 ; Is this core already in the list? -; -; /* Add ourselves to the list. */ -; _tx_thread_smp_protect_wait_list_add(this_core); -; -macro_call6 _tx_thread_smp_protect_wait_list_add ; Call macro to add ourselves to the list -; -; /* Our waiting count was also reset when we were preempted. Increment it again. */ -; _tx_thread_smp_protect_wait_counts[this_core]++; -; - LDR r3, =_tx_thread_smp_protect_wait_counts ; Load wait list counts - LDR r4, [r3, r1, LSL #2] ; Load waiting value for this core - ADD r4, r4, #1 ; Increment wait value - STR r4, [r3, r1, LSL #2] ; Store new wait value value -; -; } -; -_already_in_list1 -; -; /* Restore interrupts and try again. */ -; - MSR CPSR_c, r0 ; Restore CPSR - IF :DEF:TX_ENABLE_WFE - WFE ; Go into standby - ENDIF - B _try_to_get_lock ; On waking, restart the protection attempt - -_got_lock_after_waiting -; -; /* We're no longer waiting. */ -; _tx_thread_smp_protect_wait_counts[this_core]--; -; - LDR r3, =_tx_thread_smp_protect_wait_counts ; Load waiting list - LDR r4, [r3, r1, LSL #2] ; Load current wait value - SUB r4, r4, #1 ; Decrement wait value - STR r4, [r3, r1, LSL #2] ; Store new wait value value - -; -; /* Restore link register and return. */ -; -_return - - POP {r4-r6} ; Restore registers - IF {INTER} = {TRUE} BX lr ; Return to caller ELSE @@ -360,4 +181,3 @@ _return ENDIF END - diff --git a/ports_smp/cortex_a5_smp/ac5/src/tx_thread_smp_protection_wait_list_macros.h b/ports_smp/cortex_a5_smp/ac5/src/tx_thread_smp_protection_wait_list_macros.h deleted file mode 100644 index fec51581..00000000 --- a/ports_smp/cortex_a5_smp/ac5/src/tx_thread_smp_protection_wait_list_macros.h +++ /dev/null @@ -1,314 +0,0 @@ -;/*************************************************************************** -; * Copyright (c) 2024 Microsoft Corporation -; * -; * This program and the accompanying materials are made available under the -; * terms of the MIT License which is available at -; * https://opensource.org/licenses/MIT. -; * -; * SPDX-License-Identifier: MIT -; **************************************************************************/ -; -; -;/**************************************************************************/ -;/**************************************************************************/ -;/** */ -;/** ThreadX Component */ -;/** */ -;/** Thread - Low Level SMP Support */ -;/** */ -;/**************************************************************************/ -;/**************************************************************************/ - - MACRO -$label _tx_thread_smp_protect_lock_got -; -; /* Set the currently owned core. */ -; _tx_thread_smp_protection.tx_thread_smp_protect_core = this_core; -; - STR r1, [r2, #8] ; Store this core -; -; /* Increment the protection count. */ -; _tx_thread_smp_protection.tx_thread_smp_protect_count++; -; - LDR r3, [r2, #12] ; Pickup ownership count - ADD r3, r3, #1 ; Increment ownership count - STR r3, [r2, #12] ; Store ownership count - DMB - - IF :DEF:TX_MPCORE_DEBUG_ENABLE - LSL r3, r1, #2 ; Build offset to array indexes - LDR r4, =_tx_thread_current_ptr ; Pickup start of the current thread array - ADD r4, r3, r4 ; Build index into the current thread array - LDR r3, [r4] ; Pickup current thread for this core - STR r3, [r2, #4] ; Save current thread pointer - STR LR, [r2, #16] ; Save caller's return address - STR r0, [r2, #20] ; Save CPSR - ENDIF - - MEND - - MACRO -$label _tx_thread_smp_protect_remove_from_front_of_list -; -; /* Remove ourselves from the list. */ -; _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_head++] = 0xFFFFFFFF; -; - MOV r3, #0xFFFFFFFF ; Build the invalid core value - LDR r4, =_tx_thread_smp_protect_wait_list_head ; Get the address of the head - LDR r5, [r4] ; Get the value of the head - LDR r6, =_tx_thread_smp_protect_wait_list ; Get the address of the list - STR r3, [r6, r5, LSL #2] ; Store the invalid core value - ADD r5, r5, #1 ; Increment the head -; -; /* Did we wrap? */ -; if (_tx_thread_smp_protect_wait_list_head == TX_THREAD_SMP_MAX_CORES + 1) -; { -; - LDR r3, =_tx_thread_smp_protect_wait_list_size ; Load address of core list size - LDR r3, [r3] ; Load the max cores value - CMP r5, r3 ; Compare the head to it - BNE $label._store_new_head ; Are we at the max? -; -; _tx_thread_smp_protect_wait_list_head = 0; -; - EOR r5, r5, r5 ; We're at the max. Set it to zero -; -; } -; -$label._store_new_head - - STR r5, [r4] ; Store the new head -; -; /* We have the lock! */ -; return; -; - MEND - - - MACRO -$label _tx_thread_smp_protect_wait_list_lock_get -;VOID _tx_thread_smp_protect_wait_list_lock_get() -;{ -; /* We do this until we have the lock. */ -; while (1) -; { -; -$label._tx_thread_smp_protect_wait_list_lock_get__try_to_get_lock -; -; /* Is the list lock available? */ -; _tx_thread_smp_protect_wait_list_lock_protect_in_force = load_exclusive(&_tx_thread_smp_protect_wait_list_lock_protect_in_force); -; - LDR r1, =_tx_thread_smp_protect_wait_list_lock_protect_in_force - LDREX r2, [r1] ; Pickup the protection flag -; -; if (protect_in_force == 0) -; { -; - CMP r2, #0 - BNE $label._tx_thread_smp_protect_wait_list_lock_get__try_to_get_lock ; No, protection not available -; -; /* Try to get the list. */ -; int status = store_exclusive(&_tx_thread_smp_protect_wait_list_lock_protect_in_force, 1); -; - MOV r2, #1 ; Build lock value - STREX r3, r2, [r1] ; Attempt to get the protection -; -; if (status == SUCCESS) -; - CMP r3, #0 - BNE $label._tx_thread_smp_protect_wait_list_lock_get__try_to_get_lock ; Did it fail? If so, try again. -; -; /* We have the lock! */ -; return; -; - MEND - - - MACRO -$label _tx_thread_smp_protect_wait_list_add -;VOID _tx_thread_smp_protect_wait_list_add(UINT new_core) -;{ -; -; /* We're about to modify the list, so get the list lock. */ -; _tx_thread_smp_protect_wait_list_lock_get(); -; - PUSH {r1-r2} - -$label _tx_thread_smp_protect_wait_list_lock_get - - POP {r1-r2} -; -; /* Add this core. */ -; _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_tail++] = new_core; -; - LDR r3, =_tx_thread_smp_protect_wait_list_tail ; Get the address of the tail - LDR r4, [r3] ; Get the value of tail - LDR r5, =_tx_thread_smp_protect_wait_list ; Get the address of the list - STR r1, [r5, r4, LSL #2] ; Store the new core value - ADD r4, r4, #1 ; Increment the tail -; -; /* Did we wrap? */ -; if (_tx_thread_smp_protect_wait_list_tail == _tx_thread_smp_protect_wait_list_size) -; { -; - LDR r5, =_tx_thread_smp_protect_wait_list_size ; Load max cores address - LDR r5, [r5] ; Load max cores value - CMP r4, r5 ; Compare max cores to tail - BNE $label._tx_thread_smp_protect_wait_list_add__no_wrap ; Did we wrap? -; -; _tx_thread_smp_protect_wait_list_tail = 0; -; - MOV r4, #0 -; -; } -; -$label._tx_thread_smp_protect_wait_list_add__no_wrap - - STR r4, [r3] ; Store the new tail value. -; -; /* Release the list lock. */ -; _tx_thread_smp_protect_wait_list_lock_protect_in_force = 0; -; - MOV r3, #0 ; Build lock value - LDR r4, =_tx_thread_smp_protect_wait_list_lock_protect_in_force - STR r3, [r4] ; Store the new value - - MEND - - - MACRO -$label _tx_thread_smp_protect_wait_list_remove -;VOID _tx_thread_smp_protect_wait_list_remove(UINT core) -;{ -; -; /* Get the core index. */ -; UINT core_index; -; for (core_index = 0;; core_index++) -; - EOR r1, r1, r1 ; Clear for 'core_index' - LDR r2, =_tx_thread_smp_protect_wait_list ; Get the address of the list -; -; { -; -$label._tx_thread_smp_protect_wait_list_remove__check_cur_core -; -; /* Is this the core? */ -; if (_tx_thread_smp_protect_wait_list[core_index] == core) -; { -; break; -; - LDR r3, [r2, r1, LSL #2] ; Get the value at the current index - CMP r3, r0 ; Did we find the core? - BEQ $label._tx_thread_smp_protect_wait_list_remove__found_core -; -; } -; - ADD r1, r1, #1 ; Increment cur index - B $label._tx_thread_smp_protect_wait_list_remove__check_cur_core ; Restart the loop -; -; } -; -$label._tx_thread_smp_protect_wait_list_remove__found_core -; -; /* We're about to modify the list. Get the lock. We need the lock because another -; core could be simultaneously adding (a core is simultaneously trying to get -; the inter-core lock) or removing (a core is simultaneously being preempted, -; like what is currently happening). */ -; _tx_thread_smp_protect_wait_list_lock_get(); -; - PUSH {r1} - -$label _tx_thread_smp_protect_wait_list_lock_get - - POP {r1} -; -; /* We remove by shifting. */ -; while (core_index != _tx_thread_smp_protect_wait_list_tail) -; { -; -$label._tx_thread_smp_protect_wait_list_remove__compare_index_to_tail - - LDR r2, =_tx_thread_smp_protect_wait_list_tail ; Load tail address - LDR r2, [r2] ; Load tail value - CMP r1, r2 ; Compare cur index and tail - BEQ $label._tx_thread_smp_protect_wait_list_remove__removed -; -; UINT next_index = core_index + 1; -; - MOV r2, r1 ; Move current index to next index register - ADD r2, r2, #1 ; Add 1 -; -; if (next_index == _tx_thread_smp_protect_wait_list_size) -; { -; - LDR r3, =_tx_thread_smp_protect_wait_list_size - LDR r3, [r3] - CMP r2, r3 - BNE $label._tx_thread_smp_protect_wait_list_remove__next_index_no_wrap -; -; next_index = 0; -; - MOV r2, #0 -; -; } -; -$label._tx_thread_smp_protect_wait_list_remove__next_index_no_wrap -; -; list_cores[core_index] = list_cores[next_index]; -; - LDR r0, =_tx_thread_smp_protect_wait_list ; Get the address of the list - LDR r3, [r0, r2, LSL #2] ; Get the value at the next index - STR r3, [r0, r1, LSL #2] ; Store the value at the current index -; -; core_index = next_index; -; - MOV r1, r2 - - B $label._tx_thread_smp_protect_wait_list_remove__compare_index_to_tail -; -; } -; -$label._tx_thread_smp_protect_wait_list_remove__removed -; -; /* Now update the tail. */ -; if (_tx_thread_smp_protect_wait_list_tail == 0) -; { -; - LDR r0, =_tx_thread_smp_protect_wait_list_tail ; Load tail address - LDR r1, [r0] ; Load tail value - CMP r1, #0 - BNE $label._tx_thread_smp_protect_wait_list_remove__tail_not_zero -; -; _tx_thread_smp_protect_wait_list_tail = _tx_thread_smp_protect_wait_list_size; -; - LDR r2, =_tx_thread_smp_protect_wait_list_size - LDR r1, [r2] -; -; } -; -$label._tx_thread_smp_protect_wait_list_remove__tail_not_zero -; -; _tx_thread_smp_protect_wait_list_tail--; -; - SUB r1, r1, #1 - STR r1, [r0] ; Store new tail value -; -; /* Release the list lock. */ -; _tx_thread_smp_protect_wait_list_lock_protect_in_force = 0; -; - MOV r0, #0 ; Build lock value - LDR r1, =_tx_thread_smp_protect_wait_list_lock_protect_in_force ; Load lock address - STR r0, [r1] ; Store the new value -; -; /* We're no longer waiting. Note that this should be zero since, again, -; this function is only called when a thread preemption is occurring. */ -; _tx_thread_smp_protect_wait_counts[core]--; -; - MRC p15, 0, r0, c0, c0, 5 ; Read CPU ID register - AND r0, r0, #0x03 ; Mask off, leaving the CPU ID field - LDR r1, =_tx_thread_smp_protect_wait_counts ; Load wait list counts - LDR r2, [r1, r0, LSL #2] ; Load waiting value - SUB r2, r2, #1 ; Subtract 1 - STR r2, [r1, r0, LSL #2] ; Store new waiting value - MEND - diff --git a/ports_smp/cortex_a5_smp/ac5/src/tx_thread_smp_unprotect.s b/ports_smp/cortex_a5_smp/ac5/src/tx_thread_smp_unprotect.s index 61645b3e..f19723e2 100644 --- a/ports_smp/cortex_a5_smp/ac5/src/tx_thread_smp_unprotect.s +++ b/ports_smp/cortex_a5_smp/ac5/src/tx_thread_smp_unprotect.s @@ -1,5 +1,6 @@ ;/*************************************************************************** ; * Copyright (c) 2024 Microsoft Corporation +; * Copyright (c) 2026 Eclipse ThreadX contributors ; * ; * This program and the accompanying materials are made available under the ; * terms of the MIT License which is available at @@ -7,6 +8,7 @@ ; * ; * SPDX-License-Identifier: MIT ; **************************************************************************/ +; Some portions generated by Copilot (Opus 5). ; ; ;/**************************************************************************/ @@ -33,7 +35,6 @@ IMPORT _tx_thread_current_ptr IMPORT _tx_thread_smp_protection IMPORT _tx_thread_preempt_disable - IMPORT _tx_thread_smp_protect_wait_counts AREA ||.text||, CODE, READONLY PRESERVE8 @@ -103,10 +104,6 @@ _tx_thread_smp_unprotect CMP r3, #0 ; Is the preempt disable flag set? BNE _still_protected ; Yes, skip the protection release - LDR r2,=_tx_thread_smp_protect_wait_counts ; Build build address of wait counts - LDR r3, [r2, r1, LSL #2] ; Pickup wait list value - CMP r3, #0 ; Are any entities on this core waiting? - BNE _still_protected ; Yes, skip the protection release LDR r2,=_tx_thread_smp_protection ; Build address of protection structure MOV r3, #0xFFFFFFFF ; Build invalid value diff --git a/ports_smp/cortex_a5_smp/gnu/src/tx_thread_context_restore.S b/ports_smp/cortex_a5_smp/gnu/src/tx_thread_context_restore.S index 53ca2cc2..bd1b08ec 100644 --- a/ports_smp/cortex_a5_smp/gnu/src/tx_thread_context_restore.S +++ b/ports_smp/cortex_a5_smp/gnu/src/tx_thread_context_restore.S @@ -1,5 +1,6 @@ @/*************************************************************************** @ * Copyright (c) 2024 Microsoft Corporation +@ * Copyright (c) 2026 Eclipse ThreadX contributors @ * @ * This program and the accompanying materials are made available under the @ * terms of the MIT License which is available at @@ -7,6 +8,7 @@ @ * @ * SPDX-License-Identifier: MIT @ **************************************************************************/ +@ Some portions generated by Copilot (Opus 5). @ @ @/**************************************************************************/ @@ -29,8 +31,6 @@ @#include "tx_thread.h" @#include "tx_timer.h" @ -@/* Include macros for modifying the wait list. */ -#include "tx_thread_smp_protection_wait_list_macros.h" #ifdef TX_ENABLE_FIQ_SUPPORT DISABLE_INTS = 0xC0 @ Disable IRQ & FIQ interrupts @@ -51,11 +51,6 @@ SVC_MODE = 0x93 @ SVC mode .global _tx_thread_preempt_disable .global _tx_timer_interrupt_active .global _tx_thread_smp_protection - .global _tx_thread_smp_protect_wait_counts - .global _tx_thread_smp_protect_wait_list - .global _tx_thread_smp_protect_wait_list_lock_protect_in_force - .global _tx_thread_smp_protect_wait_list_tail - .global _tx_thread_smp_protect_wait_list_size #ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY .global _tx_execution_isr_exit #endif @@ -198,77 +193,6 @@ __tx_thread_no_preempt_restore: @ { @ __tx_thread_preempt_restore: -@ -@ /* Was the thread being preempted waiting for the lock? */ -@ if (_tx_thread_smp_protect_wait_counts[this_core] != 0) -@ { -@ - LDR r1, =_tx_thread_smp_protect_wait_counts @ Load waiting count list - LDR r2, [r1, r10, LSL #2] @ Load waiting value for this core - CMP r2, #0 - BEQ _nobody_waiting_for_lock @ Is the core waiting for the lock? -@ -@ /* Do we not have the lock? This means the ISR never got the inter-core lock. */ -@ if (_tx_thread_smp_protection.tx_thread_smp_protect_owned != this_core) -@ { -@ - LDR r1, =_tx_thread_smp_protection @ Load address of protection structure - LDR r2, [r1, #8] @ Pickup the owning core - CMP r10, r2 @ Compare our core to the owning core - BEQ _this_core_has_lock @ Do we have the lock? -@ -@ /* We don't have the lock. This core should be in the list. Remove it. */ -@ _tx_thread_smp_protect_wait_list_remove(this_core); -@ - MOV r0, r10 @ Move the core ID to r0 for the macro - _tx_thread_smp_protect_wait_list_remove @ Call macro to remove core from the list - B _nobody_waiting_for_lock @ Leave -@ -@ } -@ else -@ { -@ /* We have the lock. This means the ISR got the inter-core lock, but -@ never released it because it saw that there was someone waiting. -@ Note this core is not in the list. */ -@ -_this_core_has_lock: -@ -@ /* We're no longer waiting. Note that this should be zero since this happens during thread preemption. */ -@ _tx_thread_smp_protect_wait_counts[core]--; -@ - LDR r1, =_tx_thread_smp_protect_wait_counts @ Load waiting count list - LDR r2, [r1, r10, LSL #2] @ Load waiting value for this core - SUB r2, r2, #1 @ Decrement waiting value. Should be zero now - STR r2, [r1, r10, LSL #2] @ Store new waiting value -@ -@ /* Now release the inter-core lock. */ -@ -@ /* Set protected core as invalid. */ -@ _tx_thread_smp_protection.tx_thread_smp_protect_core = 0xFFFFFFFF; -@ - LDR r1, =_tx_thread_smp_protection @ Load address of protection structure - MOV r2, #0xFFFFFFFF @ Build invalid value - STR r2, [r1, #8] @ Mark the protected core as invalid - DMB @ Ensure that accesses to shared resource have completed -@ -@ /* Release protection. */ -@ _tx_thread_smp_protection.tx_thread_smp_protect_in_force = 0; -@ - MOV r2, #0 @ Build release protection value - STR r2, [r1, #0] @ Release the protection - DSB ISH @ To ensure update of the protection occurs before other CPUs awake -@ -@ /* Wake up waiting processors. Note interrupts are already enabled. */ -@ -#ifdef TX_ENABLE_WFE - SEV @ Send event to other CPUs -#endif -@ -@ } -@ } -@ - -_nobody_waiting_for_lock: LDMIA sp!, {r3, r10, r12, lr} @ Recover temporarily saved registers MOV r1, lr @ Save lr (point of interrupt) diff --git a/ports_smp/cortex_a5_smp/gnu/src/tx_thread_smp_protect.S b/ports_smp/cortex_a5_smp/gnu/src/tx_thread_smp_protect.S index 103dcd71..0a537318 100644 --- a/ports_smp/cortex_a5_smp/gnu/src/tx_thread_smp_protect.S +++ b/ports_smp/cortex_a5_smp/gnu/src/tx_thread_smp_protect.S @@ -1,5 +1,6 @@ @/*************************************************************************** @ * Copyright (c) 2024 Microsoft Corporation +@ * Copyright (c) 2026 Eclipse ThreadX contributors @ * @ * This program and the accompanying materials are made available under the @ * terms of the MIT License which is available at @@ -7,6 +8,7 @@ @ * @ * SPDX-License-Identifier: MIT @ **************************************************************************/ +@ Some portions generated by Copilot (Opus 5). @ @ @/**************************************************************************/ @@ -31,17 +33,9 @@ @ @ -@/* Include macros for modifying the wait list. */ -#include "tx_thread_smp_protection_wait_list_macros.h" .global _tx_thread_current_ptr .global _tx_thread_smp_protection - .global _tx_thread_smp_protect_wait_counts - .global _tx_thread_smp_protect_wait_list - .global _tx_thread_smp_protect_wait_list_lock_protect_in_force - .global _tx_thread_smp_protect_wait_list_head - .global _tx_thread_smp_protect_wait_list_tail - .global _tx_thread_smp_protect_wait_list_size .arm .text @@ -82,12 +76,12 @@ .global _tx_thread_smp_protect .type _tx_thread_smp_protect,function _tx_thread_smp_protect: - - PUSH {r4-r6} @ Save registers we'll be using +@VOID _tx_thread_smp_protect(VOID) +@{ @ @ /* Disable interrupts so we don't get preempted. */ @ - MRS r0, CPSR @ Pickup current CPSR + MRS r3, CPSR @ Pickup current CPSR #ifdef TX_ENABLE_FIQ_SUPPORT CPSID if @ Disable IRQ and FIQ interrupts @@ -95,270 +89,96 @@ _tx_thread_smp_protect: CPSID i @ Disable IRQ interrupts #endif @ +@ /* Pickup the CPU ID. */ +@ + MRC p15, 0, r2, c0, c0, 5 @ Read CPU ID register + AND r2, r2, #0x03 @ Mask off, leaving the CPU ID field +@ @ /* Do we already have protection? */ @ if (this_core == _tx_thread_smp_protection.tx_thread_smp_protect_core) @ { @ - MRC p15, 0, r1, c0, c0, 5 @ Read CPU ID register - AND r1, r1, #0x03 @ Mask off, leaving the CPU ID field - LDR r2, =_tx_thread_smp_protection @ Build address to protection structure - LDR r3, [r2, #8] @ Pickup the owning core - CMP r1, r3 @ Is it not this core? - BNE _protection_not_owned @ No, the protection is not already owned + LDR r0, =_tx_thread_smp_protection @ Build address to protection structure + LDR r1, [r0, #8] @ Pickup the owning core + CMP r1, r2 @ Is it this core? + BEQ _owned @ Yes, the protection is already owned @ -@ /* We already have protection. */ -@ -@ /* Increment the protection count. */ -@ _tx_thread_smp_protection.tx_thread_smp_protect_count++; -@ - LDR r3, [r2, #12] @ Pickup ownership count - ADD r3, r3, #1 @ Increment ownership count - STR r3, [r2, #12] @ Store ownership count - DMB - - B _return - -_protection_not_owned: +@ } @ @ /* Is the lock available? */ @ if (_tx_thread_smp_protection.tx_thread_smp_protect_in_force == 0) @ { @ - LDREX r3, [r2] @ Pickup the protection flag - CMP r3, #0 - BNE _start_waiting @ No, protection not available + LDREX r1, [r0] @ Pickup the protection flag + CMP r1, #0 @ Is it available? + BEQ _get_protection @ Yes, attempt to get the protection @ -@ /* Is the list empty? */ -@ if (_tx_thread_smp_protect_wait_list_head == _tx_thread_smp_protect_wait_list_tail) -@ { +@ } @ - LDR r3, =_tx_thread_smp_protect_wait_list_head - LDR r3, [r3] - LDR r4, =_tx_thread_smp_protect_wait_list_tail - LDR r4, [r4] - CMP r3, r4 - BNE _list_not_empty +@ /* The protection is held elsewhere. Restore interrupts so this core can be +@ preempted while it waits, then try the whole sequence again. */ +@ + MSR CPSR_c, r3 @ Restore CPSR +#ifdef TX_ENABLE_WFE + WFE @ Go into standby +#endif + B _tx_thread_smp_protect @ On waking, restart the protection attempt + +_get_protection: @ @ /* Try to get the lock. */ @ if (write_exclusive(&_tx_thread_smp_protection.tx_thread_smp_protect_in_force, 1) == SUCCESS) @ { @ - MOV r3, #1 @ Build lock value - STREX r4, r3, [r2] @ Attempt to get the protection - CMP r4, #0 - BNE _start_waiting @ Did it fail? + MOV r1, #1 @ Build lock value + STREX r2, r1, [r0] @ Attempt to get the protection + CMP r2, #0 @ Check whether the store succeeded (0 = success) + BEQ _got_protection @ Yes, we have the protection @ -@ /* We got the lock! */ -@ _tx_thread_smp_protect_lock_got(); +@ } @ - DMB @ Ensure write to protection finishes - _tx_thread_smp_protect_lock_got @ Call the lock got function +@ /* Another core beat us to it. Restore interrupts and try again. */ +@ + MSR CPSR_c, r3 @ Restore CPSR + B _tx_thread_smp_protect @ Try the whole process again - B _return +_got_protection: +@ +@ /* Got the lock. Record the owning core. */ +@ _tx_thread_smp_protection.tx_thread_smp_protect_core = this_core; +@ + DMB @ Ensure the protection write completes before it is used + MRC p15, 0, r2, c0, c0, 5 @ Read CPU ID register + AND r2, r2, #0x03 @ Mask off, leaving the CPU ID field + STR r2, [r0, #8] @ Save the owning core -_list_not_empty: -@ -@ /* Are we at the front of the list? */ -@ if (this_core == _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_head]) -@ { -@ - LDR r3, =_tx_thread_smp_protect_wait_list_head @ Get the address of the head - LDR r3, [r3] @ Get the value of the head - LDR r4, =_tx_thread_smp_protect_wait_list @ Get the address of the list - LDR r4, [r4, r3, LSL #2] @ Get the value at the head index +#ifdef TX_MPCORE_DEBUG_ENABLE + LSL r2, r2, #2 @ Build offset to array indexes + LDR r1, =_tx_thread_current_ptr @ Pickup start of the current thread array + ADD r1, r1, r2 @ Build index into the current thread array + LDR r2, [r1] @ Pickup current thread for this core + STR r2, [r0, #4] @ Save current thread pointer + STR LR, [r0, #16] @ Save caller's return address + STR r3, [r0, #20] @ Save CPSR +#endif - CMP r1, r4 - BNE _start_waiting +_owned: @ -@ /* Is the lock still available? */ -@ if (_tx_thread_smp_protection.tx_thread_smp_protect_in_force == 0) -@ { +@ /* Increment the protection count. */ +@ _tx_thread_smp_protection.tx_thread_smp_protect_count++; @ - LDR r3, [r2, #0] @ Pickup the protection flag - CMP r3, #0 - BNE _start_waiting @ No, protection not available -@ -@ /* Get the lock. */ -@ _tx_thread_smp_protection.tx_thread_smp_protect_in_force = 1; -@ - MOV r3, #1 @ Build lock value - STR r3, [r2, #0] @ Store lock value + LDR r1, [r0, #12] @ Pickup ownership count + ADD r1, r1, #1 @ Increment ownership count + STR r1, [r0, #12] @ Store new ownership count DMB @ -@ -@ /* Got the lock. */ -@ _tx_thread_smp_protect_lock_got(); -@ - _tx_thread_smp_protect_lock_got -@ -@ /* Remove this core from the wait list. */ -@ _tx_thread_smp_protect_remove_from_front_of_list(); -@ - _tx_thread_smp_protect_remove_from_front_of_list - B _return - -_start_waiting: + MOV r0, r3 @ Return the previous CPSR @ -@ /* For one reason or another, we didn't get the lock. */ +@} @ -@ /* Increment wait count. */ -@ _tx_thread_smp_protect_wait_counts[this_core]++; -@ - LDR r3, =_tx_thread_smp_protect_wait_counts @ Load wait list counts - LDR r4, [r3, r1, LSL #2] @ Load waiting value for this core - ADD r4, r4, #1 @ Increment wait value - STR r4, [r3, r1, LSL #2] @ Store new wait value -@ -@ /* Have we not added ourselves to the list yet? */ -@ if (_tx_thread_smp_protect_wait_counts[this_core] == 1) -@ { -@ - CMP r4, #1 - BNE _already_in_list0 @ Is this core already waiting? -@ -@ /* Add ourselves to the list. */ -@ _tx_thread_smp_protect_wait_list_add(this_core); -@ - _tx_thread_smp_protect_wait_list_add @ Call macro to add ourselves to the list -@ -@ } -@ -_already_in_list0: -@ -@ /* Restore interrupts. */ -@ - MSR CPSR_c, r0 @ Restore CPSR -#ifdef TX_ENABLE_WFE - WFE @ Go into standby -#endif -@ -@ /* We do this until we have the lock. */ -@ while (1) -@ { -@ -_try_to_get_lock: -@ -@ /* Disable interrupts so we don't get preempted. */ -@ -#ifdef TX_ENABLE_FIQ_SUPPORT - CPSID if @ Disable IRQ and FIQ interrupts -#else - CPSID i @ Disable IRQ interrupts -#endif - - MRC p15, 0, r1, c0, c0, 5 @ Read CPU ID register - AND r1, r1, #0x03 @ Mask off, leaving the CPU ID field -@ -@ /* Do we already have protection? */ -@ if (this_core == _tx_thread_smp_protection.tx_thread_smp_protect_core) -@ { -@ - LDR r3, [r2, #8] @ Pickup the owning core - CMP r3, r1 @ Is it this core? - BEQ _got_lock_after_waiting @ Yes, the protection is already owned. This means - @ an ISR preempted us and got protection -@ -@ } -@ -@ /* Are we at the front of the list? */ -@ if (this_core == _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_head]) -@ { -@ - LDR r3, =_tx_thread_smp_protect_wait_list_head @ Get the address of the head - LDR r3, [r3] @ Get the value of the head - LDR r4, =_tx_thread_smp_protect_wait_list @ Get the address of the list - LDR r4, [r4, r3, LSL #2] @ Get the value at the head index - - CMP r1, r4 - BNE _did_not_get_lock -@ -@ /* Is the lock still available? */ -@ if (_tx_thread_smp_protection.tx_thread_smp_protect_in_force == 0) -@ { -@ - LDR r3, [r2, #0] @ Pickup the protection flag - CMP r3, #0 - BNE _did_not_get_lock @ No, protection not available -@ -@ /* Get the lock. */ -@ _tx_thread_smp_protection.tx_thread_smp_protect_in_force = 1; -@ - MOV r3, #1 @ Build lock value - STR r3, [r2, #0] @ Store lock value - DMB @ -@ -@ /* Got the lock. */ -@ _tx_thread_smp_protect_lock_got(); -@ - _tx_thread_smp_protect_lock_got -@ -@ /* Remove this core from the wait list. */ -@ _tx_thread_smp_protect_remove_from_front_of_list(); -@ - _tx_thread_smp_protect_remove_from_front_of_list - - B _got_lock_after_waiting - -_did_not_get_lock: -@ -@ /* For one reason or another, we didn't get the lock. */ -@ -@ /* Were we removed from the list? This can happen if we're a thread -@ and we got preempted. */ -@ if (_tx_thread_smp_protect_wait_counts[this_core] == 0) -@ { -@ - LDR r3, =_tx_thread_smp_protect_wait_counts @ Load wait list counts - LDR r4, [r3, r1, LSL #2] @ Load waiting value for this core - CMP r4, #0 - BNE _already_in_list1 @ Is this core already in the list? -@ -@ /* Add ourselves to the list. */ -@ _tx_thread_smp_protect_wait_list_add(this_core); -@ - _tx_thread_smp_protect_wait_list_add @ Call macro to add ourselves to the list -@ -@ /* Our waiting count was also reset when we were preempted. Increment it again. */ -@ _tx_thread_smp_protect_wait_counts[this_core]++; -@ - LDR r3, =_tx_thread_smp_protect_wait_counts @ Load wait list counts - LDR r4, [r3, r1, LSL #2] @ Load waiting value for this core - ADD r4, r4, #1 @ Increment wait value - STR r4, [r3, r1, LSL #2] @ Store new wait value value -@ -@ } -@ -_already_in_list1: -@ -@ /* Restore interrupts and try again. */ -@ - MSR CPSR_c, r0 @ Restore CPSR -#ifdef TX_ENABLE_WFE - WFE @ Go into standby -#endif - B _try_to_get_lock @ On waking, restart the protection attempt - -_got_lock_after_waiting: -@ -@ /* We're no longer waiting. */ -@ _tx_thread_smp_protect_wait_counts[this_core]--; -@ - LDR r3, =_tx_thread_smp_protect_wait_counts @ Load waiting list - LDR r4, [r3, r1, LSL #2] @ Load current wait value - SUB r4, r4, #1 @ Decrement wait value - STR r4, [r3, r1, LSL #2] @ Store new wait value value - -@ -@ /* Restore link register and return. */ -@ -_return: - - POP {r4-r6} @ Restore registers - #ifdef __THUMB_INTERWORK BX lr @ Return to caller #else MOV pc, lr @ Return to caller #endif - diff --git a/ports_smp/cortex_a5_smp/gnu/src/tx_thread_smp_protection_wait_list_macros.h b/ports_smp/cortex_a5_smp/gnu/src/tx_thread_smp_protection_wait_list_macros.h deleted file mode 100644 index f1ad80e8..00000000 --- a/ports_smp/cortex_a5_smp/gnu/src/tx_thread_smp_protection_wait_list_macros.h +++ /dev/null @@ -1,309 +0,0 @@ -@/*************************************************************************** -@ * Copyright (c) 2024 Microsoft Corporation -@ * -@ * This program and the accompanying materials are made available under the -@ * terms of the MIT License which is available at -@ * https://opensource.org/licenses/MIT. -@ * -@ * SPDX-License-Identifier: MIT -@ **************************************************************************/ -@ -@ -@/**************************************************************************/ -@/**************************************************************************/ -@/** */ -@/** ThreadX Component */ -@/** */ -@/** Thread - Low Level SMP Support */ -@/** */ -@/**************************************************************************/ -@/**************************************************************************/ - - .macro _tx_thread_smp_protect_lock_got -@ -@ /* Set the currently owned core. */ -@ _tx_thread_smp_protection.tx_thread_smp_protect_core = this_core; -@ - STR r1, [r2, #8] @ Store this core -@ -@ /* Increment the protection count. */ -@ _tx_thread_smp_protection.tx_thread_smp_protect_count++; -@ - LDR r3, [r2, #12] @ Pickup ownership count - ADD r3, r3, #1 @ Increment ownership count - STR r3, [r2, #12] @ Store ownership count - DMB - -#ifdef TX_MPCORE_DEBUG_ENABLE - LSL r3, r1, #2 @ Build offset to array indexes - LDR r4, =_tx_thread_current_ptr @ Pickup start of the current thread array - ADD r4, r3, r4 @ Build index into the current thread array - LDR r3, [r4] @ Pickup current thread for this core - STR r3, [r2, #4] @ Save current thread pointer - STR LR, [r2, #16] @ Save caller's return address - STR r0, [r2, #20] @ Save CPSR -#endif - - .endm - - .macro _tx_thread_smp_protect_remove_from_front_of_list -@ -@ /* Remove ourselves from the list. */ -@ _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_head++] = 0xFFFFFFFF; -@ - MOV r3, #0xFFFFFFFF @ Build the invalid core value - LDR r4, =_tx_thread_smp_protect_wait_list_head @ Get the address of the head - LDR r5, [r4] @ Get the value of the head - LDR r6, =_tx_thread_smp_protect_wait_list @ Get the address of the list - STR r3, [r6, r5, LSL #2] @ Store the invalid core value - ADD r5, r5, #1 @ Increment the head -@ -@ /* Did we wrap? */ -@ if (_tx_thread_smp_protect_wait_list_head == TX_THREAD_SMP_MAX_CORES + 1) -@ { -@ - LDR r3, =_tx_thread_smp_protect_wait_list_size @ Load address of core list size - LDR r3, [r3] @ Load the max cores value - CMP r5, r3 @ Compare the head to it - BNE _store_new_head\@ @ Are we at the max? -@ -@ _tx_thread_smp_protect_wait_list_head = 0; -@ - EOR r5, r5, r5 @ We're at the max. Set it to zero -@ -@ } -@ -_store_new_head\@: - - STR r5, [r4] @ Store the new head -@ -@ /* We have the lock! */ -@ return; -@ - .endm - - - .macro _tx_thread_smp_protect_wait_list_lock_get -@VOID _tx_thread_smp_protect_wait_list_lock_get() -@{ -@ /* We do this until we have the lock. */ -@ while (1) -@ { -@ -_tx_thread_smp_protect_wait_list_lock_get__try_to_get_lock\@: -@ -@ /* Is the list lock available? */ -@ _tx_thread_smp_protect_wait_list_lock_protect_in_force = load_exclusive(&_tx_thread_smp_protect_wait_list_lock_protect_in_force); -@ - LDR r1, =_tx_thread_smp_protect_wait_list_lock_protect_in_force - LDREX r2, [r1] @ Pickup the protection flag -@ -@ if (protect_in_force == 0) -@ { -@ - CMP r2, #0 - BNE _tx_thread_smp_protect_wait_list_lock_get__try_to_get_lock\@ @ No, protection not available -@ -@ /* Try to get the list. */ -@ int status = store_exclusive(&_tx_thread_smp_protect_wait_list_lock_protect_in_force, 1); -@ - MOV r2, #1 @ Build lock value - STREX r3, r2, [r1] @ Attempt to get the protection -@ -@ if (status == SUCCESS) -@ - CMP r3, #0 - BNE _tx_thread_smp_protect_wait_list_lock_get__try_to_get_lock\@ @ Did it fail? If so, try again. -@ -@ /* We have the lock! */ -@ return; -@ - .endm - - - .macro _tx_thread_smp_protect_wait_list_add -@VOID _tx_thread_smp_protect_wait_list_add(UINT new_core) -@{ -@ -@ /* We're about to modify the list, so get the list lock. */ -@ _tx_thread_smp_protect_wait_list_lock_get(); -@ - PUSH {r1-r2} - - _tx_thread_smp_protect_wait_list_lock_get - - POP {r1-r2} -@ -@ /* Add this core. */ -@ _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_tail++] = new_core; -@ - LDR r3, =_tx_thread_smp_protect_wait_list_tail @ Get the address of the tail - LDR r4, [r3] @ Get the value of tail - LDR r5, =_tx_thread_smp_protect_wait_list @ Get the address of the list - STR r1, [r5, r4, LSL #2] @ Store the new core value - ADD r4, r4, #1 @ Increment the tail -@ -@ /* Did we wrap? */ -@ if (_tx_thread_smp_protect_wait_list_tail == _tx_thread_smp_protect_wait_list_size) -@ { -@ - LDR r5, =_tx_thread_smp_protect_wait_list_size @ Load max cores address - LDR r5, [r5] @ Load max cores value - CMP r4, r5 @ Compare max cores to tail - BNE _tx_thread_smp_protect_wait_list_add__no_wrap\@ @ Did we wrap? -@ -@ _tx_thread_smp_protect_wait_list_tail = 0; -@ - MOV r4, #0 -@ -@ } -@ -_tx_thread_smp_protect_wait_list_add__no_wrap\@: - - STR r4, [r3] @ Store the new tail value. -@ -@ /* Release the list lock. */ -@ _tx_thread_smp_protect_wait_list_lock_protect_in_force = 0; -@ - MOV r3, #0 @ Build lock value - LDR r4, =_tx_thread_smp_protect_wait_list_lock_protect_in_force - STR r3, [r4] @ Store the new value - - .endm - - - .macro _tx_thread_smp_protect_wait_list_remove -@VOID _tx_thread_smp_protect_wait_list_remove(UINT core) -@{ -@ -@ /* Get the core index. */ -@ UINT core_index; -@ for (core_index = 0;; core_index++) -@ - EOR r1, r1, r1 @ Clear for 'core_index' - LDR r2, =_tx_thread_smp_protect_wait_list @ Get the address of the list -@ -@ { -@ -_tx_thread_smp_protect_wait_list_remove__check_cur_core\@: -@ -@ /* Is this the core? */ -@ if (_tx_thread_smp_protect_wait_list[core_index] == core) -@ { -@ break; -@ - LDR r3, [r2, r1, LSL #2] @ Get the value at the current index - CMP r3, r0 @ Did we find the core? - BEQ _tx_thread_smp_protect_wait_list_remove__found_core\@ -@ -@ } -@ - ADD r1, r1, #1 @ Increment cur index - B _tx_thread_smp_protect_wait_list_remove__check_cur_core\@ @ Restart the loop -@ -@ } -@ -_tx_thread_smp_protect_wait_list_remove__found_core\@: -@ -@ /* We're about to modify the list. Get the lock. We need the lock because another -@ core could be simultaneously adding (a core is simultaneously trying to get -@ the inter-core lock) or removing (a core is simultaneously being preempted, -@ like what is currently happening). */ -@ _tx_thread_smp_protect_wait_list_lock_get(); -@ - PUSH {r1} - - _tx_thread_smp_protect_wait_list_lock_get - - POP {r1} -@ -@ /* We remove by shifting. */ -@ while (core_index != _tx_thread_smp_protect_wait_list_tail) -@ { -@ -_tx_thread_smp_protect_wait_list_remove__compare_index_to_tail\@: - - LDR r2, =_tx_thread_smp_protect_wait_list_tail @ Load tail address - LDR r2, [r2] @ Load tail value - CMP r1, r2 @ Compare cur index and tail - BEQ _tx_thread_smp_protect_wait_list_remove__removed\@ -@ -@ UINT next_index = core_index + 1; -@ - MOV r2, r1 @ Move current index to next index register - ADD r2, r2, #1 @ Add 1 -@ -@ if (next_index == _tx_thread_smp_protect_wait_list_size) -@ { -@ - LDR r3, =_tx_thread_smp_protect_wait_list_size - LDR r3, [r3] - CMP r2, r3 - BNE _tx_thread_smp_protect_wait_list_remove__next_index_no_wrap\@ -@ -@ next_index = 0; -@ - MOV r2, #0 -@ -@ } -@ -_tx_thread_smp_protect_wait_list_remove__next_index_no_wrap\@: -@ -@ list_cores[core_index] = list_cores[next_index]; -@ - LDR r0, =_tx_thread_smp_protect_wait_list @ Get the address of the list - LDR r3, [r0, r2, LSL #2] @ Get the value at the next index - STR r3, [r0, r1, LSL #2] @ Store the value at the current index -@ -@ core_index = next_index; -@ - MOV r1, r2 - - B _tx_thread_smp_protect_wait_list_remove__compare_index_to_tail\@ -@ -@ } -@ -_tx_thread_smp_protect_wait_list_remove__removed\@: -@ -@ /* Now update the tail. */ -@ if (_tx_thread_smp_protect_wait_list_tail == 0) -@ { -@ - LDR r0, =_tx_thread_smp_protect_wait_list_tail @ Load tail address - LDR r1, [r0] @ Load tail value - CMP r1, #0 - BNE _tx_thread_smp_protect_wait_list_remove__tail_not_zero\@ -@ -@ _tx_thread_smp_protect_wait_list_tail = _tx_thread_smp_protect_wait_list_size; -@ - LDR r2, =_tx_thread_smp_protect_wait_list_size - LDR r1, [r2] -@ -@ } -@ -_tx_thread_smp_protect_wait_list_remove__tail_not_zero\@: -@ -@ _tx_thread_smp_protect_wait_list_tail--; -@ - SUB r1, r1, #1 - STR r1, [r0] @ Store new tail value -@ -@ /* Release the list lock. */ -@ _tx_thread_smp_protect_wait_list_lock_protect_in_force = 0; -@ - MOV r0, #0 @ Build lock value - LDR r1, =_tx_thread_smp_protect_wait_list_lock_protect_in_force @ Load lock address - STR r0, [r1] @ Store the new value -@ -@ /* We're no longer waiting. Note that this should be zero since, again, -@ this function is only called when a thread preemption is occurring. */ -@ _tx_thread_smp_protect_wait_counts[core]--; -@ - MRC p15, 0, r0, c0, c0, 5 @ Read CPU ID register - AND r0, r0, #0x03 @ Mask off, leaving the CPU ID field - LDR r1, =_tx_thread_smp_protect_wait_counts @ Load wait list counts - LDR r2, [r1, r0, LSL #2] @ Load waiting value - SUB r2, r2, #1 @ Subtract 1 - STR r2, [r1, r0, LSL #2] @ Store new waiting value - .endm - diff --git a/ports_smp/cortex_a5_smp/gnu/src/tx_thread_smp_unprotect.S b/ports_smp/cortex_a5_smp/gnu/src/tx_thread_smp_unprotect.S index 4cccae92..8facdc3c 100644 --- a/ports_smp/cortex_a5_smp/gnu/src/tx_thread_smp_unprotect.S +++ b/ports_smp/cortex_a5_smp/gnu/src/tx_thread_smp_unprotect.S @@ -1,5 +1,6 @@ @/*************************************************************************** @ * Copyright (c) 2024 Microsoft Corporation +@ * Copyright (c) 2026 Eclipse ThreadX contributors @ * @ * This program and the accompanying materials are made available under the @ * terms of the MIT License which is available at @@ -7,6 +8,7 @@ @ * @ * SPDX-License-Identifier: MIT @ **************************************************************************/ +@ Some portions generated by Copilot (Opus 5). @ @ @/**************************************************************************/ @@ -33,7 +35,6 @@ .global _tx_thread_current_ptr .global _tx_thread_smp_protection .global _tx_thread_preempt_disable - .global _tx_thread_smp_protect_wait_counts .arm .text @@ -105,10 +106,6 @@ _tx_thread_smp_unprotect: CMP r3, #0 @ Is the preempt disable flag set? BNE _still_protected @ Yes, skip the protection release - LDR r2,=_tx_thread_smp_protect_wait_counts @ Build build address of wait counts - LDR r3, [r2, r1, LSL #2] @ Pickup wait list value - CMP r3, #0 @ Are any entities on this core waiting? - BNE _still_protected @ Yes, skip the protection release LDR r2,=_tx_thread_smp_protection @ Build address of protection structure MOV r3, #0xFFFFFFFF @ Build invalid value diff --git a/ports_smp/cortex_a7_smp/ac5/src/tx_thread_context_restore.s b/ports_smp/cortex_a7_smp/ac5/src/tx_thread_context_restore.s index 78ddfee1..110958b1 100644 --- a/ports_smp/cortex_a7_smp/ac5/src/tx_thread_context_restore.s +++ b/ports_smp/cortex_a7_smp/ac5/src/tx_thread_context_restore.s @@ -1,5 +1,6 @@ ;/*************************************************************************** ; * Copyright (c) 2024 Microsoft Corporation +; * Copyright (c) 2026 Eclipse ThreadX contributors ; * ; * This program and the accompanying materials are made available under the ; * terms of the MIT License which is available at @@ -7,6 +8,7 @@ ; * ; * SPDX-License-Identifier: MIT ; **************************************************************************/ +; Some portions generated by Copilot (Opus 5). ; ; ;/**************************************************************************/ @@ -29,8 +31,6 @@ ;#include "tx_thread.h" ;#include "tx_timer.h" ; -;/* Include macros for modifying the wait list. */ -#include "tx_thread_smp_protection_wait_list_macros.h" IF :DEF:TX_ENABLE_FIQ_SUPPORT DISABLE_INTS EQU 0xC0 ; Disable IRQ & FIQ interrupts @@ -51,11 +51,6 @@ SVC_MODE EQU 0x93 ; SVC mode IMPORT _tx_thread_preempt_disable IMPORT _tx_timer_interrupt_active IMPORT _tx_thread_smp_protection - IMPORT _tx_thread_smp_protect_wait_counts - IMPORT _tx_thread_smp_protect_wait_list - IMPORT _tx_thread_smp_protect_wait_list_lock_protect_in_force - IMPORT _tx_thread_smp_protect_wait_list_tail - IMPORT _tx_thread_smp_protect_wait_list_size IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY IMPORT _tx_execution_isr_exit ENDIF @@ -195,76 +190,6 @@ __tx_thread_no_preempt_restore ; else ; { __tx_thread_preempt_restore -; -; /* Was the thread being preempted waiting for the lock? */ -; if (_tx_thread_smp_protect_wait_counts[this_core] != 0) -; { -; - LDR r1, =_tx_thread_smp_protect_wait_counts ; Load waiting count list - LDR r2, [r1, r10, LSL #2] ; Load waiting value for this core - CMP r2, #0 - BEQ _nobody_waiting_for_lock ; Is the core waiting for the lock? -; -; /* Do we not have the lock? This means the ISR never got the inter-core lock. */ -; if (_tx_thread_smp_protection.tx_thread_smp_protect_owned != this_core) -; { -; - LDR r1, =_tx_thread_smp_protection ; Load address of protection structure - LDR r2, [r1, #8] ; Pickup the owning core - CMP r10, r2 ; Compare our core to the owning core - BEQ _this_core_has_lock ; Do we have the lock? -; -; /* We don't have the lock. This core should be in the list. Remove it. */ -; _tx_thread_smp_protect_wait_list_remove(this_core); -; -macro_call0 _tx_thread_smp_protect_wait_list_remove ; Call macro to remove core from the list - B _nobody_waiting_for_lock ; Leave -; -; } -; else -; { -; /* We have the lock. This means the ISR got the inter-core lock, but -; never released it because it saw that there was someone waiting. -; Note this core is not in the list. */ -; -_this_core_has_lock -; -; /* We're no longer waiting. Note that this should be zero since this happens during thread preemption. */ -; _tx_thread_smp_protect_wait_counts[core]--; -; - LDR r1, =_tx_thread_smp_protect_wait_counts ; Load waiting count list - LDR r2, [r1, r10, LSL #2] ; Load waiting value for this core - SUB r2, r2, #1 ; Decrement waiting value. Should be zero now - STR r2, [r1, r10, LSL #2] ; Store new waiting value -; -; /* Now release the inter-core lock. */ -; -; /* Set protected core as invalid. */ -; _tx_thread_smp_protection.tx_thread_smp_protect_core = 0xFFFFFFFF; -; - LDR r1, =_tx_thread_smp_protection ; Load address of protection structure - MOV r2, #0xFFFFFFFF ; Build invalid value - STR r2, [r1, #8] ; Mark the protected core as invalid - DMB ; Ensure that accesses to shared resource have completed -; -; /* Release protection. */ -; _tx_thread_smp_protection.tx_thread_smp_protect_in_force = 0; -; - MOV r2, #0 ; Build release protection value - STR r2, [r1, #0] ; Release the protection - DSB ISH ; To ensure update of the protection occurs before other CPUs awake -; -; /* Wake up waiting processors. Note interrupts are already enabled. */ -; - IF :DEF:TX_ENABLE_WFE - SEV ; Send event to other CPUs - ENDIF -; -; } -; } -; - -_nobody_waiting_for_lock LDMIA sp!, {r3, r10, r12, lr} ; Recover temporarily saved registers MOV r1, lr ; Save lr (point of interrupt) diff --git a/ports_smp/cortex_a7_smp/ac5/src/tx_thread_smp_protect.s b/ports_smp/cortex_a7_smp/ac5/src/tx_thread_smp_protect.s index 5cc9f04e..f59d04d2 100644 --- a/ports_smp/cortex_a7_smp/ac5/src/tx_thread_smp_protect.s +++ b/ports_smp/cortex_a7_smp/ac5/src/tx_thread_smp_protect.s @@ -1,5 +1,6 @@ ;/*************************************************************************** ; * Copyright (c) 2024 Microsoft Corporation +; * Copyright (c) 2026 Eclipse ThreadX contributors ; * ; * This program and the accompanying materials are made available under the ; * terms of the MIT License which is available at @@ -7,6 +8,7 @@ ; * ; * SPDX-License-Identifier: MIT ; **************************************************************************/ +; Some portions generated by Copilot (Opus 5). ; ; ;/**************************************************************************/ @@ -29,17 +31,9 @@ ;#include "tx_thread.h" ;#include "tx_timer.h" */ -;/* Include macros for modifying the wait list. */ -#include "tx_thread_smp_protection_wait_list_macros.h" IMPORT _tx_thread_current_ptr IMPORT _tx_thread_smp_protection - IMPORT _tx_thread_smp_protect_wait_counts - IMPORT _tx_thread_smp_protect_wait_list - IMPORT _tx_thread_smp_protect_wait_list_lock_protect_in_force - IMPORT _tx_thread_smp_protect_wait_list_head - IMPORT _tx_thread_smp_protect_wait_list_tail - IMPORT _tx_thread_smp_protect_wait_list_size AREA ||.text||, CODE, READONLY PRESERVE8 @@ -80,12 +74,10 @@ _tx_thread_smp_protect ;VOID _tx_thread_smp_protect(VOID) ;{ -; - PUSH {r4-r6} ; Save registers we'll be using ; ; /* Disable interrupts so we don't get preempted. */ ; - MRS r0, CPSR ; Pickup current CPSR + MRS r3, CPSR ; Pickup current CPSR IF :DEF:TX_ENABLE_FIQ_SUPPORT CPSID if ; Disable IRQ and FIQ interrupts @@ -93,266 +85,93 @@ _tx_thread_smp_protect CPSID i ; Disable IRQ interrupts ENDIF ; +; /* Pickup the CPU ID. */ +; + MRC p15, 0, r2, c0, c0, 5 ; Read CPU ID register + AND r2, r2, #0x03 ; Mask off, leaving the CPU ID field +; ; /* Do we already have protection? */ ; if (this_core == _tx_thread_smp_protection.tx_thread_smp_protect_core) ; { ; - MRC p15, 0, r1, c0, c0, 5 ; Read CPU ID register - AND r1, r1, #0x03 ; Mask off, leaving the CPU ID field - LDR r2, =_tx_thread_smp_protection ; Build address to protection structure - LDR r3, [r2, #8] ; Pickup the owning core - CMP r1, r3 ; Is it not this core? - BNE _protection_not_owned ; No, the protection is not already owned + LDR r0, =_tx_thread_smp_protection ; Build address to protection structure + LDR r1, [r0, #8] ; Pickup the owning core + CMP r1, r2 ; Is it this core? + BEQ _owned ; Yes, the protection is already owned ; -; /* We already have protection. */ -; -; /* Increment the protection count. */ -; _tx_thread_smp_protection.tx_thread_smp_protect_count++; -; - LDR r3, [r2, #12] ; Pickup ownership count - ADD r3, r3, #1 ; Increment ownership count - STR r3, [r2, #12] ; Store ownership count - DMB - - B _return - -_protection_not_owned +; } ; ; /* Is the lock available? */ ; if (_tx_thread_smp_protection.tx_thread_smp_protect_in_force == 0) ; { ; - LDREX r3, [r2, #0] ; Pickup the protection flag - CMP r3, #0 - BNE _start_waiting ; No, protection not available + LDREX r1, [r0] ; Pickup the protection flag + CMP r1, #0 ; Is it available? + BEQ _get_protection ; Yes, attempt to get the protection ; -; /* Is the list empty? */ -; if (_tx_thread_smp_protect_wait_list_head == _tx_thread_smp_protect_wait_list_tail) -; { +; } ; - LDR r3, =_tx_thread_smp_protect_wait_list_head - LDR r3, [r3] - LDR r4, =_tx_thread_smp_protect_wait_list_tail - LDR r4, [r4] - CMP r3, r4 - BNE _list_not_empty +; /* The protection is held elsewhere. Restore interrupts so this core can be +; preempted while it waits, then try the whole sequence again. */ +; + MSR CPSR_c, r3 ; Restore CPSR + IF :DEF:TX_ENABLE_WFE + WFE ; Go into standby + ENDIF + B _tx_thread_smp_protect ; On waking, restart the protection attempt + +_get_protection ; ; /* Try to get the lock. */ ; if (write_exclusive(&_tx_thread_smp_protection.tx_thread_smp_protect_in_force, 1) == SUCCESS) ; { ; - MOV r3, #1 ; Build lock value - STREX r4, r3, [r2, #0] ; Attempt to get the protection - CMP r4, #0 - BNE _start_waiting ; Did it fail? + MOV r1, #1 ; Build lock value + STREX r2, r1, [r0] ; Attempt to get the protection + CMP r2, #0 ; Check whether the store succeeded (0 = success) + BEQ _got_protection ; Yes, we have the protection ; -; /* We got the lock! */ -; _tx_thread_smp_protect_lock_got(); +; } ; - DMB ; Ensure write to protection finishes -macro_call0 _tx_thread_smp_protect_lock_got ; Call the lock got function +; /* Another core beat us to it. Restore interrupts and try again. */ +; + MSR CPSR_c, r3 ; Restore CPSR + B _tx_thread_smp_protect ; Try the whole process again - B _return +_got_protection +; +; /* Got the lock. Record the owning core. */ +; _tx_thread_smp_protection.tx_thread_smp_protect_core = this_core; +; + DMB ; Ensure the protection write completes before it is used + MRC p15, 0, r2, c0, c0, 5 ; Read CPU ID register + AND r2, r2, #0x03 ; Mask off, leaving the CPU ID field + STR r2, [r0, #8] ; Save the owning core -_list_not_empty -; -; /* Are we at the front of the list? */ -; if (this_core == _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_head]) -; { -; - LDR r3, =_tx_thread_smp_protect_wait_list_head ; Get the address of the head - LDR r3, [r3] ; Get the value of the head - LDR r4, =_tx_thread_smp_protect_wait_list ; Get the address of the list - LDR r4, [r4, r3, LSL #2] ; Get the value at the head index + IF :DEF:TX_MPCORE_DEBUG_ENABLE + LSL r2, r2, #2 ; Build offset to array indexes + LDR r1, =_tx_thread_current_ptr ; Pickup start of the current thread array + ADD r1, r1, r2 ; Build index into the current thread array + LDR r2, [r1] ; Pickup current thread for this core + STR r2, [r0, #4] ; Save current thread pointer + STR LR, [r0, #16] ; Save caller's return address + STR r3, [r0, #20] ; Save CPSR + ENDIF - CMP r1, r4 - BNE _start_waiting +_owned ; -; /* Is the lock still available? */ -; if (_tx_thread_smp_protection.tx_thread_smp_protect_in_force == 0) -; { +; /* Increment the protection count. */ +; _tx_thread_smp_protection.tx_thread_smp_protect_count++; ; - LDR r3, [r2, #0] ; Pickup the protection flag - CMP r3, #0 - BNE _start_waiting ; No, protection not available -; -; /* Get the lock. */ -; _tx_thread_smp_protection.tx_thread_smp_protect_in_force = 1; -; - MOV r3, #1 ; Build lock value - STR r3, [r2, #0] ; Store lock value + LDR r1, [r0, #12] ; Pickup ownership count + ADD r1, r1, #1 ; Increment ownership count + STR r1, [r0, #12] ; Store new ownership count DMB ; -; -; /* Got the lock. */ -; _tx_thread_smp_protect_lock_got(); -; -macro_call1 _tx_thread_smp_protect_lock_got -; -; /* Remove this core from the wait list. */ -; _tx_thread_smp_protect_remove_from_front_of_list(); -; -macro_call2 _tx_thread_smp_protect_remove_from_front_of_list - B _return - -_start_waiting + MOV r0, r3 ; Return the previous CPSR ; -; /* For one reason or another, we didn't get the lock. */ +;} ; -; /* Increment wait count. */ -; _tx_thread_smp_protect_wait_counts[this_core]++; -; - LDR r3, =_tx_thread_smp_protect_wait_counts ; Load wait list counts - LDR r4, [r3, r1, LSL #2] ; Load waiting value for this core - ADD r4, r4, #1 ; Increment wait value - STR r4, [r3, r1, LSL #2] ; Store new wait value -; -; /* Have we not added ourselves to the list yet? */ -; if (_tx_thread_smp_protect_wait_counts[this_core] == 1) -; { -; - CMP r4, #1 - BNE _already_in_list0 ; Is this core already waiting? -; -; /* Add ourselves to the list. */ -; _tx_thread_smp_protect_wait_list_add(this_core); -; -macro_call3 _tx_thread_smp_protect_wait_list_add ; Call macro to add ourselves to the list -; -; } -; -_already_in_list0 -; -; /* Restore interrupts. */ -; - MSR CPSR_c, r0 ; Restore CPSR - IF :DEF:TX_ENABLE_WFE - WFE ; Go into standby - ENDIF -; -; /* We do this until we have the lock. */ -; while (1) -; { -; -_try_to_get_lock -; -; /* Disable interrupts so we don't get preempted. */ -; - IF :DEF:TX_ENABLE_FIQ_SUPPORT - CPSID if ; Disable IRQ and FIQ interrupts - ELSE - CPSID i ; Disable IRQ interrupts - ENDIF - - MRC p15, 0, r1, c0, c0, 5 ; Read CPU ID register - AND r1, r1, #0x03 ; Mask off, leaving the CPU ID field -; -; /* Do we already have protection? */ -; if (this_core == _tx_thread_smp_protection.tx_thread_smp_protect_core) -; { -; - LDR r3, [r2, #8] ; Pickup the owning core - CMP r3, r1 ; Is it this core? - BEQ _got_lock_after_waiting ; Yes, the protection is already owned. This means - ; an ISR preempted us and got protection -; -; } -; -; /* Are we at the front of the list? */ -; if (this_core == _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_head]) -; { -; - LDR r3, =_tx_thread_smp_protect_wait_list_head ; Get the address of the head - LDR r3, [r3] ; Get the value of the head - LDR r4, =_tx_thread_smp_protect_wait_list ; Get the address of the list - LDR r4, [r4, r3, LSL #2] ; Get the value at the head index - - CMP r1, r4 - BNE _did_not_get_lock -; -; /* Is the lock still available? */ -; if (_tx_thread_smp_protection.tx_thread_smp_protect_in_force == 0) -; { -; - LDR r3, [r2, #0] ; Pickup the protection flag - CMP r3, #0 - BNE _did_not_get_lock ; No, protection not available -; -; /* Get the lock. */ -; _tx_thread_smp_protection.tx_thread_smp_protect_in_force = 1; -; - MOV r3, #1 ; Build lock value - STR r3, [r2, #0] ; Store lock value - DMB ; -; -; /* Got the lock. */ -; _tx_thread_smp_protect_lock_got(); -; -macro_call4 _tx_thread_smp_protect_lock_got -; -; /* Remove this core from the wait list. */ -; _tx_thread_smp_protect_remove_from_front_of_list(); -; -macro_call5 _tx_thread_smp_protect_remove_from_front_of_list - - B _got_lock_after_waiting - -_did_not_get_lock -; -; /* For one reason or another, we didn't get the lock. */ -; -; /* Were we removed from the list? This can happen if we're a thread -; and we got preempted. */ -; if (_tx_thread_smp_protect_wait_counts[this_core] == 0) -; { -; - LDR r3, =_tx_thread_smp_protect_wait_counts ; Load wait list counts - LDR r4, [r3, r1, LSL #2] ; Load waiting value for this core - CMP r4, #0 - BNE _already_in_list1 ; Is this core already in the list? -; -; /* Add ourselves to the list. */ -; _tx_thread_smp_protect_wait_list_add(this_core); -; -macro_call6 _tx_thread_smp_protect_wait_list_add ; Call macro to add ourselves to the list -; -; /* Our waiting count was also reset when we were preempted. Increment it again. */ -; _tx_thread_smp_protect_wait_counts[this_core]++; -; - LDR r3, =_tx_thread_smp_protect_wait_counts ; Load wait list counts - LDR r4, [r3, r1, LSL #2] ; Load waiting value for this core - ADD r4, r4, #1 ; Increment wait value - STR r4, [r3, r1, LSL #2] ; Store new wait value value -; -; } -; -_already_in_list1 -; -; /* Restore interrupts and try again. */ -; - MSR CPSR_c, r0 ; Restore CPSR - IF :DEF:TX_ENABLE_WFE - WFE ; Go into standby - ENDIF - B _try_to_get_lock ; On waking, restart the protection attempt - -_got_lock_after_waiting -; -; /* We're no longer waiting. */ -; _tx_thread_smp_protect_wait_counts[this_core]--; -; - LDR r3, =_tx_thread_smp_protect_wait_counts ; Load waiting list - LDR r4, [r3, r1, LSL #2] ; Load current wait value - SUB r4, r4, #1 ; Decrement wait value - STR r4, [r3, r1, LSL #2] ; Store new wait value value - -; -; /* Restore link register and return. */ -; -_return - - POP {r4-r6} ; Restore registers - IF {INTER} = {TRUE} BX lr ; Return to caller ELSE @@ -360,4 +179,3 @@ _return ENDIF END - diff --git a/ports_smp/cortex_a7_smp/ac5/src/tx_thread_smp_protection_wait_list_macros.h b/ports_smp/cortex_a7_smp/ac5/src/tx_thread_smp_protection_wait_list_macros.h deleted file mode 100644 index f7581458..00000000 --- a/ports_smp/cortex_a7_smp/ac5/src/tx_thread_smp_protection_wait_list_macros.h +++ /dev/null @@ -1,312 +0,0 @@ -;/*************************************************************************** -; * Copyright (c) 2024 Microsoft Corporation -; * -; * This program and the accompanying materials are made available under the -; * terms of the MIT License which is available at -; * https://opensource.org/licenses/MIT. -; * -; * SPDX-License-Identifier: MIT -; **************************************************************************/ -; -; -;/**************************************************************************/ -;/**************************************************************************/ -;/** */ -;/** ThreadX Component */ -;/** */ -;/** Thread - Low Level SMP Support */ -;/** */ -;/**************************************************************************/ -;/**************************************************************************/ - - MACRO -$label _tx_thread_smp_protect_lock_got -; -; /* Set the currently owned core. */ -; _tx_thread_smp_protection.tx_thread_smp_protect_core = this_core; -; - STR r1, [r2, #8] ; Store this core -; -; /* Increment the protection count. */ -; _tx_thread_smp_protection.tx_thread_smp_protect_count++; -; - LDR r3, [r2, #12] ; Pickup ownership count - ADD r3, r3, #1 ; Increment ownership count - STR r3, [r2, #12] ; Store ownership count - DMB - - IF :DEF:TX_MPCORE_DEBUG_ENABLE - LSL r3, r1, #2 ; Build offset to array indexes - LDR r4, =_tx_thread_current_ptr ; Pickup start of the current thread array - ADD r4, r3, r4 ; Build index into the current thread array - LDR r3, [r4] ; Pickup current thread for this core - STR r3, [r2, #4] ; Save current thread pointer - STR LR, [r2, #16] ; Save caller's return address - STR r0, [r2, #20] ; Save CPSR - ENDIF - - MEND - - MACRO -$label _tx_thread_smp_protect_remove_from_front_of_list -; -; /* Remove ourselves from the list. */ -; _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_head++] = 0xFFFFFFFF; -; - MOV r3, #0xFFFFFFFF ; Build the invalid core value - LDR r4, =_tx_thread_smp_protect_wait_list_head ; Get the address of the head - LDR r5, [r4] ; Get the value of the head - LDR r6, =_tx_thread_smp_protect_wait_list ; Get the address of the list - STR r3, [r6, r5, LSL #2] ; Store the invalid core value - ADD r5, r5, #1 ; Increment the head -; -; /* Did we wrap? */ -; if (_tx_thread_smp_protect_wait_list_head == TX_THREAD_SMP_MAX_CORES + 1) -; { -; - LDR r3, =_tx_thread_smp_protect_wait_list_size ; Load address of core list size - LDR r3, [r3] ; Load the max cores value - CMP r5, r3 ; Compare the head to it - BNE $label._store_new_head ; Are we at the max? -; -; _tx_thread_smp_protect_wait_list_head = 0; -; - EOR r5, r5, r5 ; We're at the max. Set it to zero -; -; } -; -$label._store_new_head - - STR r5, [r4] ; Store the new head -; -; /* We have the lock! */ -; return; -; - MEND - - - MACRO -$label _tx_thread_smp_protect_wait_list_lock_get -;VOID _tx_thread_smp_protect_wait_list_lock_get() -;{ -; /* We do this until we have the lock. */ -; while (1) -; { -; -$label._tx_thread_smp_protect_wait_list_lock_get__try_to_get_lock -; -; /* Is the list lock available? */ -; _tx_thread_smp_protect_wait_list_lock_protect_in_force = load_exclusive(&_tx_thread_smp_protect_wait_list_lock_protect_in_force); -; - LDR r1, =_tx_thread_smp_protect_wait_list_lock_protect_in_force - LDREX r2, [r1] ; Pickup the protection flag -; -; if (protect_in_force == 0) -; { -; - CMP r2, #0 - BNE $label._tx_thread_smp_protect_wait_list_lock_get__try_to_get_lock ; No, protection not available -; -; /* Try to get the list. */ -; int status = store_exclusive(&_tx_thread_smp_protect_wait_list_lock_protect_in_force, 1); -; - MOV r2, #1 ; Build lock value - STREX r3, r2, [r1] ; Attempt to get the protection -; -; if (status == SUCCESS) -; - CMP r3, #0 - BNE $label._tx_thread_smp_protect_wait_list_lock_get__try_to_get_lock ; Did it fail? If so, try again. -; -; /* We have the lock! */ -; return; -; - MEND - - - MACRO -$label _tx_thread_smp_protect_wait_list_add -;VOID _tx_thread_smp_protect_wait_list_add(UINT new_core) -;{ -; -; /* We're about to modify the list, so get the list lock. */ -; _tx_thread_smp_protect_wait_list_lock_get(); -; - PUSH {r1-r2} - -$label _tx_thread_smp_protect_wait_list_lock_get - - POP {r1-r2} -; -; /* Add this core. */ -; _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_tail++] = new_core; -; - LDR r3, =_tx_thread_smp_protect_wait_list_tail ; Get the address of the tail - LDR r4, [r3] ; Get the value of tail - LDR r5, =_tx_thread_smp_protect_wait_list ; Get the address of the list - STR r1, [r5, r4, LSL #2] ; Store the new core value - ADD r4, r4, #1 ; Increment the tail -; -; /* Did we wrap? */ -; if (_tx_thread_smp_protect_wait_list_tail == _tx_thread_smp_protect_wait_list_size) -; { -; - LDR r5, =_tx_thread_smp_protect_wait_list_size ; Load max cores address - LDR r5, [r5] ; Load max cores value - CMP r4, r5 ; Compare max cores to tail - BNE $label._tx_thread_smp_protect_wait_list_add__no_wrap ; Did we wrap? -; -; _tx_thread_smp_protect_wait_list_tail = 0; -; - MOV r4, #0 -; -; } -; -$label._tx_thread_smp_protect_wait_list_add__no_wrap - - STR r4, [r3] ; Store the new tail value. -; -; /* Release the list lock. */ -; _tx_thread_smp_protect_wait_list_lock_protect_in_force = 0; -; - MOV r3, #0 ; Build lock value - LDR r4, =_tx_thread_smp_protect_wait_list_lock_protect_in_force - STR r3, [r4] ; Store the new value - - MEND - - - MACRO -$label _tx_thread_smp_protect_wait_list_remove -;VOID _tx_thread_smp_protect_wait_list_remove(UINT core) -;{ -; -; /* Get the core index. */ -; UINT core_index; -; for (core_index = 0;; core_index++) -; - EOR r1, r1, r1 ; Clear for 'core_index' - LDR r2, =_tx_thread_smp_protect_wait_list ; Get the address of the list -; -; { -; -$label._tx_thread_smp_protect_wait_list_remove__check_cur_core -; -; /* Is this the core? */ -; if (_tx_thread_smp_protect_wait_list[core_index] == core) -; { -; break; -; - LDR r3, [r2, r1, LSL #2] ; Get the value at the current index - CMP r3, r10 ; Did we find the core? - BEQ $label._tx_thread_smp_protect_wait_list_remove__found_core -; -; } -; - ADD r1, r1, #1 ; Increment cur index - B $label._tx_thread_smp_protect_wait_list_remove__check_cur_core ; Restart the loop -; -; } -; -$label._tx_thread_smp_protect_wait_list_remove__found_core -; -; /* We're about to modify the list. Get the lock. We need the lock because another -; core could be simultaneously adding (a core is simultaneously trying to get -; the inter-core lock) or removing (a core is simultaneously being preempted, -; like what is currently happening). */ -; _tx_thread_smp_protect_wait_list_lock_get(); -; - PUSH {r1} - -$label _tx_thread_smp_protect_wait_list_lock_get - - POP {r1} -; -; /* We remove by shifting. */ -; while (core_index != _tx_thread_smp_protect_wait_list_tail) -; { -; -$label._tx_thread_smp_protect_wait_list_remove__compare_index_to_tail - - LDR r2, =_tx_thread_smp_protect_wait_list_tail ; Load tail address - LDR r2, [r2] ; Load tail value - CMP r1, r2 ; Compare cur index and tail - BEQ $label._tx_thread_smp_protect_wait_list_remove__removed -; -; UINT next_index = core_index + 1; -; - MOV r2, r1 ; Move current index to next index register - ADD r2, r2, #1 ; Add 1 -; -; if (next_index == _tx_thread_smp_protect_wait_list_size) -; { -; - LDR r3, =_tx_thread_smp_protect_wait_list_size - LDR r3, [r3] - CMP r2, r3 - BNE $label._tx_thread_smp_protect_wait_list_remove__next_index_no_wrap -; -; next_index = 0; -; - MOV r2, #0 -; -; } -; -$label._tx_thread_smp_protect_wait_list_remove__next_index_no_wrap -; -; list_cores[core_index] = list_cores[next_index]; -; - LDR r0, =_tx_thread_smp_protect_wait_list ; Get the address of the list - LDR r3, [r0, r2, LSL #2] ; Get the value at the next index - STR r3, [r0, r1, LSL #2] ; Store the value at the current index -; -; core_index = next_index; -; - MOV r1, r2 - - B $label._tx_thread_smp_protect_wait_list_remove__compare_index_to_tail -; -; } -; -$label._tx_thread_smp_protect_wait_list_remove__removed -; -; /* Now update the tail. */ -; if (_tx_thread_smp_protect_wait_list_tail == 0) -; { -; - LDR r0, =_tx_thread_smp_protect_wait_list_tail ; Load tail address - LDR r1, [r0] ; Load tail value - CMP r1, #0 - BNE $label._tx_thread_smp_protect_wait_list_remove__tail_not_zero -; -; _tx_thread_smp_protect_wait_list_tail = _tx_thread_smp_protect_wait_list_size; -; - LDR r2, =_tx_thread_smp_protect_wait_list_size - LDR r1, [r2] -; -; } -; -$label._tx_thread_smp_protect_wait_list_remove__tail_not_zero -; -; _tx_thread_smp_protect_wait_list_tail--; -; - SUB r1, r1, #1 - STR r1, [r0] ; Store new tail value -; -; /* Release the list lock. */ -; _tx_thread_smp_protect_wait_list_lock_protect_in_force = 0; -; - MOV r0, #0 ; Build lock value - LDR r1, =_tx_thread_smp_protect_wait_list_lock_protect_in_force ; Load lock address - STR r0, [r1] ; Store the new value -; -; /* We're no longer waiting. Note that this should be zero since, again, -; this function is only called when a thread preemption is occurring. */ -; _tx_thread_smp_protect_wait_counts[core]--; -; - LDR r1, =_tx_thread_smp_protect_wait_counts ; Load wait list counts - LDR r2, [r1, r10, LSL #2] ; Load waiting value - SUB r2, r2, #1 ; Subtract 1 - STR r2, [r1, r10, LSL #2] ; Store new waiting value - MEND - diff --git a/ports_smp/cortex_a7_smp/ac5/src/tx_thread_smp_unprotect.s b/ports_smp/cortex_a7_smp/ac5/src/tx_thread_smp_unprotect.s index 260d13dc..07220047 100644 --- a/ports_smp/cortex_a7_smp/ac5/src/tx_thread_smp_unprotect.s +++ b/ports_smp/cortex_a7_smp/ac5/src/tx_thread_smp_unprotect.s @@ -1,5 +1,6 @@ ;/*************************************************************************** ; * Copyright (c) 2024 Microsoft Corporation +; * Copyright (c) 2026 Eclipse ThreadX contributors ; * ; * This program and the accompanying materials are made available under the ; * terms of the MIT License which is available at @@ -7,6 +8,7 @@ ; * ; * SPDX-License-Identifier: MIT ; **************************************************************************/ +; Some portions generated by Copilot (Opus 5). ; ; ;/**************************************************************************/ @@ -33,7 +35,6 @@ IMPORT _tx_thread_current_ptr IMPORT _tx_thread_smp_protection IMPORT _tx_thread_preempt_disable - IMPORT _tx_thread_smp_protect_wait_counts AREA ||.text||, CODE, READONLY PRESERVE8 @@ -103,10 +104,6 @@ _tx_thread_smp_unprotect CMP r3, #0 ; Is the preempt disable flag set? BNE _still_protected ; Yes, skip the protection release - LDR r2,=_tx_thread_smp_protect_wait_counts ; Build build address of wait counts - LDR r3, [r2, r1, LSL #2] ; Pickup wait list value - CMP r3, #0 ; Are any entities on this core waiting? - BNE _still_protected ; Yes, skip the protection release LDR r2,=_tx_thread_smp_protection ; Build address of protection structure MOV r3, #0xFFFFFFFF ; Build invalid value diff --git a/ports_smp/cortex_a7_smp/gnu/src/tx_thread_context_restore.S b/ports_smp/cortex_a7_smp/gnu/src/tx_thread_context_restore.S index 94e85ad3..398aac35 100644 --- a/ports_smp/cortex_a7_smp/gnu/src/tx_thread_context_restore.S +++ b/ports_smp/cortex_a7_smp/gnu/src/tx_thread_context_restore.S @@ -1,5 +1,6 @@ @/*************************************************************************** @ * Copyright (c) 2024 Microsoft Corporation +@ * Copyright (c) 2026 Eclipse ThreadX contributors @ * @ * This program and the accompanying materials are made available under the @ * terms of the MIT License which is available at @@ -7,6 +8,7 @@ @ * @ * SPDX-License-Identifier: MIT @ **************************************************************************/ +@ Some portions generated by Copilot (Opus 5). @ @ @/**************************************************************************/ @@ -28,8 +30,6 @@ @#include "tx_api.h" @#include "tx_thread.h" @#include "tx_timer.h" -@/* Include macros for modifying the wait list. */ -#include "tx_thread_smp_protection_wait_list_macros.h" .arm @@ -50,11 +50,6 @@ IRQ_MODE = 0x92 @ Disable IRQ, IRQ mode .global _tx_thread_preempt_disable .global _tx_timer_interrupt_active .global _tx_thread_smp_protection - .global _tx_thread_smp_protect_wait_counts - .global _tx_thread_smp_protect_wait_list - .global _tx_thread_smp_protect_wait_list_lock_protect_in_force - .global _tx_thread_smp_protect_wait_list_tail - .global _tx_thread_smp_protect_wait_list_size #ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY .global _tx_execution_isr_exit #endif @@ -200,76 +195,6 @@ __tx_thread_no_preempt_restore: @ else @ { __tx_thread_preempt_restore: -@ -@ /* Was the thread being preempted waiting for the lock? */ -@ if (_tx_thread_smp_protect_wait_counts[this_core] != 0) -@ { -@ - LDR r1, =_tx_thread_smp_protect_wait_counts @ Load waiting count list - LDR r2, [r1, r10, LSL #2] @ Load waiting value for this core - CMP r2, #0 - BEQ _nobody_waiting_for_lock @ Is the core waiting for the lock? -@ -@ /* Do we not have the lock? This means the ISR never got the inter-core lock. */ -@ if (_tx_thread_smp_protection.tx_thread_smp_protect_owned != this_core) -@ { -@ - LDR r1, =_tx_thread_smp_protection @ Load address of protection structure - LDR r2, [r1, #8] @ Pickup the owning core - CMP r10, r2 @ Compare our core to the owning core - BEQ _this_core_has_lock @ Do we have the lock? -@ -@ /* We don't have the lock. This core should be in the list. Remove it. */ -@ _tx_thread_smp_protect_wait_list_remove(this_core); -@ - _tx_thread_smp_protect_wait_list_remove @ Call macro to remove core from the list - B _nobody_waiting_for_lock @ Leave -@ -@ } -@ else -@ { -@ /* We have the lock. This means the ISR got the inter-core lock, but -@ never released it because it saw that there was someone waiting. -@ Note this core is not in the list. */ -@ -_this_core_has_lock: -@ -@ /* We're no longer waiting. Note that this should be zero since this happens during thread preemption. */ -@ _tx_thread_smp_protect_wait_counts[core]--; -@ - LDR r1, =_tx_thread_smp_protect_wait_counts @ Load waiting count list - LDR r2, [r1, r10, LSL #2] @ Load waiting value for this core - SUB r2, r2, #1 @ Decrement waiting value. Should be zero now - STR r2, [r1, r10, LSL #2] @ Store new waiting value -@ -@ /* Now release the inter-core lock. */ -@ -@ /* Set protected core as invalid. */ -@ _tx_thread_smp_protection.tx_thread_smp_protect_core = 0xFFFFFFFF; -@ - LDR r1, =_tx_thread_smp_protection @ Load address of protection structure - MOV r2, #0xFFFFFFFF @ Build invalid value - STR r2, [r1, #8] @ Mark the protected core as invalid - DMB @ Ensure that accesses to shared resource have completed -@ -@ /* Release protection. */ -@ _tx_thread_smp_protection.tx_thread_smp_protect_in_force = 0; -@ - MOV r2, #0 @ Build release protection value - STR r2, [r1, #0] @ Release the protection - DSB ISH @ To ensure update of the protection occurs before other CPUs awake -@ -@ /* Wake up waiting processors. Note interrupts are already enabled. */ -@ -#ifdef TX_ENABLE_WFE - SEV @ Send event to other CPUs -#endif -@ -@ } -@ } -@ - -_nobody_waiting_for_lock: LDMIA sp!, {r3, r10, r12, lr} @ Recover temporarily saved registers MOV r1, lr @ Save lr (point of interrupt) diff --git a/ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_protect.S b/ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_protect.S index 638db958..5cf03be8 100644 --- a/ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_protect.S +++ b/ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_protect.S @@ -1,5 +1,6 @@ @/*************************************************************************** @ * Copyright (c) 2024 Microsoft Corporation +@ * Copyright (c) 2026 Eclipse ThreadX contributors @ * @ * This program and the accompanying materials are made available under the @ * terms of the MIT License which is available at @@ -7,6 +8,7 @@ @ * @ * SPDX-License-Identifier: MIT @ **************************************************************************/ +@ Some portions generated by Copilot (Opus 5). @ @ @/**************************************************************************/ @@ -29,17 +31,9 @@ @#include "tx_thread.h" @#include "tx_timer.h" */ -@/* Include macros for modifying the wait list. */ -#include "tx_thread_smp_protection_wait_list_macros.h" .global _tx_thread_current_ptr .global _tx_thread_smp_protection - .global _tx_thread_smp_protect_wait_counts - .global _tx_thread_smp_protect_wait_list - .global _tx_thread_smp_protect_wait_list_lock_protect_in_force - .global _tx_thread_smp_protect_wait_list_head - .global _tx_thread_smp_protect_wait_list_tail - .global _tx_thread_smp_protect_wait_list_size .arm .text @@ -82,12 +76,10 @@ _tx_thread_smp_protect: @VOID _tx_thread_smp_protect(VOID) @{ -@ - PUSH {r4-r6} @ Save registers we'll be using @ @ /* Disable interrupts so we don't get preempted. */ @ - MRS r0, CPSR @ Pickup current CPSR + MRS r3, CPSR @ Pickup current CPSR #ifdef TX_ENABLE_FIQ_SUPPORT CPSID if @ Disable IRQ and FIQ interrupts @@ -95,266 +87,93 @@ _tx_thread_smp_protect: CPSID i @ Disable IRQ interrupts #endif @ +@ /* Pickup the CPU ID. */ +@ + MRC p15, 0, r2, c0, c0, 5 @ Read CPU ID register + AND r2, r2, #0x03 @ Mask off, leaving the CPU ID field +@ @ /* Do we already have protection? */ @ if (this_core == _tx_thread_smp_protection.tx_thread_smp_protect_core) @ { @ - MRC p15, 0, r1, c0, c0, 5 @ Read CPU ID register - AND r1, r1, #0x03 @ Mask off, leaving the CPU ID field - LDR r2, =_tx_thread_smp_protection @ Build address to protection structure - LDR r3, [r2, #8] @ Pickup the owning core - CMP r1, r3 @ Is it not this core? - BNE _protection_not_owned @ No, the protection is not already owned + LDR r0, =_tx_thread_smp_protection @ Build address to protection structure + LDR r1, [r0, #8] @ Pickup the owning core + CMP r1, r2 @ Is it this core? + BEQ _owned @ Yes, the protection is already owned @ -@ /* We already have protection. */ -@ -@ /* Increment the protection count. */ -@ _tx_thread_smp_protection.tx_thread_smp_protect_count++; -@ - LDR r3, [r2, #12] @ Pickup ownership count - ADD r3, r3, #1 @ Increment ownership count - STR r3, [r2, #12] @ Store ownership count - DMB - - B _return - -_protection_not_owned: +@ } @ @ /* Is the lock available? */ @ if (_tx_thread_smp_protection.tx_thread_smp_protect_in_force == 0) @ { @ - LDREX r3, [r2] @ Pickup the protection flag - CMP r3, #0 - BNE _start_waiting @ No, protection not available + LDREX r1, [r0] @ Pickup the protection flag + CMP r1, #0 @ Is it available? + BEQ _get_protection @ Yes, attempt to get the protection @ -@ /* Is the list empty? */ -@ if (_tx_thread_smp_protect_wait_list_head == _tx_thread_smp_protect_wait_list_tail) -@ { +@ } @ - LDR r3, =_tx_thread_smp_protect_wait_list_head - LDR r3, [r3] - LDR r4, =_tx_thread_smp_protect_wait_list_tail - LDR r4, [r4] - CMP r3, r4 - BNE _list_not_empty +@ /* The protection is held elsewhere. Restore interrupts so this core can be +@ preempted while it waits, then try the whole sequence again. */ +@ + MSR CPSR_c, r3 @ Restore CPSR +#ifdef TX_ENABLE_WFE + WFE @ Go into standby +#endif + B _tx_thread_smp_protect @ On waking, restart the protection attempt + +_get_protection: @ @ /* Try to get the lock. */ @ if (write_exclusive(&_tx_thread_smp_protection.tx_thread_smp_protect_in_force, 1) == SUCCESS) @ { @ - MOV r3, #1 @ Build lock value - STREX r4, r3, [r2] @ Attempt to get the protection - CMP r4, #0 - BNE _start_waiting @ Did it fail? + MOV r1, #1 @ Build lock value + STREX r2, r1, [r0] @ Attempt to get the protection + CMP r2, #0 @ Check whether the store succeeded (0 = success) + BEQ _got_protection @ Yes, we have the protection @ -@ /* We got the lock! */ -@ _tx_thread_smp_protect_lock_got(); +@ } @ - DMB @ Ensure write to protection finishes - _tx_thread_smp_protect_lock_got @ Call the lock got function +@ /* Another core beat us to it. Restore interrupts and try again. */ +@ + MSR CPSR_c, r3 @ Restore CPSR + B _tx_thread_smp_protect @ Try the whole process again - B _return +_got_protection: +@ +@ /* Got the lock. Record the owning core. */ +@ _tx_thread_smp_protection.tx_thread_smp_protect_core = this_core; +@ + DMB @ Ensure the protection write completes before it is used + MRC p15, 0, r2, c0, c0, 5 @ Read CPU ID register + AND r2, r2, #0x03 @ Mask off, leaving the CPU ID field + STR r2, [r0, #8] @ Save the owning core -_list_not_empty: -@ -@ /* Are we at the front of the list? */ -@ if (this_core == _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_head]) -@ { -@ - LDR r3, =_tx_thread_smp_protect_wait_list_head @ Get the address of the head - LDR r3, [r3] @ Get the value of the head - LDR r4, =_tx_thread_smp_protect_wait_list @ Get the address of the list - LDR r4, [r4, r3, LSL #2] @ Get the value at the head index +#ifdef TX_MPCORE_DEBUG_ENABLE + LSL r2, r2, #2 @ Build offset to array indexes + LDR r1, =_tx_thread_current_ptr @ Pickup start of the current thread array + ADD r1, r1, r2 @ Build index into the current thread array + LDR r2, [r1] @ Pickup current thread for this core + STR r2, [r0, #4] @ Save current thread pointer + STR LR, [r0, #16] @ Save caller's return address + STR r3, [r0, #20] @ Save CPSR +#endif - CMP r1, r4 - BNE _start_waiting +_owned: @ -@ /* Is the lock still available? */ -@ if (_tx_thread_smp_protection.tx_thread_smp_protect_in_force == 0) -@ { +@ /* Increment the protection count. */ +@ _tx_thread_smp_protection.tx_thread_smp_protect_count++; @ - LDR r3, [r2, #0] @ Pickup the protection flag - CMP r3, #0 - BNE _start_waiting @ No, protection not available -@ -@ /* Get the lock. */ -@ _tx_thread_smp_protection.tx_thread_smp_protect_in_force = 1; -@ - MOV r3, #1 @ Build lock value - STR r3, [r2, #0] @ Store lock value + LDR r1, [r0, #12] @ Pickup ownership count + ADD r1, r1, #1 @ Increment ownership count + STR r1, [r0, #12] @ Store new ownership count DMB @ -@ -@ /* Got the lock. */ -@ _tx_thread_smp_protect_lock_got(); -@ - _tx_thread_smp_protect_lock_got -@ -@ /* Remove this core from the wait list. */ -@ _tx_thread_smp_protect_remove_from_front_of_list(); -@ - _tx_thread_smp_protect_remove_from_front_of_list - B _return - -_start_waiting: + MOV r0, r3 @ Return the previous CPSR @ -@ /* For one reason or another, we didn't get the lock. */ +@} @ -@ /* Increment wait count. */ -@ _tx_thread_smp_protect_wait_counts[this_core]++; -@ - LDR r3, =_tx_thread_smp_protect_wait_counts @ Load wait list counts - LDR r4, [r3, r1, LSL #2] @ Load waiting value for this core - ADD r4, r4, #1 @ Increment wait value - STR r4, [r3, r1, LSL #2] @ Store new wait value -@ -@ /* Have we not added ourselves to the list yet? */ -@ if (_tx_thread_smp_protect_wait_counts[this_core] == 1) -@ { -@ - CMP r4, #1 - BNE _already_in_list0 @ Is this core already waiting? -@ -@ /* Add ourselves to the list. */ -@ _tx_thread_smp_protect_wait_list_add(this_core); -@ - _tx_thread_smp_protect_wait_list_add @ Call macro to add ourselves to the list -@ -@ } -@ -_already_in_list0: -@ -@ /* Restore interrupts. */ -@ - MSR CPSR_c, r0 @ Restore CPSR -#ifdef TX_ENABLE_WFE - WFE @ Go into standby -#endif -@ -@ /* We do this until we have the lock. */ -@ while (1) -@ { -@ -_try_to_get_lock: -@ -@ /* Disable interrupts so we don't get preempted. */ -@ -#ifdef TX_ENABLE_FIQ_SUPPORT - CPSID if @ Disable IRQ and FIQ interrupts -#else - CPSID i @ Disable IRQ interrupts -#endif - - MRC p15, 0, r1, c0, c0, 5 @ Read CPU ID register - AND r1, r1, #0x03 @ Mask off, leaving the CPU ID field -@ -@ /* Do we already have protection? */ -@ if (this_core == _tx_thread_smp_protection.tx_thread_smp_protect_core) -@ { -@ - LDR r3, [r2, #8] @ Pickup the owning core - CMP r3, r1 @ Is it this core? - BEQ _got_lock_after_waiting @ Yes, the protection is already owned. This means - @ an ISR preempted us and got protection -@ -@ } -@ -@ /* Are we at the front of the list? */ -@ if (this_core == _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_head]) -@ { -@ - LDR r3, =_tx_thread_smp_protect_wait_list_head @ Get the address of the head - LDR r3, [r3] @ Get the value of the head - LDR r4, =_tx_thread_smp_protect_wait_list @ Get the address of the list - LDR r4, [r4, r3, LSL #2] @ Get the value at the head index - - CMP r1, r4 - BNE _did_not_get_lock -@ -@ /* Is the lock still available? */ -@ if (_tx_thread_smp_protection.tx_thread_smp_protect_in_force == 0) -@ { -@ - LDR r3, [r2, #0] @ Pickup the protection flag - CMP r3, #0 - BNE _did_not_get_lock @ No, protection not available -@ -@ /* Get the lock. */ -@ _tx_thread_smp_protection.tx_thread_smp_protect_in_force = 1; -@ - MOV r3, #1 @ Build lock value - STR r3, [r2, #0] @ Store lock value - DMB @ -@ -@ /* Got the lock. */ -@ _tx_thread_smp_protect_lock_got(); -@ - _tx_thread_smp_protect_lock_got -@ -@ /* Remove this core from the wait list. */ -@ _tx_thread_smp_protect_remove_from_front_of_list(); -@ - _tx_thread_smp_protect_remove_from_front_of_list - - B _got_lock_after_waiting - -_did_not_get_lock: -@ -@ /* For one reason or another, we didn't get the lock. */ -@ -@ /* Were we removed from the list? This can happen if we're a thread -@ and we got preempted. */ -@ if (_tx_thread_smp_protect_wait_counts[this_core] == 0) -@ { -@ - LDR r3, =_tx_thread_smp_protect_wait_counts @ Load wait list counts - LDR r4, [r3, r1, LSL #2] @ Load waiting value for this core - CMP r4, #0 - BNE _already_in_list1 @ Is this core already in the list? -@ -@ /* Add ourselves to the list. */ -@ _tx_thread_smp_protect_wait_list_add(this_core); -@ - _tx_thread_smp_protect_wait_list_add @ Call macro to add ourselves to the list -@ -@ /* Our waiting count was also reset when we were preempted. Increment it again. */ -@ _tx_thread_smp_protect_wait_counts[this_core]++; -@ - LDR r3, =_tx_thread_smp_protect_wait_counts @ Load wait list counts - LDR r4, [r3, r1, LSL #2] @ Load waiting value for this core - ADD r4, r4, #1 @ Increment wait value - STR r4, [r3, r1, LSL #2] @ Store new wait value value -@ -@ } -@ -_already_in_list1: -@ -@ /* Restore interrupts and try again. */ -@ - MSR CPSR_c, r0 @ Restore CPSR -#ifdef TX_ENABLE_WFE - WFE @ Go into standby -#endif - B _try_to_get_lock @ On waking, restart the protection attempt - -_got_lock_after_waiting: -@ -@ /* We're no longer waiting. */ -@ _tx_thread_smp_protect_wait_counts[this_core]--; -@ - LDR r3, =_tx_thread_smp_protect_wait_counts @ Load waiting list - LDR r4, [r3, r1, LSL #2] @ Load current wait value - SUB r4, r4, #1 @ Decrement wait value - STR r4, [r3, r1, LSL #2] @ Store new wait value value - -@ -@ /* Restore link register and return. */ -@ -_return: - - POP {r4-r6} @ Restore registers - #ifdef __THUMB_INTERWORK BX lr @ Return to caller #else diff --git a/ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_protection_wait_list_macros.h b/ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_protection_wait_list_macros.h deleted file mode 100644 index dff747d1..00000000 --- a/ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_protection_wait_list_macros.h +++ /dev/null @@ -1,308 +0,0 @@ -@/*************************************************************************** -@ * Copyright (c) 2024 Microsoft Corporation -@ * -@ * This program and the accompanying materials are made available under the -@ * terms of the MIT License which is available at -@ * https://opensource.org/licenses/MIT. -@ * -@ * SPDX-License-Identifier: MIT -@ **************************************************************************/ -@ -@ -@/**************************************************************************/ -@/**************************************************************************/ -@/** */ -@/** ThreadX Component */ -@/** */ -@/** Thread - Low Level SMP Support */ -@/** */ -@/**************************************************************************/ -@/**************************************************************************/ - - .macro _tx_thread_smp_protect_lock_got -@ -@ /* Set the currently owned core. */ -@ _tx_thread_smp_protection.tx_thread_smp_protect_core = this_core; -@ - STR r1, [r2, #8] @ Store this core -@ -@ /* Increment the protection count. */ -@ _tx_thread_smp_protection.tx_thread_smp_protect_count++; -@ - LDR r3, [r2, #12] @ Pickup ownership count - ADD r3, r3, #1 @ Increment ownership count - STR r3, [r2, #12] @ Store ownership count - DMB - -#ifdef TX_MPCORE_DEBUG_ENABLE - LSL r3, r1, #2 @ Build offset to array indexes - LDR r4, =_tx_thread_current_ptr @ Pickup start of the current thread array - ADD r4, r3, r4 @ Build index into the current thread array - LDR r3, [r4] @ Pickup current thread for this core - STR r3, [r2, #4] @ Save current thread pointer - STR LR, [r2, #16] @ Save caller's return address - STR r0, [r2, #20] @ Save CPSR -#endif - - .endm - - .macro _tx_thread_smp_protect_remove_from_front_of_list -@ -@ /* Remove ourselves from the list. */ -@ _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_head++] = 0xFFFFFFFF; -@ - MOV r3, #0xFFFFFFFF @ Build the invalid core value - LDR r4, =_tx_thread_smp_protect_wait_list_head @ Get the address of the head - LDR r5, [r4] @ Get the value of the head - LDR r6, =_tx_thread_smp_protect_wait_list @ Get the address of the list - STR r3, [r6, r5, LSL #2] @ Store the invalid core value - ADD r5, r5, #1 @ Increment the head -@ -@ /* Did we wrap? */ -@ if (_tx_thread_smp_protect_wait_list_head == TX_THREAD_SMP_MAX_CORES + 1) -@ { -@ - LDR r3, =_tx_thread_smp_protect_wait_list_size @ Load address of core list size - LDR r3, [r3] @ Load the max cores value - CMP r5, r3 @ Compare the head to it - BNE _store_new_head\@ @ Are we at the max? -@ -@ _tx_thread_smp_protect_wait_list_head = 0; -@ - EOR r5, r5, r5 @ We're at the max. Set it to zero -@ -@ } -@ -_store_new_head\@: - - STR r5, [r4] @ Store the new head -@ -@ /* We have the lock! */ -@ return; -@ - .endm - - - .macro _tx_thread_smp_protect_wait_list_lock_get -@VOID _tx_thread_smp_protect_wait_list_lock_get() -@{ -@ /* We do this until we have the lock. */ -@ while (1) -@ { -@ -_tx_thread_smp_protect_wait_list_lock_get__try_to_get_lock\@: -@ -@ /* Is the list lock available? */ -@ _tx_thread_smp_protect_wait_list_lock_protect_in_force = load_exclusive(&_tx_thread_smp_protect_wait_list_lock_protect_in_force); -@ - LDR r1, =_tx_thread_smp_protect_wait_list_lock_protect_in_force - LDREX r2, [r1] @ Pickup the protection flag -@ -@ if (protect_in_force == 0) -@ { -@ - CMP r2, #0 - BNE _tx_thread_smp_protect_wait_list_lock_get__try_to_get_lock\@ @ No, protection not available -@ -@ /* Try to get the list. */ -@ int status = store_exclusive(&_tx_thread_smp_protect_wait_list_lock_protect_in_force, 1); -@ - MOV r2, #1 @ Build lock value - STREX r3, r2, [r1] @ Attempt to get the protection -@ -@ if (status == SUCCESS) -@ - CMP r3, #0 - BNE _tx_thread_smp_protect_wait_list_lock_get__try_to_get_lock\@ @ Did it fail? If so, try again. -@ -@ /* We have the lock! */ -@ return; -@ - .endm - - - .macro _tx_thread_smp_protect_wait_list_add -@VOID _tx_thread_smp_protect_wait_list_add(UINT new_core) -@{ -@ -@ /* We're about to modify the list, so get the list lock. */ -@ _tx_thread_smp_protect_wait_list_lock_get(); -@ - PUSH {r1-r2} - - _tx_thread_smp_protect_wait_list_lock_get - - POP {r1-r2} -@ -@ /* Add this core. */ -@ _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_tail++] = new_core; -@ - LDR r3, =_tx_thread_smp_protect_wait_list_tail @ Get the address of the tail - LDR r4, [r3] @ Get the value of tail - LDR r5, =_tx_thread_smp_protect_wait_list @ Get the address of the list - STR r1, [r5, r4, LSL #2] @ Store the new core value - ADD r4, r4, #1 @ Increment the tail -@ -@ /* Did we wrap? */ -@ if (_tx_thread_smp_protect_wait_list_tail == _tx_thread_smp_protect_wait_list_size) -@ { -@ - LDR r5, =_tx_thread_smp_protect_wait_list_size @ Load max cores address - LDR r5, [r5] @ Load max cores value - CMP r4, r5 @ Compare max cores to tail - BNE _tx_thread_smp_protect_wait_list_add__no_wrap\@ @ Did we wrap? -@ -@ _tx_thread_smp_protect_wait_list_tail = 0; -@ - MOV r4, #0 -@ -@ } -@ -_tx_thread_smp_protect_wait_list_add__no_wrap\@: - - STR r4, [r3] @ Store the new tail value. -@ -@ /* Release the list lock. */ -@ _tx_thread_smp_protect_wait_list_lock_protect_in_force = 0; -@ - MOV r3, #0 @ Build lock value - LDR r4, =_tx_thread_smp_protect_wait_list_lock_protect_in_force - STR r3, [r4] @ Store the new value - - .endm - - - .macro _tx_thread_smp_protect_wait_list_remove -@VOID _tx_thread_smp_protect_wait_list_remove(UINT core) -@{ -@ -@ /* Get the core index. */ -@ UINT core_index; -@ for (core_index = 0;; core_index++) -@ - EOR r1, r1, r1 @ Clear for 'core_index' - LDR r2, =_tx_thread_smp_protect_wait_list @ Get the address of the list -@ -@ { -@ -_tx_thread_smp_protect_wait_list_remove__check_cur_core\@: -@ -@ /* Is this the core? */ -@ if (_tx_thread_smp_protect_wait_list[core_index] == core) -@ { -@ break; -@ - LDR r3, [r2, r1, LSL #2] @ Get the value at the current index - CMP r3, r10 @ Did we find the core? - BEQ _tx_thread_smp_protect_wait_list_remove__found_core\@ -@ -@ } -@ - ADD r1, r1, #1 @ Increment cur index - B _tx_thread_smp_protect_wait_list_remove__check_cur_core\@ @ Restart the loop -@ -@ } -@ -_tx_thread_smp_protect_wait_list_remove__found_core\@: -@ -@ /* We're about to modify the list. Get the lock. We need the lock because another -@ core could be simultaneously adding (a core is simultaneously trying to get -@ the inter-core lock) or removing (a core is simultaneously being preempted, -@ like what is currently happening). */ -@ _tx_thread_smp_protect_wait_list_lock_get(); -@ - PUSH {r1} - - _tx_thread_smp_protect_wait_list_lock_get - - POP {r1} -@ -@ /* We remove by shifting. */ -@ while (core_index != _tx_thread_smp_protect_wait_list_tail) -@ { -@ -_tx_thread_smp_protect_wait_list_remove__compare_index_to_tail\@: - - LDR r2, =_tx_thread_smp_protect_wait_list_tail @ Load tail address - LDR r2, [r2] @ Load tail value - CMP r1, r2 @ Compare cur index and tail - BEQ _tx_thread_smp_protect_wait_list_remove__removed\@ -@ -@ UINT next_index = core_index + 1; -@ - MOV r2, r1 @ Move current index to next index register - ADD r2, r2, #1 @ Add 1 -@ -@ if (next_index == _tx_thread_smp_protect_wait_list_size) -@ { -@ - LDR r3, =_tx_thread_smp_protect_wait_list_size - LDR r3, [r3] - CMP r2, r3 - BNE _tx_thread_smp_protect_wait_list_remove__next_index_no_wrap\@ -@ -@ next_index = 0; -@ - MOV r2, #0 -@ -@ } -@ -_tx_thread_smp_protect_wait_list_remove__next_index_no_wrap\@: -@ -@ list_cores[core_index] = list_cores[next_index]; -@ - LDR r0, =_tx_thread_smp_protect_wait_list @ Get the address of the list - LDR r3, [r0, r2, LSL #2] @ Get the value at the next index - STR r3, [r0, r1, LSL #2] @ Store the value at the current index -@ -@ core_index = next_index; -@ - MOV r1, r2 - - B _tx_thread_smp_protect_wait_list_remove__compare_index_to_tail\@ -@ -@ } -@ -_tx_thread_smp_protect_wait_list_remove__removed\@: -@ -@ /* Now update the tail. */ -@ if (_tx_thread_smp_protect_wait_list_tail == 0) -@ { -@ - LDR r0, =_tx_thread_smp_protect_wait_list_tail @ Load tail address - LDR r1, [r0] @ Load tail value - CMP r1, #0 - BNE _tx_thread_smp_protect_wait_list_remove__tail_not_zero\@ -@ -@ _tx_thread_smp_protect_wait_list_tail = _tx_thread_smp_protect_wait_list_size; -@ - LDR r2, =_tx_thread_smp_protect_wait_list_size - LDR r1, [r2] -@ -@ } -@ -_tx_thread_smp_protect_wait_list_remove__tail_not_zero\@: -@ -@ _tx_thread_smp_protect_wait_list_tail--; -@ - SUB r1, r1, #1 - STR r1, [r0] @ Store new tail value -@ -@ /* Release the list lock. */ -@ _tx_thread_smp_protect_wait_list_lock_protect_in_force = 0; -@ - MOV r0, #0 @ Build lock value - LDR r1, =_tx_thread_smp_protect_wait_list_lock_protect_in_force @ Load lock address - STR r0, [r1] @ Store the new value -@ -@ /* We're no longer waiting. Note that this should be zero since, again, -@ this function is only called when a thread preemption is occurring. */ -@ _tx_thread_smp_protect_wait_counts[core]--; -@ - LDR r1, =_tx_thread_smp_protect_wait_counts @ Load wait list counts - LDR r2, [r1, r10, LSL #2] @ Load waiting value - SUB r2, r2, #1 @ Subtract 1 - STR r2, [r1, r10, LSL #2] @ Store new waiting value - - .endm - diff --git a/ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_unprotect.S b/ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_unprotect.S index 5b939a05..8d47131a 100644 --- a/ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_unprotect.S +++ b/ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_unprotect.S @@ -1,5 +1,6 @@ @/*************************************************************************** @ * Copyright (c) 2024 Microsoft Corporation +@ * Copyright (c) 2026 Eclipse ThreadX contributors @ * @ * This program and the accompanying materials are made available under the @ * terms of the MIT License which is available at @@ -7,6 +8,7 @@ @ * @ * SPDX-License-Identifier: MIT @ **************************************************************************/ +@ Some portions generated by Copilot (Opus 5). @ @ @/**************************************************************************/ @@ -33,7 +35,6 @@ .global _tx_thread_current_ptr .global _tx_thread_smp_protection .global _tx_thread_preempt_disable - .global _tx_thread_smp_protect_wait_counts .arm .text @@ -105,10 +106,6 @@ _tx_thread_smp_unprotect: CMP r3, #0 @ Is the preempt disable flag set? BNE _still_protected @ Yes, skip the protection release - LDR r2,=_tx_thread_smp_protect_wait_counts @ Build build address of wait counts - LDR r3, [r2, r1, LSL #2] @ Pickup wait list value - CMP r3, #0 @ Are any entities on this core waiting? - BNE _still_protected @ Yes, skip the protection release LDR r2,=_tx_thread_smp_protection @ Build address of protection structure MOV r3, #0xFFFFFFFF @ Build invalid value diff --git a/ports_smp/cortex_a9_smp/ac5/src/tx_thread_context_restore.s b/ports_smp/cortex_a9_smp/ac5/src/tx_thread_context_restore.s index b6c179cd..6327d05d 100644 --- a/ports_smp/cortex_a9_smp/ac5/src/tx_thread_context_restore.s +++ b/ports_smp/cortex_a9_smp/ac5/src/tx_thread_context_restore.s @@ -1,5 +1,6 @@ ;/*************************************************************************** ; * Copyright (c) 2024 Microsoft Corporation +; * Copyright (c) 2026 Eclipse ThreadX contributors ; * ; * This program and the accompanying materials are made available under the ; * terms of the MIT License which is available at @@ -7,6 +8,7 @@ ; * ; * SPDX-License-Identifier: MIT ; **************************************************************************/ +; Some portions generated by Copilot (Opus 5). ; ; ;/**************************************************************************/ @@ -29,8 +31,6 @@ ;#include "tx_thread.h" ;#include "tx_timer.h" ; -;/* Include macros for modifying the wait list. */ -#include "tx_thread_smp_protection_wait_list_macros.h" IF :DEF:TX_ENABLE_FIQ_SUPPORT DISABLE_INTS EQU 0xC0 ; Disable IRQ & FIQ interrupts @@ -51,11 +51,6 @@ SVC_MODE EQU 0x93 ; SVC mode IMPORT _tx_thread_preempt_disable IMPORT _tx_timer_interrupt_active IMPORT _tx_thread_smp_protection - IMPORT _tx_thread_smp_protect_wait_counts - IMPORT _tx_thread_smp_protect_wait_list - IMPORT _tx_thread_smp_protect_wait_list_lock_protect_in_force - IMPORT _tx_thread_smp_protect_wait_list_tail - IMPORT _tx_thread_smp_protect_wait_list_size IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY IMPORT _tx_execution_isr_exit ENDIF @@ -196,77 +191,6 @@ __tx_thread_no_preempt_restore ; { ; __tx_thread_preempt_restore -; -; /* Was the thread being preempted waiting for the lock? */ -; if (_tx_thread_smp_protect_wait_counts[this_core] != 0) -; { -; - LDR r1, =_tx_thread_smp_protect_wait_counts ; Load waiting count list - LDR r2, [r1, r10, LSL #2] ; Load waiting value for this core - CMP r2, #0 - BEQ _nobody_waiting_for_lock ; Is the core waiting for the lock? -; -; /* Do we not have the lock? This means the ISR never got the inter-core lock. */ -; if (_tx_thread_smp_protection.tx_thread_smp_protect_owned != this_core) -; { -; - LDR r1, =_tx_thread_smp_protection ; Load address of protection structure - LDR r2, [r1, #8] ; Pickup the owning core - CMP r10, r2 ; Compare our core to the owning core - BEQ _this_core_has_lock ; Do we have the lock? -; -; /* We don't have the lock. This core should be in the list. Remove it. */ -; _tx_thread_smp_protect_wait_list_remove(this_core); -; - MOV r0, r10 ; Move the core ID to r0 for the macro -macro_call0 _tx_thread_smp_protect_wait_list_remove ; Call macro to remove core from the list - B _nobody_waiting_for_lock ; Leave -; -; } -; else -; { -; /* We have the lock. This means the ISR got the inter-core lock, but -; never released it because it saw that there was someone waiting. -; Note this core is not in the list. */ -; -_this_core_has_lock -; -; /* We're no longer waiting. Note that this should be zero since this happens during thread preemption. */ -; _tx_thread_smp_protect_wait_counts[core]--; -; - LDR r1, =_tx_thread_smp_protect_wait_counts ; Load waiting count list - LDR r2, [r1, r10, LSL #2] ; Load waiting value for this core - SUB r2, r2, #1 ; Decrement waiting value. Should be zero now - STR r2, [r1, r10, LSL #2] ; Store new waiting value -; -; /* Now release the inter-core lock. */ -; -; /* Set protected core as invalid. */ -; _tx_thread_smp_protection.tx_thread_smp_protect_core = 0xFFFFFFFF; -; - LDR r1, =_tx_thread_smp_protection ; Load address of protection structure - MOV r2, #0xFFFFFFFF ; Build invalid value - STR r2, [r1, #8] ; Mark the protected core as invalid - DMB ; Ensure that accesses to shared resource have completed -; -; /* Release protection. */ -; _tx_thread_smp_protection.tx_thread_smp_protect_in_force = 0; -; - MOV r2, #0 ; Build release protection value - STR r2, [r1, #0] ; Release the protection - DSB ISH ; To ensure update of the protection occurs before other CPUs awake -; -; /* Wake up waiting processors. Note interrupts are already enabled. */ -; - IF :DEF:TX_ENABLE_WFE - SEV ; Send event to other CPUs - ENDIF -; -; } -; } -; - -_nobody_waiting_for_lock LDMIA sp!, {r3, r10, r12, lr} ; Recover temporarily saved registers MOV r1, lr ; Save lr (point of interrupt) diff --git a/ports_smp/cortex_a9_smp/ac5/src/tx_thread_smp_protect.s b/ports_smp/cortex_a9_smp/ac5/src/tx_thread_smp_protect.s index 1f2330d9..82fa0b91 100644 --- a/ports_smp/cortex_a9_smp/ac5/src/tx_thread_smp_protect.s +++ b/ports_smp/cortex_a9_smp/ac5/src/tx_thread_smp_protect.s @@ -1,5 +1,6 @@ ;/*************************************************************************** ; * Copyright (c) 2024 Microsoft Corporation +; * Copyright (c) 2026 Eclipse ThreadX contributors ; * ; * This program and the accompanying materials are made available under the ; * terms of the MIT License which is available at @@ -7,6 +8,7 @@ ; * ; * SPDX-License-Identifier: MIT ; **************************************************************************/ +; Some portions generated by Copilot (Opus 5). ; ; ;/**************************************************************************/ @@ -31,17 +33,9 @@ ; ; -;/* Include macros for modifying the wait list. */ -#include "tx_thread_smp_protection_wait_list_macros.h" IMPORT _tx_thread_current_ptr IMPORT _tx_thread_smp_protection - IMPORT _tx_thread_smp_protect_wait_counts - IMPORT _tx_thread_smp_protect_wait_list - IMPORT _tx_thread_smp_protect_wait_list_lock_protect_in_force - IMPORT _tx_thread_smp_protect_wait_list_head - IMPORT _tx_thread_smp_protect_wait_list_tail - IMPORT _tx_thread_smp_protect_wait_list_size AREA ||.text||, CODE, READONLY PRESERVE8 @@ -82,12 +76,10 @@ _tx_thread_smp_protect ;VOID _tx_thread_smp_protect(VOID) ;{ -; - PUSH {r4-r6} ; Save registers we'll be using ; ; /* Disable interrupts so we don't get preempted. */ ; - MRS r0, CPSR ; Pickup current CPSR + MRS r3, CPSR ; Pickup current CPSR IF :DEF:TX_ENABLE_FIQ_SUPPORT CPSID if ; Disable IRQ and FIQ interrupts @@ -95,266 +87,93 @@ _tx_thread_smp_protect CPSID i ; Disable IRQ interrupts ENDIF ; +; /* Pickup the CPU ID. */ +; + MRC p15, 0, r2, c0, c0, 5 ; Read CPU ID register + AND r2, r2, #0x03 ; Mask off, leaving the CPU ID field +; ; /* Do we already have protection? */ ; if (this_core == _tx_thread_smp_protection.tx_thread_smp_protect_core) ; { ; - MRC p15, 0, r1, c0, c0, 5 ; Read CPU ID register - AND r1, r1, #0x03 ; Mask off, leaving the CPU ID field - LDR r2, =_tx_thread_smp_protection ; Build address to protection structure - LDR r3, [r2, #8] ; Pickup the owning core - CMP r1, r3 ; Is it not this core? - BNE _protection_not_owned ; No, the protection is not already owned + LDR r0, =_tx_thread_smp_protection ; Build address to protection structure + LDR r1, [r0, #8] ; Pickup the owning core + CMP r1, r2 ; Is it this core? + BEQ _owned ; Yes, the protection is already owned ; -; /* We already have protection. */ -; -; /* Increment the protection count. */ -; _tx_thread_smp_protection.tx_thread_smp_protect_count++; -; - LDR r3, [r2, #12] ; Pickup ownership count - ADD r3, r3, #1 ; Increment ownership count - STR r3, [r2, #12] ; Store ownership count - DMB - - B _return - -_protection_not_owned +; } ; ; /* Is the lock available? */ ; if (_tx_thread_smp_protection.tx_thread_smp_protect_in_force == 0) ; { ; - LDREX r3, [r2, #0] ; Pickup the protection flag - CMP r3, #0 - BNE _start_waiting ; No, protection not available + LDREX r1, [r0] ; Pickup the protection flag + CMP r1, #0 ; Is it available? + BEQ _get_protection ; Yes, attempt to get the protection ; -; /* Is the list empty? */ -; if (_tx_thread_smp_protect_wait_list_head == _tx_thread_smp_protect_wait_list_tail) -; { +; } ; - LDR r3, =_tx_thread_smp_protect_wait_list_head - LDR r3, [r3] - LDR r4, =_tx_thread_smp_protect_wait_list_tail - LDR r4, [r4] - CMP r3, r4 - BNE _list_not_empty +; /* The protection is held elsewhere. Restore interrupts so this core can be +; preempted while it waits, then try the whole sequence again. */ +; + MSR CPSR_c, r3 ; Restore CPSR + IF :DEF:TX_ENABLE_WFE + WFE ; Go into standby + ENDIF + B _tx_thread_smp_protect ; On waking, restart the protection attempt + +_get_protection ; ; /* Try to get the lock. */ ; if (write_exclusive(&_tx_thread_smp_protection.tx_thread_smp_protect_in_force, 1) == SUCCESS) ; { ; - MOV r3, #1 ; Build lock value - STREX r4, r3, [r2, #0] ; Attempt to get the protection - CMP r4, #0 - BNE _start_waiting ; Did it fail? + MOV r1, #1 ; Build lock value + STREX r2, r1, [r0] ; Attempt to get the protection + CMP r2, #0 ; Check whether the store succeeded (0 = success) + BEQ _got_protection ; Yes, we have the protection ; -; /* We got the lock! */ -; _tx_thread_smp_protect_lock_got(); +; } ; - DMB ; Ensure write to protection finishes -macro_call0 _tx_thread_smp_protect_lock_got ; Call the lock got function +; /* Another core beat us to it. Restore interrupts and try again. */ +; + MSR CPSR_c, r3 ; Restore CPSR + B _tx_thread_smp_protect ; Try the whole process again - B _return +_got_protection +; +; /* Got the lock. Record the owning core. */ +; _tx_thread_smp_protection.tx_thread_smp_protect_core = this_core; +; + DMB ; Ensure the protection write completes before it is used + MRC p15, 0, r2, c0, c0, 5 ; Read CPU ID register + AND r2, r2, #0x03 ; Mask off, leaving the CPU ID field + STR r2, [r0, #8] ; Save the owning core -_list_not_empty -; -; /* Are we at the front of the list? */ -; if (this_core == _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_head]) -; { -; - LDR r3, =_tx_thread_smp_protect_wait_list_head ; Get the address of the head - LDR r3, [r3] ; Get the value of the head - LDR r4, =_tx_thread_smp_protect_wait_list ; Get the address of the list - LDR r4, [r4, r3, LSL #2] ; Get the value at the head index + IF :DEF:TX_MPCORE_DEBUG_ENABLE + LSL r2, r2, #2 ; Build offset to array indexes + LDR r1, =_tx_thread_current_ptr ; Pickup start of the current thread array + ADD r1, r1, r2 ; Build index into the current thread array + LDR r2, [r1] ; Pickup current thread for this core + STR r2, [r0, #4] ; Save current thread pointer + STR LR, [r0, #16] ; Save caller's return address + STR r3, [r0, #20] ; Save CPSR + ENDIF - CMP r1, r4 - BNE _start_waiting +_owned ; -; /* Is the lock still available? */ -; if (_tx_thread_smp_protection.tx_thread_smp_protect_in_force == 0) -; { +; /* Increment the protection count. */ +; _tx_thread_smp_protection.tx_thread_smp_protect_count++; ; - LDR r3, [r2, #0] ; Pickup the protection flag - CMP r3, #0 - BNE _start_waiting ; No, protection not available -; -; /* Get the lock. */ -; _tx_thread_smp_protection.tx_thread_smp_protect_in_force = 1; -; - MOV r3, #1 ; Build lock value - STR r3, [r2, #0] ; Store lock value + LDR r1, [r0, #12] ; Pickup ownership count + ADD r1, r1, #1 ; Increment ownership count + STR r1, [r0, #12] ; Store new ownership count DMB ; -; -; /* Got the lock. */ -; _tx_thread_smp_protect_lock_got(); -; -macro_call1 _tx_thread_smp_protect_lock_got -; -; /* Remove this core from the wait list. */ -; _tx_thread_smp_protect_remove_from_front_of_list(); -; -macro_call2 _tx_thread_smp_protect_remove_from_front_of_list - B _return - -_start_waiting + MOV r0, r3 ; Return the previous CPSR ; -; /* For one reason or another, we didn't get the lock. */ +;} ; -; /* Increment wait count. */ -; _tx_thread_smp_protect_wait_counts[this_core]++; -; - LDR r3, =_tx_thread_smp_protect_wait_counts ; Load wait list counts - LDR r4, [r3, r1, LSL #2] ; Load waiting value for this core - ADD r4, r4, #1 ; Increment wait value - STR r4, [r3, r1, LSL #2] ; Store new wait value -; -; /* Have we not added ourselves to the list yet? */ -; if (_tx_thread_smp_protect_wait_counts[this_core] == 1) -; { -; - CMP r4, #1 - BNE _already_in_list0 ; Is this core already waiting? -; -; /* Add ourselves to the list. */ -; _tx_thread_smp_protect_wait_list_add(this_core); -; -macro_call3 _tx_thread_smp_protect_wait_list_add ; Call macro to add ourselves to the list -; -; } -; -_already_in_list0 -; -; /* Restore interrupts. */ -; - MSR CPSR_c, r0 ; Restore CPSR - IF :DEF:TX_ENABLE_WFE - WFE ; Go into standby - ENDIF -; -; /* We do this until we have the lock. */ -; while (1) -; { -; -_try_to_get_lock -; -; /* Disable interrupts so we don't get preempted. */ -; - IF :DEF:TX_ENABLE_FIQ_SUPPORT - CPSID if ; Disable IRQ and FIQ interrupts - ELSE - CPSID i ; Disable IRQ interrupts - ENDIF - - MRC p15, 0, r1, c0, c0, 5 ; Read CPU ID register - AND r1, r1, #0x03 ; Mask off, leaving the CPU ID field -; -; /* Do we already have protection? */ -; if (this_core == _tx_thread_smp_protection.tx_thread_smp_protect_core) -; { -; - LDR r3, [r2, #8] ; Pickup the owning core - CMP r3, r1 ; Is it this core? - BEQ _got_lock_after_waiting ; Yes, the protection is already owned. This means - ; an ISR preempted us and got protection -; -; } -; -; /* Are we at the front of the list? */ -; if (this_core == _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_head]) -; { -; - LDR r3, =_tx_thread_smp_protect_wait_list_head ; Get the address of the head - LDR r3, [r3] ; Get the value of the head - LDR r4, =_tx_thread_smp_protect_wait_list ; Get the address of the list - LDR r4, [r4, r3, LSL #2] ; Get the value at the head index - - CMP r1, r4 - BNE _did_not_get_lock -; -; /* Is the lock still available? */ -; if (_tx_thread_smp_protection.tx_thread_smp_protect_in_force == 0) -; { -; - LDR r3, [r2, #0] ; Pickup the protection flag - CMP r3, #0 - BNE _did_not_get_lock ; No, protection not available -; -; /* Get the lock. */ -; _tx_thread_smp_protection.tx_thread_smp_protect_in_force = 1; -; - MOV r3, #1 ; Build lock value - STR r3, [r2, #0] ; Store lock value - DMB ; -; -; /* Got the lock. */ -; _tx_thread_smp_protect_lock_got(); -; -macro_call4 _tx_thread_smp_protect_lock_got -; -; /* Remove this core from the wait list. */ -; _tx_thread_smp_protect_remove_from_front_of_list(); -; -macro_call5 _tx_thread_smp_protect_remove_from_front_of_list - - B _got_lock_after_waiting - -_did_not_get_lock -; -; /* For one reason or another, we didn't get the lock. */ -; -; /* Were we removed from the list? This can happen if we're a thread -; and we got preempted. */ -; if (_tx_thread_smp_protect_wait_counts[this_core] == 0) -; { -; - LDR r3, =_tx_thread_smp_protect_wait_counts ; Load wait list counts - LDR r4, [r3, r1, LSL #2] ; Load waiting value for this core - CMP r4, #0 - BNE _already_in_list1 ; Is this core already in the list? -; -; /* Add ourselves to the list. */ -; _tx_thread_smp_protect_wait_list_add(this_core); -; -macro_call6 _tx_thread_smp_protect_wait_list_add ; Call macro to add ourselves to the list -; -; /* Our waiting count was also reset when we were preempted. Increment it again. */ -; _tx_thread_smp_protect_wait_counts[this_core]++; -; - LDR r3, =_tx_thread_smp_protect_wait_counts ; Load wait list counts - LDR r4, [r3, r1, LSL #2] ; Load waiting value for this core - ADD r4, r4, #1 ; Increment wait value - STR r4, [r3, r1, LSL #2] ; Store new wait value value -; -; } -; -_already_in_list1 -; -; /* Restore interrupts and try again. */ -; - MSR CPSR_c, r0 ; Restore CPSR - IF :DEF:TX_ENABLE_WFE - WFE ; Go into standby - ENDIF - B _try_to_get_lock ; On waking, restart the protection attempt - -_got_lock_after_waiting -; -; /* We're no longer waiting. */ -; _tx_thread_smp_protect_wait_counts[this_core]--; -; - LDR r3, =_tx_thread_smp_protect_wait_counts ; Load waiting list - LDR r4, [r3, r1, LSL #2] ; Load current wait value - SUB r4, r4, #1 ; Decrement wait value - STR r4, [r3, r1, LSL #2] ; Store new wait value value - -; -; /* Restore link register and return. */ -; -_return - - POP {r4-r6} ; Restore registers - IF {INTER} = {TRUE} BX lr ; Return to caller ELSE @@ -362,4 +181,3 @@ _return ENDIF END - diff --git a/ports_smp/cortex_a9_smp/ac5/src/tx_thread_smp_protection_wait_list_macros.h b/ports_smp/cortex_a9_smp/ac5/src/tx_thread_smp_protection_wait_list_macros.h deleted file mode 100644 index fec51581..00000000 --- a/ports_smp/cortex_a9_smp/ac5/src/tx_thread_smp_protection_wait_list_macros.h +++ /dev/null @@ -1,314 +0,0 @@ -;/*************************************************************************** -; * Copyright (c) 2024 Microsoft Corporation -; * -; * This program and the accompanying materials are made available under the -; * terms of the MIT License which is available at -; * https://opensource.org/licenses/MIT. -; * -; * SPDX-License-Identifier: MIT -; **************************************************************************/ -; -; -;/**************************************************************************/ -;/**************************************************************************/ -;/** */ -;/** ThreadX Component */ -;/** */ -;/** Thread - Low Level SMP Support */ -;/** */ -;/**************************************************************************/ -;/**************************************************************************/ - - MACRO -$label _tx_thread_smp_protect_lock_got -; -; /* Set the currently owned core. */ -; _tx_thread_smp_protection.tx_thread_smp_protect_core = this_core; -; - STR r1, [r2, #8] ; Store this core -; -; /* Increment the protection count. */ -; _tx_thread_smp_protection.tx_thread_smp_protect_count++; -; - LDR r3, [r2, #12] ; Pickup ownership count - ADD r3, r3, #1 ; Increment ownership count - STR r3, [r2, #12] ; Store ownership count - DMB - - IF :DEF:TX_MPCORE_DEBUG_ENABLE - LSL r3, r1, #2 ; Build offset to array indexes - LDR r4, =_tx_thread_current_ptr ; Pickup start of the current thread array - ADD r4, r3, r4 ; Build index into the current thread array - LDR r3, [r4] ; Pickup current thread for this core - STR r3, [r2, #4] ; Save current thread pointer - STR LR, [r2, #16] ; Save caller's return address - STR r0, [r2, #20] ; Save CPSR - ENDIF - - MEND - - MACRO -$label _tx_thread_smp_protect_remove_from_front_of_list -; -; /* Remove ourselves from the list. */ -; _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_head++] = 0xFFFFFFFF; -; - MOV r3, #0xFFFFFFFF ; Build the invalid core value - LDR r4, =_tx_thread_smp_protect_wait_list_head ; Get the address of the head - LDR r5, [r4] ; Get the value of the head - LDR r6, =_tx_thread_smp_protect_wait_list ; Get the address of the list - STR r3, [r6, r5, LSL #2] ; Store the invalid core value - ADD r5, r5, #1 ; Increment the head -; -; /* Did we wrap? */ -; if (_tx_thread_smp_protect_wait_list_head == TX_THREAD_SMP_MAX_CORES + 1) -; { -; - LDR r3, =_tx_thread_smp_protect_wait_list_size ; Load address of core list size - LDR r3, [r3] ; Load the max cores value - CMP r5, r3 ; Compare the head to it - BNE $label._store_new_head ; Are we at the max? -; -; _tx_thread_smp_protect_wait_list_head = 0; -; - EOR r5, r5, r5 ; We're at the max. Set it to zero -; -; } -; -$label._store_new_head - - STR r5, [r4] ; Store the new head -; -; /* We have the lock! */ -; return; -; - MEND - - - MACRO -$label _tx_thread_smp_protect_wait_list_lock_get -;VOID _tx_thread_smp_protect_wait_list_lock_get() -;{ -; /* We do this until we have the lock. */ -; while (1) -; { -; -$label._tx_thread_smp_protect_wait_list_lock_get__try_to_get_lock -; -; /* Is the list lock available? */ -; _tx_thread_smp_protect_wait_list_lock_protect_in_force = load_exclusive(&_tx_thread_smp_protect_wait_list_lock_protect_in_force); -; - LDR r1, =_tx_thread_smp_protect_wait_list_lock_protect_in_force - LDREX r2, [r1] ; Pickup the protection flag -; -; if (protect_in_force == 0) -; { -; - CMP r2, #0 - BNE $label._tx_thread_smp_protect_wait_list_lock_get__try_to_get_lock ; No, protection not available -; -; /* Try to get the list. */ -; int status = store_exclusive(&_tx_thread_smp_protect_wait_list_lock_protect_in_force, 1); -; - MOV r2, #1 ; Build lock value - STREX r3, r2, [r1] ; Attempt to get the protection -; -; if (status == SUCCESS) -; - CMP r3, #0 - BNE $label._tx_thread_smp_protect_wait_list_lock_get__try_to_get_lock ; Did it fail? If so, try again. -; -; /* We have the lock! */ -; return; -; - MEND - - - MACRO -$label _tx_thread_smp_protect_wait_list_add -;VOID _tx_thread_smp_protect_wait_list_add(UINT new_core) -;{ -; -; /* We're about to modify the list, so get the list lock. */ -; _tx_thread_smp_protect_wait_list_lock_get(); -; - PUSH {r1-r2} - -$label _tx_thread_smp_protect_wait_list_lock_get - - POP {r1-r2} -; -; /* Add this core. */ -; _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_tail++] = new_core; -; - LDR r3, =_tx_thread_smp_protect_wait_list_tail ; Get the address of the tail - LDR r4, [r3] ; Get the value of tail - LDR r5, =_tx_thread_smp_protect_wait_list ; Get the address of the list - STR r1, [r5, r4, LSL #2] ; Store the new core value - ADD r4, r4, #1 ; Increment the tail -; -; /* Did we wrap? */ -; if (_tx_thread_smp_protect_wait_list_tail == _tx_thread_smp_protect_wait_list_size) -; { -; - LDR r5, =_tx_thread_smp_protect_wait_list_size ; Load max cores address - LDR r5, [r5] ; Load max cores value - CMP r4, r5 ; Compare max cores to tail - BNE $label._tx_thread_smp_protect_wait_list_add__no_wrap ; Did we wrap? -; -; _tx_thread_smp_protect_wait_list_tail = 0; -; - MOV r4, #0 -; -; } -; -$label._tx_thread_smp_protect_wait_list_add__no_wrap - - STR r4, [r3] ; Store the new tail value. -; -; /* Release the list lock. */ -; _tx_thread_smp_protect_wait_list_lock_protect_in_force = 0; -; - MOV r3, #0 ; Build lock value - LDR r4, =_tx_thread_smp_protect_wait_list_lock_protect_in_force - STR r3, [r4] ; Store the new value - - MEND - - - MACRO -$label _tx_thread_smp_protect_wait_list_remove -;VOID _tx_thread_smp_protect_wait_list_remove(UINT core) -;{ -; -; /* Get the core index. */ -; UINT core_index; -; for (core_index = 0;; core_index++) -; - EOR r1, r1, r1 ; Clear for 'core_index' - LDR r2, =_tx_thread_smp_protect_wait_list ; Get the address of the list -; -; { -; -$label._tx_thread_smp_protect_wait_list_remove__check_cur_core -; -; /* Is this the core? */ -; if (_tx_thread_smp_protect_wait_list[core_index] == core) -; { -; break; -; - LDR r3, [r2, r1, LSL #2] ; Get the value at the current index - CMP r3, r0 ; Did we find the core? - BEQ $label._tx_thread_smp_protect_wait_list_remove__found_core -; -; } -; - ADD r1, r1, #1 ; Increment cur index - B $label._tx_thread_smp_protect_wait_list_remove__check_cur_core ; Restart the loop -; -; } -; -$label._tx_thread_smp_protect_wait_list_remove__found_core -; -; /* We're about to modify the list. Get the lock. We need the lock because another -; core could be simultaneously adding (a core is simultaneously trying to get -; the inter-core lock) or removing (a core is simultaneously being preempted, -; like what is currently happening). */ -; _tx_thread_smp_protect_wait_list_lock_get(); -; - PUSH {r1} - -$label _tx_thread_smp_protect_wait_list_lock_get - - POP {r1} -; -; /* We remove by shifting. */ -; while (core_index != _tx_thread_smp_protect_wait_list_tail) -; { -; -$label._tx_thread_smp_protect_wait_list_remove__compare_index_to_tail - - LDR r2, =_tx_thread_smp_protect_wait_list_tail ; Load tail address - LDR r2, [r2] ; Load tail value - CMP r1, r2 ; Compare cur index and tail - BEQ $label._tx_thread_smp_protect_wait_list_remove__removed -; -; UINT next_index = core_index + 1; -; - MOV r2, r1 ; Move current index to next index register - ADD r2, r2, #1 ; Add 1 -; -; if (next_index == _tx_thread_smp_protect_wait_list_size) -; { -; - LDR r3, =_tx_thread_smp_protect_wait_list_size - LDR r3, [r3] - CMP r2, r3 - BNE $label._tx_thread_smp_protect_wait_list_remove__next_index_no_wrap -; -; next_index = 0; -; - MOV r2, #0 -; -; } -; -$label._tx_thread_smp_protect_wait_list_remove__next_index_no_wrap -; -; list_cores[core_index] = list_cores[next_index]; -; - LDR r0, =_tx_thread_smp_protect_wait_list ; Get the address of the list - LDR r3, [r0, r2, LSL #2] ; Get the value at the next index - STR r3, [r0, r1, LSL #2] ; Store the value at the current index -; -; core_index = next_index; -; - MOV r1, r2 - - B $label._tx_thread_smp_protect_wait_list_remove__compare_index_to_tail -; -; } -; -$label._tx_thread_smp_protect_wait_list_remove__removed -; -; /* Now update the tail. */ -; if (_tx_thread_smp_protect_wait_list_tail == 0) -; { -; - LDR r0, =_tx_thread_smp_protect_wait_list_tail ; Load tail address - LDR r1, [r0] ; Load tail value - CMP r1, #0 - BNE $label._tx_thread_smp_protect_wait_list_remove__tail_not_zero -; -; _tx_thread_smp_protect_wait_list_tail = _tx_thread_smp_protect_wait_list_size; -; - LDR r2, =_tx_thread_smp_protect_wait_list_size - LDR r1, [r2] -; -; } -; -$label._tx_thread_smp_protect_wait_list_remove__tail_not_zero -; -; _tx_thread_smp_protect_wait_list_tail--; -; - SUB r1, r1, #1 - STR r1, [r0] ; Store new tail value -; -; /* Release the list lock. */ -; _tx_thread_smp_protect_wait_list_lock_protect_in_force = 0; -; - MOV r0, #0 ; Build lock value - LDR r1, =_tx_thread_smp_protect_wait_list_lock_protect_in_force ; Load lock address - STR r0, [r1] ; Store the new value -; -; /* We're no longer waiting. Note that this should be zero since, again, -; this function is only called when a thread preemption is occurring. */ -; _tx_thread_smp_protect_wait_counts[core]--; -; - MRC p15, 0, r0, c0, c0, 5 ; Read CPU ID register - AND r0, r0, #0x03 ; Mask off, leaving the CPU ID field - LDR r1, =_tx_thread_smp_protect_wait_counts ; Load wait list counts - LDR r2, [r1, r0, LSL #2] ; Load waiting value - SUB r2, r2, #1 ; Subtract 1 - STR r2, [r1, r0, LSL #2] ; Store new waiting value - MEND - diff --git a/ports_smp/cortex_a9_smp/ac5/src/tx_thread_smp_unprotect.s b/ports_smp/cortex_a9_smp/ac5/src/tx_thread_smp_unprotect.s index ed3fae48..c161987c 100644 --- a/ports_smp/cortex_a9_smp/ac5/src/tx_thread_smp_unprotect.s +++ b/ports_smp/cortex_a9_smp/ac5/src/tx_thread_smp_unprotect.s @@ -1,5 +1,6 @@ ;/*************************************************************************** ; * Copyright (c) 2024 Microsoft Corporation +; * Copyright (c) 2026 Eclipse ThreadX contributors ; * ; * This program and the accompanying materials are made available under the ; * terms of the MIT License which is available at @@ -7,6 +8,7 @@ ; * ; * SPDX-License-Identifier: MIT ; **************************************************************************/ +; Some portions generated by Copilot (Opus 5). ; ; ;/**************************************************************************/ @@ -33,7 +35,6 @@ IMPORT _tx_thread_current_ptr IMPORT _tx_thread_smp_protection IMPORT _tx_thread_preempt_disable - IMPORT _tx_thread_smp_protect_wait_counts AREA ||.text||, CODE, READONLY PRESERVE8 @@ -103,10 +104,6 @@ _tx_thread_smp_unprotect CMP r3, #0 ; Is the preempt disable flag set? BNE _still_protected ; Yes, skip the protection release - LDR r2,=_tx_thread_smp_protect_wait_counts ; Build build address of wait counts - LDR r3, [r2, r1, LSL #2] ; Pickup wait list value - CMP r3, #0 ; Are any entities on this core waiting? - BNE _still_protected ; Yes, skip the protection release LDR r2,=_tx_thread_smp_protection ; Build address of protection structure MOV r3, #0xFFFFFFFF ; Build invalid value diff --git a/ports_smp/cortex_a9_smp/gnu/src/tx_thread_context_restore.S b/ports_smp/cortex_a9_smp/gnu/src/tx_thread_context_restore.S index 2fbf25fd..c96d9638 100644 --- a/ports_smp/cortex_a9_smp/gnu/src/tx_thread_context_restore.S +++ b/ports_smp/cortex_a9_smp/gnu/src/tx_thread_context_restore.S @@ -1,5 +1,6 @@ @/*************************************************************************** @ * Copyright (c) 2024 Microsoft Corporation +@ * Copyright (c) 2026 Eclipse ThreadX contributors @ * @ * This program and the accompanying materials are made available under the @ * terms of the MIT License which is available at @@ -7,6 +8,7 @@ @ * @ * SPDX-License-Identifier: MIT @ **************************************************************************/ +@ Some portions generated by Copilot (Opus 5). @ @ @/**************************************************************************/ @@ -29,8 +31,6 @@ @#include "tx_thread.h" @#include "tx_timer.h" @ -@/* Include macros for modifying the wait list. */ -#include "tx_thread_smp_protection_wait_list_macros.h" #ifdef TX_ENABLE_FIQ_SUPPORT DISABLE_INTS = 0xC0 @ Disable IRQ & FIQ interrupts @@ -51,11 +51,6 @@ SVC_MODE = 0x93 @ SVC mode .global _tx_thread_preempt_disable .global _tx_timer_interrupt_active .global _tx_thread_smp_protection - .global _tx_thread_smp_protect_wait_counts - .global _tx_thread_smp_protect_wait_list - .global _tx_thread_smp_protect_wait_list_lock_protect_in_force - .global _tx_thread_smp_protect_wait_list_tail - .global _tx_thread_smp_protect_wait_list_size #ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY .global _tx_execution_isr_exit #endif @@ -198,77 +193,6 @@ __tx_thread_no_preempt_restore: @ { @ __tx_thread_preempt_restore: -@ -@ /* Was the thread being preempted waiting for the lock? */ -@ if (_tx_thread_smp_protect_wait_counts[this_core] != 0) -@ { -@ - LDR r1, =_tx_thread_smp_protect_wait_counts @ Load waiting count list - LDR r2, [r1, r10, LSL #2] @ Load waiting value for this core - CMP r2, #0 - BEQ _nobody_waiting_for_lock @ Is the core waiting for the lock? -@ -@ /* Do we not have the lock? This means the ISR never got the inter-core lock. */ -@ if (_tx_thread_smp_protection.tx_thread_smp_protect_owned != this_core) -@ { -@ - LDR r1, =_tx_thread_smp_protection @ Load address of protection structure - LDR r2, [r1, #8] @ Pickup the owning core - CMP r10, r2 @ Compare our core to the owning core - BEQ _this_core_has_lock @ Do we have the lock? -@ -@ /* We don't have the lock. This core should be in the list. Remove it. */ -@ _tx_thread_smp_protect_wait_list_remove(this_core); -@ - MOV r0, r10 @ Move the core ID to r0 for the macro - _tx_thread_smp_protect_wait_list_remove @ Call macro to remove core from the list - B _nobody_waiting_for_lock @ Leave -@ -@ } -@ else -@ { -@ /* We have the lock. This means the ISR got the inter-core lock, but -@ never released it because it saw that there was someone waiting. -@ Note this core is not in the list. */ -@ -_this_core_has_lock: -@ -@ /* We're no longer waiting. Note that this should be zero since this happens during thread preemption. */ -@ _tx_thread_smp_protect_wait_counts[core]--; -@ - LDR r1, =_tx_thread_smp_protect_wait_counts @ Load waiting count list - LDR r2, [r1, r10, LSL #2] @ Load waiting value for this core - SUB r2, r2, #1 @ Decrement waiting value. Should be zero now - STR r2, [r1, r10, LSL #2] @ Store new waiting value -@ -@ /* Now release the inter-core lock. */ -@ -@ /* Set protected core as invalid. */ -@ _tx_thread_smp_protection.tx_thread_smp_protect_core = 0xFFFFFFFF; -@ - LDR r1, =_tx_thread_smp_protection @ Load address of protection structure - MOV r2, #0xFFFFFFFF @ Build invalid value - STR r2, [r1, #8] @ Mark the protected core as invalid - DMB @ Ensure that accesses to shared resource have completed -@ -@ /* Release protection. */ -@ _tx_thread_smp_protection.tx_thread_smp_protect_in_force = 0; -@ - MOV r2, #0 @ Build release protection value - STR r2, [r1, #0] @ Release the protection - DSB ISH @ To ensure update of the protection occurs before other CPUs awake -@ -@ /* Wake up waiting processors. Note interrupts are already enabled. */ -@ -#ifdef TX_ENABLE_WFE - SEV @ Send event to other CPUs -#endif -@ -@ } -@ } -@ - -_nobody_waiting_for_lock: LDMIA sp!, {r3, r10, r12, lr} @ Recover temporarily saved registers MOV r1, lr @ Save lr (point of interrupt) diff --git a/ports_smp/cortex_a9_smp/gnu/src/tx_thread_smp_protect.S b/ports_smp/cortex_a9_smp/gnu/src/tx_thread_smp_protect.S index 44b36587..05bf5256 100644 --- a/ports_smp/cortex_a9_smp/gnu/src/tx_thread_smp_protect.S +++ b/ports_smp/cortex_a9_smp/gnu/src/tx_thread_smp_protect.S @@ -1,5 +1,6 @@ @/*************************************************************************** @ * Copyright (c) 2024 Microsoft Corporation +@ * Copyright (c) 2026 Eclipse ThreadX contributors @ * @ * This program and the accompanying materials are made available under the @ * terms of the MIT License which is available at @@ -7,6 +8,7 @@ @ * @ * SPDX-License-Identifier: MIT @ **************************************************************************/ +@ Some portions generated by Copilot (Opus 5). @ @ @/**************************************************************************/ @@ -31,17 +33,9 @@ @ @ -@/* Include macros for modifying the wait list. */ -#include "tx_thread_smp_protection_wait_list_macros.h" .global _tx_thread_current_ptr .global _tx_thread_smp_protection - .global _tx_thread_smp_protect_wait_counts - .global _tx_thread_smp_protect_wait_list - .global _tx_thread_smp_protect_wait_list_lock_protect_in_force - .global _tx_thread_smp_protect_wait_list_head - .global _tx_thread_smp_protect_wait_list_tail - .global _tx_thread_smp_protect_wait_list_size .arm .text @@ -84,12 +78,10 @@ _tx_thread_smp_protect: @VOID _tx_thread_smp_protect(VOID) @{ -@ - PUSH {r4-r6} @ Save registers we'll be using @ @ /* Disable interrupts so we don't get preempted. */ @ - MRS r0, CPSR @ Pickup current CPSR + MRS r3, CPSR @ Pickup current CPSR #ifdef TX_ENABLE_FIQ_SUPPORT CPSID if @ Disable IRQ and FIQ interrupts @@ -97,270 +89,96 @@ _tx_thread_smp_protect: CPSID i @ Disable IRQ interrupts #endif @ +@ /* Pickup the CPU ID. */ +@ + MRC p15, 0, r2, c0, c0, 5 @ Read CPU ID register + AND r2, r2, #0x03 @ Mask off, leaving the CPU ID field +@ @ /* Do we already have protection? */ @ if (this_core == _tx_thread_smp_protection.tx_thread_smp_protect_core) @ { @ - MRC p15, 0, r1, c0, c0, 5 @ Read CPU ID register - AND r1, r1, #0x03 @ Mask off, leaving the CPU ID field - LDR r2, =_tx_thread_smp_protection @ Build address to protection structure - LDR r3, [r2, #8] @ Pickup the owning core - CMP r1, r3 @ Is it not this core? - BNE _protection_not_owned @ No, the protection is not already owned + LDR r0, =_tx_thread_smp_protection @ Build address to protection structure + LDR r1, [r0, #8] @ Pickup the owning core + CMP r1, r2 @ Is it this core? + BEQ _owned @ Yes, the protection is already owned @ -@ /* We already have protection. */ -@ -@ /* Increment the protection count. */ -@ _tx_thread_smp_protection.tx_thread_smp_protect_count++; -@ - LDR r3, [r2, #12] @ Pickup ownership count - ADD r3, r3, #1 @ Increment ownership count - STR r3, [r2, #12] @ Store ownership count - DMB - - B _return - -_protection_not_owned: +@ } @ @ /* Is the lock available? */ @ if (_tx_thread_smp_protection.tx_thread_smp_protect_in_force == 0) @ { @ - LDREX r3, [r2] @ Pickup the protection flag - CMP r3, #0 - BNE _start_waiting @ No, protection not available + LDREX r1, [r0] @ Pickup the protection flag + CMP r1, #0 @ Is it available? + BEQ _get_protection @ Yes, attempt to get the protection @ -@ /* Is the list empty? */ -@ if (_tx_thread_smp_protect_wait_list_head == _tx_thread_smp_protect_wait_list_tail) -@ { +@ } @ - LDR r3, =_tx_thread_smp_protect_wait_list_head - LDR r3, [r3] - LDR r4, =_tx_thread_smp_protect_wait_list_tail - LDR r4, [r4] - CMP r3, r4 - BNE _list_not_empty +@ /* The protection is held elsewhere. Restore interrupts so this core can be +@ preempted while it waits, then try the whole sequence again. */ +@ + MSR CPSR_c, r3 @ Restore CPSR +#ifdef TX_ENABLE_WFE + WFE @ Go into standby +#endif + B _tx_thread_smp_protect @ On waking, restart the protection attempt + +_get_protection: @ @ /* Try to get the lock. */ @ if (write_exclusive(&_tx_thread_smp_protection.tx_thread_smp_protect_in_force, 1) == SUCCESS) @ { @ - MOV r3, #1 @ Build lock value - STREX r4, r3, [r2] @ Attempt to get the protection - CMP r4, #0 - BNE _start_waiting @ Did it fail? + MOV r1, #1 @ Build lock value + STREX r2, r1, [r0] @ Attempt to get the protection + CMP r2, #0 @ Check whether the store succeeded (0 = success) + BEQ _got_protection @ Yes, we have the protection @ -@ /* We got the lock! */ -@ _tx_thread_smp_protect_lock_got(); +@ } @ - DMB @ Ensure write to protection finishes - _tx_thread_smp_protect_lock_got @ Call the lock got function +@ /* Another core beat us to it. Restore interrupts and try again. */ +@ + MSR CPSR_c, r3 @ Restore CPSR + B _tx_thread_smp_protect @ Try the whole process again - B _return +_got_protection: +@ +@ /* Got the lock. Record the owning core. */ +@ _tx_thread_smp_protection.tx_thread_smp_protect_core = this_core; +@ + DMB @ Ensure the protection write completes before it is used + MRC p15, 0, r2, c0, c0, 5 @ Read CPU ID register + AND r2, r2, #0x03 @ Mask off, leaving the CPU ID field + STR r2, [r0, #8] @ Save the owning core -_list_not_empty: -@ -@ /* Are we at the front of the list? */ -@ if (this_core == _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_head]) -@ { -@ - LDR r3, =_tx_thread_smp_protect_wait_list_head @ Get the address of the head - LDR r3, [r3] @ Get the value of the head - LDR r4, =_tx_thread_smp_protect_wait_list @ Get the address of the list - LDR r4, [r4, r3, LSL #2] @ Get the value at the head index +#ifdef TX_MPCORE_DEBUG_ENABLE + LSL r2, r2, #2 @ Build offset to array indexes + LDR r1, =_tx_thread_current_ptr @ Pickup start of the current thread array + ADD r1, r1, r2 @ Build index into the current thread array + LDR r2, [r1] @ Pickup current thread for this core + STR r2, [r0, #4] @ Save current thread pointer + STR LR, [r0, #16] @ Save caller's return address + STR r3, [r0, #20] @ Save CPSR +#endif - CMP r1, r4 - BNE _start_waiting +_owned: @ -@ /* Is the lock still available? */ -@ if (_tx_thread_smp_protection.tx_thread_smp_protect_in_force == 0) -@ { +@ /* Increment the protection count. */ +@ _tx_thread_smp_protection.tx_thread_smp_protect_count++; @ - LDR r3, [r2, #0] @ Pickup the protection flag - CMP r3, #0 - BNE _start_waiting @ No, protection not available -@ -@ /* Get the lock. */ -@ _tx_thread_smp_protection.tx_thread_smp_protect_in_force = 1; -@ - MOV r3, #1 @ Build lock value - STR r3, [r2, #0] @ Store lock value + LDR r1, [r0, #12] @ Pickup ownership count + ADD r1, r1, #1 @ Increment ownership count + STR r1, [r0, #12] @ Store new ownership count DMB @ -@ -@ /* Got the lock. */ -@ _tx_thread_smp_protect_lock_got(); -@ - _tx_thread_smp_protect_lock_got -@ -@ /* Remove this core from the wait list. */ -@ _tx_thread_smp_protect_remove_from_front_of_list(); -@ - _tx_thread_smp_protect_remove_from_front_of_list - B _return - -_start_waiting: + MOV r0, r3 @ Return the previous CPSR @ -@ /* For one reason or another, we didn't get the lock. */ +@} @ -@ /* Increment wait count. */ -@ _tx_thread_smp_protect_wait_counts[this_core]++; -@ - LDR r3, =_tx_thread_smp_protect_wait_counts @ Load wait list counts - LDR r4, [r3, r1, LSL #2] @ Load waiting value for this core - ADD r4, r4, #1 @ Increment wait value - STR r4, [r3, r1, LSL #2] @ Store new wait value -@ -@ /* Have we not added ourselves to the list yet? */ -@ if (_tx_thread_smp_protect_wait_counts[this_core] == 1) -@ { -@ - CMP r4, #1 - BNE _already_in_list0 @ Is this core already waiting? -@ -@ /* Add ourselves to the list. */ -@ _tx_thread_smp_protect_wait_list_add(this_core); -@ - _tx_thread_smp_protect_wait_list_add @ Call macro to add ourselves to the list -@ -@ } -@ -_already_in_list0: -@ -@ /* Restore interrupts. */ -@ - MSR CPSR_c, r0 @ Restore CPSR -#ifdef TX_ENABLE_WFE - WFE @ Go into standby -#endif -@ -@ /* We do this until we have the lock. */ -@ while (1) -@ { -@ -_try_to_get_lock: -@ -@ /* Disable interrupts so we don't get preempted. */ -@ -#ifdef TX_ENABLE_FIQ_SUPPORT - CPSID if @ Disable IRQ and FIQ interrupts -#else - CPSID i @ Disable IRQ interrupts -#endif - - MRC p15, 0, r1, c0, c0, 5 @ Read CPU ID register - AND r1, r1, #0x03 @ Mask off, leaving the CPU ID field -@ -@ /* Do we already have protection? */ -@ if (this_core == _tx_thread_smp_protection.tx_thread_smp_protect_core) -@ { -@ - LDR r3, [r2, #8] @ Pickup the owning core - CMP r3, r1 @ Is it this core? - BEQ _got_lock_after_waiting @ Yes, the protection is already owned. This means - @ an ISR preempted us and got protection -@ -@ } -@ -@ /* Are we at the front of the list? */ -@ if (this_core == _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_head]) -@ { -@ - LDR r3, =_tx_thread_smp_protect_wait_list_head @ Get the address of the head - LDR r3, [r3] @ Get the value of the head - LDR r4, =_tx_thread_smp_protect_wait_list @ Get the address of the list - LDR r4, [r4, r3, LSL #2] @ Get the value at the head index - - CMP r1, r4 - BNE _did_not_get_lock -@ -@ /* Is the lock still available? */ -@ if (_tx_thread_smp_protection.tx_thread_smp_protect_in_force == 0) -@ { -@ - LDR r3, [r2, #0] @ Pickup the protection flag - CMP r3, #0 - BNE _did_not_get_lock @ No, protection not available -@ -@ /* Get the lock. */ -@ _tx_thread_smp_protection.tx_thread_smp_protect_in_force = 1; -@ - MOV r3, #1 @ Build lock value - STR r3, [r2, #0] @ Store lock value - DMB @ -@ -@ /* Got the lock. */ -@ _tx_thread_smp_protect_lock_got(); -@ - _tx_thread_smp_protect_lock_got -@ -@ /* Remove this core from the wait list. */ -@ _tx_thread_smp_protect_remove_from_front_of_list(); -@ - _tx_thread_smp_protect_remove_from_front_of_list - - B _got_lock_after_waiting - -_did_not_get_lock: -@ -@ /* For one reason or another, we didn't get the lock. */ -@ -@ /* Were we removed from the list? This can happen if we're a thread -@ and we got preempted. */ -@ if (_tx_thread_smp_protect_wait_counts[this_core] == 0) -@ { -@ - LDR r3, =_tx_thread_smp_protect_wait_counts @ Load wait list counts - LDR r4, [r3, r1, LSL #2] @ Load waiting value for this core - CMP r4, #0 - BNE _already_in_list1 @ Is this core already in the list? -@ -@ /* Add ourselves to the list. */ -@ _tx_thread_smp_protect_wait_list_add(this_core); -@ - _tx_thread_smp_protect_wait_list_add @ Call macro to add ourselves to the list -@ -@ /* Our waiting count was also reset when we were preempted. Increment it again. */ -@ _tx_thread_smp_protect_wait_counts[this_core]++; -@ - LDR r3, =_tx_thread_smp_protect_wait_counts @ Load wait list counts - LDR r4, [r3, r1, LSL #2] @ Load waiting value for this core - ADD r4, r4, #1 @ Increment wait value - STR r4, [r3, r1, LSL #2] @ Store new wait value value -@ -@ } -@ -_already_in_list1: -@ -@ /* Restore interrupts and try again. */ -@ - MSR CPSR_c, r0 @ Restore CPSR -#ifdef TX_ENABLE_WFE - WFE @ Go into standby -#endif - B _try_to_get_lock @ On waking, restart the protection attempt - -_got_lock_after_waiting: -@ -@ /* We're no longer waiting. */ -@ _tx_thread_smp_protect_wait_counts[this_core]--; -@ - LDR r3, =_tx_thread_smp_protect_wait_counts @ Load waiting list - LDR r4, [r3, r1, LSL #2] @ Load current wait value - SUB r4, r4, #1 @ Decrement wait value - STR r4, [r3, r1, LSL #2] @ Store new wait value value - -@ -@ /* Restore link register and return. */ -@ -_return: - - POP {r4-r6} @ Restore registers - #ifdef __THUMB_INTERWORK BX lr @ Return to caller #else MOV pc, lr @ Return to caller #endif - diff --git a/ports_smp/cortex_a9_smp/gnu/src/tx_thread_smp_protection_wait_list_macros.h b/ports_smp/cortex_a9_smp/gnu/src/tx_thread_smp_protection_wait_list_macros.h deleted file mode 100644 index f1ad80e8..00000000 --- a/ports_smp/cortex_a9_smp/gnu/src/tx_thread_smp_protection_wait_list_macros.h +++ /dev/null @@ -1,309 +0,0 @@ -@/*************************************************************************** -@ * Copyright (c) 2024 Microsoft Corporation -@ * -@ * This program and the accompanying materials are made available under the -@ * terms of the MIT License which is available at -@ * https://opensource.org/licenses/MIT. -@ * -@ * SPDX-License-Identifier: MIT -@ **************************************************************************/ -@ -@ -@/**************************************************************************/ -@/**************************************************************************/ -@/** */ -@/** ThreadX Component */ -@/** */ -@/** Thread - Low Level SMP Support */ -@/** */ -@/**************************************************************************/ -@/**************************************************************************/ - - .macro _tx_thread_smp_protect_lock_got -@ -@ /* Set the currently owned core. */ -@ _tx_thread_smp_protection.tx_thread_smp_protect_core = this_core; -@ - STR r1, [r2, #8] @ Store this core -@ -@ /* Increment the protection count. */ -@ _tx_thread_smp_protection.tx_thread_smp_protect_count++; -@ - LDR r3, [r2, #12] @ Pickup ownership count - ADD r3, r3, #1 @ Increment ownership count - STR r3, [r2, #12] @ Store ownership count - DMB - -#ifdef TX_MPCORE_DEBUG_ENABLE - LSL r3, r1, #2 @ Build offset to array indexes - LDR r4, =_tx_thread_current_ptr @ Pickup start of the current thread array - ADD r4, r3, r4 @ Build index into the current thread array - LDR r3, [r4] @ Pickup current thread for this core - STR r3, [r2, #4] @ Save current thread pointer - STR LR, [r2, #16] @ Save caller's return address - STR r0, [r2, #20] @ Save CPSR -#endif - - .endm - - .macro _tx_thread_smp_protect_remove_from_front_of_list -@ -@ /* Remove ourselves from the list. */ -@ _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_head++] = 0xFFFFFFFF; -@ - MOV r3, #0xFFFFFFFF @ Build the invalid core value - LDR r4, =_tx_thread_smp_protect_wait_list_head @ Get the address of the head - LDR r5, [r4] @ Get the value of the head - LDR r6, =_tx_thread_smp_protect_wait_list @ Get the address of the list - STR r3, [r6, r5, LSL #2] @ Store the invalid core value - ADD r5, r5, #1 @ Increment the head -@ -@ /* Did we wrap? */ -@ if (_tx_thread_smp_protect_wait_list_head == TX_THREAD_SMP_MAX_CORES + 1) -@ { -@ - LDR r3, =_tx_thread_smp_protect_wait_list_size @ Load address of core list size - LDR r3, [r3] @ Load the max cores value - CMP r5, r3 @ Compare the head to it - BNE _store_new_head\@ @ Are we at the max? -@ -@ _tx_thread_smp_protect_wait_list_head = 0; -@ - EOR r5, r5, r5 @ We're at the max. Set it to zero -@ -@ } -@ -_store_new_head\@: - - STR r5, [r4] @ Store the new head -@ -@ /* We have the lock! */ -@ return; -@ - .endm - - - .macro _tx_thread_smp_protect_wait_list_lock_get -@VOID _tx_thread_smp_protect_wait_list_lock_get() -@{ -@ /* We do this until we have the lock. */ -@ while (1) -@ { -@ -_tx_thread_smp_protect_wait_list_lock_get__try_to_get_lock\@: -@ -@ /* Is the list lock available? */ -@ _tx_thread_smp_protect_wait_list_lock_protect_in_force = load_exclusive(&_tx_thread_smp_protect_wait_list_lock_protect_in_force); -@ - LDR r1, =_tx_thread_smp_protect_wait_list_lock_protect_in_force - LDREX r2, [r1] @ Pickup the protection flag -@ -@ if (protect_in_force == 0) -@ { -@ - CMP r2, #0 - BNE _tx_thread_smp_protect_wait_list_lock_get__try_to_get_lock\@ @ No, protection not available -@ -@ /* Try to get the list. */ -@ int status = store_exclusive(&_tx_thread_smp_protect_wait_list_lock_protect_in_force, 1); -@ - MOV r2, #1 @ Build lock value - STREX r3, r2, [r1] @ Attempt to get the protection -@ -@ if (status == SUCCESS) -@ - CMP r3, #0 - BNE _tx_thread_smp_protect_wait_list_lock_get__try_to_get_lock\@ @ Did it fail? If so, try again. -@ -@ /* We have the lock! */ -@ return; -@ - .endm - - - .macro _tx_thread_smp_protect_wait_list_add -@VOID _tx_thread_smp_protect_wait_list_add(UINT new_core) -@{ -@ -@ /* We're about to modify the list, so get the list lock. */ -@ _tx_thread_smp_protect_wait_list_lock_get(); -@ - PUSH {r1-r2} - - _tx_thread_smp_protect_wait_list_lock_get - - POP {r1-r2} -@ -@ /* Add this core. */ -@ _tx_thread_smp_protect_wait_list[_tx_thread_smp_protect_wait_list_tail++] = new_core; -@ - LDR r3, =_tx_thread_smp_protect_wait_list_tail @ Get the address of the tail - LDR r4, [r3] @ Get the value of tail - LDR r5, =_tx_thread_smp_protect_wait_list @ Get the address of the list - STR r1, [r5, r4, LSL #2] @ Store the new core value - ADD r4, r4, #1 @ Increment the tail -@ -@ /* Did we wrap? */ -@ if (_tx_thread_smp_protect_wait_list_tail == _tx_thread_smp_protect_wait_list_size) -@ { -@ - LDR r5, =_tx_thread_smp_protect_wait_list_size @ Load max cores address - LDR r5, [r5] @ Load max cores value - CMP r4, r5 @ Compare max cores to tail - BNE _tx_thread_smp_protect_wait_list_add__no_wrap\@ @ Did we wrap? -@ -@ _tx_thread_smp_protect_wait_list_tail = 0; -@ - MOV r4, #0 -@ -@ } -@ -_tx_thread_smp_protect_wait_list_add__no_wrap\@: - - STR r4, [r3] @ Store the new tail value. -@ -@ /* Release the list lock. */ -@ _tx_thread_smp_protect_wait_list_lock_protect_in_force = 0; -@ - MOV r3, #0 @ Build lock value - LDR r4, =_tx_thread_smp_protect_wait_list_lock_protect_in_force - STR r3, [r4] @ Store the new value - - .endm - - - .macro _tx_thread_smp_protect_wait_list_remove -@VOID _tx_thread_smp_protect_wait_list_remove(UINT core) -@{ -@ -@ /* Get the core index. */ -@ UINT core_index; -@ for (core_index = 0;; core_index++) -@ - EOR r1, r1, r1 @ Clear for 'core_index' - LDR r2, =_tx_thread_smp_protect_wait_list @ Get the address of the list -@ -@ { -@ -_tx_thread_smp_protect_wait_list_remove__check_cur_core\@: -@ -@ /* Is this the core? */ -@ if (_tx_thread_smp_protect_wait_list[core_index] == core) -@ { -@ break; -@ - LDR r3, [r2, r1, LSL #2] @ Get the value at the current index - CMP r3, r0 @ Did we find the core? - BEQ _tx_thread_smp_protect_wait_list_remove__found_core\@ -@ -@ } -@ - ADD r1, r1, #1 @ Increment cur index - B _tx_thread_smp_protect_wait_list_remove__check_cur_core\@ @ Restart the loop -@ -@ } -@ -_tx_thread_smp_protect_wait_list_remove__found_core\@: -@ -@ /* We're about to modify the list. Get the lock. We need the lock because another -@ core could be simultaneously adding (a core is simultaneously trying to get -@ the inter-core lock) or removing (a core is simultaneously being preempted, -@ like what is currently happening). */ -@ _tx_thread_smp_protect_wait_list_lock_get(); -@ - PUSH {r1} - - _tx_thread_smp_protect_wait_list_lock_get - - POP {r1} -@ -@ /* We remove by shifting. */ -@ while (core_index != _tx_thread_smp_protect_wait_list_tail) -@ { -@ -_tx_thread_smp_protect_wait_list_remove__compare_index_to_tail\@: - - LDR r2, =_tx_thread_smp_protect_wait_list_tail @ Load tail address - LDR r2, [r2] @ Load tail value - CMP r1, r2 @ Compare cur index and tail - BEQ _tx_thread_smp_protect_wait_list_remove__removed\@ -@ -@ UINT next_index = core_index + 1; -@ - MOV r2, r1 @ Move current index to next index register - ADD r2, r2, #1 @ Add 1 -@ -@ if (next_index == _tx_thread_smp_protect_wait_list_size) -@ { -@ - LDR r3, =_tx_thread_smp_protect_wait_list_size - LDR r3, [r3] - CMP r2, r3 - BNE _tx_thread_smp_protect_wait_list_remove__next_index_no_wrap\@ -@ -@ next_index = 0; -@ - MOV r2, #0 -@ -@ } -@ -_tx_thread_smp_protect_wait_list_remove__next_index_no_wrap\@: -@ -@ list_cores[core_index] = list_cores[next_index]; -@ - LDR r0, =_tx_thread_smp_protect_wait_list @ Get the address of the list - LDR r3, [r0, r2, LSL #2] @ Get the value at the next index - STR r3, [r0, r1, LSL #2] @ Store the value at the current index -@ -@ core_index = next_index; -@ - MOV r1, r2 - - B _tx_thread_smp_protect_wait_list_remove__compare_index_to_tail\@ -@ -@ } -@ -_tx_thread_smp_protect_wait_list_remove__removed\@: -@ -@ /* Now update the tail. */ -@ if (_tx_thread_smp_protect_wait_list_tail == 0) -@ { -@ - LDR r0, =_tx_thread_smp_protect_wait_list_tail @ Load tail address - LDR r1, [r0] @ Load tail value - CMP r1, #0 - BNE _tx_thread_smp_protect_wait_list_remove__tail_not_zero\@ -@ -@ _tx_thread_smp_protect_wait_list_tail = _tx_thread_smp_protect_wait_list_size; -@ - LDR r2, =_tx_thread_smp_protect_wait_list_size - LDR r1, [r2] -@ -@ } -@ -_tx_thread_smp_protect_wait_list_remove__tail_not_zero\@: -@ -@ _tx_thread_smp_protect_wait_list_tail--; -@ - SUB r1, r1, #1 - STR r1, [r0] @ Store new tail value -@ -@ /* Release the list lock. */ -@ _tx_thread_smp_protect_wait_list_lock_protect_in_force = 0; -@ - MOV r0, #0 @ Build lock value - LDR r1, =_tx_thread_smp_protect_wait_list_lock_protect_in_force @ Load lock address - STR r0, [r1] @ Store the new value -@ -@ /* We're no longer waiting. Note that this should be zero since, again, -@ this function is only called when a thread preemption is occurring. */ -@ _tx_thread_smp_protect_wait_counts[core]--; -@ - MRC p15, 0, r0, c0, c0, 5 @ Read CPU ID register - AND r0, r0, #0x03 @ Mask off, leaving the CPU ID field - LDR r1, =_tx_thread_smp_protect_wait_counts @ Load wait list counts - LDR r2, [r1, r0, LSL #2] @ Load waiting value - SUB r2, r2, #1 @ Subtract 1 - STR r2, [r1, r0, LSL #2] @ Store new waiting value - .endm - diff --git a/ports_smp/cortex_a9_smp/gnu/src/tx_thread_smp_unprotect.S b/ports_smp/cortex_a9_smp/gnu/src/tx_thread_smp_unprotect.S index a76677ec..a9baf0c8 100644 --- a/ports_smp/cortex_a9_smp/gnu/src/tx_thread_smp_unprotect.S +++ b/ports_smp/cortex_a9_smp/gnu/src/tx_thread_smp_unprotect.S @@ -1,5 +1,6 @@ @/*************************************************************************** @ * Copyright (c) 2024 Microsoft Corporation +@ * Copyright (c) 2026 Eclipse ThreadX contributors @ * @ * This program and the accompanying materials are made available under the @ * terms of the MIT License which is available at @@ -7,6 +8,7 @@ @ * @ * SPDX-License-Identifier: MIT @ **************************************************************************/ +@ Some portions generated by Copilot (Opus 5). @ @ @/**************************************************************************/ @@ -33,7 +35,6 @@ .global _tx_thread_current_ptr .global _tx_thread_smp_protection .global _tx_thread_preempt_disable - .global _tx_thread_smp_protect_wait_counts .arm .text @@ -105,10 +106,6 @@ _tx_thread_smp_unprotect: CMP r3, #0 @ Is the preempt disable flag set? BNE _still_protected @ Yes, skip the protection release - LDR r2,=_tx_thread_smp_protect_wait_counts @ Build build address of wait counts - LDR r3, [r2, r1, LSL #2] @ Pickup wait list value - CMP r3, #0 @ Are any entities on this core waiting? - BNE _still_protected @ Yes, skip the protection release LDR r2,=_tx_thread_smp_protection @ Build address of protection structure MOV r3, #0xFFFFFFFF @ Build invalid value