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