1/* $NetBSD: atomic_init_m68k.c,v 1.2 2025/12/20 16:25:09 thorpej Exp $ */ 2 3/*- 4 * Copyright (c) 2008, 2025 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33__RCSID("$NetBSD: atomic_init_m68k.c,v 1.2 2025/12/20 16:25:09 thorpej Exp $"); 34 35#include "extern.h" 36#include "../../../atomic/atomic_op_namespace.h" 37 38#include <sys/types.h> 39#include <sys/atomic.h> 40#include <sys/ras.h> 41#include <sys/sysctl.h> 42 43 /* __sysctl syscall stub */ 44#include "../../../../../../lib/libc/include/__sysctl.h" 45 46#include <machine/cpu.h> 47 48#include <stdlib.h> 49 50/* 51 * libc glue for m68k atomic operations. 52 * 53 * 68020 and later have a CAS instruction that can be used to implement 54 * everything. However, CAS (and TAS) are unusable on some 68020 systems 55 * (see __HAVE_M68K_BROKEN_RMC). 56 * 57 * The 68010 has no CAS instruction. 58 * 59 * So, for BROKEN_RMC and 68010, we use a restartable atomic sequence. 60 * 61 * Whichever compare-and-swap implementation is chosen is used to implement 62 * all of the other atomic operations: 63 * 64 * ==> The *_nv() variants generally require a compare-and-swap implementation 65 * anyway. 66 * 67 * ==> The other single-instruction operations (ADDx, ORx, etc.) are not 68 * truly atomic in that they do not generate a non-interruptible bus 69 * cycle, and thus would not work in a multi-processor environment. 70 * (We don't support any multiprocessor m68k systems today, but hey, 71 * it could happen!) 72 */ 73 74extern uint32_t _atomic_cas_32_ras(volatile uint32_t *, uint32_t, uint32_t); 75RAS_DECL(_atomic_cas_32_ras); 76 77extern uint16_t _atomic_cas_16_ras(volatile uint16_t *, uint16_t, uint16_t); 78RAS_DECL(_atomic_cas_16_ras); 79 80extern uint8_t _atomic_cas_8_ras(volatile uint8_t *, uint8_t, uint8_t); 81RAS_DECL(_atomic_cas_8_ras); 82 83#ifdef __mc68010__ 84#define CAS32_DEFAULT \ 85 ((uint32_t (*)(volatile uint32_t *, uint32_t, uint32_t))abort) 86#define CAS16_DEFAULT \ 87 ((uint16_t (*)(volatile uint16_t *, uint16_t, uint16_t))abort) 88#define CAS8_DEFAULT \ 89 ((uint8_t (*)(volatile uint8_t *, uint8_t, uint8_t))abort) 90#else 91extern uint32_t _atomic_cas_32_casl(volatile uint32_t *, uint32_t, uint32_t); 92extern uint16_t _atomic_cas_16_casw(volatile uint16_t *, uint16_t, uint16_t); 93extern uint8_t _atomic_cas_8_casb(volatile uint8_t *, uint8_t, uint8_t); 94 95/* Default to CASx implementation, fall back on RAS only when necessary. */ 96#define CAS32_DEFAULT _atomic_cas_32_casl 97#define CAS16_DEFAULT _atomic_cas_16_casw 98#define CAS8_DEFAULT _atomic_cas_8_casb 99#endif /* ! __mc68010__ */ 100 101static uint32_t (*_atomic_cas_32_fn)(volatile uint32_t *, uint32_t, uint32_t); 102static uint16_t (*_atomic_cas_16_fn)(volatile uint16_t *, uint16_t, uint16_t); 103static uint8_t (*_atomic_cas_8_fn)(volatile uint8_t *, uint8_t, uint8_t); 104 105void *_atomic_cas_32_a0(volatile uint32_t *, uint32_t, uint32_t); 106 107void * 108_atomic_cas_32_a0(volatile uint32_t *ptr, uint32_t old, uint32_t new) 109{ 110 /* Force return value to be duplicated into %a0. */ 111 return (void *)(*_atomic_cas_32_fn)(ptr, old, new); 112} 113 114#undef atomic_cas_32 115#undef atomic_cas_uint 116#undef atomic_cas_ulong 117#undef atomic_cas_ptr 118#undef atomic_cas_32_ni 119#undef atomic_cas_uint_ni 120#undef atomic_cas_ulong_ni 121#undef atomic_cas_ptr_ni 122 123__strong_alias(_atomic_cas_32,_atomic_cas_32_a0) 124atomic_op_alias(atomic_cas_32,_atomic_cas_32_a0) 125atomic_op_alias(atomic_cas_uint,_atomic_cas_32_a0) 126__strong_alias(_atomic_cas_uint,_atomic_cas_32_a0) 127atomic_op_alias(atomic_cas_ulong,_atomic_cas_32_a0) 128__strong_alias(_atomic_cas_ulong,_atomic_cas_32_a0) 129atomic_op_alias(atomic_cas_ptr,_atomic_cas_32_a0) 130__strong_alias(_atomic_cas_ptr,_atomic_cas_32_a0) 131 132atomic_op_alias(atomic_cas_32_ni,_atomic_cas_32_a0) 133__strong_alias(_atomic_cas_32_ni,_atomic_cas_32_a0) 134atomic_op_alias(atomic_cas_uint_ni,_atomic_cas_32_a0) 135__strong_alias(_atomic_cas_uint_ni,_atomic_cas_32_a0) 136atomic_op_alias(atomic_cas_ulong_ni,_atomic_cas_32_a0) 137__strong_alias(_atomic_cas_ulong_ni,_atomic_cas_32_a0) 138atomic_op_alias(atomic_cas_ptr_ni,_atomic_cas_32_a0) 139__strong_alias(_atomic_cas_ptr_ni,_atomic_cas_32_a0) 140 141crt_alias(__sync_val_compare_and_swap_4,_atomic_cas_32_a0) 142 143uint16_t 144_atomic_cas_16(volatile uint16_t *ptr, uint16_t old, uint16_t new) 145{ 146 return (*_atomic_cas_16_fn)(ptr, old, new); 147} 148 149#undef atomic_cas_16 150atomic_op_alias(atomic_cas_16,_atomic_cas_16) 151crt_alias(__sync_val_compare_and_swap_2,_atomic_cas_16) 152 153uint8_t 154_atomic_cas_8(volatile uint8_t *ptr, uint8_t old, uint8_t new) 155{ 156 return (*_atomic_cas_8_fn)(ptr, old, new); 157} 158 159#undef atomic_cas_8 160atomic_op_alias(atomic_cas_8,_atomic_cas_8) 161crt_alias(__sync_val_compare_and_swap_1,_atomic_cas_8) 162 163void __section(".text.startup") __attribute__ ((__visibility__("hidden"))) 164__libc_atomic_init(void) 165{ 166 _atomic_cas_32_fn = CAS32_DEFAULT; 167 _atomic_cas_16_fn = CAS16_DEFAULT; 168 _atomic_cas_8_fn = CAS8_DEFAULT; 169 170#ifndef __mc68010__ 171 int mib[2]; 172 size_t len; 173 bool broken_rmc; 174 175 /* 176 * Check to see if this system has a non-working /RMC. If 177 * the __sysctl() call fails, or if it indicates that /RMC 178 * works fine, then we have no further work to do because 179 * the stubs default to the CASx-using _atomic_cas_*() 180 * functions. 181 */ 182 mib[0] = CTL_MACHDEP; 183 mib[1] = CPU_BROKEN_RMC; 184 len = sizeof(broken_rmc); 185 if (__sysctl(mib, 2, &broken_rmc, &len, NULL, 0) == -1 || !broken_rmc) { 186 return; 187 } 188#endif /* ! __mc68010__ */ 189 190 /* 191 * If we get here, we either have a broken RMC system or a 192 * 68010. In either case, we need to register the restartable 193 * atomic sequences with the kernel. 194 * 195 * XXX Should consider a lazy initialization of these. 196 */ 197 if (rasctl(RAS_ADDR(_atomic_cas_32_ras), RAS_SIZE(_atomic_cas_32_ras), 198 RAS_INSTALL) == 0) { 199 _atomic_cas_32_fn = _atomic_cas_32_ras; 200 } 201 if (rasctl(RAS_ADDR(_atomic_cas_16_ras), RAS_SIZE(_atomic_cas_16_ras), 202 RAS_INSTALL) == 0) { 203 _atomic_cas_16_fn = _atomic_cas_16_ras; 204 } 205 if (rasctl(RAS_ADDR(_atomic_cas_8_ras), RAS_SIZE(_atomic_cas_8_ras), 206 RAS_INSTALL) == 0) { 207 _atomic_cas_8_fn = _atomic_cas_8_ras; 208 } 209} 210