/*1* Copyright (C) 2008-2009 Michal Simek <[email protected]>2* Copyright (C) 2008-2009 PetaLogix3* Copyright (C) 2007 John Williams4*5* Reasonably optimised generic C-code for memcpy on Microblaze6* This is generic C code to do efficient, alignment-aware memmove.7*8* It is based on demo code originally Copyright 2001 by Intel Corp, taken from9* http://www.embedded.com/showArticle.jhtml?articleID=1920556710*11* Attempts were made, unsuccessfully, to contact the original12* author of this code (Michael Morrow, Intel). Below is the original13* copyright notice.14*15* This software has been developed by Intel Corporation.16* Intel specifically disclaims all warranties, express or17* implied, and all liability, including consequential and18* other indirect damages, for the use of this program, including19* liability for infringement of any proprietary rights,20* and including the warranties of merchantability and fitness21* for a particular purpose. Intel does not assume any22* responsibility for and errors which may appear in this program23* not any responsibility to update it.24*/2526#include <linux/export.h>27#include <linux/types.h>28#include <linux/stddef.h>29#include <linux/compiler.h>30#include <linux/string.h>3132#ifdef CONFIG_OPT_LIB_FUNCTION33void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)34{35const char *src = v_src;36char *dst = v_dst;37const uint32_t *i_src;38uint32_t *i_dst;3940if (!c)41return v_dst;4243/* Use memcpy when source is higher than dest */44if (v_dst <= v_src)45return memcpy(v_dst, v_src, c);4647/* The following code tries to optimize the copy by using unsigned48* alignment. This will work fine if both source and destination are49* aligned on the same boundary. However, if they are aligned on50* different boundaries shifts will be necessary. This might result in51* bad performance on MicroBlaze systems without a barrel shifter.52*/53/* FIXME this part needs more test */54/* Do a descending copy - this is a bit trickier! */55dst += c;56src += c;5758if (c >= 4) {59unsigned value, buf_hold;6061/* Align the destination to a word boundary. */62/* This is done in an endian independent manner. */6364switch ((unsigned long)dst & 3) {65case 3:66*--dst = *--src;67--c;68fallthrough;69case 2:70*--dst = *--src;71--c;72fallthrough;73case 1:74*--dst = *--src;75--c;76}7778i_dst = (void *)dst;79/* Choose a copy scheme based on the source */80/* alignment relative to destination. */81switch ((unsigned long)src & 3) {82case 0x0: /* Both byte offsets are aligned */8384i_src = (const void *)src;8586for (; c >= 4; c -= 4)87*--i_dst = *--i_src;8889src = (const void *)i_src;90break;91case 0x1: /* Unaligned - Off by 1 */92/* Word align the source */93i_src = (const void *) (((unsigned)src + 4) & ~3);94#ifndef __MICROBLAZEEL__95/* Load the holding buffer */96buf_hold = *--i_src >> 24;9798for (; c >= 4; c -= 4) {99value = *--i_src;100*--i_dst = buf_hold << 8 | value;101buf_hold = value >> 24;102}103#else104/* Load the holding buffer */105buf_hold = (*--i_src & 0xFF) << 24;106107for (; c >= 4; c -= 4) {108value = *--i_src;109*--i_dst = buf_hold |110((value & 0xFFFFFF00) >> 8);111buf_hold = (value & 0xFF) << 24;112}113#endif114/* Realign the source */115src = (const void *)i_src;116src += 1;117break;118case 0x2: /* Unaligned - Off by 2 */119/* Word align the source */120i_src = (const void *) (((unsigned)src + 4) & ~3);121#ifndef __MICROBLAZEEL__122/* Load the holding buffer */123buf_hold = *--i_src >> 16;124125for (; c >= 4; c -= 4) {126value = *--i_src;127*--i_dst = buf_hold << 16 | value;128buf_hold = value >> 16;129}130#else131/* Load the holding buffer */132buf_hold = (*--i_src & 0xFFFF) << 16;133134for (; c >= 4; c -= 4) {135value = *--i_src;136*--i_dst = buf_hold |137((value & 0xFFFF0000) >> 16);138buf_hold = (value & 0xFFFF) << 16;139}140#endif141/* Realign the source */142src = (const void *)i_src;143src += 2;144break;145case 0x3: /* Unaligned - Off by 3 */146/* Word align the source */147i_src = (const void *) (((unsigned)src + 4) & ~3);148#ifndef __MICROBLAZEEL__149/* Load the holding buffer */150buf_hold = *--i_src >> 8;151152for (; c >= 4; c -= 4) {153value = *--i_src;154*--i_dst = buf_hold << 24 | value;155buf_hold = value >> 8;156}157#else158/* Load the holding buffer */159buf_hold = (*--i_src & 0xFFFFFF) << 8;160161for (; c >= 4; c -= 4) {162value = *--i_src;163*--i_dst = buf_hold |164((value & 0xFF000000) >> 24);165buf_hold = (value & 0xFFFFFF) << 8;166}167#endif168/* Realign the source */169src = (const void *)i_src;170src += 3;171break;172}173dst = (void *)i_dst;174}175176/* simple fast copy, ... unless a cache boundary is crossed */177/* Finish off any remaining bytes */178switch (c) {179case 4:180*--dst = *--src;181fallthrough;182case 3:183*--dst = *--src;184fallthrough;185case 2:186*--dst = *--src;187fallthrough;188case 1:189*--dst = *--src;190}191return v_dst;192}193EXPORT_SYMBOL(memmove);194#endif /* CONFIG_OPT_LIB_FUNCTION */195196197