xref: /openbmc/linux/arch/x86/lib/copy_mc_64.S (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
1ec6347bbSDan Williams/* SPDX-License-Identifier: GPL-2.0-only */
2ec6347bbSDan Williams/* Copyright(c) 2016-2020 Intel Corporation. All rights reserved. */
3ec6347bbSDan Williams
4ec6347bbSDan Williams#include <linux/linkage.h>
5ec6347bbSDan Williams#include <asm/asm.h>
6ec6347bbSDan Williams
7ec6347bbSDan Williams#ifndef CONFIG_UML
8ec6347bbSDan Williams
9ec6347bbSDan Williams#ifdef CONFIG_X86_MCE
10ec6347bbSDan Williams
11ec6347bbSDan Williams/*
12ec6347bbSDan Williams * copy_mc_fragile - copy memory with indication if an exception / fault happened
13ec6347bbSDan Williams *
14ec6347bbSDan Williams * The 'fragile' version is opted into by platform quirks and takes
15ec6347bbSDan Williams * pains to avoid unrecoverable corner cases like 'fast-string'
16ec6347bbSDan Williams * instruction sequences, and consuming poison across a cacheline
17ec6347bbSDan Williams * boundary. The non-fragile version is equivalent to memcpy()
18ec6347bbSDan Williams * regardless of CPU machine-check-recovery capability.
19ec6347bbSDan Williams */
20ec6347bbSDan WilliamsSYM_FUNC_START(copy_mc_fragile)
21ec6347bbSDan Williams	cmpl $8, %edx
22ec6347bbSDan Williams	/* Less than 8 bytes? Go to byte copy loop */
23ec6347bbSDan Williams	jb .L_no_whole_words
24ec6347bbSDan Williams
25ec6347bbSDan Williams	/* Check for bad alignment of source */
26ec6347bbSDan Williams	testl $7, %esi
27ec6347bbSDan Williams	/* Already aligned */
28ec6347bbSDan Williams	jz .L_8byte_aligned
29ec6347bbSDan Williams
30ec6347bbSDan Williams	/* Copy one byte at a time until source is 8-byte aligned */
31ec6347bbSDan Williams	movl %esi, %ecx
32ec6347bbSDan Williams	andl $7, %ecx
33ec6347bbSDan Williams	subl $8, %ecx
34ec6347bbSDan Williams	negl %ecx
35ec6347bbSDan Williams	subl %ecx, %edx
36ec6347bbSDan Williams.L_read_leading_bytes:
37ec6347bbSDan Williams	movb (%rsi), %al
38ec6347bbSDan Williams.L_write_leading_bytes:
39ec6347bbSDan Williams	movb %al, (%rdi)
40ec6347bbSDan Williams	incq %rsi
41ec6347bbSDan Williams	incq %rdi
42ec6347bbSDan Williams	decl %ecx
43ec6347bbSDan Williams	jnz .L_read_leading_bytes
44ec6347bbSDan Williams
45ec6347bbSDan Williams.L_8byte_aligned:
46ec6347bbSDan Williams	movl %edx, %ecx
47ec6347bbSDan Williams	andl $7, %edx
48ec6347bbSDan Williams	shrl $3, %ecx
49ec6347bbSDan Williams	jz .L_no_whole_words
50ec6347bbSDan Williams
51ec6347bbSDan Williams.L_read_words:
52ec6347bbSDan Williams	movq (%rsi), %r8
53ec6347bbSDan Williams.L_write_words:
54ec6347bbSDan Williams	movq %r8, (%rdi)
55ec6347bbSDan Williams	addq $8, %rsi
56ec6347bbSDan Williams	addq $8, %rdi
57ec6347bbSDan Williams	decl %ecx
58ec6347bbSDan Williams	jnz .L_read_words
59ec6347bbSDan Williams
60ec6347bbSDan Williams	/* Any trailing bytes? */
61ec6347bbSDan Williams.L_no_whole_words:
62ec6347bbSDan Williams	andl %edx, %edx
63ec6347bbSDan Williams	jz .L_done_memcpy_trap
64ec6347bbSDan Williams
65ec6347bbSDan Williams	/* Copy trailing bytes */
66ec6347bbSDan Williams	movl %edx, %ecx
67ec6347bbSDan Williams.L_read_trailing_bytes:
68ec6347bbSDan Williams	movb (%rsi), %al
69ec6347bbSDan Williams.L_write_trailing_bytes:
70ec6347bbSDan Williams	movb %al, (%rdi)
71ec6347bbSDan Williams	incq %rsi
72ec6347bbSDan Williams	incq %rdi
73ec6347bbSDan Williams	decl %ecx
74ec6347bbSDan Williams	jnz .L_read_trailing_bytes
75ec6347bbSDan Williams
76ec6347bbSDan Williams	/* Copy successful. Return zero */
77ec6347bbSDan Williams.L_done_memcpy_trap:
78ec6347bbSDan Williams	xorl %eax, %eax
79ec6347bbSDan Williams.L_done:
80f94909ceSPeter Zijlstra	RET
81ec6347bbSDan Williams
82ec6347bbSDan Williams	/*
83ec6347bbSDan Williams	 * Return number of bytes not copied for any failure. Note that
84ec6347bbSDan Williams	 * there is no "tail" handling since the source buffer is 8-byte
85ec6347bbSDan Williams	 * aligned and poison is cacheline aligned.
86ec6347bbSDan Williams	 */
87ec6347bbSDan Williams.E_read_words:
88ec6347bbSDan Williams	shll	$3, %ecx
89ec6347bbSDan Williams.E_leading_bytes:
90ec6347bbSDan Williams	addl	%edx, %ecx
91ec6347bbSDan Williams.E_trailing_bytes:
92ec6347bbSDan Williams	mov	%ecx, %eax
93ec6347bbSDan Williams	jmp	.L_done
94ec6347bbSDan Williams
95ec6347bbSDan Williams	/*
96ec6347bbSDan Williams	 * For write fault handling, given the destination is unaligned,
97ec6347bbSDan Williams	 * we handle faults on multi-byte writes with a byte-by-byte
98ec6347bbSDan Williams	 * copy up to the write-protected page.
99ec6347bbSDan Williams	 */
100ec6347bbSDan Williams.E_write_words:
101ec6347bbSDan Williams	shll	$3, %ecx
102ec6347bbSDan Williams	addl	%edx, %ecx
103ec6347bbSDan Williams	movl	%ecx, %edx
104ec6347bbSDan Williams	jmp copy_mc_fragile_handle_tail
105ec6347bbSDan Williams
106c1c97d17SThomas Gleixner	_ASM_EXTABLE_TYPE(.L_read_leading_bytes, .E_leading_bytes, EX_TYPE_DEFAULT_MCE_SAFE)
107c1c97d17SThomas Gleixner	_ASM_EXTABLE_TYPE(.L_read_words, .E_read_words, EX_TYPE_DEFAULT_MCE_SAFE)
108c1c97d17SThomas Gleixner	_ASM_EXTABLE_TYPE(.L_read_trailing_bytes, .E_trailing_bytes, EX_TYPE_DEFAULT_MCE_SAFE)
109ec6347bbSDan Williams	_ASM_EXTABLE(.L_write_leading_bytes, .E_leading_bytes)
110ec6347bbSDan Williams	_ASM_EXTABLE(.L_write_words, .E_write_words)
111ec6347bbSDan Williams	_ASM_EXTABLE(.L_write_trailing_bytes, .E_trailing_bytes)
112*ab0fedccSPeter Zijlstra
113*ab0fedccSPeter ZijlstraSYM_FUNC_END(copy_mc_fragile)
114ec6347bbSDan Williams#endif /* CONFIG_X86_MCE */
1155da8e4a6SDan Williams
1165da8e4a6SDan Williams/*
1175da8e4a6SDan Williams * copy_mc_enhanced_fast_string - memory copy with exception handling
1185da8e4a6SDan Williams *
1195da8e4a6SDan Williams * Fast string copy + fault / exception handling. If the CPU does
1205da8e4a6SDan Williams * support machine check exception recovery, but does not support
1215da8e4a6SDan Williams * recovering from fast-string exceptions then this CPU needs to be
1225da8e4a6SDan Williams * added to the copy_mc_fragile_key set of quirks. Otherwise, absent any
1235da8e4a6SDan Williams * machine check recovery support this version should be no slower than
1245da8e4a6SDan Williams * standard memcpy.
1255da8e4a6SDan Williams */
1265da8e4a6SDan WilliamsSYM_FUNC_START(copy_mc_enhanced_fast_string)
1275da8e4a6SDan Williams	movq %rdi, %rax
1285da8e4a6SDan Williams	movq %rdx, %rcx
1295da8e4a6SDan Williams.L_copy:
1305da8e4a6SDan Williams	rep movsb
1315da8e4a6SDan Williams	/* Copy successful. Return zero */
1325da8e4a6SDan Williams	xorl %eax, %eax
133f94909ceSPeter Zijlstra	RET
1345da8e4a6SDan Williams
1355da8e4a6SDan Williams.E_copy:
1365da8e4a6SDan Williams	/*
1375da8e4a6SDan Williams	 * On fault %rcx is updated such that the copy instruction could
1385da8e4a6SDan Williams	 * optionally be restarted at the fault position, i.e. it
1395da8e4a6SDan Williams	 * contains 'bytes remaining'. A non-zero return indicates error
1405da8e4a6SDan Williams	 * to copy_mc_generic() users, or indicate short transfers to
1415da8e4a6SDan Williams	 * user-copy routines.
1425da8e4a6SDan Williams	 */
1435da8e4a6SDan Williams	movq %rcx, %rax
144f94909ceSPeter Zijlstra	RET
1455da8e4a6SDan Williams
146c1c97d17SThomas Gleixner	_ASM_EXTABLE_TYPE(.L_copy, .E_copy, EX_TYPE_DEFAULT_MCE_SAFE)
147*ab0fedccSPeter Zijlstra
148*ab0fedccSPeter ZijlstraSYM_FUNC_END(copy_mc_enhanced_fast_string)
149ec6347bbSDan Williams#endif /* !CONFIG_UML */
150