/* | |
* 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_ADJUST_CFA_OFFSET 4 | |
cli | |
.endm | |
.macro UNLOCK reg | |
popfl | |
CFI_ADJUST_CFA_OFFSET -4 | |
.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 %ecx | |
BEGIN(add_unless) | |
addl %eax, %esi | |
adcl %edx, %edi | |
addl (v), %eax | |
adcl 4(v), %edx | |
cmpl %eax, %esi | |
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 |