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