iPXE
bitops.h
Go to the documentation of this file.
00001 #ifndef _BITS_BITOPS_H
00002 #define _BITS_BITOPS_H
00003 
00004 /** @file
00005  *
00006  * x86 bit operations
00007  *
00008  * We perform atomic bit set and bit clear operations using "lock bts"
00009  * and "lock btr".  We use the output constraint to inform the
00010  * compiler that any memory from the start of the bit field up to and
00011  * including the byte containing the bit may be modified.  (This is
00012  * overkill but shouldn't matter in practice since we're unlikely to
00013  * subsequently read other bits from the same bit field.)
00014  */
00015 
00016 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00017 
00018 #include <stdint.h>
00019 
00020 /**
00021  * Set bit atomically
00022  *
00023  * @v bit               Bit to set
00024  * @v bits              Bit field
00025  */
00026 static inline __attribute__ (( always_inline )) void
00027 set_bit ( unsigned int bit, volatile void *bits ) {
00028         volatile struct {
00029                 uint8_t byte[ ( bit / 8 ) + 1 ];
00030         } *bytes = bits;
00031 
00032         __asm__ __volatile__ ( "lock bts %1, %0"
00033                                : "+m" ( *bytes ) : "Ir" ( bit ) );
00034 }
00035 
00036 /**
00037  * Clear bit atomically
00038  *
00039  * @v bit               Bit to set
00040  * @v bits              Bit field
00041  */
00042 static inline __attribute__ (( always_inline )) void
00043 clear_bit ( unsigned int bit, volatile void *bits ) {
00044         volatile struct {
00045                 uint8_t byte[ ( bit / 8 ) + 1 ];
00046         } *bytes = bits;
00047 
00048         __asm__ __volatile__ ( "lock btr %1, %0"
00049                                : "+m" ( *bytes ) : "Ir" ( bit ) );
00050 }
00051 
00052 /**
00053  * Test and set bit atomically
00054  *
00055  * @v bit               Bit to set
00056  * @v bits              Bit field
00057  * @ret old             Old value of bit (zero or non-zero)
00058  */
00059 static inline __attribute__ (( always_inline )) int
00060 test_and_set_bit ( unsigned int bit, volatile void *bits ) {
00061         volatile struct {
00062                 uint8_t byte[ ( bit / 8 ) + 1 ];
00063         } *bytes = bits;
00064         int old;
00065 
00066         __asm__ __volatile__ ( "lock bts %2, %0\n\t"
00067                                "sbb %1, %1\n\t"
00068                                : "+m" ( *bytes ), "=r"  ( old )
00069                                : "Ir" ( bit ) );
00070         return old;
00071 }
00072 
00073 /**
00074  * Test and clear bit atomically
00075  *
00076  * @v bit               Bit to set
00077  * @v bits              Bit field
00078  * @ret old             Old value of bit (zero or non-zero)
00079  */
00080 static inline __attribute__ (( always_inline )) int
00081 test_and_clear_bit ( unsigned int bit, volatile void *bits ) {
00082         volatile struct {
00083                 uint8_t byte[ ( bit / 8 ) + 1 ];
00084         } *bytes = bits;
00085         int old;
00086 
00087         __asm__ __volatile__ ( "lock btr %2, %0\n\t"
00088                                "sbb %1, %1\n\t"
00089                                : "+m" ( *bytes ), "=r"  ( old )
00090                                : "Ir" ( bit ) );
00091         return old;
00092 }
00093 
00094 #endif /* _BITS_BITOPS_H */