162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci#include <linux/linkage.h> 362306a36Sopenharmony_ci#include <asm/percpu.h> 462306a36Sopenharmony_ci#include <asm/processor-flags.h> 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci.text 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/* 962306a36Sopenharmony_ci * Emulate 'cmpxchg16b %gs:(%rsi)' 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Inputs: 1262306a36Sopenharmony_ci * %rsi : memory location to compare 1362306a36Sopenharmony_ci * %rax : low 64 bits of old value 1462306a36Sopenharmony_ci * %rdx : high 64 bits of old value 1562306a36Sopenharmony_ci * %rbx : low 64 bits of new value 1662306a36Sopenharmony_ci * %rcx : high 64 bits of new value 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * Notably this is not LOCK prefixed and is not safe against NMIs 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_ciSYM_FUNC_START(this_cpu_cmpxchg16b_emu) 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci pushfq 2362306a36Sopenharmony_ci cli 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci /* if (*ptr == old) */ 2662306a36Sopenharmony_ci cmpq PER_CPU_VAR(0(%rsi)), %rax 2762306a36Sopenharmony_ci jne .Lnot_same 2862306a36Sopenharmony_ci cmpq PER_CPU_VAR(8(%rsi)), %rdx 2962306a36Sopenharmony_ci jne .Lnot_same 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci /* *ptr = new */ 3262306a36Sopenharmony_ci movq %rbx, PER_CPU_VAR(0(%rsi)) 3362306a36Sopenharmony_ci movq %rcx, PER_CPU_VAR(8(%rsi)) 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci /* set ZF in EFLAGS to indicate success */ 3662306a36Sopenharmony_ci orl $X86_EFLAGS_ZF, (%rsp) 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci popfq 3962306a36Sopenharmony_ci RET 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci.Lnot_same: 4262306a36Sopenharmony_ci /* *ptr != old */ 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci /* old = *ptr */ 4562306a36Sopenharmony_ci movq PER_CPU_VAR(0(%rsi)), %rax 4662306a36Sopenharmony_ci movq PER_CPU_VAR(8(%rsi)), %rdx 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* clear ZF in EFLAGS to indicate failure */ 4962306a36Sopenharmony_ci andl $(~X86_EFLAGS_ZF), (%rsp) 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci popfq 5262306a36Sopenharmony_ci RET 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ciSYM_FUNC_END(this_cpu_cmpxchg16b_emu) 55