root/arch/x86/lib/atomic64_386_32.S
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * atomic64_t for 386/486
 *
 * Copyright © 2010  Luca Barbieri
 */

#include <linux/linkage.h>
#include <asm/alternative.h>

/* if you want SMP support, implement these with real spinlocks */
.macro IRQ_SAVE reg
        pushfl
        cli
.endm

.macro IRQ_RESTORE reg
        popfl
.endm

#define BEGIN_IRQ_SAVE(op) \
.macro endp; \
SYM_FUNC_END(atomic64_##op##_386); \
.purgem endp; \
.endm; \
SYM_FUNC_START(atomic64_##op##_386); \
        IRQ_SAVE v;

#define ENDP endp

#define RET_IRQ_RESTORE \
        IRQ_RESTORE v; \
        RET

#define v %ecx
BEGIN_IRQ_SAVE(read)
        movl  (v), %eax
        movl 4(v), %edx
        RET_IRQ_RESTORE
ENDP
#undef v

#define v %esi
BEGIN_IRQ_SAVE(set)
        movl %ebx,  (v)
        movl %ecx, 4(v)
        RET_IRQ_RESTORE
ENDP
#undef v

#define v  %esi
BEGIN_IRQ_SAVE(xchg)
        movl  (v), %eax
        movl 4(v), %edx
        movl %ebx,  (v)
        movl %ecx, 4(v)
        RET_IRQ_RESTORE
ENDP
#undef v

#define v %ecx
BEGIN_IRQ_SAVE(add)
        addl %eax,  (v)
        adcl %edx, 4(v)
        RET_IRQ_RESTORE
ENDP
#undef v

#define v %ecx
BEGIN_IRQ_SAVE(add_return)
        addl  (v), %eax
        adcl 4(v), %edx
        movl %eax,  (v)
        movl %edx, 4(v)
        RET_IRQ_RESTORE
ENDP
#undef v

#define v %ecx
BEGIN_IRQ_SAVE(sub)
        subl %eax,  (v)
        sbbl %edx, 4(v)
        RET_IRQ_RESTORE
ENDP
#undef v

#define v %ecx
BEGIN_IRQ_SAVE(sub_return)
        negl %edx
        negl %eax
        sbbl $0, %edx
        addl  (v), %eax
        adcl 4(v), %edx
        movl %eax,  (v)
        movl %edx, 4(v)
        RET_IRQ_RESTORE
ENDP
#undef v

#define v %esi
BEGIN_IRQ_SAVE(inc)
        addl $1,  (v)
        adcl $0, 4(v)
        RET_IRQ_RESTORE
ENDP
#undef v

#define v %esi
BEGIN_IRQ_SAVE(inc_return)
        movl  (v), %eax
        movl 4(v), %edx
        addl $1, %eax
        adcl $0, %edx
        movl %eax,  (v)
        movl %edx, 4(v)
        RET_IRQ_RESTORE
ENDP
#undef v

#define v %esi
BEGIN_IRQ_SAVE(dec)
        subl $1,  (v)
        sbbl $0, 4(v)
        RET_IRQ_RESTORE
ENDP
#undef v

#define v %esi
BEGIN_IRQ_SAVE(dec_return)
        movl  (v), %eax
        movl 4(v), %edx
        subl $1, %eax
        sbbl $0, %edx
        movl %eax,  (v)
        movl %edx, 4(v)
        RET_IRQ_RESTORE
ENDP
#undef v

#define v %esi
BEGIN_IRQ_SAVE(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_IRQ_RESTORE
3:
        cmpl %edx, %edi
        jne 1b
        xorl %eax, %eax
        jmp 2b
ENDP
#undef v

#define v %esi
BEGIN_IRQ_SAVE(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_IRQ_RESTORE
3:
        testl %edx, %edx
        jne 1b
        jmp 2b
ENDP
#undef v

#define v %esi
BEGIN_IRQ_SAVE(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_IRQ_RESTORE
ENDP
#undef v