linux/arch/x86/boot/compressed/string.c
<<
>>
Prefs
   1/*
   2 * This provides an optimized implementation of memcpy, and a simplified
   3 * implementation of memset and memmove. These are used here because the
   4 * standard kernel runtime versions are not yet available and we don't
   5 * trust the gcc built-in implementations as they may do unexpected things
   6 * (e.g. FPU ops) in the minimal decompression stub execution environment.
   7 */
   8#include "error.h"
   9
  10#include "../string.c"
  11
  12#ifdef CONFIG_X86_32
  13static void *__memcpy(void *dest, const void *src, size_t n)
  14{
  15        int d0, d1, d2;
  16        asm volatile(
  17                "rep ; movsl\n\t"
  18                "movl %4,%%ecx\n\t"
  19                "rep ; movsb\n\t"
  20                : "=&c" (d0), "=&D" (d1), "=&S" (d2)
  21                : "0" (n >> 2), "g" (n & 3), "1" (dest), "2" (src)
  22                : "memory");
  23
  24        return dest;
  25}
  26#else
  27static void *__memcpy(void *dest, const void *src, size_t n)
  28{
  29        long d0, d1, d2;
  30        asm volatile(
  31                "rep ; movsq\n\t"
  32                "movq %4,%%rcx\n\t"
  33                "rep ; movsb\n\t"
  34                : "=&c" (d0), "=&D" (d1), "=&S" (d2)
  35                : "0" (n >> 3), "g" (n & 7), "1" (dest), "2" (src)
  36                : "memory");
  37
  38        return dest;
  39}
  40#endif
  41
  42void *memset(void *s, int c, size_t n)
  43{
  44        int i;
  45        char *ss = s;
  46
  47        for (i = 0; i < n; i++)
  48                ss[i] = c;
  49        return s;
  50}
  51
  52void *memmove(void *dest, const void *src, size_t n)
  53{
  54        unsigned char *d = dest;
  55        const unsigned char *s = src;
  56
  57        if (d <= s || d - s >= n)
  58                return __memcpy(dest, src, n);
  59
  60        while (n-- > 0)
  61                d[n] = s[n];
  62
  63        return dest;
  64}
  65
  66/* Detect and warn about potential overlaps, but handle them with memmove. */
  67void *memcpy(void *dest, const void *src, size_t n)
  68{
  69        if (dest > src && dest - src < n) {
  70                warn("Avoiding potentially unsafe overlapping memcpy()!");
  71                return memmove(dest, src, n);
  72        }
  73        return __memcpy(dest, src, n);
  74}
  75