| 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	__percpu (%rsi), %rax | 
|---|
| 27 | jne	.Lnot_same | 
|---|
| 28 | cmpq	__percpu 8(%rsi), %rdx | 
|---|
| 29 | jne	.Lnot_same | 
|---|
| 30 |  | 
|---|
| 31 | /* *ptr = new */ | 
|---|
| 32 | movq	%rbx, __percpu (%rsi) | 
|---|
| 33 | movq	%rcx, __percpu 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	__percpu (%rsi), %rax | 
|---|
| 46 | movq	__percpu 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) | 
|---|
| 55 |  | 
|---|