关于linux bitops的使用

来源:互联网 发布:吴镇宇曹格 知乎 编辑:程序博客网 时间:2024/05/24 16:13
内核API没有通用的标准 即使在内核的文档和头文件也没详细给出
一个多平台开发中多处用到bitops   结果碰到许多问题

1
int find_first_zero_bit(void * addr, unsigned size);
int find_next_zero_bit(void * addr, int size, int offset);
找到0bit时,各平台都返回0~size-1
在x86下,没有找到0bit时,返回size
在arm下,没有找到0bit时,则返回size+1
所以通用的判断方法是,检查返回值是否>=size

2
test_bit
test_and_set_bit
test_and_clear_bit

0 bit 返回0是一定的
1 bit各个平台不一样  arm返回1  x86返回 ~0(全FF)
因此通用的检查方法是判断是0或者非0

3
2.6 引入了
find_first_bit
find_next_bit
用来查找1bit
内核头文件确实有了新的特性
但是在fc4的用户头文件中却没看到这个新特性,这个头文件在内核和用户空间不是应该一样么??

arm平台的uclinux中也没有,因此打算自己加上
它的实现在arch/armnommu/lib/findbits.S中

#include <linux/linkage.h>
#include <asm/assembler.h>
                .text

/*
 * Purpose  : Find a 'zero' bit
 * Prototype: int find_first_zero_bit(void *addr, int maxbit);
 */
ENTRY(find_first_zero_bit)
        mov    r2, #0
.bytelp:    ldrb    r3, [r0, r2, lsr #3]
        eors    r3, r3, #0xff        @ invert bits
        bne    .found            @ any now set - found zero bit
        add    r2, r2, #8        @ next bit pointer
        cmp    r2, r1            @ any more?
        bcc    .bytelp
        add    r0, r1, #1        @ no free bits
        RETINSTR(mov,pc,lr)

/*
 * Purpose  : Find next 'zero' bit
 * Prototype: int find_next_zero_bit(void *addr, int maxbit, int offset)
 */
ENTRY(find_next_zero_bit)
        ands    ip, r2, #7
        beq    .bytelp            @ If new byte, goto old routine
        ldrb    r3, [r0, r2, lsr#3]
        eor    r3, r3, #0xff        @ now looking for a 1 bit
        movs    r3, r3, lsr ip        @ shift off unused bits
        orreq    r2, r2, #7        @ if zero, then no bits here
        addeq    r2, r2, #1        @ align bit pointer
        beq    .bytelp            @ loop for next bit

/*
 * One or more bits in the LSB of r3 are assumed to be set.
 */
.found:        tst    r3, #0x0f
        addeq    r2, r2, #4
        movne    r3, r3, lsl #4
        tst    r3, #0x30
        addeq    r2, r2, #2
        movne    r3, r3, lsl #2
        tst    r3, #0x40
        addeq    r2, r2, #1
        mov    r0, r2
        RETINSTR(mov,pc,lr)

可以发现它的操作竟然是先将数字进行反转 即0->1 1->0后对1进行搜索
那简单的修改一下就应该能够搞定了
在代码后面加入下面代码


/*
 * Purpose  : Find a 'one' bit
 * Prototype: int find_first_bit(void *addr, int maxbit);
 */
ENTRY(find_first_bit)
        mov    r2, #0
.bbytelp:    ldrb    r3, [r0, r2, lsr #3]
        movs    r3, r3              // 将xor改成movs  触发标志寄存器 保证下面的bne正确跳转
        bne    .bfound            @ any now set - found zero bit
        add    r2, r2, #8        @ next bit pointer
        cmp    r2, r1            @ any more?
        bcc    .bbytelp
        add    r0, r1, #1        @ no free bits
        RETINSTR(mov,pc,lr)

/*
 * Purpose  : Find next 'one' bit
 * Prototype: int find_next_bit(void *addr, int maxbit, int offset)
 */
ENTRY(find_next_bit)
        ands    ip, r2, #7
        beq    .bbytelp            @ If new byte, goto old routine
        ldrb    r3, [r0, r2, lsr#3]
        movs    r3, r3, lsr ip        @ shift off unused bits
                                              // 去掉了xor
        orreq    r2, r2, #7        @ if zero, then no bits here
        addeq    r2, r2, #1        @ align bit pointer
        beq    .bbytelp            @ loop for next bit
/*
 * One or more bits in the LSB of r3 are assumed to be set.
 */
.bfound:    tst    r3, #0x0f
        addeq    r2, r2, #4
        movne    r3, r3, lsl #4
        tst    r3, #0x30
        addeq    r2, r2, #2
        movne    r3, r3, lsl #2
        tst    r3, #0x40
        addeq    r2, r2, #1
        mov    r0, r2
        RETINSTR(mov,pc,lr)