cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cmpxchg.h (12280B)


      1/* SPDX-License-Identifier: GPL-2.0 */
      2#ifndef _ASM_POWERPC_CMPXCHG_H_
      3#define _ASM_POWERPC_CMPXCHG_H_
      4
      5#ifdef __KERNEL__
      6#include <linux/compiler.h>
      7#include <asm/synch.h>
      8#include <linux/bug.h>
      9
     10#ifdef __BIG_ENDIAN
     11#define BITOFF_CAL(size, off)	((sizeof(u32) - size - off) * BITS_PER_BYTE)
     12#else
     13#define BITOFF_CAL(size, off)	(off * BITS_PER_BYTE)
     14#endif
     15
     16#define XCHG_GEN(type, sfx, cl)				\
     17static inline u32 __xchg_##type##sfx(volatile void *p, u32 val)	\
     18{								\
     19	unsigned int prev, prev_mask, tmp, bitoff, off;		\
     20								\
     21	off = (unsigned long)p % sizeof(u32);			\
     22	bitoff = BITOFF_CAL(sizeof(type), off);			\
     23	p -= off;						\
     24	val <<= bitoff;						\
     25	prev_mask = (u32)(type)-1 << bitoff;			\
     26								\
     27	__asm__ __volatile__(					\
     28"1:	lwarx   %0,0,%3\n"					\
     29"	andc	%1,%0,%5\n"					\
     30"	or	%1,%1,%4\n"					\
     31"	stwcx.	%1,0,%3\n"					\
     32"	bne-	1b\n"						\
     33	: "=&r" (prev), "=&r" (tmp), "+m" (*(u32*)p)		\
     34	: "r" (p), "r" (val), "r" (prev_mask)			\
     35	: "cc", cl);						\
     36								\
     37	return prev >> bitoff;					\
     38}
     39
     40#define CMPXCHG_GEN(type, sfx, br, br2, cl)			\
     41static inline							\
     42u32 __cmpxchg_##type##sfx(volatile void *p, u32 old, u32 new)	\
     43{								\
     44	unsigned int prev, prev_mask, tmp, bitoff, off;		\
     45								\
     46	off = (unsigned long)p % sizeof(u32);			\
     47	bitoff = BITOFF_CAL(sizeof(type), off);			\
     48	p -= off;						\
     49	old <<= bitoff;						\
     50	new <<= bitoff;						\
     51	prev_mask = (u32)(type)-1 << bitoff;			\
     52								\
     53	__asm__ __volatile__(					\
     54	br							\
     55"1:	lwarx   %0,0,%3\n"					\
     56"	and	%1,%0,%6\n"					\
     57"	cmpw	0,%1,%4\n"					\
     58"	bne-	2f\n"						\
     59"	andc	%1,%0,%6\n"					\
     60"	or	%1,%1,%5\n"					\
     61"	stwcx.  %1,0,%3\n"					\
     62"	bne-    1b\n"						\
     63	br2							\
     64	"\n"							\
     65"2:"								\
     66	: "=&r" (prev), "=&r" (tmp), "+m" (*(u32*)p)		\
     67	: "r" (p), "r" (old), "r" (new), "r" (prev_mask)	\
     68	: "cc", cl);						\
     69								\
     70	return prev >> bitoff;					\
     71}
     72
     73/*
     74 * Atomic exchange
     75 *
     76 * Changes the memory location '*p' to be val and returns
     77 * the previous value stored there.
     78 */
     79
     80XCHG_GEN(u8, _local, "memory");
     81XCHG_GEN(u8, _relaxed, "cc");
     82XCHG_GEN(u16, _local, "memory");
     83XCHG_GEN(u16, _relaxed, "cc");
     84
     85static __always_inline unsigned long
     86__xchg_u32_local(volatile void *p, unsigned long val)
     87{
     88	unsigned long prev;
     89
     90	__asm__ __volatile__(
     91"1:	lwarx	%0,0,%2 \n"
     92"	stwcx.	%3,0,%2 \n\
     93	bne-	1b"
     94	: "=&r" (prev), "+m" (*(volatile unsigned int *)p)
     95	: "r" (p), "r" (val)
     96	: "cc", "memory");
     97
     98	return prev;
     99}
    100
    101static __always_inline unsigned long
    102__xchg_u32_relaxed(u32 *p, unsigned long val)
    103{
    104	unsigned long prev;
    105
    106	__asm__ __volatile__(
    107"1:	lwarx	%0,0,%2\n"
    108"	stwcx.	%3,0,%2\n"
    109"	bne-	1b"
    110	: "=&r" (prev), "+m" (*p)
    111	: "r" (p), "r" (val)
    112	: "cc");
    113
    114	return prev;
    115}
    116
    117#ifdef CONFIG_PPC64
    118static __always_inline unsigned long
    119__xchg_u64_local(volatile void *p, unsigned long val)
    120{
    121	unsigned long prev;
    122
    123	__asm__ __volatile__(
    124"1:	ldarx	%0,0,%2 \n"
    125"	stdcx.	%3,0,%2 \n\
    126	bne-	1b"
    127	: "=&r" (prev), "+m" (*(volatile unsigned long *)p)
    128	: "r" (p), "r" (val)
    129	: "cc", "memory");
    130
    131	return prev;
    132}
    133
    134static __always_inline unsigned long
    135__xchg_u64_relaxed(u64 *p, unsigned long val)
    136{
    137	unsigned long prev;
    138
    139	__asm__ __volatile__(
    140"1:	ldarx	%0,0,%2\n"
    141"	stdcx.	%3,0,%2\n"
    142"	bne-	1b"
    143	: "=&r" (prev), "+m" (*p)
    144	: "r" (p), "r" (val)
    145	: "cc");
    146
    147	return prev;
    148}
    149#endif
    150
    151static __always_inline unsigned long
    152__xchg_local(void *ptr, unsigned long x, unsigned int size)
    153{
    154	switch (size) {
    155	case 1:
    156		return __xchg_u8_local(ptr, x);
    157	case 2:
    158		return __xchg_u16_local(ptr, x);
    159	case 4:
    160		return __xchg_u32_local(ptr, x);
    161#ifdef CONFIG_PPC64
    162	case 8:
    163		return __xchg_u64_local(ptr, x);
    164#endif
    165	}
    166	BUILD_BUG_ON_MSG(1, "Unsupported size for __xchg");
    167	return x;
    168}
    169
    170static __always_inline unsigned long
    171__xchg_relaxed(void *ptr, unsigned long x, unsigned int size)
    172{
    173	switch (size) {
    174	case 1:
    175		return __xchg_u8_relaxed(ptr, x);
    176	case 2:
    177		return __xchg_u16_relaxed(ptr, x);
    178	case 4:
    179		return __xchg_u32_relaxed(ptr, x);
    180#ifdef CONFIG_PPC64
    181	case 8:
    182		return __xchg_u64_relaxed(ptr, x);
    183#endif
    184	}
    185	BUILD_BUG_ON_MSG(1, "Unsupported size for __xchg_local");
    186	return x;
    187}
    188#define arch_xchg_local(ptr,x)						     \
    189  ({									     \
    190     __typeof__(*(ptr)) _x_ = (x);					     \
    191     (__typeof__(*(ptr))) __xchg_local((ptr),				     \
    192     		(unsigned long)_x_, sizeof(*(ptr))); 			     \
    193  })
    194
    195#define arch_xchg_relaxed(ptr, x)					\
    196({									\
    197	__typeof__(*(ptr)) _x_ = (x);					\
    198	(__typeof__(*(ptr))) __xchg_relaxed((ptr),			\
    199			(unsigned long)_x_, sizeof(*(ptr)));		\
    200})
    201/*
    202 * Compare and exchange - if *p == old, set it to new,
    203 * and return the old value of *p.
    204 */
    205
    206CMPXCHG_GEN(u8, , PPC_ATOMIC_ENTRY_BARRIER, PPC_ATOMIC_EXIT_BARRIER, "memory");
    207CMPXCHG_GEN(u8, _local, , , "memory");
    208CMPXCHG_GEN(u8, _acquire, , PPC_ACQUIRE_BARRIER, "memory");
    209CMPXCHG_GEN(u8, _relaxed, , , "cc");
    210CMPXCHG_GEN(u16, , PPC_ATOMIC_ENTRY_BARRIER, PPC_ATOMIC_EXIT_BARRIER, "memory");
    211CMPXCHG_GEN(u16, _local, , , "memory");
    212CMPXCHG_GEN(u16, _acquire, , PPC_ACQUIRE_BARRIER, "memory");
    213CMPXCHG_GEN(u16, _relaxed, , , "cc");
    214
    215static __always_inline unsigned long
    216__cmpxchg_u32(volatile unsigned int *p, unsigned long old, unsigned long new)
    217{
    218	unsigned int prev;
    219
    220	__asm__ __volatile__ (
    221	PPC_ATOMIC_ENTRY_BARRIER
    222"1:	lwarx	%0,0,%2		# __cmpxchg_u32\n\
    223	cmpw	0,%0,%3\n\
    224	bne-	2f\n"
    225"	stwcx.	%4,0,%2\n\
    226	bne-	1b"
    227	PPC_ATOMIC_EXIT_BARRIER
    228	"\n\
    2292:"
    230	: "=&r" (prev), "+m" (*p)
    231	: "r" (p), "r" (old), "r" (new)
    232	: "cc", "memory");
    233
    234	return prev;
    235}
    236
    237static __always_inline unsigned long
    238__cmpxchg_u32_local(volatile unsigned int *p, unsigned long old,
    239			unsigned long new)
    240{
    241	unsigned int prev;
    242
    243	__asm__ __volatile__ (
    244"1:	lwarx	%0,0,%2		# __cmpxchg_u32\n\
    245	cmpw	0,%0,%3\n\
    246	bne-	2f\n"
    247"	stwcx.	%4,0,%2\n\
    248	bne-	1b"
    249	"\n\
    2502:"
    251	: "=&r" (prev), "+m" (*p)
    252	: "r" (p), "r" (old), "r" (new)
    253	: "cc", "memory");
    254
    255	return prev;
    256}
    257
    258static __always_inline unsigned long
    259__cmpxchg_u32_relaxed(u32 *p, unsigned long old, unsigned long new)
    260{
    261	unsigned long prev;
    262
    263	__asm__ __volatile__ (
    264"1:	lwarx	%0,0,%2		# __cmpxchg_u32_relaxed\n"
    265"	cmpw	0,%0,%3\n"
    266"	bne-	2f\n"
    267"	stwcx.	%4,0,%2\n"
    268"	bne-	1b\n"
    269"2:"
    270	: "=&r" (prev), "+m" (*p)
    271	: "r" (p), "r" (old), "r" (new)
    272	: "cc");
    273
    274	return prev;
    275}
    276
    277/*
    278 * cmpxchg family don't have order guarantee if cmp part fails, therefore we
    279 * can avoid superfluous barriers if we use assembly code to implement
    280 * cmpxchg() and cmpxchg_acquire(), however we don't do the similar for
    281 * cmpxchg_release() because that will result in putting a barrier in the
    282 * middle of a ll/sc loop, which is probably a bad idea. For example, this
    283 * might cause the conditional store more likely to fail.
    284 */
    285static __always_inline unsigned long
    286__cmpxchg_u32_acquire(u32 *p, unsigned long old, unsigned long new)
    287{
    288	unsigned long prev;
    289
    290	__asm__ __volatile__ (
    291"1:	lwarx	%0,0,%2		# __cmpxchg_u32_acquire\n"
    292"	cmpw	0,%0,%3\n"
    293"	bne-	2f\n"
    294"	stwcx.	%4,0,%2\n"
    295"	bne-	1b\n"
    296	PPC_ACQUIRE_BARRIER
    297	"\n"
    298"2:"
    299	: "=&r" (prev), "+m" (*p)
    300	: "r" (p), "r" (old), "r" (new)
    301	: "cc", "memory");
    302
    303	return prev;
    304}
    305
    306#ifdef CONFIG_PPC64
    307static __always_inline unsigned long
    308__cmpxchg_u64(volatile unsigned long *p, unsigned long old, unsigned long new)
    309{
    310	unsigned long prev;
    311
    312	__asm__ __volatile__ (
    313	PPC_ATOMIC_ENTRY_BARRIER
    314"1:	ldarx	%0,0,%2		# __cmpxchg_u64\n\
    315	cmpd	0,%0,%3\n\
    316	bne-	2f\n\
    317	stdcx.	%4,0,%2\n\
    318	bne-	1b"
    319	PPC_ATOMIC_EXIT_BARRIER
    320	"\n\
    3212:"
    322	: "=&r" (prev), "+m" (*p)
    323	: "r" (p), "r" (old), "r" (new)
    324	: "cc", "memory");
    325
    326	return prev;
    327}
    328
    329static __always_inline unsigned long
    330__cmpxchg_u64_local(volatile unsigned long *p, unsigned long old,
    331			unsigned long new)
    332{
    333	unsigned long prev;
    334
    335	__asm__ __volatile__ (
    336"1:	ldarx	%0,0,%2		# __cmpxchg_u64\n\
    337	cmpd	0,%0,%3\n\
    338	bne-	2f\n\
    339	stdcx.	%4,0,%2\n\
    340	bne-	1b"
    341	"\n\
    3422:"
    343	: "=&r" (prev), "+m" (*p)
    344	: "r" (p), "r" (old), "r" (new)
    345	: "cc", "memory");
    346
    347	return prev;
    348}
    349
    350static __always_inline unsigned long
    351__cmpxchg_u64_relaxed(u64 *p, unsigned long old, unsigned long new)
    352{
    353	unsigned long prev;
    354
    355	__asm__ __volatile__ (
    356"1:	ldarx	%0,0,%2		# __cmpxchg_u64_relaxed\n"
    357"	cmpd	0,%0,%3\n"
    358"	bne-	2f\n"
    359"	stdcx.	%4,0,%2\n"
    360"	bne-	1b\n"
    361"2:"
    362	: "=&r" (prev), "+m" (*p)
    363	: "r" (p), "r" (old), "r" (new)
    364	: "cc");
    365
    366	return prev;
    367}
    368
    369static __always_inline unsigned long
    370__cmpxchg_u64_acquire(u64 *p, unsigned long old, unsigned long new)
    371{
    372	unsigned long prev;
    373
    374	__asm__ __volatile__ (
    375"1:	ldarx	%0,0,%2		# __cmpxchg_u64_acquire\n"
    376"	cmpd	0,%0,%3\n"
    377"	bne-	2f\n"
    378"	stdcx.	%4,0,%2\n"
    379"	bne-	1b\n"
    380	PPC_ACQUIRE_BARRIER
    381	"\n"
    382"2:"
    383	: "=&r" (prev), "+m" (*p)
    384	: "r" (p), "r" (old), "r" (new)
    385	: "cc", "memory");
    386
    387	return prev;
    388}
    389#endif
    390
    391static __always_inline unsigned long
    392__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new,
    393	  unsigned int size)
    394{
    395	switch (size) {
    396	case 1:
    397		return __cmpxchg_u8(ptr, old, new);
    398	case 2:
    399		return __cmpxchg_u16(ptr, old, new);
    400	case 4:
    401		return __cmpxchg_u32(ptr, old, new);
    402#ifdef CONFIG_PPC64
    403	case 8:
    404		return __cmpxchg_u64(ptr, old, new);
    405#endif
    406	}
    407	BUILD_BUG_ON_MSG(1, "Unsupported size for __cmpxchg");
    408	return old;
    409}
    410
    411static __always_inline unsigned long
    412__cmpxchg_local(void *ptr, unsigned long old, unsigned long new,
    413	  unsigned int size)
    414{
    415	switch (size) {
    416	case 1:
    417		return __cmpxchg_u8_local(ptr, old, new);
    418	case 2:
    419		return __cmpxchg_u16_local(ptr, old, new);
    420	case 4:
    421		return __cmpxchg_u32_local(ptr, old, new);
    422#ifdef CONFIG_PPC64
    423	case 8:
    424		return __cmpxchg_u64_local(ptr, old, new);
    425#endif
    426	}
    427	BUILD_BUG_ON_MSG(1, "Unsupported size for __cmpxchg_local");
    428	return old;
    429}
    430
    431static __always_inline unsigned long
    432__cmpxchg_relaxed(void *ptr, unsigned long old, unsigned long new,
    433		  unsigned int size)
    434{
    435	switch (size) {
    436	case 1:
    437		return __cmpxchg_u8_relaxed(ptr, old, new);
    438	case 2:
    439		return __cmpxchg_u16_relaxed(ptr, old, new);
    440	case 4:
    441		return __cmpxchg_u32_relaxed(ptr, old, new);
    442#ifdef CONFIG_PPC64
    443	case 8:
    444		return __cmpxchg_u64_relaxed(ptr, old, new);
    445#endif
    446	}
    447	BUILD_BUG_ON_MSG(1, "Unsupported size for __cmpxchg_relaxed");
    448	return old;
    449}
    450
    451static __always_inline unsigned long
    452__cmpxchg_acquire(void *ptr, unsigned long old, unsigned long new,
    453		  unsigned int size)
    454{
    455	switch (size) {
    456	case 1:
    457		return __cmpxchg_u8_acquire(ptr, old, new);
    458	case 2:
    459		return __cmpxchg_u16_acquire(ptr, old, new);
    460	case 4:
    461		return __cmpxchg_u32_acquire(ptr, old, new);
    462#ifdef CONFIG_PPC64
    463	case 8:
    464		return __cmpxchg_u64_acquire(ptr, old, new);
    465#endif
    466	}
    467	BUILD_BUG_ON_MSG(1, "Unsupported size for __cmpxchg_acquire");
    468	return old;
    469}
    470#define arch_cmpxchg(ptr, o, n)						 \
    471  ({									 \
    472     __typeof__(*(ptr)) _o_ = (o);					 \
    473     __typeof__(*(ptr)) _n_ = (n);					 \
    474     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,		 \
    475				    (unsigned long)_n_, sizeof(*(ptr))); \
    476  })
    477
    478
    479#define arch_cmpxchg_local(ptr, o, n)					 \
    480  ({									 \
    481     __typeof__(*(ptr)) _o_ = (o);					 \
    482     __typeof__(*(ptr)) _n_ = (n);					 \
    483     (__typeof__(*(ptr))) __cmpxchg_local((ptr), (unsigned long)_o_,	 \
    484				    (unsigned long)_n_, sizeof(*(ptr))); \
    485  })
    486
    487#define arch_cmpxchg_relaxed(ptr, o, n)					\
    488({									\
    489	__typeof__(*(ptr)) _o_ = (o);					\
    490	__typeof__(*(ptr)) _n_ = (n);					\
    491	(__typeof__(*(ptr))) __cmpxchg_relaxed((ptr),			\
    492			(unsigned long)_o_, (unsigned long)_n_,		\
    493			sizeof(*(ptr)));				\
    494})
    495
    496#define arch_cmpxchg_acquire(ptr, o, n)					\
    497({									\
    498	__typeof__(*(ptr)) _o_ = (o);					\
    499	__typeof__(*(ptr)) _n_ = (n);					\
    500	(__typeof__(*(ptr))) __cmpxchg_acquire((ptr),			\
    501			(unsigned long)_o_, (unsigned long)_n_,		\
    502			sizeof(*(ptr)));				\
    503})
    504#ifdef CONFIG_PPC64
    505#define arch_cmpxchg64(ptr, o, n)					\
    506  ({									\
    507	BUILD_BUG_ON(sizeof(*(ptr)) != 8);				\
    508	arch_cmpxchg((ptr), (o), (n));					\
    509  })
    510#define arch_cmpxchg64_local(ptr, o, n)					\
    511  ({									\
    512	BUILD_BUG_ON(sizeof(*(ptr)) != 8);				\
    513	arch_cmpxchg_local((ptr), (o), (n));				\
    514  })
    515#define arch_cmpxchg64_relaxed(ptr, o, n)				\
    516({									\
    517	BUILD_BUG_ON(sizeof(*(ptr)) != 8);				\
    518	arch_cmpxchg_relaxed((ptr), (o), (n));				\
    519})
    520#define arch_cmpxchg64_acquire(ptr, o, n)				\
    521({									\
    522	BUILD_BUG_ON(sizeof(*(ptr)) != 8);				\
    523	arch_cmpxchg_acquire((ptr), (o), (n));				\
    524})
    525#else
    526#include <asm-generic/cmpxchg-local.h>
    527#define arch_cmpxchg64_local(ptr, o, n) __generic_cmpxchg64_local((ptr), (o), (n))
    528#endif
    529
    530#endif /* __KERNEL__ */
    531#endif /* _ASM_POWERPC_CMPXCHG_H_ */