From nobody Thu Sep 24 14:25:36 2026 Received: from mail-ej2-f17.google.com (mail-ej2-f17.google.com [74.125.228.145]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EE2ED3D810F for ; Wed, 23 Sep 2026 20:19:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.228.145 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790194766; cv=none; b=M8Nleg1o0nysAoqlknvHWLRmqc+2nBfrjND+jyd9fkyarr6DJPFpLET+AVK58yJrapnfFRNakUqgeefNtX+7yND8rTDJsY4eulbyRya8mS+hAdKi7P5njJz+taetesbbuDSLIj9Wo/Kl9sQpmPmJguPVW6PzCf3wlMioQrttuW0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790194766; c=relaxed/simple; bh=0wHYlVgoasAY1JmiSfypx9MtD3RKd0J6iTU414lX8cc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=gmz7vVVPUaffmvLV5ZQSH6FJiJTTGLXskdMzoQVcQvPJTbyoj2cG3dUiccjoAEqa3qmrFYGFo/dgfsqAYwcUxB2u3TljJ4I5PnapWyrgm3QFljywTV5mvpSg3h037mw9H4+NLGmaIIQ87V1WZw5j8HJYYOOQoQFG6/px5Wp8xOs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=sZV5K7zD; arc=none smtp.client-ip=74.125.228.145 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="sZV5K7zD" Received: by mail-ej2-f17.google.com with SMTP id a640c23a62f3a-c29d50b7cf9so185419766b.2 for ; Wed, 23 Sep 2026 13:19:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790194758; x=1790799558; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=lWUnL6Dr5OR7XEBSMs9m8RHYhNUCxYmL/3WkiHTjwQE=; b=sZV5K7zD6WLwhp2aC7GFAOGLB2ULZgX+485VMLGElvKM70b1loMuAkWpXdLsRULQ2W mtCy9BRt26fN3kJbWn1qNOzJ9SoydYrl/YmYpYd6VIv+F6nhL9v2QkgVaswwH+MxA9AH 13zkUDRVvFXaOquEZue9DJwdlwmVTmrFEmu7sNplaD6vkqaN8uRJ90xQqo5em9976SuR 0Om/eKiz0qSTwEY1dfFZKiARhm5trw1/laMaGeTSTJJB+NDQqZb+Nsz2gVb/Gs6Zo1s+ VGEixYIfsgQ/hUx9jzT7tqaajxKhr9EwaU/drXj0UUWZQWouICqwrG8x98YtraHvmko+ zOIw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790194758; x=1790799558; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=lWUnL6Dr5OR7XEBSMs9m8RHYhNUCxYmL/3WkiHTjwQE=; b=QQlQpyP8XW5BtdU7BcswtnJXorvmMaTGjW74ENwyEJPd2XYts3mxZ3sLMkkXh2WZWM gwJ83M0A8IYZDFUtqjJARh9adejOY8+PbsAIMbdm8XSQ7AyYdQSDI0cvEWkGARckQNuW emsFFnahA/Oy2/fNNeXbhb4eIApAeNTCqA9mSBgKVkLWQiTLHXVdOrGryAEUF04B+bdR NVrcfjrlYFKhzj7sPxT9XBWG6ODlO0/y4HHw6rTDctUvhkebzbrKFFyJK9rjIfRoZtwY +O6ci0DfECe4jiM9U8gjQl9RGqkSt4y7zv9aiwofskTXI+Ydy135kWYGgVcEAUjHen1b 513g== X-Forwarded-Encrypted: i=1; AKwUvBx7EA/FBO65DhM9vSd/nZ57/W+ilTpw6Iff6cHg+1xniZW/aPcfA1uABLlgVjUbdDJ5UEFGUYUR0VGITAY=@vger.kernel.org X-Gm-Message-State: AFuF++nThHkms0zS92GkifFNDhp90I5M40HX0JAe2/NxGwXfVCq8zyNf NTiZbD+hbE8P5Z8TGiAd8yTZY8fOCocPdewKLtMcC++45ehMiPGfLv0A X-Gm-Gg: AYBFou0zx7rahulAwAsOE+EwWspCfEeT88cniCB87ViQZFP+FNfekowd3eD/mEVVO25 iNVHHYEVh/NsZqyOxA07XVxfv2tIkQ1cgM1f0HGWl6OgCsWOCSwsOFdR4UwwpKfALRyrE7cB6sW awsdqxDUvowxyCm6sR0kwM1DCB4Ia80phfL8o4NmHft2Clmq83i8zEB78CrU2FfOv+Uru65G1Vb Sm3JZ8xpEseyhJ2XBYunlQpCmyAl+/72BsiIBGv85AM9kqSq1CN9aT0H2JHR0VPkKGxxwnIFP6h LHg6sh88FWmfgjxKKKqWkrQmYIb14SbTlhdxzIbJICS+dHfFnhqsszvTO2HE3StxHAO1QqMjvQj PgeaIzRCVnad8DQ9G9UX85eulSGnSpLTKp/rxrswm7vW4uY+nnMm9EAyEmNBEaCN+oTLbbK/gJl r5dAYtRcb27QoxJpEHxke64hkKSp9+GsvuW2eqO7SElMcTjL57q8eFv7irD8/saPnVHRIMHIOBG zHuH1bc9kiZePPOfceJGt+Ivg/0QclZAfWBRbJh X-Received: by 2002:a17:907:1c84:b0:c26:2f09:f2d8 with SMTP id a640c23a62f3a-c2ac2601042mr17491066b.36.1790194758486; Wed, 23 Sep 2026 13:19:18 -0700 (PDT) Received: from buildhost.darklands.se ([2001:9b1:ff:d701:51eb:176f:63d9:53f8]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-c2aae63dc17sm183626966b.33.2026.09.23.13.19.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 23 Sep 2026 13:19:18 -0700 (PDT) From: Magnus Lindholm To: davem@davemloft.net, andreas@gaisler.com Cc: sam@ravnborg.org, sparclinux@vger.kernel.org, linux-kernel@vger.kernel.org, linmag7@gmail.com Subject: [RFC PATCH 1/5] sparc32: detect the compare-and-swap instruction at boot Date: Wed, 23 Sep 2026 22:17:17 +0200 Message-ID: <20260923201830.865553-2-linmag7@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260923201830.865553-1-linmag7@gmail.com> References: <20260923201830.865553-1-linmag7@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Some 32-bit sparc implementations provide the v9 compare-and-swap as an extension, LEON3 does, plain v8 does not. Whether it is present decides how a user word can be made atomic, and the kernel has to make the same choice userspace made: a binary built for such a cpu uses casa inline, one built for v8 cannot and asks the kernel instead. Both follow from the hardware, so deciding on the hardware keeps them in step. Probe by executing one compare-and-swap that must succeed and checking that it did, rather than inferring support from the absence of a trap. A cpu without the instruction raises illegal_instruction, so do_illegal_instruction() now looks for an exception table fixup before dying, the way the data fault path already does; the same entry also covers a faulting address later. casa cannot appear in inline asm: sparc32 is built -Wa,-Av8, the assembler rejects the instruction outright, and sparc gas has no .arch pseudo-op to override that locally. It therefore lives in its own object assembled -Wa,-Aleon, which adds the one instruction without letting the rest of v9 in. This affects the assembler only, not what the compiler emits. The helpers are laid out for the LEON atomic errata rather than detecting them. GRLIB-TN-0011 wants the atomic 16-byte aligned, or an instruction TLB miss can release the bus lock before the store completes; GRLIB-TN-0010 forbids reaching one from a load or a control transfer, which a call with a load in its delay slot does. A nop at the entry plus nop padding to the boundary covers both, for less than runtime detection would cost. The padding is spelled .balignl because a plain .align lets the assembler branch over the gap, and that branch lands on the atomic - exactly the sequence TN-0010 asks us to avoid. The probe runs once, on the boot cpu, so an SMP machine whose cpus disagree about the instruction is not supported. None is known. Signed-off-by: Magnus Lindholm --- arch/sparc/include/asm/cas_32.h | 10 +++++++++ arch/sparc/include/asm/cpu_type.h | 7 +++++++ arch/sparc/kernel/cpu.c | 24 ++++++++++++++++++++++ arch/sparc/kernel/traps_32.c | 16 ++++++++++++++- arch/sparc/lib/Makefile | 5 +++++ arch/sparc/lib/casa_32.S | 34 +++++++++++++++++++++++++++++++ 6 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 arch/sparc/include/asm/cas_32.h create mode 100644 arch/sparc/lib/casa_32.S diff --git a/arch/sparc/include/asm/cas_32.h b/arch/sparc/include/asm/cas_3= 2.h new file mode 100644 index 000000000000..3658ff71fa70 --- /dev/null +++ b/arch/sparc/include/asm/cas_32.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _SPARC_CAS_32_H +#define _SPARC_CAS_32_H + +#include + +/* Returns 0 and stores the value found in *prev, or -EFAULT. */ +int __sparc32_casa(u32 *addr, u32 oldval, u32 newval, u32 *prev); + +#endif /* _SPARC_CAS_32_H */ diff --git a/arch/sparc/include/asm/cpu_type.h b/arch/sparc/include/asm/cpu= _type.h index 2b59799859d1..c54e0abfdb2b 100644 --- a/arch/sparc/include/asm/cpu_type.h +++ b/arch/sparc/include/asm/cpu_type.h @@ -2,6 +2,8 @@ #ifndef __ASM_CPU_TYPE_H #define __ASM_CPU_TYPE_H =20 +#include + /* * Sparc (general) CPU types */ @@ -18,6 +20,11 @@ enum sparc_cpu { #ifdef CONFIG_SPARC32 extern enum sparc_cpu sparc_cpu_model; =20 +/* True where the cpu implements the v9 casa extension (LEON3 does, plain = v8 + * does not). Probed once on the boot cpu. + */ +extern bool sparc32_has_casa; + #define SUN4M_NCPUS 4 /* Architectural limit of su= n4m. */ =20 #else diff --git a/arch/sparc/kernel/cpu.c b/arch/sparc/kernel/cpu.c index 79cd6ccfeac0..e09c688a5fd3 100644 --- a/arch/sparc/kernel/cpu.c +++ b/arch/sparc/kernel/cpu.c @@ -21,6 +21,9 @@ #include #include #include +#ifdef CONFIG_SPARC32 +#include +#endif =20 #include "kernel.h" #include "entry.h" @@ -437,11 +440,32 @@ const struct seq_operations cpuinfo_op =3D { }; =20 #ifdef CONFIG_SPARC32 +bool sparc32_has_casa __ro_after_init; + +/* One compare-and-swap that must succeed: a cpu without casa traps and the + * exception table reports -EFAULT. + */ +static void __init casa_probe(void) +{ + static const u32 oldval =3D 0x600df00d; + static const u32 newval =3D 0x0badcafe; + u32 word =3D oldval; + u32 prev =3D 0; + + if (!__sparc32_casa(&word, oldval, newval, &prev)) + sparc32_has_casa =3D prev =3D=3D oldval && word =3D=3D newval; + + pr_info("sparc32: compare-and-swap instruction %s\n", + sparc32_has_casa ? "present" : "not implemented"); +} + static int __init cpu_type_probe(void) { int psr_impl, psr_vers, fpu_vers; int psr; =20 + casa_probe(); + psr_impl =3D ((get_psr() >> PSR_IMPL_SHIFT) & PSR_IMPL_SHIFTED_MASK); psr_vers =3D ((get_psr() >> PSR_VERS_SHIFT) & PSR_VERS_SHIFTED_MASK); =20 diff --git a/arch/sparc/kernel/traps_32.c b/arch/sparc/kernel/traps_32.c index bb149f6cc34b..85ae2fc143ec 100644 --- a/arch/sparc/kernel/traps_32.c +++ b/arch/sparc/kernel/traps_32.c @@ -20,6 +20,7 @@ #include #include #include +#include =20 #include #include @@ -108,8 +109,21 @@ void do_hw_interrupt(struct pt_regs *regs, unsigned lo= ng type) void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsign= ed long npc, unsigned long psr) { - if(psr & PSR_PS) + if (psr & PSR_PS) { + const struct exception_table_entry *entry; + + /* + * An instruction this cpu does not implement can be probed + * for deliberately, so honour a fixup before dying. + */ + entry =3D search_exception_tables(pc); + if (entry) { + regs->pc =3D entry->fixup; + regs->npc =3D regs->pc + 4; + return; + } die_if_kernel("Kernel illegal instruction", regs); + } #ifdef TRAP_DEBUG printk("Ill instr. at pc=3D%08lx instruction is %08lx\n", regs->pc, *(unsigned long *)regs->pc); diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile index dd10cdd6f062..007d8e510ee8 100644 --- a/arch/sparc/lib/Makefile +++ b/arch/sparc/lib/Makefile @@ -12,6 +12,11 @@ lib-$(CONFIG_SPARC32) +=3D blockops.o lib-y +=3D memscan_$(BITS).o memcmp.o strncmp_$(BITS).o lib-$(CONFIG_SPARC32) +=3D divdi3.o udivdi3.o lib-$(CONFIG_SPARC32) +=3D copy_user.o locks.o +lib-$(CONFIG_SPARC32) +=3D casa_32.o + +# casa is not in v8, which the rest of sparc32 is assembled as. -Aleon ra= ther +# than -Av9: it adds the one instruction without letting anything else v9 = in. +AFLAGS_casa_32.o +=3D -Wa,-Aleon lib-$(CONFIG_SPARC64) +=3D atomic_64.o lib-$(CONFIG_SPARC32) +=3D lshrdi3.o ashldi3.o lib-$(CONFIG_SPARC32) +=3D muldi3.o bitext.o diff --git a/arch/sparc/lib/casa_32.S b/arch/sparc/lib/casa_32.S new file mode 100644 index 000000000000..67df9ea439ce --- /dev/null +++ b/arch/sparc/lib/casa_32.S @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Compare-and-swap for the 32-bit sparc implementations that have it. + */ + +#include +#include + + .text + .align 4 + +/* int __sparc32_casa(u32 *addr, u32 oldval, u32 newval, u32 *prev) + * Returns 0 and *prev, or -EFAULT. ASI 0x0b is supervisor data. + */ +ENTRY(__sparc32_casa) + /* nop + .balignl: LEON errata GRLIB-TN-0010 and TN-0011. */ + nop + .balignl 16, 0x01000000 +1: casa [%o0] 0x0b, %o1, %o2 + st %o2, [%o3] + retl + clr %o0 +ENDPROC(__sparc32_casa) + + .section .fixup,#alloc,#execinstr + .align 4 +2: retl + mov -EFAULT, %o0 + .previous + + .section __ex_table,#alloc + .align 4 + .word 1b, 2b + .previous --=20 2.43.0 From nobody Thu Sep 24 14:25:36 2026 Received: from mail-ej2-f12.google.com (mail-ej2-f12.google.com [74.125.228.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9683757D22A for ; Wed, 23 Sep 2026 20:19:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.228.140 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790194770; cv=none; b=s0GC57u4Jwtr6LQFQXLSai0VyRVOmyShvTyRHzORGcD5HKAGJZh7I1aOB/ivkBro65ulismN812sSSXpQe/tI/SjoO36LoSVc1lYq/GjXYIPOuT1O8LFl051kOuRWApbBWMuUlOSdC09kuB053uDuTSy0dmW6WbveL39PqYOZ8k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790194770; c=relaxed/simple; bh=ZcPIw4eZTdDBlXCbqQEro1ebWfUuQCWYfKDFEL48bSQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=kxJqjkXtpe6ScwAO8/81vB+AoCvXBEYZb9El2XcqNkkmLa1LqetzgTp//TibA/iLD0w3JZIYeBA5wubkV6zCV6gI5/4yT2WbjaLZtv50XikKacSF6hFACAH56972dQMUaK1ANTytNW8E/x2JqF8O5cBs1hTq+NqTRoph15TsibE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=UWz2s6kn; arc=none smtp.client-ip=74.125.228.140 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="UWz2s6kn" Received: by mail-ej2-f12.google.com with SMTP id a640c23a62f3a-c254f55efebso215718266b.1 for ; Wed, 23 Sep 2026 13:19:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790194759; x=1790799559; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=frtoc8QloQCQUfk7NjWI4KUj8MMQjADBvRstAE5cfJw=; b=UWz2s6knK/FiqzFI0Q+UtTuvme6C9omqr1NYZk2QOuVvx4+Q4TIJ5Pm9JBDtFiSbdr nWSe5M9C0mM0x1Md+zf9Cz2VQ3xnknhUOBZX/RSe1lCtXXXsd/SM/rccMbauQF4TsgDj biFMlmCv5RsMtXXcTq49wUzB3GWkH9qZx/prPJR0ayrjavjom5NR4FusfQPSw4siqDWp 5Yr0bXQ9uGEbFlNiuYGr1WP0CjcwGL09CPV151WI6pOvfrJTquNVm/ZeXctBAUDZJz3i Imq6k/ygfRHXrqz44G2XYFbLj5veG1m3kL+GzB2T90QlEFL57H4Bg+o58DhUiSDzRdEq 5I4g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790194759; x=1790799559; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=frtoc8QloQCQUfk7NjWI4KUj8MMQjADBvRstAE5cfJw=; b=EfePb/SAMxRbjSXCoeLmyv6xshAcSr/rfusoAbxttbGONk6oqRNXvRN6lXAroIkpOX OrNfzvA87lAIvVB1xPaLZSmz8jFneUpmFRaD1Nrv7coNi6cNbhVw9v9Ohq5Lf6Li4vZs QtPfKXdSNrRrDZDH6NYJwoMsDH6rl5hWPdU6FvIAmTEMkRjjeKng9GS0uxPGy9cDPAcZ X06v5sp6ZwTUGtdyRovNkTG/xlMZDQ9GEnlmtG/AzkNuEGszCI0XspSWR9kwpCn6Qlx0 dbR0BXSDgWpk56CQnnY3MdOU8YycrScuytT+UuF3TYrJ+ifWfO9NPK5O/TWcjqEUpuA8 BWRg== X-Forwarded-Encrypted: i=1; AKwUvBxaRt08ViidBp7qt04gzLdy4d13epQ3+W9RYiMlncJBzbyUIwfZl1i20ox9NP04Nn9lMXGnORQvDmQsWLQ=@vger.kernel.org X-Gm-Message-State: AFuF++md+XdZh84Up07UHWcj8TC0JAk1swJszGDUAbpowgLiG6MCIPHZ jGaoi6TbfCfMQKjohnEaRk5j6k8zcDQweVvSBwXasSLLlKaJEN7tJjkY X-Gm-Gg: AYBFou1cBYuCEg3GzyZJBvECtsGRve2tOJw2Wdcfr83LMmkj+t3f8z4Qo+JHURnd7Sg F9zItBJN9E1WegU24j12eLuvKvwg+rTQxhV5VVwnfO9lyoVRdEu9xFtO6+XOY5ets+Mp5aRUWPp +uYlT59oqjrFgVYvMUTdWHjOZtRdGWfjAdX8pAMu2t0Ejnar8s3GdcirSDAZIpp/cOocouM2B/v PtRtCg7e+mwZ8E9crWSADKJHLtjwnv36JyG+C7ZzJfx2rgpPTXdvm5UuxxTnSMtIg+SJAMoNtwA Bw5XZVrCefkeGBwv8LsvV2u5JjB54ptUROthMijbqzeK0xDG7rd5dexLC6VG0EcIS9kpXI3JG/H AH+BtN6Pygtl2Xg5Yp9rU98dkuZsZLavwf8SkiFCHJXJ2xtYMJjgVHLm3BIX289mdW3kRS2dTXh M4W2+3m8RpXpsm9WuO5NDqYdQxa8J+BnTnuXD0l3CayxBPhdRxdmonTMVbJDR+fPeODrQ3pkFBb lhjfPq3sm9rXNVJ6pY6XYp8dxmWzqs4XErfjvBGcd59pwHXc9g= X-Received: by 2002:a17:907:9811:b0:c2a:46a2:5b57 with SMTP id a640c23a62f3a-c2ac2375464mr19975466b.10.1790194759459; Wed, 23 Sep 2026 13:19:19 -0700 (PDT) Received: from buildhost.darklands.se ([2001:9b1:ff:d701:51eb:176f:63d9:53f8]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-c2aae63dc17sm183626966b.33.2026.09.23.13.19.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 23 Sep 2026 13:19:19 -0700 (PDT) From: Magnus Lindholm To: davem@davemloft.net, andreas@gaisler.com Cc: sam@ravnborg.org, sparclinux@vger.kernel.org, linux-kernel@vger.kernel.org, linmag7@gmail.com Subject: [RFC PATCH 2/5] sparc32: add a kernel assisted compare-and-swap Date: Wed, 23 Sep 2026 22:17:18 +0200 Message-ID: <20260923201830.865553-3-linmag7@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260923201830.865553-1-linmag7@gmail.com> References: <20260923201830.865553-1-linmag7@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Pre-v9 sparc has no compare-and-swap instruction, so userspace can only emulate one with a lock, and neither place to put that lock works. A lock private to a process cannot serialise against another process operating on the same page. A lock kept inside the object, what glibc did before 2019, ldstub on the top byte of the word, is correct across processes but costs value bits, so it cannot implement the full-width operations a current compiler emits calls to. A lock owned by the kernel has neither problem. parisc solves the same problem the same way with its LWS compare-and-swap. Add trap type 0x91 for this. Dispatch follows the existing do_hw_divzero pattern of reaching C rather than doing the work in trap assembly. The ABI is %o0 word aligned user address %o1 expected value %o2 new value returning the value found at the address in %o0, the previously observed value, as __sync_val_compare_and_swap does, with the carry bit set and an errno in %o0 on failure. The number is SP_TRAP_CAS in asm/traps.h, where the other software trap numbers already live, since this one is userspace ABI from now on. The instruction userspace executes is ta 0x11, not ta 0x91: sparc forms the trap type by adding 0x80 to the software trap number, which is also why the Linux system call is SP_TRAP_LINUX 0x90 and glibc issues ta 0x10. David Miller prototyped the same idea in 2016 on software trap 0x23, discovered through the get-kernel-features call and implemented first on sparc64 [2]. This is a different ABI rather than that one finished: 0x11 follows the Linux syscall trap immediately, discovery is AT_HWCAP, and sparc64 compat mode is not supported. Where the cpu implements the instruction the lock is not used at all and the swap is performed directly, with the user data ASI so that the kernel reaches the word the same way a binary built for that cpu does. Choosing on the hardware rather than on a build option is what keeps the two in step: such a binary uses casa inline and never takes this trap, so a kernel serialising on a lock would exclude nothing against it. Otherwise the lock array is used. It is hashed on address bits that lie inside the page offset, so the same physical word reached through different virtual addresses selects the same lock. asm/futex_32.h uses the same array, so a compare-and-swap from userspace and one performed by the futex code exclude each other. Page faults are disabled while the lock is held, since faulting there would take the mmap lock with interrupts off; on failure the lock is dropped, the page is faulted in with fault_in_safe_writeable(), not fault_in_writeable(), which may modify the target memory while probing it and the operation is retried. One consequence constrains the caller rather than the kernel: where the lock is used an ordinary store does not take it, so userspace must build every atomic write from this service, or those writes are not atomic against it. Andreas Larsson made the same point about kernel-emulated casa in 2016 [1]. Documentation/arch/sparc/cas-trap.rst states that, and the width and compiler-integration limits, as part of the ABI. Link: https://inbox.sourceware.org/libc-alpha/5810C1A3.9030504@gaisler.com/= [1] Link: https://inbox.sourceware.org/libc-alpha/20161107.113825.6311660231868= 79199.davem@davemloft.net/ [2] Signed-off-by: Magnus Lindholm --- arch/sparc/include/asm/cas_32.h | 23 +++++++ arch/sparc/include/uapi/asm/traps.h | 3 +- arch/sparc/kernel/Makefile | 1 + arch/sparc/kernel/cas_32.c | 96 +++++++++++++++++++++++++++++ arch/sparc/kernel/entry.S | 17 +++++ arch/sparc/kernel/ttable_32.S | 9 +-- arch/sparc/lib/casa_32.S | 12 ++++ 7 files changed, 156 insertions(+), 5 deletions(-) create mode 100644 arch/sparc/kernel/cas_32.c diff --git a/arch/sparc/include/asm/cas_32.h b/arch/sparc/include/asm/cas_3= 2.h index 3658ff71fa70..400be2b9f628 100644 --- a/arch/sparc/include/asm/cas_32.h +++ b/arch/sparc/include/asm/cas_32.h @@ -2,9 +2,32 @@ #ifndef _SPARC_CAS_32_H #define _SPARC_CAS_32_H =20 +#include #include =20 +struct pt_regs; + +asmlinkage void handle_sparc32_cas(struct pt_regs *regs, unsigned long pc, + unsigned long npc, unsigned long psr); + /* Returns 0 and stores the value found in *prev, or -EFAULT. */ int __sparc32_casa(u32 *addr, u32 oldval, u32 newval, u32 *prev); =20 +/* The same on a user address, using the user data ASI. */ +int __sparc32_casa_user(u32 __user *addr, u32 oldval, u32 newval, u32 *pre= v); + +#define SPARC32_ATOMIC_LOCKS 256 + +extern raw_spinlock_t sparc32_atomic_locks[SPARC32_ATOMIC_LOCKS]; + +/* Hash on page-offset bits only, so one physical word maps to one lock + * through any virtual address. asm/futex_32.h must hash identically. + */ +static inline raw_spinlock_t *sparc32_atomic_lock(const void __user *uaddr) +{ + unsigned long ua =3D (unsigned long)uaddr; + + return &sparc32_atomic_locks[(ua >> 2) & (SPARC32_ATOMIC_LOCKS - 1)]; +} + #endif /* _SPARC_CAS_32_H */ diff --git a/arch/sparc/include/uapi/asm/traps.h b/arch/sparc/include/uapi/= asm/traps.h index 43fe5b8fe8be..3e4d1c0c5a94 100644 --- a/arch/sparc/include/uapi/asm/traps.h +++ b/arch/sparc/include/uapi/asm/traps.h @@ -81,6 +81,7 @@ #define SP_TRAP_SOLARIS 0x88 /* Solaris System Call */ #define SP_TRAP_NETBSD 0x89 /* NetBSD System Call */ #define SP_TRAP_LINUX 0x90 /* Linux System Call */ +#define SP_TRAP_CAS 0x91 /* Compare and swap, issued as "ta 0x= 11" */ =20 /* Names used for compatibility with SunOS */ #define ST_SYSCALL 0x00 @@ -104,7 +105,7 @@ (level > SP_TRAP_BADFL && level < SP_TRAP_CPEXP) || \ (level > SP_TRAP_DMM && level < SP_TRAP_IMM) || \ (level > SP_TRAP_IMM && level < SP_TRAP_SUNOS) || \ - (level > SP_TRAP_LINUX && level < SP_TRAP_KBPT1)) + (level > SP_TRAP_CAS && level < SP_TRAP_KBPT1)) =20 /* Is this a Hardware trap? */ #define HW_TRAP_P(level) ((level > 0) && (level < SP_TRAP_SUNOS)) diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 497b5714fa8f..7ae9ab4082ca 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -18,6 +18,7 @@ CFLAGS_REMOVE_pcr.o :=3D -pg endif =20 obj-y :=3D head_$(BITS).o +obj-$(CONFIG_SPARC32) +=3D cas_32.o obj-$(CONFIG_SPARC64) +=3D urtt_fill.o obj-$(CONFIG_SPARC32) +=3D entry.o wof.o wuf.o obj-$(CONFIG_SPARC32) +=3D etrap_32.o diff --git a/arch/sparc/kernel/cas_32.c b/arch/sparc/kernel/cas_32.c new file mode 100644 index 000000000000..de9822dc80b9 --- /dev/null +++ b/arch/sparc/kernel/cas_32.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Kernel assisted compare-and-swap for pre-v9 sparc. + */ + +#include +#include +#include +#include + +#include +#include +#include + +raw_spinlock_t sparc32_atomic_locks[SPARC32_ATOMIC_LOCKS] =3D { + [0 ... (SPARC32_ATOMIC_LOCKS - 1)] =3D + __RAW_SPIN_LOCK_UNLOCKED(sparc32_atomic_locks) +}; + +/* Report errors in the carry bit as the syscall path does, then step over + * the trapping instruction. + */ +static void cas_return(struct pt_regs *regs, unsigned long value, bool err= or) +{ + regs->u_regs[UREG_I0] =3D value; + if (error) + regs->psr |=3D PSR_C; + else + regs->psr &=3D ~PSR_C; + + regs->pc =3D regs->npc; + regs->npc =3D regs->npc + 4; +} + +/* Trap type SP_TRAP_CAS; the ABI is in + * Documentation/arch/sparc/cas-trap.rst. + */ +asmlinkage void handle_sparc32_cas(struct pt_regs *regs, unsigned long pc, + unsigned long npc, unsigned long psr) +{ + u32 __user *uaddr =3D (u32 __user *)regs->u_regs[UREG_I0]; + u32 oldval =3D regs->u_regs[UREG_I1]; + u32 newval =3D regs->u_regs[UREG_I2]; + raw_spinlock_t *lock; + unsigned long flags; + u32 val; + int err; + + if (unlikely((unsigned long)uaddr & 3)) { + cas_return(regs, EINVAL, true); + return; + } + + if (unlikely(!access_ok(uaddr, sizeof(u32)))) { + cas_return(regs, EFAULT, true); + return; + } + + if (sparc32_has_casa) { + /* No lock needed: casa is atomic against userspace's own. */ + if (likely(!__sparc32_casa_user(uaddr, oldval, newval, &val))) + cas_return(regs, val, false); + else + cas_return(regs, EFAULT, true); + return; + } + + lock =3D sparc32_atomic_lock(uaddr); + +retry: + /* A fault must not take the mmap lock under a raw spinlock, so make + * it -EFAULT here and fault the page in after dropping the lock. + */ + raw_spin_lock_irqsave(lock, flags); + pagefault_disable(); + + err =3D __get_user(val, uaddr); + if (!err && val =3D=3D oldval) + err =3D __put_user(newval, uaddr); + + pagefault_enable(); + raw_spin_unlock_irqrestore(lock, flags); + + if (likely(!err)) { + cas_return(regs, val, false); + return; + } + + /* fault_in_writeable() may modify the target memory. */ + if (fault_in_safe_writeable((char __user *)uaddr, sizeof(u32))) { + cas_return(regs, EFAULT, true); + return; + } + + goto retry; +} diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index ea51ef52c952..cad48f0a0835 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S @@ -644,6 +644,23 @@ do_cp_exception: =20 RESTORE_ALL =20 + /* This routine handles the compare-and-swap trap, type 0x91. */ + .align 4 + .globl do_sparc32_cas +do_sparc32_cas: + SAVE_ALL + + wr %l0, PSR_ET, %psr ! re-enable traps + WRITE_PAUSE + + add %sp, STACKFRAME_SZ, %o0 + mov %l1, %o1 + mov %l2, %o2 + call handle_sparc32_cas + mov %l0, %o3 + + RESTORE_ALL + /* This routine handles Hardware Divide By Zero Exceptions. */ .align 4 .globl do_hw_divzero diff --git a/arch/sparc/kernel/ttable_32.S b/arch/sparc/kernel/ttable_32.S index e79fd786fbbb..0408f0dbae68 100644 --- a/arch/sparc/kernel/ttable_32.S +++ b/arch/sparc/kernel/ttable_32.S @@ -89,7 +89,8 @@ t_bad89:BAD_TRAP(0x89) /* Net-B.S. S= ystem Call */ t_bad8a:BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c) BAD_TRAP(0x8d) BAD_TR= AP(0x8e) t_bad8f:BAD_TRAP(0x8f) t_linux:LINUX_SYSCALL_TRAP /* Linux System Call = */ -t_bad91:BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94) BAD_TR= AP(0x95) +t_cas: TRAP_ENTRY(0x91, do_sparc32_cas) /* Compare and swap */ +t_bad92:BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94) BAD_TRAP(0x95) t_bad96:BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99) BAD_TR= AP(0x9a) t_bad9b:BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) BAD_TR= AP(0x9f) t_getcc:GETCC_TRAP /* Get Condition Codes = */ @@ -186,7 +187,7 @@ trapbase_cpu1: BAD_TRAP(0x87) BAD_TRAP(0x88) BAD_TRAP(0x89) BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c) BAD_TRAP(0x8d) BAD_TRAP(0x8e) BAD_TRAP(0x8f) - LINUX_SYSCALL_TRAP BAD_TRAP(0x91) + LINUX_SYSCALL_TRAP TRAP_ENTRY(0x91, do_sparc32_cas) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94) BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99) BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) @@ -286,7 +287,7 @@ trapbase_cpu2: BAD_TRAP(0x86) BAD_TRAP(0x87) BAD_TRAP(0x88) BAD_TRAP(0x89) BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c) BAD_TRAP(0x8d) BAD_TRAP(0x8e) BAD_TRAP(0x8f) - LINUX_SYSCALL_TRAP BAD_TRAP(0x91) + LINUX_SYSCALL_TRAP TRAP_ENTRY(0x91, do_sparc32_cas) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94) BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99) BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) @@ -385,7 +386,7 @@ trapbase_cpu3: BAD_TRAP(0x89) BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c) BAD_TRAP(0x8d) BAD_TRAP(0x8e) BAD_TRAP(0x8f) LINUX_SYSCALL_TRAP - BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94) + TRAP_ENTRY(0x91, do_sparc32_cas) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0= x94) BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99) BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) BAD_TRAP(0x9f) diff --git a/arch/sparc/lib/casa_32.S b/arch/sparc/lib/casa_32.S index 67df9ea439ce..c277f1f1f795 100644 --- a/arch/sparc/lib/casa_32.S +++ b/arch/sparc/lib/casa_32.S @@ -22,6 +22,17 @@ ENTRY(__sparc32_casa) clr %o0 ENDPROC(__sparc32_casa) =20 +/* The same on a user address; ASI 0x0a is user data, as userspace uses. */ +ENTRY(__sparc32_casa_user) + /* nop + .balignl: LEON errata GRLIB-TN-0010 and TN-0011. */ + nop + .balignl 16, 0x01000000 +4: casa [%o0] 0x0a, %o1, %o2 + st %o2, [%o3] + retl + clr %o0 +ENDPROC(__sparc32_casa_user) + .section .fixup,#alloc,#execinstr .align 4 2: retl @@ -31,4 +42,5 @@ ENDPROC(__sparc32_casa) .section __ex_table,#alloc .align 4 .word 1b, 2b + .word 4b, 2b .previous --=20 2.43.0 From nobody Thu Sep 24 14:25:36 2026 Received: from mail-ej2-f12.google.com (mail-ej2-f12.google.com [74.125.228.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 239A857ED8A for ; Wed, 23 Sep 2026 20:19:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.228.140 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790194769; cv=none; b=a0IlGn87gSp1z1wYxpwgwiU4qTKFUqJiJu44NIDpQNemliMZcou3AYYQMsucpjs/YV8jjMMC3BJu3eryu33ghWtclaVom1OHuNQ2m0V1oDaApDxZk8mxVPBNRXEsj1mQWguJqF1w1eiB3TeOT/WZ3y1lELDrbJB5sGlDHn3we7M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790194769; c=relaxed/simple; bh=U5kUJj8tfW2V7b3/nuO6sQr9QzMENF2JMUJE8N1DAT8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=VgDXv6ITSqBrzGrldoxKDbEzb4oH1KffeaFDSyhkF3V3JG6mmWwpqIAEZP8LKYsj77HftFBYejKAqMgbGboMvhiNI8bgp2ixFSOf1LNQQnAiUK6kYfbWda2bL+oDHk58TAcVWgJLcSPGdYccMH46WV5VhcEYmAK3zmJBrt4txIs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=C8kuizLQ; arc=none smtp.client-ip=74.125.228.140 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="C8kuizLQ" Received: by mail-ej2-f12.google.com with SMTP id a640c23a62f3a-c2940ef15d3so183424666b.2 for ; Wed, 23 Sep 2026 13:19:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790194760; x=1790799560; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=aBkTioHa1njfgepZWcJOCl/N0/x0qKl0Yu1MlhUgAqw=; b=C8kuizLQC8LCFKyWH7dW5kw8KLBQb5SSI0MEX8MNeeytGa8CpsoaPVJ+MSNFnBDfUV CPRjiyhiK1OzZr3W0aTd/ZXtalDeCVtyR/T3M0pywi6QEJvPWsV4GVh+aYmXP1CZ2XDM 5ErssEnjlRN77I8EZCrLs9ZfMDLwTjSr3U7XZyAYlg592cvQ5U4hdklEqvywbsOOFMF6 BjPHllK2+M5kA7A4SGcr9AvLH50F/e86W11Wf0yQxZ/ZCQGqNZvWUClaZ/Y+Vu3YKkOY jpw6kcITjuo2RkGkQRzYdRniePG2Hvi7errGaD4t2/Z2UYHcmsTEd+QY+77VcHFlW/I2 V4cQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790194760; x=1790799560; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=aBkTioHa1njfgepZWcJOCl/N0/x0qKl0Yu1MlhUgAqw=; b=1//nXWEl5h+6SQ6KTZaRquHK5fgPPfLvbmK5HlpR2Lh/IVnk5AIebLSHd7Wg1m7IG+ WLN+20Zw7yF7NcA19ZcF+LMqX6lEPe8+c3I8QViI/s6QEw7oi6UG0WeiVR0EL4zCHu6x P8bBmJpept7W/Xxyf+QN4Pu4HPyuDnln1i2uS0S9bue1zHCVWIXmdQjQu6a3NHGRT56/ Ck5bnpCa+pzMScYhd3kqWA5555hkIUPXTjKbjtXOWxZ/6uI/pfmJyR5+8umvlpUh8LkK UuKDtggfzYPv02/sBvq2ev7fpbS60iGiDFMOHxfEbObLlLneNXq6UeRcH70XfU8fxoHm 5b5Q== X-Forwarded-Encrypted: i=1; AKwUvBxeeaV6BtEYwgVopxvB3RnN6gAb3s2wyKkEsiyIF9H44KKRa0ztpzU/f3DDeybwMQ6w7a92SOi3y6fnKzE=@vger.kernel.org X-Gm-Message-State: AFuF++kLOAqpSERhLvkBbrGS45zI5xH2tcJzZP/+NOnDk839wlNakaKQ OgwWuWUCLbPC+boeIE5PooaYo6UEFjYcFLF1VPL0jYqnnDksnra+S34F1ouXKw5p X-Gm-Gg: AYBFou3U0JffYKFX3F77/kXTv++YSC5mmmgjqnLICFtJu7OySFeHUDw+OTvW7+W6rBK 8pbSxdNDzy+LnzL4mSS0c7+gcUZhVtK7ybYgBuz4xIMn+8BA6uFACNbpa5eOmU+4qfaEx/V1y1S nlYeV96KAjjs9V0Csz5NefNekAwt2zLVn9Gf/AojuWfj9WkzZWlpnJ76Yd5Oy4TSPcy+ySw9l2S rF29k9JzjLJH7OTNBbGmcY4A0xEwbY+54ZOtZljOd1C120Pnpt1uqzFdb1NM3uYEXvyTZZiVAgP dMQ2jaRUmghtsxDv2HWXHJ6puWn6/5cmIv+IQu9uer94yZ2N/ZRA1O1om9lQ07ASzDBWRjaTrka SeGX4NUNrktrUdtsBJ531lfmR2dMeSXl6LeCDncprhfmSRNoUQMF/NghQRohBxYvaI4X94gPdmF gjShfeb8v7sc3xI2UhlSKFETLMxZk2wtsOHYWj14Is2OntwxmwKSqIaFq/KqwM8h4X4QdQLf+cH 7B5iY8Q4bGuOgn6ll2nMO/ZTPHnmjOCpZ80StL6 X-Received: by 2002:a17:907:c48a:b0:c29:f5d5:5a9a with SMTP id a640c23a62f3a-c2ac241cb87mr18810766b.36.1790194760417; Wed, 23 Sep 2026 13:19:20 -0700 (PDT) Received: from buildhost.darklands.se ([2001:9b1:ff:d701:51eb:176f:63d9:53f8]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-c2aae63dc17sm183626966b.33.2026.09.23.13.19.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 23 Sep 2026 13:19:20 -0700 (PDT) From: Magnus Lindholm To: davem@davemloft.net, andreas@gaisler.com Cc: sam@ravnborg.org, sparclinux@vger.kernel.org, linux-kernel@vger.kernel.org, linmag7@gmail.com Subject: [RFC PATCH 3/5] sparc32: implement futex atomic ops with the compare-and-swap locks Date: Wed, 23 Sep 2026 22:17:19 +0200 Message-ID: <20260923201830.865553-4-linmag7@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260923201830.865553-1-linmag7@gmail.com> References: <20260923201830.865553-1-linmag7@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" sparc32 had no futex implementation of its own and fell back to the asm-generic one, which on SMP cannot work: it needs to update a user word atomically, and pre-v9 sparc has no instruction for that. CONFIG_FUTEX was therefore made to depend on !(SPARC32 && SMP). Now that the kernel owns a compare-and-swap on behalf of userspace, the futex code can use the same mechanism. Where the cpu lacks the instruction both sides serialise on the lock array used by the trap type 0x91 handler; both callers go through sparc32_atomic_lock(), so the two hashes cannot drift apart, parisc keeps the same invariant with a comment asking that its futex hash match its LWS code. Where the cpu has the instruction that lock cannot serve for the read-modify-write. A binary built for such a cpu does its own casa and knows nothing about the array, so a lock, get_user, put_user, unlock sequence can lose that binary's update between the two accesses while both operations appear to have succeeded and FUTEX_WAKE_OP defines its update of uaddr2 as atomic. arch_futex_atomic_op_inuser() therefore retries a casa until the word is still the one the new value was computed from, the way sparc64 does it. Only the pre-v9 path takes the lock, where it is correct because userspace takes the same lock through the trap. Both entry points are called with page faults already disabled, so the user accesses fail rather than sleeping under the lock. With a real cmpxchg available the Kconfig dependency can go, which is what lets FUTEX_PI and robust futexes be built for this configuration rather than refused. Their runtime behaviour here has not been tested. One gap is known and not closed here. futex_robust_unlock() clears the futex word with unsafe_atomic_store_release_user(), before the hash bucket is locked and without going through either helper added here. SPARC32 currently uses the generic implementation of unsafe_atomic_store_release_user(), which ultimately performs a plain user-memory store. On a no-CASA SMP system that store does not acquire the lock used by the SPARC32 software-CAS implementation. It can therefore occur between the trap handler's load and conditional store, allowing the CAS to overwrite the unlock: cpu 0, trap compare-and-swap cpu 1, robust unlock take sparc32_atomic_lock(uaddr) read *uaddr -> T store 0 -> *uaddr, no lock compare against T succeeds store T | FUTEX_WAITERS -> *uaddr release the lock, report success Neither order of those two operations permits that result, so the missing serialisation is what produced it. The flag itself is not gated CONFIG_FUTEX_ROBUST_UNLOCK covers only the rseq fixup path, so dropping the Kconfig dependency is what exposes this on SPARC32 SMP. It has not been observed in practice; it is reported because it follows from the implementation. The requirement is only that these two operations agree on how they serialise access to the word. The macro is overridable, so SPARC32 could supply its own definition and keep this inside the architecture; whether that is preferable to a futex-specific interface is a question for the futex maintainers, and is asked rather than guessed at. Signed-off-by: Magnus Lindholm --- arch/sparc/include/asm/futex_32.h | 137 +++++++++++++++++++++++++++++- init/Kconfig | 1 - 2 files changed, 135 insertions(+), 3 deletions(-) diff --git a/arch/sparc/include/asm/futex_32.h b/arch/sparc/include/asm/fut= ex_32.h index 6a332a9f099c..35ff08a6b2bd 100644 --- a/arch/sparc/include/asm/futex_32.h +++ b/arch/sparc/include/asm/futex_32.h @@ -1,6 +1,139 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _ASM_FUTEX_H #define _ASM_FUTEX_H =20 -#include +#include +#include +#include +#include +#include =20 -#endif +/* These share the compare-and-swap trap's lock array and must hash + * identically to it; see asm/cas_32.h. + */ + +static inline int sparc32_futex_op(int op, int oparg, u32 oldval, u32 *new= val) +{ + switch (op) { + case FUTEX_OP_SET: + *newval =3D oparg; + break; + case FUTEX_OP_ADD: + *newval =3D oldval + oparg; + break; + case FUTEX_OP_OR: + *newval =3D oldval | oparg; + break; + case FUTEX_OP_ANDN: + *newval =3D oldval & ~oparg; + break; + case FUTEX_OP_XOR: + *newval =3D oldval ^ oparg; + break; + default: + return -ENOSYS; + } + + return 0; +} + +static inline int +arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uadd= r) +{ + raw_spinlock_t *lock; + unsigned long flags; + u32 oldval, newval, prev; + int ret =3D 0; + + if (sparc32_has_casa) { + if (!access_ok(uaddr, sizeof(u32))) + return -EFAULT; + + if (unlikely(get_user(oldval, uaddr) !=3D 0)) + return -EFAULT; + + /* Retry until the word still holds what newval was computed + * from, making the read-modify-write one atomic step. + */ + for (;;) { + ret =3D sparc32_futex_op(op, oparg, oldval, &newval); + if (ret) + return ret; + + if (unlikely(__sparc32_casa_user(uaddr, oldval, + newval, &prev) !=3D 0)) + return -EFAULT; + + if (likely(prev =3D=3D oldval)) + break; + + oldval =3D prev; + } + + *oval =3D oldval; + return 0; + } + + lock =3D sparc32_atomic_lock(uaddr); + raw_spin_lock_irqsave(lock, flags); + + if (unlikely(get_user(oldval, uaddr) !=3D 0)) { + ret =3D -EFAULT; + goto out; + } + + ret =3D sparc32_futex_op(op, oparg, oldval, &newval); + if (ret) + goto out; + + if (unlikely(put_user(newval, uaddr) !=3D 0)) + ret =3D -EFAULT; + +out: + raw_spin_unlock_irqrestore(lock, flags); + + if (!ret) + *oval =3D oldval; + + return ret; +} + +static inline int +futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, + u32 oldval, u32 newval) +{ + raw_spinlock_t *lock; + unsigned long flags; + u32 val; + + if (!access_ok(uaddr, sizeof(u32))) + return -EFAULT; + + /* casa is atomic against userspace's own; a lock of ours is not. */ + if (sparc32_has_casa) { + if (__sparc32_casa_user(uaddr, oldval, newval, &val)) + return -EFAULT; + *uval =3D val; + return 0; + } + + lock =3D sparc32_atomic_lock(uaddr); + raw_spin_lock_irqsave(lock, flags); + + if (unlikely(get_user(val, uaddr) !=3D 0)) { + raw_spin_unlock_irqrestore(lock, flags); + return -EFAULT; + } + + if (val =3D=3D oldval && unlikely(put_user(newval, uaddr) !=3D 0)) { + raw_spin_unlock_irqrestore(lock, flags); + return -EFAULT; + } + + raw_spin_unlock_irqrestore(lock, flags); + + *uval =3D val; + return 0; +} + +#endif /* _ASM_FUTEX_H */ diff --git a/init/Kconfig b/init/Kconfig index 8583d9f06c52..9eb8086af7db 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1875,7 +1875,6 @@ config BASE_SMALL =20 config FUTEX bool "Enable futex support" if EXPERT - depends on !(SPARC32 && SMP) default y imply RT_MUTEXES help --=20 2.43.0 From nobody Thu Sep 24 14:25:36 2026 Received: from mail-ej2-f20.google.com (mail-ej2-f20.google.com [74.125.228.148]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CA8193F7AA8 for ; Wed, 23 Sep 2026 20:19:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.228.148 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790194768; cv=none; b=OmU8UXXc7JuxxCvr1TE/u1ON0V5F4IJp1VIEACKv4lvH/8jWjiQidZk4fBWXdioe7HN5GH6BYstS03jBtyqEqCiHdmki+RIA6xqiL0rzfxO4+CBr3wH4JhguBtYMNOS3bR6iUpDbPT8CXwLG8XRTwVkwOJb73lk35uC4PHArw44= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790194768; c=relaxed/simple; bh=LQwGWaSUCyV6P2RE8COWcXuJNQ6L+hNmHeoyYuwXRxA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=XxdcAbKSGta/hscCmF9sgi71r88mlpg5Ee7VE6T0kPJmAtT3ryj/7X1P9F/TlxmoAffVqtAopBmYF1UpJXVDfL2psMKIbsrzGYXY9ZXx64GzADYXG22DpxRXyF4XaUINAqgk2jLEDyBMctZ3brbAxZybZHO4EGl46xkvPlarhDI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=qIAa72YK; arc=none smtp.client-ip=74.125.228.148 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="qIAa72YK" Received: by mail-ej2-f20.google.com with SMTP id a640c23a62f3a-c293c683202so209018066b.3 for ; Wed, 23 Sep 2026 13:19:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790194761; x=1790799561; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=c8bT5gThy+ia4/Qr5Ql/txaiXmBbXP80XdJ68NHOdVU=; b=qIAa72YKTydPYGawugTA05UZG85wlFhqwmD1k30BBGUCe00y5ykonlX+2mX+hhaFbN hu4F/14GfwVgG55FkUzzkXeYdMXlDOy6+GVyxZwEpmFB4QxoBPdjMp7V/oZG15iAj7Oi FRgQlmy4bnrAMXibXwozYzBMxvgDYAIXUG6fEfs2ZxYZUKzhTSJE+VQG32fDcg7eQBMT c/ZMw7lB+tx06YbIFwG2suxfu+BAStBQ0/yb4jOKPmADOS/mpTRw/RpTkR6O5hmrHjvi 7b6PHUoqDVkDNd4Mxtsmy+qAoR0fP2WXwhTpWs+2Qlg2zsC13DauilZrr1KDVQDZt4iV e4gw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790194761; x=1790799561; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=c8bT5gThy+ia4/Qr5Ql/txaiXmBbXP80XdJ68NHOdVU=; b=JN9rfhbSYi+IdUdS2RUc82H4rFcYRVIiVSk1vVXe/OI7u2/ZC+eIF3anMV/Vreck+l 55DUByFISyBXJdguIeQ4rEDQX72YchnCcfrVj4opcq2dLCNjaLT5kw1rBI7cMZ4q/aKo 86aaiVprRS0EmALMh+1au8ZgPzq26h2x9m+psDUqqcA4K00EhzVeaKMzOuQRbkdJezld ErSLcgSH5NwAE6xFDovpfC4JzEw4fv0QWjyttU1/YNiWrj7vAPXPLlAlWMX4YNxbWoW2 bJcPUVlKaMtGlZUc3dbX7tXcacbCrahvwYfl4gojkbCUVUnIOomtSO6yYnSSvs8RdsTM 3YAg== X-Forwarded-Encrypted: i=1; AKwUvBy1FgmeIdXP7q0dqyFMyZkeOd/SxKdrhIoVVrCxaKt51HqJf/aEtwP5d8f9ErPyLMqmWXg/YflQ3rSQBLU=@vger.kernel.org X-Gm-Message-State: AFuF++lDuvRIH3LqwJf5g5SYxUDdRju5tpPnB9qUxO1tIuRjEFX6EPwZ L2XYPvrj8LXdA9VAeM2/140qPma2VNNlsblurIbUr7hnuiln/GfcBCzd X-Gm-Gg: AYBFou2d/dA+fSPmTHA3fIrS4F/PwJz7JmCuUuXsNDt2NrnRAVxZdEo7+LwrN+1umKQ LZs0oZyjgWbLsAPqF1rCfurdr+nisbHiUGhf12TFDCFb6OQ7vYo769nUkjSCUv0ybm8RDWWXkdw 1FDwZGhbGH5qtVmAVrBGrADZDZ2qmKDRCfOZ32bns2W3XudIs+cnrzwkAKopM5/uGS0vBvYfZna 7Vf0NNkYr6FHoGn6G5Rn8UeX4uGTNKrhD1j3VwepmrXa4KQifp2Bq/l9PibB6orJkekzr6L/zFT CN78as3aMdcUZkTNMUzjEDmPbYBLaumPuAi9m+MtPCuCIeXoroqGmLJ32YNXsiyy7jdBFrrikZ5 mU/HGERC5cPxa4NMnaBqrNfXfbmMI1FET53OZ8scodr0/4dzUxlDV5yjKLILy0x3xrxfXq1ZN/c +dAp5TwOaNGRpd5ngkHLQW5VtHYT9+Z7JamGlnvg2ckgDQYraRsAHJl2abhADqQN5qHAHrmUrVq ddrehYTEvhuR7f88vVihnKRHjORNSJR9GrRY9xu X-Received: by 2002:a17:907:3d08:b0:c26:2c3d:67aa with SMTP id a640c23a62f3a-c2ac2373eb0mr21656366b.47.1790194761401; Wed, 23 Sep 2026 13:19:21 -0700 (PDT) Received: from buildhost.darklands.se ([2001:9b1:ff:d701:51eb:176f:63d9:53f8]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-c2aae63dc17sm183626966b.33.2026.09.23.13.19.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 23 Sep 2026 13:19:21 -0700 (PDT) From: Magnus Lindholm To: davem@davemloft.net, andreas@gaisler.com Cc: sam@ravnborg.org, sparclinux@vger.kernel.org, linux-kernel@vger.kernel.org, linmag7@gmail.com Subject: [RFC PATCH 4/5] sparc32: advertise the compare-and-swap trap in AT_HWCAP Date: Wed, 23 Sep 2026 22:17:20 +0200 Message-ID: <20260923201830.865553-5-linmag7@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260923201830.865553-1-linmag7@gmail.com> References: <20260923201830.865553-1-linmag7@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" A process that wants the kernel to perform a compare-and-swap has no way to find out whether this kernel will do it, and issuing the trap to find out is not an option: on a kernel without it the trap is a bad trap and the process dies. Guessing is worse than dying. On sparc64 ta 0x11 is not an illegal instruction but the old 64-bit system call trap, so a process that issued it there would make a wild syscall rather than take a signal. Advertise it in AT_HWCAP so the question can be asked first. Bit 0x10000000 is unused on sparc32 and on sparc64, so it reads as clear in exactly the cases where the trap is absent: an older kernel, or sparc64 compat mode, where a 32-bit process reads its hwcap word from elf_64.h. Reserve the same bit there with a comment so it is not handed to something else later and mistaken for this. A caller that finds the bit clear must fall back to whatever it can do by itself or report the operation unsupported. A private lock is not a general answer: it cannot make a word atomic against another process, which is the reason for the trap in the first place. Signed-off-by: Magnus Lindholm --- arch/sparc/include/asm/elf_32.h | 7 ++++++- arch/sparc/include/asm/elf_64.h | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/sparc/include/asm/elf_32.h b/arch/sparc/include/asm/elf_3= 2.h index 37a6016c9ccd..c60d803cf556 100644 --- a/arch/sparc/include/asm/elf_32.h +++ b/arch/sparc/include/asm/elf_32.h @@ -64,6 +64,10 @@ #define HWCAP_SPARC_MULDIV 8 #define HWCAP_SPARC_V9 16 #define HWCAP_SPARC_ULTRA3 32 +/* Kernel compare-and-swap trap available; see + * Documentation/arch/sparc/cas-trap.rst. Do not issue the trap if clear. + */ +#define HWCAP_SPARC_CASTRAP 0x10000000 =20 #define CORE_DUMP_USE_REGSET =20 @@ -121,7 +125,8 @@ typedef struct { =20 /* Most sun4m's have them all. */ #define ELF_HWCAP (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | \ - HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV) + HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV | \ + HWCAP_SPARC_CASTRAP) =20 /* This yields a string that ld.so will use to load implementation specific libraries for optimization. This is more specific in diff --git a/arch/sparc/include/asm/elf_64.h b/arch/sparc/include/asm/elf_6= 4.h index 694ed081cf8d..a2117a81b6d8 100644 --- a/arch/sparc/include/asm/elf_64.h +++ b/arch/sparc/include/asm/elf_64.h @@ -98,6 +98,9 @@ */ #define HWCAP_SPARC_CRYPTO 0x04000000 /* CRYPTO insns available */ #define HWCAP_SPARC_ADI 0x08000000 /* ADI available */ +/* 0x10000000 is HWCAP_SPARC_CASTRAP on sparc32 and must stay clear here; + * a 32-bit process reads this word too and there is no such trap on sparc= 64. + */ =20 #define CORE_DUMP_USE_REGSET =20 --=20 2.43.0 From nobody Thu Sep 24 14:25:36 2026 Received: from mail-ej2-f12.google.com (mail-ej2-f12.google.com [74.125.228.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AB44457EDA9 for ; Wed, 23 Sep 2026 20:19:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.228.140 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790194771; cv=none; b=ZnKIJd1ybSWlQbDyNgxY/AMauWNV7gWL51uP+sGyh3oWWWkS1N5COYiR5Lm1bKTo/vpBZOBHOQ57Ar89lpZ6/cdZFkdg16O11xWn7cwH70Uj1HLkh+KIrKzMWYrdLcR0yHQyZJ6qc68KbNx+sUcj0jZ8Gfe26HtyQXs3klIxRSs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790194771; c=relaxed/simple; bh=AC8oylFdwQ8cFzwdlHbb126te9vtXzziDP7/wP1B/5E=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=NnQIDPzh5C6QcVvbv/Dl4pWsDZaZwZu1wjOVaSy5ShiayszN8YQlUdjqzUbhIHfJudk3s0/PQC/N2jB8pw4XRiJ12S7E0/iVr5OYdH+9+lSleJ7GUG4WlLPoOS9H4I/7waIzRiv3miBOHsZpMAyi5+yDHBWwFOTiBVik/1kSB68= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=GOZM/cQ+; arc=none smtp.client-ip=74.125.228.140 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="GOZM/cQ+" Received: by mail-ej2-f12.google.com with SMTP id a640c23a62f3a-c254f55eff0so202943966b.0 for ; Wed, 23 Sep 2026 13:19:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790194763; x=1790799563; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=TSFltJ3k/9xOW9Dlp3D0ImCoh69p5cGuVhZZbL+BLyM=; b=GOZM/cQ+o7m6jYlRgzO8Aw2YVG3SM9pBEaWRxwuq0Li9EuVL2YVsS2tTFFFp1XFW+v FqNNtBe6pIhFtC/PMIBhKUNKu41wpn8rItDcoEZGH6WvawP+E6GzRVday4TiZKHrbrOh ZaRK2ip8mt4PnAk403cXOx3BDaQ8O2DqddzaDatfv3fVaYulVECGVyNg7gToRfyaFWVF oDBx24VoYI5Q8y7NkSc6poe1gqobw2dSN8FlU7e1izq2S5Xg2bkrHvlt9zR4SJLqrF1K 07acmlfmIzA1syW1ZVhv7xoBP8eM4A17AfHZpqg+iU4q1MW6evgRo7yvR5wGd+jtOWlS jMCQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790194763; x=1790799563; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=TSFltJ3k/9xOW9Dlp3D0ImCoh69p5cGuVhZZbL+BLyM=; b=SEUHSrmdH5Bix+Xrag0nm+s5gCgphRNM/bneIyx5CJPdb75PXjrlwQXQZA5X7ESHUe xw/T43ODEGTbjsaNo7hDBmipF1fNwCpw+ezc2zGydNg7oKMdTAkoIhMTm3kZLPku/AJy 2WQfTtkHT+gxXFFTUpACNPhUP0t55lF0ll7gNB8+vKLx9g32LQrvTAfbDw/UQ9xrO4Jc zQYG6HTMacEJ54adEhKz2WKXEpgSh/9hWk1w2fgnTPrXYoxbyYHI5UhtDYPODw14HxdD 0ymkRzS56eSk2snXxPy4wheznbPEj9dEFLQhVSeFQM1eVnVO/b9A+ODBuvtD6tKcJFl9 cdhw== X-Forwarded-Encrypted: i=1; AKwUvBwjgoyazpp/V5aQ7TWeq5pBkgUc5EJT+xcCjXqVHmIysATn0p8Me+j/ZB0lq+gBLhoNkoDYMuw8gvyZMQU=@vger.kernel.org X-Gm-Message-State: AFuF++mx/7ZpNHrT7xI8vbaS6+IEbz85HtGRItXPScBJS95C7R4rWC5m z082aN3jenWwkGI6mYDdFV3iC+whZovvmva+BaFE8zwJcq0hM5CRKFSD X-Gm-Gg: AYBFou3usjsR/U0h4a74m5rxQ9fgvrWn6Mv/tZjp34+5JVPgt3pBitycm9DJXDvTUjG 0SGaawQStqAFRc9oMswzZNEU5WoP6SiilyMIEWVXY7qWQaPj8ks9U3vLnT/C2WVHxrZOJnCHMji gGtW6IcSuJo9L/7pQcqUENnBkhjpX3SI4/T7DhvkcYUsOrzqbWZm1WRqpZAyQvunGV3vOZExbxX Ayf/eSWlxleUp9wuLMhsOStq3KVESajck/RCJwpNEU4SKAZHnUkky4SqFnWm4LeVeTf3SLEYxpm ou/Ypgzl3RaV0lnty3g+c0qbP5J48NUleI2MNE3bL8mo/EuRoV/BpHLfIEoHs61/BrI4lnPU0x0 FlLgN2cBmCWBFXoSHvrhYkx9vmfE4muOYO40Ag7Ug2l4exy+lO0UNXh3vvoqA/oNyFlag8sVD9s gXKmRGP/Q7+Y/hEWkv7n0ofDMMGBwetULtXgVGhP3Ldid1lR2HCfb1jcy8jsgFEWlv9V8h4QvhR Qdnv6W+D6KzkwdRwwmf5mKnciMzxQmVwLomL3ef X-Received: by 2002:a17:907:c23:b0:c2a:704c:8c75 with SMTP id a640c23a62f3a-c2ac25123f2mr22944766b.39.1790194762351; Wed, 23 Sep 2026 13:19:22 -0700 (PDT) Received: from buildhost.darklands.se ([2001:9b1:ff:d701:51eb:176f:63d9:53f8]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-c2aae63dc17sm183626966b.33.2026.09.23.13.19.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 23 Sep 2026 13:19:22 -0700 (PDT) From: Magnus Lindholm To: davem@davemloft.net, andreas@gaisler.com Cc: sam@ravnborg.org, sparclinux@vger.kernel.org, linux-kernel@vger.kernel.org, linmag7@gmail.com Subject: [RFC PATCH 5/5] sparc32: document the compare-and-swap trap ABI Date: Wed, 23 Sep 2026 22:17:21 +0200 Message-ID: <20260923201830.865553-6-linmag7@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260923201830.865553-1-linmag7@gmail.com> References: <20260923201830.865553-1-linmag7@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The trap is userspace ABI rather than an internal kernel facility, so write down what it promises: the instruction and trap type, the register convention, the failure cases, what the AT_HWCAP bit means, and the limits a caller has to work within. Several of those limits are easy to miss. Replacing the __atomic_* helper symbols does not by itself route every atomic write through the trap, because the compiler can expand some of them inline and covering libc's own uses is a different scope from covering application code built with atomic builtins. The service is one aligned 32-bit word, which is not the same as general byte and halfword atomics. The guarantee is indivisibility of that one word and no ordering beyond it. And futex_robust_unlock() currently writes the futex word without taking the lock the trap uses, so that one kernel path is outside the guarantee. Signed-off-by: Magnus Lindholm --- Documentation/arch/sparc/cas-trap.rst | 163 ++++++++++++++++++++++++++ Documentation/arch/sparc/index.rst | 1 + 2 files changed, 164 insertions(+) create mode 100644 Documentation/arch/sparc/cas-trap.rst diff --git a/Documentation/arch/sparc/cas-trap.rst b/Documentation/arch/spa= rc/cas-trap.rst new file mode 100644 index 000000000000..f09d81e8f1ed --- /dev/null +++ b/Documentation/arch/sparc/cas-trap.rst @@ -0,0 +1,163 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D +The sparc32 compare-and-swap trap +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D + +Pre-v9 sparc has no compare-and-swap instruction. A lock held inside one +process cannot make a word atomic against another process mapping the same +page, and a lock kept inside the word itself costs value bits, so the kern= el +performs the operation instead. parisc provides the same service for the = same +reason. + +Interface +=3D=3D=3D=3D=3D=3D=3D=3D=3D + +``ta 0x11`` - software trap 0x11, trap type 0x91, ``SP_TRAP_CAS`` in +``asm/traps.h`` - asks the kernel to compare and swap one 32-bit word: + +=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +``%o0`` word aligned user address +``%o1`` expected value +``%o2`` new value +=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +On return the carry bit is clear and ``%o0`` holds the value that was foun= d at +the address. The caller compares it against what it expected to learn whe= ther +the swap happened; there is no separate success flag. + +Registers +--------- + +``%o0`` is read and written. ``%o1`` and ``%o2`` are read and are not +modified. Every other windowed and global register is preserved across the +trap. The integer condition codes are written - that is how success and +failure are reported - and must be treated as clobbered. + +An inline-assembly wrapper therefore wants ``%o0`` as an in/out operand, +``%o1`` and ``%o2`` as inputs, and both ``"cc"`` and ``"memory"`` in the +clobber list, the latter so the compiler does not move accesses across the +operation. + +On failure the carry bit is set and ``%o0`` holds an error number: + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D +``EINVAL`` the address is not word aligned +``EFAULT`` the memory access could not be completed +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D + +A successful return does not establish that the mapping is writable. On t= he +software path the kernel writes only when the comparison succeeds, so a +mismatching value on a read-only mapping can be returned without the kernel +ever discovering that the mapping could not be written. The two +implementations are not required to agree about an invalid operand: pass an +aligned word in memory that is both readable and writable. + +The operation is atomic against another process issuing the same trap, aga= inst +the futex operations in ``asm/futex_32.h``, and - on a cpu that implements +``casa`` - against a binary using that instruction directly. + +The service guarantees an indivisible compare-and-swap on the addressed wo= rd +under the participation rules below. It does not provide any additional +acquire, release or full-barrier guarantee for other memory locations. +Userspace must supply whatever ordering the operation it is implementing +requires. + +One kernel path does not participate. ``futex_robust_unlock()`` clears the +futex word through ``unsafe_atomic_store_release_user()``, for which sparc= 32 +uses the generic definition - ultimately a plain user store. On a no-casa= SMP +system that store does not acquire the lock this trap uses, so it can land +between the trap's load and its conditional store, and the compare-and-swap +then overwrites the unlock while still reporting success. + +On no-casa SMP systems the non-PI robust-unlock operations +``FUTEX_UNLOCK_WAKE_LIST32`` and ``FUTEX_UNLOCK_BITSET_LIST32``, including +their private variants, therefore do not serialise with the software-CAS l= ock +domain. Their store can race with a trap-based compare-and-swap, and equa= lly +with the lock-backed operations in ``asm/futex_32.h``, which take the lock= but +still load and store separately. + +The integration point for this store remains an open question for review. + +What userspace has to do as well +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D + +On a cpu without ``casa`` the kernel does the swap under a lock of its own= , and +**an ordinary store does not take that lock**:: + + trap another thread's plain store + + lock + read word -> A + store B -> word + write C -> word + unlock + +``B`` is lost, and no ordering of an atomic compare-and-swap and an atomic +store makes that a legal outcome. + +So userspace using this service to build atomic operations must build *eve= ry* +atomic write from it, not just compare-and-exchange: an atomic store and an +atomic exchange each become a compare-and-swap retry loop. An implementat= ion +that routes read-modify-writes through the trap but leaves atomic stores as +plain stores is not atomic, and the failure is silent. + +This does not apply to a cpu that has ``casa``, where the kernel uses the +instruction and userspace can too. + +Replacing the ``__atomic_*`` helpers is not sufficient +----------------------------------------------------- + +Providing replacement ``__atomic_store_4`` and ``__atomic_exchange_4`` sym= bols +does not by itself route every atomic write through the trap. gcc can exp= and +an atomic store to a plain store, a 32-bit atomic exchange to ``swap``, an= d an +atomic test-and-set to ``ldstub`` on v8. ``swap`` and ``ldstub`` are +themselves atomic, but they do not take the kernel's lock and so do not ex= clude +against its separate read and write. A call the compiler never emits cann= ot be +intercepted. + +Two different integration scopes follow from that, and they are not +interchangeable. Changing libc's internal atomic macros covers libc's own +uses. It does not change application code compiled with atomic builtins; = that +needs compiler support - the possibility Andreas Larsson raised in 2019 - = or a +build that avoids the inline expansions. + +One aligned word is not general byte and halfword atomics +-------------------------------------------------------- + +The service operates on one naturally aligned 32-bit word. A byte or half= word +atomic synthesised by read-modify-writing its containing word is not safe +merely because every atomic on the target uses the trap:: + + word: [ atomic byte A | ordinary byte B | ... ] + + cpu 0 cpu 1 + + read the whole word under the lock + plain store to B + write the whole word back, + including the old B + +The ordinary writer of the neighbouring object ``B`` has no reason to +participate, and its store is lost. Byte and halfword atomics built this = way +need either width-aware accesses sharing this lock domain, or storage rules +that give the atomic object its containing word to itself. + +Availability +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +``AT_HWCAP`` carries ``HWCAP_SPARC_CASTRAP`` (0x10000000) when the kernel +implements the trap. Userspace must consult it rather than probing, becau= se +there is no safe way to probe: + +- on a kernel without this support the trap is fatal; +- on sparc64 a 32-bit process reads its hwcap word from ``asm/elf_64.h``, = where + the bit is reserved and always clear, and ``ta 0x11`` there is not an il= legal + instruction but the old 64-bit system call trap. + +The bit describes the kernel service, not the hardware. It is set whether= or +not the cpu has ``casa``, because a binary built for plain v8 cannot use t= hat +instruction even on a cpu that has it. A binary that does have ``casa`` +available - one built for LEON3 - should use it inline and ignore the bit +entirely; the kernel uses the instruction too where it exists, so the two = agree +on the same word. diff --git a/Documentation/arch/sparc/index.rst b/Documentation/arch/sparc/= index.rst index ae884224eec2..3a7d6df91a84 100644 --- a/Documentation/arch/sparc/index.rst +++ b/Documentation/arch/sparc/index.rst @@ -7,6 +7,7 @@ Sparc Architecture =20 console adi + cas-trap =20 oradax/oracle-dax =20 --=20 2.43.0