kernel: Move GPL'd kernel files to sys/gnu to have them all in one place.
[dragonfly.git] / sys / gnu / vfs / ext2fs / i386-bitops.h
1 /*
2  * $FreeBSD: src/sys/gnu/ext2fs/i386-bitops.h,v 1.5 1999/11/15 23:16:06 obrien Exp $
3  */
4 /*
5  * this is mixture of i386/bitops.h and asm/string.h
6  * taken from the Linux source tree
7  *
8  * XXX replace with Mach routines or reprogram in C
9  */
10 #ifndef _VFS_GNU_EXT2FS_I386_BITOPS_H_
11 #define _VFS_GNU_EXT2FS_I386_BITOPS_H_
12
13 /*
14  * Copyright 1992, Linus Torvalds.
15  */
16
17 /*
18  * These have to be done with inline assembly: that way the bit-setting
19  * is guaranteed to be atomic. All bit operations return 0 if the bit
20  * was cleared before the operation and != 0 if it was not.
21  *
22  * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
23  */
24
25 /*
26  * Some hacks to defeat gcc over-optimizations..
27  */
28 struct __dummy { unsigned long a[100]; };
29 #define ADDR (*(struct __dummy *) addr)
30
31 static __inline__ int
32 set_bit(int nr, void *addr)
33 {
34         int oldbit;
35
36         __asm__ __volatile__("btsl %2,%1\n\tsbbl %0,%0"
37                 :"=r" (oldbit),"=m" (ADDR)
38                 :"ir" (nr));
39         return oldbit;
40 }
41
42 static __inline__ int
43 clear_bit(int nr, void *addr)
44 {
45         int oldbit;
46
47         __asm__ __volatile__("btrl %2,%1\n\tsbbl %0,%0"
48                 :"=r" (oldbit),"=m" (ADDR)
49                 :"ir" (nr));
50         return oldbit;
51 }
52
53 static __inline__ int
54 change_bit(int nr, void *addr)
55 {
56         int oldbit;
57
58         __asm__ __volatile__("btcl %2,%1\n\tsbbl %0,%0"
59                 :"=r" (oldbit),"=m" (ADDR)
60                 :"ir" (nr));
61         return oldbit;
62 }
63
64 /*
65  * This routine doesn't need to be atomic, but it's faster to code it
66  * this way.
67  */
68 static __inline__ int
69 test_bit(int nr, void *addr)
70 {
71         int oldbit;
72
73         __asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0"
74                 :"=r" (oldbit)
75                 :"m" (ADDR),"ir" (nr));
76         return oldbit;
77 }
78
79 /*
80  * Find-bit routines..
81  */
82 static __inline__ int
83 find_first_zero_bit(void *addr, unsigned size)
84 {
85         int res;
86         int _count = (size + 31) >> 5;
87
88         if (!size)
89                 return 0;
90         __asm__("                       \n\
91                 cld                     \n\
92                 movl $-1,%%eax          \n\
93                 xorl %%edx,%%edx        \n\
94                 repe; scasl             \n\
95                 je 1f                   \n\
96                 xorl -4(%%edi),%%eax    \n\
97                 subl $4,%%edi           \n\
98                 bsfl %%eax,%%edx        \n\
99 1:              subl %%ebx,%%edi        \n\
100                 shll $3,%%edi           \n\
101                 addl %%edi,%%edx"
102                 : "=c" (_count), "=D" (addr), "=d" (res)
103                 : "0" (_count), "1" (addr), "b" (addr)
104                 : "ax");
105         return res;
106 }
107
108 static __inline__ int
109 find_next_zero_bit(void *addr, int size, int offset)
110 {
111         unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
112         int set = 0, bit = offset & 31, res;
113
114         if (bit) {
115                 /*
116                  * Look for zero in first byte
117                  */
118                 __asm__("                       \n\
119                         bsfl %1,%0              \n\
120                         jne 1f                  \n\
121                         movl $32, %0            \n\
122 1:                      "
123                         : "=r" (set)
124                         : "r" (~(*p >> bit)));
125                 if (set < (32 - bit))
126                         return set + offset;
127                 set = 32 - bit;
128                 p++;
129         }
130         /*
131          * No zero yet, search remaining full bytes for a zero
132          */
133         res = find_first_zero_bit (p, size - 32 * (p - (unsigned long *) addr));
134         return (offset + set + res);
135 }
136
137 /*
138  * ffz = Find First Zero in word. Undefined if no zero exists,
139  * so code should check against ~0UL first..
140  */
141 static __inline__ unsigned long
142 ffz(unsigned long word)
143 {
144         __asm__("bsfl %1,%0"
145                 :"=r" (word)
146                 :"r" (~word));
147         return word;
148 }
149
150 /*
151  * memscan() taken from linux asm/string.h
152  */
153 /*
154  * find the first occurrence of byte 'c', or 1 past the area if none
155  */
156 static __inline__ char *
157 memscan(void *addr, unsigned char c, int size)
158 {
159         if (!size)
160                 return addr;
161         __asm__("                       \n\
162                 cld                     \n\
163                 repnz; scasb            \n\
164                 jnz 1f                  \n\
165                 dec %%edi               \n\
166 1:              "
167                 : "=D" (addr), "=c" (size)
168                 : "0" (addr), "1" (size), "a" (c));
169         return addr;
170 }
171
172 #endif /* _VFS_GNU_EXT2FS_I386_BITOPS_H_ */