Files
ipxe/src/arch/x86/include/bits/bitops.h
Michael Brown 16d95227a4 [bitops] Provide an explicit operand size for bit test instructions
Recent versions of the GNU assembler (observed with GNU as 2.35 on
Fedora 33) will produce a warning message

  Warning: no instruction mnemonic suffix given and no register
  operands; using default for `bts'

The operand size affects only the potential range for the bit number.
Since we pass the bit number as an unsigned int, it is already
constrained to 32 bits for both i386 and x86_64.

Silence the assembler warning by specifying an explicit 32-bit operand
size (and thereby matching the choice that the assembler would
otherwise make automatically).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-27 15:45:31 +00:00

95 lines
2.2 KiB
C

#ifndef _BITS_BITOPS_H
#define _BITS_BITOPS_H
/** @file
*
* x86 bit operations
*
* We perform atomic bit set and bit clear operations using "lock bts"
* and "lock btr". We use the output constraint to inform the
* compiler that any memory from the start of the bit field up to and
* including the byte containing the bit may be modified. (This is
* overkill but shouldn't matter in practice since we're unlikely to
* subsequently read other bits from the same bit field.)
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
/**
* Set bit atomically
*
* @v bit Bit to set
* @v bits Bit field
*/
static inline __attribute__ (( always_inline )) void
set_bit ( unsigned int bit, volatile void *bits ) {
volatile struct {
uint8_t byte[ ( bit / 8 ) + 1 ];
} *bytes = bits;
__asm__ __volatile__ ( "lock btsl %k1, %0"
: "+m" ( *bytes ) : "Ir" ( bit ) );
}
/**
* Clear bit atomically
*
* @v bit Bit to set
* @v bits Bit field
*/
static inline __attribute__ (( always_inline )) void
clear_bit ( unsigned int bit, volatile void *bits ) {
volatile struct {
uint8_t byte[ ( bit / 8 ) + 1 ];
} *bytes = bits;
__asm__ __volatile__ ( "lock btrl %k1, %0"
: "+m" ( *bytes ) : "Ir" ( bit ) );
}
/**
* Test and set bit atomically
*
* @v bit Bit to set
* @v bits Bit field
* @ret old Old value of bit (zero or non-zero)
*/
static inline __attribute__ (( always_inline )) int
test_and_set_bit ( unsigned int bit, volatile void *bits ) {
volatile struct {
uint8_t byte[ ( bit / 8 ) + 1 ];
} *bytes = bits;
int old;
__asm__ __volatile__ ( "lock btsl %k2, %0\n\t"
"sbb %1, %1\n\t"
: "+m" ( *bytes ), "=r" ( old )
: "Ir" ( bit ) );
return old;
}
/**
* Test and clear bit atomically
*
* @v bit Bit to set
* @v bits Bit field
* @ret old Old value of bit (zero or non-zero)
*/
static inline __attribute__ (( always_inline )) int
test_and_clear_bit ( unsigned int bit, volatile void *bits ) {
volatile struct {
uint8_t byte[ ( bit / 8 ) + 1 ];
} *bytes = bits;
int old;
__asm__ __volatile__ ( "lock btrl %k2, %0\n\t"
"sbb %1, %1\n\t"
: "+m" ( *bytes ), "=r" ( old )
: "Ir" ( bit ) );
return old;
}
#endif /* _BITS_BITOPS_H */