18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* Copyright(c) 2016-2020 Intel Corporation. All rights reserved. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/linkage.h> 58c2ecf20Sopenharmony_ci#include <asm/copy_mc_test.h> 68c2ecf20Sopenharmony_ci#include <asm/export.h> 78c2ecf20Sopenharmony_ci#include <asm/asm.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#ifndef CONFIG_UML 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_MCE 128c2ecf20Sopenharmony_ciCOPY_MC_TEST_CTL 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/* 158c2ecf20Sopenharmony_ci * copy_mc_fragile - copy memory with indication if an exception / fault happened 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * The 'fragile' version is opted into by platform quirks and takes 188c2ecf20Sopenharmony_ci * pains to avoid unrecoverable corner cases like 'fast-string' 198c2ecf20Sopenharmony_ci * instruction sequences, and consuming poison across a cacheline 208c2ecf20Sopenharmony_ci * boundary. The non-fragile version is equivalent to memcpy() 218c2ecf20Sopenharmony_ci * regardless of CPU machine-check-recovery capability. 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_ciSYM_FUNC_START(copy_mc_fragile) 248c2ecf20Sopenharmony_ci cmpl $8, %edx 258c2ecf20Sopenharmony_ci /* Less than 8 bytes? Go to byte copy loop */ 268c2ecf20Sopenharmony_ci jb .L_no_whole_words 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci /* Check for bad alignment of source */ 298c2ecf20Sopenharmony_ci testl $7, %esi 308c2ecf20Sopenharmony_ci /* Already aligned */ 318c2ecf20Sopenharmony_ci jz .L_8byte_aligned 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci /* Copy one byte at a time until source is 8-byte aligned */ 348c2ecf20Sopenharmony_ci movl %esi, %ecx 358c2ecf20Sopenharmony_ci andl $7, %ecx 368c2ecf20Sopenharmony_ci subl $8, %ecx 378c2ecf20Sopenharmony_ci negl %ecx 388c2ecf20Sopenharmony_ci subl %ecx, %edx 398c2ecf20Sopenharmony_ci.L_read_leading_bytes: 408c2ecf20Sopenharmony_ci movb (%rsi), %al 418c2ecf20Sopenharmony_ci COPY_MC_TEST_SRC %rsi 1 .E_leading_bytes 428c2ecf20Sopenharmony_ci COPY_MC_TEST_DST %rdi 1 .E_leading_bytes 438c2ecf20Sopenharmony_ci.L_write_leading_bytes: 448c2ecf20Sopenharmony_ci movb %al, (%rdi) 458c2ecf20Sopenharmony_ci incq %rsi 468c2ecf20Sopenharmony_ci incq %rdi 478c2ecf20Sopenharmony_ci decl %ecx 488c2ecf20Sopenharmony_ci jnz .L_read_leading_bytes 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci.L_8byte_aligned: 518c2ecf20Sopenharmony_ci movl %edx, %ecx 528c2ecf20Sopenharmony_ci andl $7, %edx 538c2ecf20Sopenharmony_ci shrl $3, %ecx 548c2ecf20Sopenharmony_ci jz .L_no_whole_words 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci.L_read_words: 578c2ecf20Sopenharmony_ci movq (%rsi), %r8 588c2ecf20Sopenharmony_ci COPY_MC_TEST_SRC %rsi 8 .E_read_words 598c2ecf20Sopenharmony_ci COPY_MC_TEST_DST %rdi 8 .E_write_words 608c2ecf20Sopenharmony_ci.L_write_words: 618c2ecf20Sopenharmony_ci movq %r8, (%rdi) 628c2ecf20Sopenharmony_ci addq $8, %rsi 638c2ecf20Sopenharmony_ci addq $8, %rdi 648c2ecf20Sopenharmony_ci decl %ecx 658c2ecf20Sopenharmony_ci jnz .L_read_words 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci /* Any trailing bytes? */ 688c2ecf20Sopenharmony_ci.L_no_whole_words: 698c2ecf20Sopenharmony_ci andl %edx, %edx 708c2ecf20Sopenharmony_ci jz .L_done_memcpy_trap 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci /* Copy trailing bytes */ 738c2ecf20Sopenharmony_ci movl %edx, %ecx 748c2ecf20Sopenharmony_ci.L_read_trailing_bytes: 758c2ecf20Sopenharmony_ci movb (%rsi), %al 768c2ecf20Sopenharmony_ci COPY_MC_TEST_SRC %rsi 1 .E_trailing_bytes 778c2ecf20Sopenharmony_ci COPY_MC_TEST_DST %rdi 1 .E_trailing_bytes 788c2ecf20Sopenharmony_ci.L_write_trailing_bytes: 798c2ecf20Sopenharmony_ci movb %al, (%rdi) 808c2ecf20Sopenharmony_ci incq %rsi 818c2ecf20Sopenharmony_ci incq %rdi 828c2ecf20Sopenharmony_ci decl %ecx 838c2ecf20Sopenharmony_ci jnz .L_read_trailing_bytes 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci /* Copy successful. Return zero */ 868c2ecf20Sopenharmony_ci.L_done_memcpy_trap: 878c2ecf20Sopenharmony_ci xorl %eax, %eax 888c2ecf20Sopenharmony_ci.L_done: 898c2ecf20Sopenharmony_ci RET 908c2ecf20Sopenharmony_ciSYM_FUNC_END(copy_mc_fragile) 918c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(copy_mc_fragile) 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci .section .fixup, "ax" 948c2ecf20Sopenharmony_ci /* 958c2ecf20Sopenharmony_ci * Return number of bytes not copied for any failure. Note that 968c2ecf20Sopenharmony_ci * there is no "tail" handling since the source buffer is 8-byte 978c2ecf20Sopenharmony_ci * aligned and poison is cacheline aligned. 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_ci.E_read_words: 1008c2ecf20Sopenharmony_ci shll $3, %ecx 1018c2ecf20Sopenharmony_ci.E_leading_bytes: 1028c2ecf20Sopenharmony_ci addl %edx, %ecx 1038c2ecf20Sopenharmony_ci.E_trailing_bytes: 1048c2ecf20Sopenharmony_ci mov %ecx, %eax 1058c2ecf20Sopenharmony_ci jmp .L_done 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* 1088c2ecf20Sopenharmony_ci * For write fault handling, given the destination is unaligned, 1098c2ecf20Sopenharmony_ci * we handle faults on multi-byte writes with a byte-by-byte 1108c2ecf20Sopenharmony_ci * copy up to the write-protected page. 1118c2ecf20Sopenharmony_ci */ 1128c2ecf20Sopenharmony_ci.E_write_words: 1138c2ecf20Sopenharmony_ci shll $3, %ecx 1148c2ecf20Sopenharmony_ci addl %edx, %ecx 1158c2ecf20Sopenharmony_ci movl %ecx, %edx 1168c2ecf20Sopenharmony_ci jmp copy_mc_fragile_handle_tail 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci .previous 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci _ASM_EXTABLE_FAULT(.L_read_leading_bytes, .E_leading_bytes) 1218c2ecf20Sopenharmony_ci _ASM_EXTABLE_FAULT(.L_read_words, .E_read_words) 1228c2ecf20Sopenharmony_ci _ASM_EXTABLE_FAULT(.L_read_trailing_bytes, .E_trailing_bytes) 1238c2ecf20Sopenharmony_ci _ASM_EXTABLE(.L_write_leading_bytes, .E_leading_bytes) 1248c2ecf20Sopenharmony_ci _ASM_EXTABLE(.L_write_words, .E_write_words) 1258c2ecf20Sopenharmony_ci _ASM_EXTABLE(.L_write_trailing_bytes, .E_trailing_bytes) 1268c2ecf20Sopenharmony_ci#endif /* CONFIG_X86_MCE */ 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci/* 1298c2ecf20Sopenharmony_ci * copy_mc_enhanced_fast_string - memory copy with exception handling 1308c2ecf20Sopenharmony_ci * 1318c2ecf20Sopenharmony_ci * Fast string copy + fault / exception handling. If the CPU does 1328c2ecf20Sopenharmony_ci * support machine check exception recovery, but does not support 1338c2ecf20Sopenharmony_ci * recovering from fast-string exceptions then this CPU needs to be 1348c2ecf20Sopenharmony_ci * added to the copy_mc_fragile_key set of quirks. Otherwise, absent any 1358c2ecf20Sopenharmony_ci * machine check recovery support this version should be no slower than 1368c2ecf20Sopenharmony_ci * standard memcpy. 1378c2ecf20Sopenharmony_ci */ 1388c2ecf20Sopenharmony_ciSYM_FUNC_START(copy_mc_enhanced_fast_string) 1398c2ecf20Sopenharmony_ci movq %rdi, %rax 1408c2ecf20Sopenharmony_ci movq %rdx, %rcx 1418c2ecf20Sopenharmony_ci.L_copy: 1428c2ecf20Sopenharmony_ci rep movsb 1438c2ecf20Sopenharmony_ci /* Copy successful. Return zero */ 1448c2ecf20Sopenharmony_ci xorl %eax, %eax 1458c2ecf20Sopenharmony_ci RET 1468c2ecf20Sopenharmony_ciSYM_FUNC_END(copy_mc_enhanced_fast_string) 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci .section .fixup, "ax" 1498c2ecf20Sopenharmony_ci.E_copy: 1508c2ecf20Sopenharmony_ci /* 1518c2ecf20Sopenharmony_ci * On fault %rcx is updated such that the copy instruction could 1528c2ecf20Sopenharmony_ci * optionally be restarted at the fault position, i.e. it 1538c2ecf20Sopenharmony_ci * contains 'bytes remaining'. A non-zero return indicates error 1548c2ecf20Sopenharmony_ci * to copy_mc_generic() users, or indicate short transfers to 1558c2ecf20Sopenharmony_ci * user-copy routines. 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_ci movq %rcx, %rax 1588c2ecf20Sopenharmony_ci RET 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci .previous 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci _ASM_EXTABLE_FAULT(.L_copy, .E_copy) 1638c2ecf20Sopenharmony_ci#endif /* !CONFIG_UML */ 164