GNU Linux-libre 6.8.9-gnu
[releases.git] / arch / x86 / lib / cmpxchg16b_emu.S
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 #include <linux/linkage.h>
3 #include <asm/percpu.h>
4 #include <asm/processor-flags.h>
5
6 .text
7
8 /*
9  * Emulate 'cmpxchg16b %gs:(%rsi)'
10  *
11  * Inputs:
12  * %rsi : memory location to compare
13  * %rax : low 64 bits of old value
14  * %rdx : high 64 bits of old value
15  * %rbx : low 64 bits of new value
16  * %rcx : high 64 bits of new value
17  *
18  * Notably this is not LOCK prefixed and is not safe against NMIs
19  */
20 SYM_FUNC_START(this_cpu_cmpxchg16b_emu)
21
22         pushfq
23         cli
24
25         /* if (*ptr == old) */
26         cmpq    PER_CPU_VAR(0(%rsi)), %rax
27         jne     .Lnot_same
28         cmpq    PER_CPU_VAR(8(%rsi)), %rdx
29         jne     .Lnot_same
30
31         /* *ptr = new */
32         movq    %rbx, PER_CPU_VAR(0(%rsi))
33         movq    %rcx, PER_CPU_VAR(8(%rsi))
34
35         /* set ZF in EFLAGS to indicate success */
36         orl     $X86_EFLAGS_ZF, (%rsp)
37
38         popfq
39         RET
40
41 .Lnot_same:
42         /* *ptr != old */
43
44         /* old = *ptr */
45         movq    PER_CPU_VAR(0(%rsi)), %rax
46         movq    PER_CPU_VAR(8(%rsi)), %rdx
47
48         /* clear ZF in EFLAGS to indicate failure */
49         andl    $(~X86_EFLAGS_ZF), (%rsp)
50
51         popfq
52         RET
53
54 SYM_FUNC_END(this_cpu_cmpxchg16b_emu)