162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Crypto library utility functions 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <asm/unaligned.h> 962306a36Sopenharmony_ci#include <crypto/utils.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci/* 1362306a36Sopenharmony_ci * XOR @len bytes from @src1 and @src2 together, writing the result to @dst 1462306a36Sopenharmony_ci * (which may alias one of the sources). Don't call this directly; call 1562306a36Sopenharmony_ci * crypto_xor() or crypto_xor_cpy() instead. 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_civoid __crypto_xor(u8 *dst, const u8 *src1, const u8 *src2, unsigned int len) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci int relalign = 0; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) { 2262306a36Sopenharmony_ci int size = sizeof(unsigned long); 2362306a36Sopenharmony_ci int d = (((unsigned long)dst ^ (unsigned long)src1) | 2462306a36Sopenharmony_ci ((unsigned long)dst ^ (unsigned long)src2)) & 2562306a36Sopenharmony_ci (size - 1); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci relalign = d ? 1 << __ffs(d) : size; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci /* 3062306a36Sopenharmony_ci * If we care about alignment, process as many bytes as 3162306a36Sopenharmony_ci * needed to advance dst and src to values whose alignments 3262306a36Sopenharmony_ci * equal their relative alignment. This will allow us to 3362306a36Sopenharmony_ci * process the remainder of the input using optimal strides. 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_ci while (((unsigned long)dst & (relalign - 1)) && len > 0) { 3662306a36Sopenharmony_ci *dst++ = *src1++ ^ *src2++; 3762306a36Sopenharmony_ci len--; 3862306a36Sopenharmony_ci } 3962306a36Sopenharmony_ci } 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci while (IS_ENABLED(CONFIG_64BIT) && len >= 8 && !(relalign & 7)) { 4262306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) { 4362306a36Sopenharmony_ci u64 l = get_unaligned((u64 *)src1) ^ 4462306a36Sopenharmony_ci get_unaligned((u64 *)src2); 4562306a36Sopenharmony_ci put_unaligned(l, (u64 *)dst); 4662306a36Sopenharmony_ci } else { 4762306a36Sopenharmony_ci *(u64 *)dst = *(u64 *)src1 ^ *(u64 *)src2; 4862306a36Sopenharmony_ci } 4962306a36Sopenharmony_ci dst += 8; 5062306a36Sopenharmony_ci src1 += 8; 5162306a36Sopenharmony_ci src2 += 8; 5262306a36Sopenharmony_ci len -= 8; 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci while (len >= 4 && !(relalign & 3)) { 5662306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) { 5762306a36Sopenharmony_ci u32 l = get_unaligned((u32 *)src1) ^ 5862306a36Sopenharmony_ci get_unaligned((u32 *)src2); 5962306a36Sopenharmony_ci put_unaligned(l, (u32 *)dst); 6062306a36Sopenharmony_ci } else { 6162306a36Sopenharmony_ci *(u32 *)dst = *(u32 *)src1 ^ *(u32 *)src2; 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci dst += 4; 6462306a36Sopenharmony_ci src1 += 4; 6562306a36Sopenharmony_ci src2 += 4; 6662306a36Sopenharmony_ci len -= 4; 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci while (len >= 2 && !(relalign & 1)) { 7062306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) { 7162306a36Sopenharmony_ci u16 l = get_unaligned((u16 *)src1) ^ 7262306a36Sopenharmony_ci get_unaligned((u16 *)src2); 7362306a36Sopenharmony_ci put_unaligned(l, (u16 *)dst); 7462306a36Sopenharmony_ci } else { 7562306a36Sopenharmony_ci *(u16 *)dst = *(u16 *)src1 ^ *(u16 *)src2; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci dst += 2; 7862306a36Sopenharmony_ci src1 += 2; 7962306a36Sopenharmony_ci src2 += 2; 8062306a36Sopenharmony_ci len -= 2; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci while (len--) 8462306a36Sopenharmony_ci *dst++ = *src1++ ^ *src2++; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__crypto_xor); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 89