linux kernel 中的 CPU指令cmpxchg函数=分析

2700阅读 0评论2013-12-08 embeddedlwp
分类:LINUX

  在Linux内核中,提供了比较交换的函数cmpxchg,代码在include/asm-i386/cmpxchg.h中,函数的原型是:
[code]
  cmpxchg ( void *ptr, unsigned long old, unsigned long new);
[/code]

 函数作用:将old和ptr指向内容作比较,如果相等那么将new写入ptr中,返回old;否则,不行等就返回ptr的内容。EAX是提供返回使用的。
[code]
#define cmpxchg(ptr,o,n)\
    ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
                    (unsigned long)(n),sizeof(*(ptr))))[/code]
[code]
static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
                      unsigned long new, int size)
{
    unsigned long prev;
    switch (size) {
    case 1:
        __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2" 
                     : "=a"(prev)
                     : "q"(new), "m"(*__xg(ptr)), "0"(old)
                     : "memory");
        return prev;
    case 2:
        __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
         : "=a"(prev)
                     : "r"(new), "m"(*__xg(ptr)), "0"(old)
                     : "memory");
        return prev;
    case 4:
        __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
                     : "=a"(prev)
                     : "r"(new), "m"(*__xg(ptr)), "0"(old)
                     : "memory");
        return prev;
    }
    return old;
}
[/code]
以2字节交换为例,主要的操作就是汇编指令cmpxchgw %1,%2,注意一下其中的%2,也就是后面的"m"(*__xg(ptr))。
__xg是在这个文件中定义的宏:
struct __xchg_dummy { unsigned long a[100]; };
#define __xg(x) ((struct __xchg_dummy *)(x))
那么%2经过预处理,展开就是"m"(*((struct __xchg_dummy *)(ptr))),这种做法,就可以达到在cmpxchg中的%2是一个地址,就是ptr指向的地址。如果%2是"m"(ptr),那么指针本身的值就出现在cmpxchg指令中。

 奔腾指令:

Opcode   Instruction   64-Bit Mode  Compat/     Description
                                   Leg Mode
 
0F B1/r  CMPXCHG r/m16, r16  Valid   Valid*      Compare AX with r/m16. If
                                               equal, ZF is set and r16 is
                                                 loaded into r/m16. Else,
                                                  clear ZF and load r/m16
                                                  into AX.

 

cmpxchg bx, cx:
如果AX与BX相等,则CX送BX且ZF置1;否则BX送AX,且ZF清0
 换成AT&T的格式就是
由于ATT汇编与Intel不同,操作数2,和操作数1互换。
cmpxchg %cx, %bx;
送入AX,再看AX就是prev。

上一篇:内核poll和select系统调用的图解(1)-poll系统调用的整体结构图
下一篇:do_vmx_vcpu_run函数实现了VM entry和VM exit的处理