[PATCH v4 02/10] sparc64: honor queued spinlock layout in secondary startup
From: Magnus Lindholm
Date: Sun Oct 18 2026 - 09:50:33 EST
The trampoline uses ldstub on byte zero of prom_entry_lock, which is a
queue-tail byte in the big-endian queued-spinlock layout. This writes
0xff000000; with NR_CPUS < 16384, a C locker can decode that tail as
CPU 16319 and access beyond the per-CPU table. Testing this byte also
fails to exclude a C holder of the locked byte at offset three.
Acquire the word with CASA, release byte three and poll while contended.
Retain explicit assembly ordering and the predicted branch for Spitfire
erratum 51; C unlock relies on TSO and compiler ordering.
See qspinlock_types.h and JPS2 A.10/A.35 for CASA/MEMBAR.
Fixes: 145d97858597 ("arch/sparc: Enable queued spinlock support for SPARC")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Magnus Lindholm <linmag7@xxxxxxxxx>
---
arch/sparc/kernel/trampoline_64.S | 40 +++++++++++++++++++++++++++----
1 file changed, 36 insertions(+), 4 deletions(-)
diff --git a/arch/sparc/kernel/trampoline_64.S b/arch/sparc/kernel/trampoline_64.S
index 51bf1eb92a36..447334730122 100644
--- a/arch/sparc/kernel/trampoline_64.S
+++ b/arch/sparc/kernel/trampoline_64.S
@@ -106,9 +106,19 @@ startup_continue:
* We lock 'num_kernel_image_mappings' consequetive entries.
*/
sethi %hi(prom_entry_lock), %g2
-1: ldstub [%g2 + %lo(prom_entry_lock)], %g1
+ /* Big-endian qspinlock: acquire the whole 32-bit value, not byte 0. */
+ or %g2, %lo(prom_entry_lock), %g2
+1: lduw [%g2], %g1
brnz,pn %g1, 1b
nop
+ mov 1, %g1
+ casa [%g2] ASI_P, %g0, %g1
+ brnz,pn %g1, 1b
+ nop
+ /* Spitfire erratum 51: barrier in a predicted-taken delay slot. */
+ ba,pt %xcc, 2f
+ membar #Sync
+2:
/* Get onto temporary stack which will be in the locked
* kernel image.
@@ -212,7 +222,13 @@ startup_continue:
nop
sethi %hi(prom_entry_lock), %g2
- stb %g0, [%g2 + %lo(prom_entry_lock)]
+ /*
+ * Retain explicit assembly release ordering; C unlock relies on TSO.
+ * The predicted branch protects Spitfire erratum 51.
+ */
+ ba,pt %xcc, 2f
+ membar #StoreStore | #LoadStore
+2: stb %g0, [%g2 + %lo(prom_entry_lock) + 3]
ba,pt %xcc, after_lock_tlb
nop
@@ -326,9 +342,19 @@ after_lock_tlb:
wrpr %g0, 0, %wstate
sethi %hi(prom_entry_lock), %g2
-1: ldstub [%g2 + %lo(prom_entry_lock)], %g1
+ /* Big-endian qspinlock: acquire the whole 32-bit value, not byte 0. */
+ or %g2, %lo(prom_entry_lock), %g2
+1: lduw [%g2], %g1
brnz,pn %g1, 1b
nop
+ mov 1, %g1
+ casa [%g2] ASI_P, %g0, %g1
+ brnz,pn %g1, 1b
+ nop
+ /* Spitfire erratum 51: barrier in a predicted-taken delay slot. */
+ ba,pt %xcc, 2f
+ membar #Sync
+2:
/* As a hack, put &init_thread_union into %g6.
* prom_world() loads from here to restore the %asi
@@ -389,7 +415,13 @@ after_lock_tlb:
add %sp, (2047 + 128), %o0
3: sethi %hi(prom_entry_lock), %g2
- stb %g0, [%g2 + %lo(prom_entry_lock)]
+ /*
+ * Retain explicit assembly release ordering; C unlock relies on TSO.
+ * The predicted branch protects Spitfire erratum 51.
+ */
+ ba,pt %xcc, 2f
+ membar #StoreStore | #LoadStore
+2: stb %g0, [%g2 + %lo(prom_entry_lock) + 3]
ldx [%l0], %g6
ldx [%g6 + TI_TASK], %g4
--
2.43.0