Browse Source

[bitops] Add generic atomic bit test, set, and clear functions

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 8 years ago
parent
commit
c867b5ab1f
4 changed files with 216 additions and 0 deletions
  1. 94
    0
      src/arch/x86/include/bits/bitops.h
  2. 19
    0
      src/include/ipxe/bitops.h
  3. 102
    0
      src/tests/bitops_test.c
  4. 1
    0
      src/tests/tests.c

+ 94
- 0
src/arch/x86/include/bits/bitops.h View File

@@ -0,0 +1,94 @@
1
+#ifndef _BITS_BITOPS_H
2
+#define _BITS_BITOPS_H
3
+
4
+/** @file
5
+ *
6
+ * x86 bit operations
7
+ *
8
+ * We perform atomic bit set and bit clear operations using "lock bts"
9
+ * and "lock btr".  We use the output constraint to inform the
10
+ * compiler that any memory from the start of the bit field up to and
11
+ * including the byte containing the bit may be modified.  (This is
12
+ * overkill but shouldn't matter in practice since we're unlikely to
13
+ * subsequently read other bits from the same bit field.)
14
+ */
15
+
16
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
17
+
18
+#include <stdint.h>
19
+
20
+/**
21
+ * Set bit atomically
22
+ *
23
+ * @v bit		Bit to set
24
+ * @v bits		Bit field
25
+ */
26
+static inline __attribute__ (( always_inline )) void
27
+set_bit ( unsigned int bit, volatile void *bits ) {
28
+	volatile struct {
29
+		uint8_t byte[ ( bit / 8 ) + 1 ];
30
+	} *bytes = bits;
31
+
32
+	__asm__ __volatile__ ( "lock bts %1, %0"
33
+			       : "+m" ( *bytes ) : "Ir" ( bit ) );
34
+}
35
+
36
+/**
37
+ * Clear bit atomically
38
+ *
39
+ * @v bit		Bit to set
40
+ * @v bits		Bit field
41
+ */
42
+static inline __attribute__ (( always_inline )) void
43
+clear_bit ( unsigned int bit, volatile void *bits ) {
44
+	volatile struct {
45
+		uint8_t byte[ ( bit / 8 ) + 1 ];
46
+	} *bytes = bits;
47
+
48
+	__asm__ __volatile__ ( "lock btr %1, %0"
49
+			       : "+m" ( *bytes ) : "Ir" ( bit ) );
50
+}
51
+
52
+/**
53
+ * Test and set bit atomically
54
+ *
55
+ * @v bit		Bit to set
56
+ * @v bits		Bit field
57
+ * @ret old		Old value of bit (zero or non-zero)
58
+ */
59
+static inline __attribute__ (( always_inline )) int
60
+test_and_set_bit ( unsigned int bit, volatile void *bits ) {
61
+	volatile struct {
62
+		uint8_t byte[ ( bit / 8 ) + 1 ];
63
+	} *bytes = bits;
64
+	int old;
65
+
66
+	__asm__ __volatile__ ( "lock bts %2, %0\n\t"
67
+			       "sbb %1, %1\n\t"
68
+			       : "+m" ( *bytes ), "=r"  ( old )
69
+			       : "Ir" ( bit ) );
70
+	return old;
71
+}
72
+
73
+/**
74
+ * Test and clear bit atomically
75
+ *
76
+ * @v bit		Bit to set
77
+ * @v bits		Bit field
78
+ * @ret old		Old value of bit (zero or non-zero)
79
+ */
80
+static inline __attribute__ (( always_inline )) int
81
+test_and_clear_bit ( unsigned int bit, volatile void *bits ) {
82
+	volatile struct {
83
+		uint8_t byte[ ( bit / 8 ) + 1 ];
84
+	} *bytes = bits;
85
+	int old;
86
+
87
+	__asm__ __volatile__ ( "lock btr %2, %0\n\t"
88
+			       "sbb %1, %1\n\t"
89
+			       : "+m" ( *bytes ), "=r"  ( old )
90
+			       : "Ir" ( bit ) );
91
+	return old;
92
+}
93
+
94
+#endif /* _BITS_BITOPS_H */

+ 19
- 0
src/include/ipxe/bitops.h View File

@@ -0,0 +1,19 @@
1
+#ifndef _IPXE_BITOPS_H
2
+#define _IPXE_BITOPS_H
3
+
4
+/** @file
5
+ *
6
+ * Bit operations
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
11
+
12
+#include <bits/bitops.h>
13
+
14
+void set_bit ( unsigned int bit, volatile void *bits );
15
+void clear_bit ( unsigned int bit, volatile void *bits );
16
+int test_and_set_bit ( unsigned int bit, volatile void *bits );
17
+int test_and_clear_bit ( unsigned int bit, volatile void *bits );
18
+
19
+#endif /* _IPXE_BITOPS_H */

+ 102
- 0
src/tests/bitops_test.c View File

@@ -0,0 +1,102 @@
1
+/*
2
+ * Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or (at your option) any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ *
19
+ * You can also choose to distribute this program under the terms of
20
+ * the Unmodified Binary Distribution Licence (as given in the file
21
+ * COPYING.UBDL), provided that you have satisfied its requirements.
22
+ */
23
+
24
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
+
26
+/** @file
27
+ *
28
+ * Bit operations self-tests
29
+ *
30
+ */
31
+
32
+/* Forcibly enable assertions */
33
+#undef NDEBUG
34
+
35
+#include <stdint.h>
36
+#include <string.h>
37
+#include <assert.h>
38
+#include <ipxe/bitops.h>
39
+#include <ipxe/test.h>
40
+
41
+/**
42
+ * Perform bit operations self-tests
43
+ *
44
+ */
45
+static void bitops_test_exec ( void ) {
46
+	uint8_t bits[32];
47
+
48
+	/* Initialise bits */
49
+	memset ( bits, 0, sizeof ( bits ) );
50
+
51
+	/* Test set_bit() */
52
+	set_bit ( 0, bits );
53
+	ok ( bits[0] == 0x01 );
54
+	set_bit ( 17, bits );
55
+	ok ( bits[2] == 0x02 );
56
+	set_bit ( 22, bits );
57
+	ok ( bits[2] == 0x42 );
58
+	set_bit ( 22, bits );
59
+	ok ( bits[2] == 0x42 );
60
+
61
+	/* Test clear_bit() */
62
+	clear_bit ( 0, bits );
63
+	ok ( bits[5] == 0x00 );
64
+	bits[5] = 0xff;
65
+	clear_bit ( 42, bits );
66
+	ok ( bits[5] == 0xfb );
67
+	clear_bit ( 42, bits );
68
+	ok ( bits[5] == 0xfb );
69
+	clear_bit ( 44, bits );
70
+	ok ( bits[5] == 0xeb );
71
+
72
+	/* Test test_and_set_bit() */
73
+	ok ( test_and_set_bit ( 0, bits ) == 0 );
74
+	ok ( bits[0] == 0x01 );
75
+	ok ( test_and_set_bit ( 0, bits ) != 0 );
76
+	ok ( bits[0] == 0x01 );
77
+	ok ( test_and_set_bit ( 69, bits ) == 0 );
78
+	ok ( bits[8] == 0x20 );
79
+	ok ( test_and_set_bit ( 69, bits ) != 0 );
80
+	ok ( bits[8] == 0x20 );
81
+	ok ( test_and_set_bit ( 69, bits ) != 0 );
82
+	ok ( bits[8] == 0x20 );
83
+
84
+	/* Test test_and_clear_bit() */
85
+	ok ( test_and_clear_bit ( 0, bits ) != 0 );
86
+	ok ( bits[0] == 0x00 );
87
+	ok ( test_and_clear_bit ( 0, bits ) == 0 );
88
+	ok ( bits[0] == 0x00 );
89
+	bits[31] = 0xeb;
90
+	ok ( test_and_clear_bit ( 255, bits ) != 0 );
91
+	ok ( bits[31] == 0x6b );
92
+	ok ( test_and_clear_bit ( 255, bits ) == 0 );
93
+	ok ( bits[31] == 0x6b );
94
+	ok ( test_and_clear_bit ( 255, bits ) == 0 );
95
+	ok ( bits[31] == 0x6b );
96
+}
97
+
98
+/** Bit operations self-test */
99
+struct self_test bitops_test __self_test = {
100
+	.name = "bitops",
101
+	.exec = bitops_test_exec,
102
+};

+ 1
- 0
src/tests/tests.c View File

@@ -68,3 +68,4 @@ REQUIRE_OBJECT ( setjmp_test );
68 68
 REQUIRE_OBJECT ( pccrc_test );
69 69
 REQUIRE_OBJECT ( linebuf_test );
70 70
 REQUIRE_OBJECT ( iobuf_test );
71
+REQUIRE_OBJECT ( bitops_test );

Loading…
Cancel
Save