cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

memcpy.c (4735B)


      1/*
      2 * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
      3 * Copyright (C) 2008-2009 PetaLogix
      4 * Copyright (C) 2007 John Williams
      5 *
      6 * Reasonably optimised generic C-code for memcpy on Microblaze
      7 * This is generic C code to do efficient, alignment-aware memcpy.
      8 *
      9 * It is based on demo code originally Copyright 2001 by Intel Corp, taken from
     10 * http://www.embedded.com/showArticle.jhtml?articleID=19205567
     11 *
     12 * Attempts were made, unsuccessfully, to contact the original
     13 * author of this code (Michael Morrow, Intel).  Below is the original
     14 * copyright notice.
     15 *
     16 * This software has been developed by Intel Corporation.
     17 * Intel specifically disclaims all warranties, express or
     18 * implied, and all liability, including consequential and
     19 * other indirect damages, for the use of this program, including
     20 * liability for infringement of any proprietary rights,
     21 * and including the warranties of merchantability and fitness
     22 * for a particular purpose. Intel does not assume any
     23 * responsibility for and errors which may appear in this program
     24 * not any responsibility to update it.
     25 */
     26
     27#include <linux/export.h>
     28#include <linux/types.h>
     29#include <linux/stddef.h>
     30#include <linux/compiler.h>
     31
     32#include <linux/string.h>
     33
     34#ifdef CONFIG_OPT_LIB_FUNCTION
     35void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
     36{
     37	const char *src = v_src;
     38	char *dst = v_dst;
     39
     40	/* The following code tries to optimize the copy by using unsigned
     41	 * alignment. This will work fine if both source and destination are
     42	 * aligned on the same boundary. However, if they are aligned on
     43	 * different boundaries shifts will be necessary. This might result in
     44	 * bad performance on MicroBlaze systems without a barrel shifter.
     45	 */
     46	const uint32_t *i_src;
     47	uint32_t *i_dst;
     48
     49	if (likely(c >= 4)) {
     50		unsigned  value, buf_hold;
     51
     52		/* Align the destination to a word boundary. */
     53		/* This is done in an endian independent manner. */
     54		switch ((unsigned long)dst & 3) {
     55		case 1:
     56			*dst++ = *src++;
     57			--c;
     58			fallthrough;
     59		case 2:
     60			*dst++ = *src++;
     61			--c;
     62			fallthrough;
     63		case 3:
     64			*dst++ = *src++;
     65			--c;
     66		}
     67
     68		i_dst = (void *)dst;
     69
     70		/* Choose a copy scheme based on the source */
     71		/* alignment relative to destination. */
     72		switch ((unsigned long)src & 3) {
     73		case 0x0:	/* Both byte offsets are aligned */
     74			i_src  = (const void *)src;
     75
     76			for (; c >= 4; c -= 4)
     77				*i_dst++ = *i_src++;
     78
     79			src  = (const void *)i_src;
     80			break;
     81		case 0x1:	/* Unaligned - Off by 1 */
     82			/* Word align the source */
     83			i_src = (const void *) ((unsigned)src & ~3);
     84#ifndef __MICROBLAZEEL__
     85			/* Load the holding buffer */
     86			buf_hold = *i_src++ << 8;
     87
     88			for (; c >= 4; c -= 4) {
     89				value = *i_src++;
     90				*i_dst++ = buf_hold | value >> 24;
     91				buf_hold = value << 8;
     92			}
     93#else
     94			/* Load the holding buffer */
     95			buf_hold = (*i_src++ & 0xFFFFFF00) >> 8;
     96
     97			for (; c >= 4; c -= 4) {
     98				value = *i_src++;
     99				*i_dst++ = buf_hold | ((value & 0xFF) << 24);
    100				buf_hold = (value & 0xFFFFFF00) >> 8;
    101			}
    102#endif
    103			/* Realign the source */
    104			src = (const void *)i_src;
    105			src -= 3;
    106			break;
    107		case 0x2:	/* Unaligned - Off by 2 */
    108			/* Word align the source */
    109			i_src = (const void *) ((unsigned)src & ~3);
    110#ifndef __MICROBLAZEEL__
    111			/* Load the holding buffer */
    112			buf_hold = *i_src++ << 16;
    113
    114			for (; c >= 4; c -= 4) {
    115				value = *i_src++;
    116				*i_dst++ = buf_hold | value >> 16;
    117				buf_hold = value << 16;
    118			}
    119#else
    120			/* Load the holding buffer */
    121			buf_hold = (*i_src++ & 0xFFFF0000) >> 16;
    122
    123			for (; c >= 4; c -= 4) {
    124				value = *i_src++;
    125				*i_dst++ = buf_hold | ((value & 0xFFFF) << 16);
    126				buf_hold = (value & 0xFFFF0000) >> 16;
    127			}
    128#endif
    129			/* Realign the source */
    130			src = (const void *)i_src;
    131			src -= 2;
    132			break;
    133		case 0x3:	/* Unaligned - Off by 3 */
    134			/* Word align the source */
    135			i_src = (const void *) ((unsigned)src & ~3);
    136#ifndef __MICROBLAZEEL__
    137			/* Load the holding buffer */
    138			buf_hold = *i_src++ << 24;
    139
    140			for (; c >= 4; c -= 4) {
    141				value = *i_src++;
    142				*i_dst++ = buf_hold | value >> 8;
    143				buf_hold = value << 24;
    144			}
    145#else
    146			/* Load the holding buffer */
    147			buf_hold = (*i_src++ & 0xFF000000) >> 24;
    148
    149			for (; c >= 4; c -= 4) {
    150				value = *i_src++;
    151				*i_dst++ = buf_hold | ((value & 0xFFFFFF) << 8);
    152				buf_hold = (value & 0xFF000000) >> 24;
    153			}
    154#endif
    155			/* Realign the source */
    156			src = (const void *)i_src;
    157			src -= 1;
    158			break;
    159		}
    160		dst = (void *)i_dst;
    161	}
    162
    163	/* Finish off any remaining bytes */
    164	/* simple fast copy, ... unless a cache boundary is crossed */
    165	switch (c) {
    166	case 3:
    167		*dst++ = *src++;
    168		fallthrough;
    169	case 2:
    170		*dst++ = *src++;
    171		fallthrough;
    172	case 1:
    173		*dst++ = *src++;
    174	}
    175
    176	return v_dst;
    177}
    178EXPORT_SYMBOL(memcpy);
    179#endif /* CONFIG_OPT_LIB_FUNCTION */