|  | /* | 
|  | * atomic64_t for 386/486 | 
|  | * | 
|  | * Copyright © 2010  Luca Barbieri | 
|  | * | 
|  | * This program is free software; you can redistribute it and/or modify | 
|  | * it under the terms of the GNU General Public License as published by | 
|  | * the Free Software Foundation; either version 2 of the License, or | 
|  | * (at your option) any later version. | 
|  | */ | 
|  |  | 
|  | #include <linux/linkage.h> | 
|  | #include <asm/alternative-asm.h> | 
|  | #include <asm/dwarf2.h> | 
|  |  | 
|  | /* if you want SMP support, implement these with real spinlocks */ | 
|  | .macro LOCK reg | 
|  | pushfl_cfi | 
|  | cli | 
|  | .endm | 
|  |  | 
|  | .macro UNLOCK reg | 
|  | popfl_cfi | 
|  | .endm | 
|  |  | 
|  | #define BEGIN(op) \ | 
|  | .macro endp; \ | 
|  | CFI_ENDPROC; \ | 
|  | ENDPROC(atomic64_##op##_386); \ | 
|  | .purgem endp; \ | 
|  | .endm; \ | 
|  | ENTRY(atomic64_##op##_386); \ | 
|  | CFI_STARTPROC; \ | 
|  | LOCK v; | 
|  |  | 
|  | #define ENDP endp | 
|  |  | 
|  | #define RET \ | 
|  | UNLOCK v; \ | 
|  | ret | 
|  |  | 
|  | #define RET_ENDP \ | 
|  | RET; \ | 
|  | ENDP | 
|  |  | 
|  | #define v %ecx | 
|  | BEGIN(read) | 
|  | movl  (v), %eax | 
|  | movl 4(v), %edx | 
|  | RET_ENDP | 
|  | #undef v | 
|  |  | 
|  | #define v %esi | 
|  | BEGIN(set) | 
|  | movl %ebx,  (v) | 
|  | movl %ecx, 4(v) | 
|  | RET_ENDP | 
|  | #undef v | 
|  |  | 
|  | #define v  %esi | 
|  | BEGIN(xchg) | 
|  | movl  (v), %eax | 
|  | movl 4(v), %edx | 
|  | movl %ebx,  (v) | 
|  | movl %ecx, 4(v) | 
|  | RET_ENDP | 
|  | #undef v | 
|  |  | 
|  | #define v %ecx | 
|  | BEGIN(add) | 
|  | addl %eax,  (v) | 
|  | adcl %edx, 4(v) | 
|  | RET_ENDP | 
|  | #undef v | 
|  |  | 
|  | #define v %ecx | 
|  | BEGIN(add_return) | 
|  | addl  (v), %eax | 
|  | adcl 4(v), %edx | 
|  | movl %eax,  (v) | 
|  | movl %edx, 4(v) | 
|  | RET_ENDP | 
|  | #undef v | 
|  |  | 
|  | #define v %ecx | 
|  | BEGIN(sub) | 
|  | subl %eax,  (v) | 
|  | sbbl %edx, 4(v) | 
|  | RET_ENDP | 
|  | #undef v | 
|  |  | 
|  | #define v %ecx | 
|  | BEGIN(sub_return) | 
|  | negl %edx | 
|  | negl %eax | 
|  | sbbl $0, %edx | 
|  | addl  (v), %eax | 
|  | adcl 4(v), %edx | 
|  | movl %eax,  (v) | 
|  | movl %edx, 4(v) | 
|  | RET_ENDP | 
|  | #undef v | 
|  |  | 
|  | #define v %esi | 
|  | BEGIN(inc) | 
|  | addl $1,  (v) | 
|  | adcl $0, 4(v) | 
|  | RET_ENDP | 
|  | #undef v | 
|  |  | 
|  | #define v %esi | 
|  | BEGIN(inc_return) | 
|  | movl  (v), %eax | 
|  | movl 4(v), %edx | 
|  | addl $1, %eax | 
|  | adcl $0, %edx | 
|  | movl %eax,  (v) | 
|  | movl %edx, 4(v) | 
|  | RET_ENDP | 
|  | #undef v | 
|  |  | 
|  | #define v %esi | 
|  | BEGIN(dec) | 
|  | subl $1,  (v) | 
|  | sbbl $0, 4(v) | 
|  | RET_ENDP | 
|  | #undef v | 
|  |  | 
|  | #define v %esi | 
|  | BEGIN(dec_return) | 
|  | movl  (v), %eax | 
|  | movl 4(v), %edx | 
|  | subl $1, %eax | 
|  | sbbl $0, %edx | 
|  | movl %eax,  (v) | 
|  | movl %edx, 4(v) | 
|  | RET_ENDP | 
|  | #undef v | 
|  |  | 
|  | #define v %esi | 
|  | BEGIN(add_unless) | 
|  | addl %eax, %ecx | 
|  | adcl %edx, %edi | 
|  | addl  (v), %eax | 
|  | adcl 4(v), %edx | 
|  | cmpl %eax, %ecx | 
|  | je 3f | 
|  | 1: | 
|  | movl %eax,  (v) | 
|  | movl %edx, 4(v) | 
|  | movl $1, %eax | 
|  | 2: | 
|  | RET | 
|  | 3: | 
|  | cmpl %edx, %edi | 
|  | jne 1b | 
|  | xorl %eax, %eax | 
|  | jmp 2b | 
|  | ENDP | 
|  | #undef v | 
|  |  | 
|  | #define v %esi | 
|  | BEGIN(inc_not_zero) | 
|  | movl  (v), %eax | 
|  | movl 4(v), %edx | 
|  | testl %eax, %eax | 
|  | je 3f | 
|  | 1: | 
|  | addl $1, %eax | 
|  | adcl $0, %edx | 
|  | movl %eax,  (v) | 
|  | movl %edx, 4(v) | 
|  | movl $1, %eax | 
|  | 2: | 
|  | RET | 
|  | 3: | 
|  | testl %edx, %edx | 
|  | jne 1b | 
|  | jmp 2b | 
|  | ENDP | 
|  | #undef v | 
|  |  | 
|  | #define v %esi | 
|  | BEGIN(dec_if_positive) | 
|  | movl  (v), %eax | 
|  | movl 4(v), %edx | 
|  | subl $1, %eax | 
|  | sbbl $0, %edx | 
|  | js 1f | 
|  | movl %eax,  (v) | 
|  | movl %edx, 4(v) | 
|  | 1: | 
|  | RET_ENDP | 
|  | #undef v |