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 (6115B)


      1/* SPDX-License-Identifier: GPL-2.0-only */
      2/*
      3 * Bit operations for the Hexagon architecture
      4 *
      5 * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
      6 */
      7
      8#ifndef _ASM_BITOPS_H
      9#define _ASM_BITOPS_H
     10
     11#include <linux/compiler.h>
     12#include <asm/byteorder.h>
     13#include <asm/atomic.h>
     14#include <asm/barrier.h>
     15
     16#ifdef __KERNEL__
     17
     18/*
     19 * The offset calculations for these are based on BITS_PER_LONG == 32
     20 * (i.e. I get to shift by #5-2 (32 bits per long, 4 bytes per access),
     21 * mask by 0x0000001F)
     22 *
     23 * Typically, R10 is clobbered for address, R11 bit nr, and R12 is temp
     24 */
     25
     26/**
     27 * test_and_clear_bit - clear a bit and return its old value
     28 * @nr:  bit number to clear
     29 * @addr:  pointer to memory
     30 */
     31static inline int test_and_clear_bit(int nr, volatile void *addr)
     32{
     33	int oldval;
     34
     35	__asm__ __volatile__ (
     36	"	{R10 = %1; R11 = asr(%2,#5); }\n"
     37	"	{R10 += asl(R11,#2); R11 = and(%2,#0x1f)}\n"
     38	"1:	R12 = memw_locked(R10);\n"
     39	"	{ P0 = tstbit(R12,R11); R12 = clrbit(R12,R11); }\n"
     40	"	memw_locked(R10,P1) = R12;\n"
     41	"	{if (!P1) jump 1b; %0 = mux(P0,#1,#0);}\n"
     42	: "=&r" (oldval)
     43	: "r" (addr), "r" (nr)
     44	: "r10", "r11", "r12", "p0", "p1", "memory"
     45	);
     46
     47	return oldval;
     48}
     49
     50/**
     51 * test_and_set_bit - set a bit and return its old value
     52 * @nr:  bit number to set
     53 * @addr:  pointer to memory
     54 */
     55static inline int test_and_set_bit(int nr, volatile void *addr)
     56{
     57	int oldval;
     58
     59	__asm__ __volatile__ (
     60	"	{R10 = %1; R11 = asr(%2,#5); }\n"
     61	"	{R10 += asl(R11,#2); R11 = and(%2,#0x1f)}\n"
     62	"1:	R12 = memw_locked(R10);\n"
     63	"	{ P0 = tstbit(R12,R11); R12 = setbit(R12,R11); }\n"
     64	"	memw_locked(R10,P1) = R12;\n"
     65	"	{if (!P1) jump 1b; %0 = mux(P0,#1,#0);}\n"
     66	: "=&r" (oldval)
     67	: "r" (addr), "r" (nr)
     68	: "r10", "r11", "r12", "p0", "p1", "memory"
     69	);
     70
     71
     72	return oldval;
     73
     74}
     75
     76/**
     77 * test_and_change_bit - toggle a bit and return its old value
     78 * @nr:  bit number to set
     79 * @addr:  pointer to memory
     80 */
     81static inline int test_and_change_bit(int nr, volatile void *addr)
     82{
     83	int oldval;
     84
     85	__asm__ __volatile__ (
     86	"	{R10 = %1; R11 = asr(%2,#5); }\n"
     87	"	{R10 += asl(R11,#2); R11 = and(%2,#0x1f)}\n"
     88	"1:	R12 = memw_locked(R10);\n"
     89	"	{ P0 = tstbit(R12,R11); R12 = togglebit(R12,R11); }\n"
     90	"	memw_locked(R10,P1) = R12;\n"
     91	"	{if (!P1) jump 1b; %0 = mux(P0,#1,#0);}\n"
     92	: "=&r" (oldval)
     93	: "r" (addr), "r" (nr)
     94	: "r10", "r11", "r12", "p0", "p1", "memory"
     95	);
     96
     97	return oldval;
     98
     99}
    100
    101/*
    102 * Atomic, but doesn't care about the return value.
    103 * Rewrite later to save a cycle or two.
    104 */
    105
    106static inline void clear_bit(int nr, volatile void *addr)
    107{
    108	test_and_clear_bit(nr, addr);
    109}
    110
    111static inline void set_bit(int nr, volatile void *addr)
    112{
    113	test_and_set_bit(nr, addr);
    114}
    115
    116static inline void change_bit(int nr, volatile void *addr)
    117{
    118	test_and_change_bit(nr, addr);
    119}
    120
    121
    122/*
    123 * These are allowed to be non-atomic.  In fact the generic flavors are
    124 * in non-atomic.h.  Would it be better to use intrinsics for this?
    125 *
    126 * OK, writes in our architecture do not invalidate LL/SC, so this has to
    127 * be atomic, particularly for things like slab_lock and slab_unlock.
    128 *
    129 */
    130static inline void __clear_bit(int nr, volatile unsigned long *addr)
    131{
    132	test_and_clear_bit(nr, addr);
    133}
    134
    135static inline void __set_bit(int nr, volatile unsigned long *addr)
    136{
    137	test_and_set_bit(nr, addr);
    138}
    139
    140static inline void __change_bit(int nr, volatile unsigned long *addr)
    141{
    142	test_and_change_bit(nr, addr);
    143}
    144
    145/*  Apparently, at least some of these are allowed to be non-atomic  */
    146static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr)
    147{
    148	return test_and_clear_bit(nr, addr);
    149}
    150
    151static inline int __test_and_set_bit(int nr, volatile unsigned long *addr)
    152{
    153	return test_and_set_bit(nr, addr);
    154}
    155
    156static inline int __test_and_change_bit(int nr, volatile unsigned long *addr)
    157{
    158	return test_and_change_bit(nr, addr);
    159}
    160
    161static inline int __test_bit(int nr, const volatile unsigned long *addr)
    162{
    163	int retval;
    164
    165	asm volatile(
    166	"{P0 = tstbit(%1,%2); if (P0.new) %0 = #1; if (!P0.new) %0 = #0;}\n"
    167	: "=&r" (retval)
    168	: "r" (addr[BIT_WORD(nr)]), "r" (nr % BITS_PER_LONG)
    169	: "p0"
    170	);
    171
    172	return retval;
    173}
    174
    175#define test_bit(nr, addr) __test_bit(nr, addr)
    176
    177/*
    178 * ffz - find first zero in word.
    179 * @word: The word to search
    180 *
    181 * Undefined if no zero exists, so code should check against ~0UL first.
    182 */
    183static inline long ffz(int x)
    184{
    185	int r;
    186
    187	asm("%0 = ct1(%1);\n"
    188		: "=&r" (r)
    189		: "r" (x));
    190	return r;
    191}
    192
    193/*
    194 * fls - find last (most-significant) bit set
    195 * @x: the word to search
    196 *
    197 * This is defined the same way as ffs.
    198 * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
    199 */
    200static inline int fls(unsigned int x)
    201{
    202	int r;
    203
    204	asm("{ %0 = cl0(%1);}\n"
    205		"%0 = sub(#32,%0);\n"
    206		: "=&r" (r)
    207		: "r" (x)
    208		: "p0");
    209
    210	return r;
    211}
    212
    213/*
    214 * ffs - find first bit set
    215 * @x: the word to search
    216 *
    217 * This is defined the same way as
    218 * the libc and compiler builtin ffs routines, therefore
    219 * differs in spirit from the above ffz (man ffs).
    220 */
    221static inline int ffs(int x)
    222{
    223	int r;
    224
    225	asm("{ P0 = cmp.eq(%1,#0); %0 = ct0(%1);}\n"
    226		"{ if (P0) %0 = #0; if (!P0) %0 = add(%0,#1);}\n"
    227		: "=&r" (r)
    228		: "r" (x)
    229		: "p0");
    230
    231	return r;
    232}
    233
    234/*
    235 * __ffs - find first bit in word.
    236 * @word: The word to search
    237 *
    238 * Undefined if no bit exists, so code should check against 0 first.
    239 *
    240 * bits_per_long assumed to be 32
    241 * numbering starts at 0 I think (instead of 1 like ffs)
    242 */
    243static inline unsigned long __ffs(unsigned long word)
    244{
    245	int num;
    246
    247	asm("%0 = ct0(%1);\n"
    248		: "=&r" (num)
    249		: "r" (word));
    250
    251	return num;
    252}
    253
    254/*
    255 * __fls - find last (most-significant) set bit in a long word
    256 * @word: the word to search
    257 *
    258 * Undefined if no set bit exists, so code should check against 0 first.
    259 * bits_per_long assumed to be 32
    260 */
    261static inline unsigned long __fls(unsigned long word)
    262{
    263	int num;
    264
    265	asm("%0 = cl0(%1);\n"
    266		"%0 = sub(#31,%0);\n"
    267		: "=&r" (num)
    268		: "r" (word));
    269
    270	return num;
    271}
    272
    273#include <asm-generic/bitops/lock.h>
    274
    275#include <asm-generic/bitops/fls64.h>
    276#include <asm-generic/bitops/sched.h>
    277#include <asm-generic/bitops/hweight.h>
    278
    279#include <asm-generic/bitops/le.h>
    280#include <asm-generic/bitops/ext2-atomic.h>
    281
    282#endif /* __KERNEL__ */
    283#endif