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

bitops.h (5772B)


      1/* SPDX-License-Identifier: GPL-2.0-only */
      2/*
      3 * Copyright (C) 2012 Regents of the University of California
      4 */
      5
      6#ifndef _ASM_RISCV_BITOPS_H
      7#define _ASM_RISCV_BITOPS_H
      8
      9#ifndef _LINUX_BITOPS_H
     10#error "Only <linux/bitops.h> can be included directly"
     11#endif /* _LINUX_BITOPS_H */
     12
     13#include <linux/compiler.h>
     14#include <linux/irqflags.h>
     15#include <asm/barrier.h>
     16#include <asm/bitsperlong.h>
     17
     18#include <asm-generic/bitops/__ffs.h>
     19#include <asm-generic/bitops/ffz.h>
     20#include <asm-generic/bitops/fls.h>
     21#include <asm-generic/bitops/__fls.h>
     22#include <asm-generic/bitops/fls64.h>
     23#include <asm-generic/bitops/sched.h>
     24#include <asm-generic/bitops/ffs.h>
     25
     26#include <asm-generic/bitops/hweight.h>
     27
     28#if (BITS_PER_LONG == 64)
     29#define __AMO(op)	"amo" #op ".d"
     30#elif (BITS_PER_LONG == 32)
     31#define __AMO(op)	"amo" #op ".w"
     32#else
     33#error "Unexpected BITS_PER_LONG"
     34#endif
     35
     36#define __test_and_op_bit_ord(op, mod, nr, addr, ord)		\
     37({								\
     38	unsigned long __res, __mask;				\
     39	__mask = BIT_MASK(nr);					\
     40	__asm__ __volatile__ (					\
     41		__AMO(op) #ord " %0, %2, %1"			\
     42		: "=r" (__res), "+A" (addr[BIT_WORD(nr)])	\
     43		: "r" (mod(__mask))				\
     44		: "memory");					\
     45	((__res & __mask) != 0);				\
     46})
     47
     48#define __op_bit_ord(op, mod, nr, addr, ord)			\
     49	__asm__ __volatile__ (					\
     50		__AMO(op) #ord " zero, %1, %0"			\
     51		: "+A" (addr[BIT_WORD(nr)])			\
     52		: "r" (mod(BIT_MASK(nr)))			\
     53		: "memory");
     54
     55#define __test_and_op_bit(op, mod, nr, addr) 			\
     56	__test_and_op_bit_ord(op, mod, nr, addr, .aqrl)
     57#define __op_bit(op, mod, nr, addr)				\
     58	__op_bit_ord(op, mod, nr, addr, )
     59
     60/* Bitmask modifiers */
     61#define __NOP(x)	(x)
     62#define __NOT(x)	(~(x))
     63
     64/**
     65 * test_and_set_bit - Set a bit and return its old value
     66 * @nr: Bit to set
     67 * @addr: Address to count from
     68 *
     69 * This operation may be reordered on other architectures than x86.
     70 */
     71static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
     72{
     73	return __test_and_op_bit(or, __NOP, nr, addr);
     74}
     75
     76/**
     77 * test_and_clear_bit - Clear a bit and return its old value
     78 * @nr: Bit to clear
     79 * @addr: Address to count from
     80 *
     81 * This operation can be reordered on other architectures other than x86.
     82 */
     83static inline int test_and_clear_bit(int nr, volatile unsigned long *addr)
     84{
     85	return __test_and_op_bit(and, __NOT, nr, addr);
     86}
     87
     88/**
     89 * test_and_change_bit - Change a bit and return its old value
     90 * @nr: Bit to change
     91 * @addr: Address to count from
     92 *
     93 * This operation is atomic and cannot be reordered.
     94 * It also implies a memory barrier.
     95 */
     96static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
     97{
     98	return __test_and_op_bit(xor, __NOP, nr, addr);
     99}
    100
    101/**
    102 * set_bit - Atomically set a bit in memory
    103 * @nr: the bit to set
    104 * @addr: the address to start counting from
    105 *
    106 * Note: there are no guarantees that this function will not be reordered
    107 * on non x86 architectures, so if you are writing portable code,
    108 * make sure not to rely on its reordering guarantees.
    109 *
    110 * Note that @nr may be almost arbitrarily large; this function is not
    111 * restricted to acting on a single-word quantity.
    112 */
    113static inline void set_bit(int nr, volatile unsigned long *addr)
    114{
    115	__op_bit(or, __NOP, nr, addr);
    116}
    117
    118/**
    119 * clear_bit - Clears a bit in memory
    120 * @nr: Bit to clear
    121 * @addr: Address to start counting from
    122 *
    123 * Note: there are no guarantees that this function will not be reordered
    124 * on non x86 architectures, so if you are writing portable code,
    125 * make sure not to rely on its reordering guarantees.
    126 */
    127static inline void clear_bit(int nr, volatile unsigned long *addr)
    128{
    129	__op_bit(and, __NOT, nr, addr);
    130}
    131
    132/**
    133 * change_bit - Toggle a bit in memory
    134 * @nr: Bit to change
    135 * @addr: Address to start counting from
    136 *
    137 * change_bit()  may be reordered on other architectures than x86.
    138 * Note that @nr may be almost arbitrarily large; this function is not
    139 * restricted to acting on a single-word quantity.
    140 */
    141static inline void change_bit(int nr, volatile unsigned long *addr)
    142{
    143	__op_bit(xor, __NOP, nr, addr);
    144}
    145
    146/**
    147 * test_and_set_bit_lock - Set a bit and return its old value, for lock
    148 * @nr: Bit to set
    149 * @addr: Address to count from
    150 *
    151 * This operation is atomic and provides acquire barrier semantics.
    152 * It can be used to implement bit locks.
    153 */
    154static inline int test_and_set_bit_lock(
    155	unsigned long nr, volatile unsigned long *addr)
    156{
    157	return __test_and_op_bit_ord(or, __NOP, nr, addr, .aq);
    158}
    159
    160/**
    161 * clear_bit_unlock - Clear a bit in memory, for unlock
    162 * @nr: the bit to set
    163 * @addr: the address to start counting from
    164 *
    165 * This operation is atomic and provides release barrier semantics.
    166 */
    167static inline void clear_bit_unlock(
    168	unsigned long nr, volatile unsigned long *addr)
    169{
    170	__op_bit_ord(and, __NOT, nr, addr, .rl);
    171}
    172
    173/**
    174 * __clear_bit_unlock - Clear a bit in memory, for unlock
    175 * @nr: the bit to set
    176 * @addr: the address to start counting from
    177 *
    178 * This operation is like clear_bit_unlock, however it is not atomic.
    179 * It does provide release barrier semantics so it can be used to unlock
    180 * a bit lock, however it would only be used if no other CPU can modify
    181 * any bits in the memory until the lock is released (a good example is
    182 * if the bit lock itself protects access to the other bits in the word).
    183 *
    184 * On RISC-V systems there seems to be no benefit to taking advantage of the
    185 * non-atomic property here: it's a lot more instructions and we still have to
    186 * provide release semantics anyway.
    187 */
    188static inline void __clear_bit_unlock(
    189	unsigned long nr, volatile unsigned long *addr)
    190{
    191	clear_bit_unlock(nr, addr);
    192}
    193
    194#undef __test_and_op_bit
    195#undef __op_bit
    196#undef __NOP
    197#undef __NOT
    198#undef __AMO
    199
    200#include <asm-generic/bitops/non-atomic.h>
    201#include <asm-generic/bitops/le.h>
    202#include <asm-generic/bitops/ext2-atomic.h>
    203
    204#endif /* _ASM_RISCV_BITOPS_H */