| /* SPDX-License-Identifier: MIT */ |
| /* |
| * Copyright © 2005-2014 Rich Felker, et al. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining |
| * a copy of this software and associated documentation files (the |
| * "Software"), to deal in the Software without restriction, including |
| * without limitation the rights to use, copy, modify, merge, publish, |
| * distribute, sublicense, and/or sell copies of the Software, and to |
| * permit persons to whom the Software is furnished to do so, subject to |
| * the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be |
| * included in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
| * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
| * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| |
| #include "util.h" |
| |
| void *__sel4runtime_memcpy(void *restrict dest, const void *restrict src, sel4runtime_size_t n) |
| { |
| unsigned char *d = dest; |
| const unsigned char *s = src; |
| |
| #ifdef __GNUC__ |
| |
| #if __BYTE_ORDER == __LITTLE_ENDIAN |
| #define LS >> |
| #define RS << |
| #else |
| #define LS << |
| #define RS >> |
| #endif |
| |
| typedef sel4runtime_uint32_t __attribute__((__may_alias__)) u32; |
| sel4runtime_uint32_t w, x; |
| |
| for (; (sel4runtime_uintptr_t)s % 4 && n; n--) { |
| *d++ = *s++; |
| } |
| |
| if ((sel4runtime_uintptr_t)d % 4 == 0) { |
| for (; n >= 16; s += 16, d += 16, n -= 16) { |
| *(u32 *)(d + 0) = *(u32 *)(s + 0); |
| *(u32 *)(d + 4) = *(u32 *)(s + 4); |
| *(u32 *)(d + 8) = *(u32 *)(s + 8); |
| *(u32 *)(d + 12) = *(u32 *)(s + 12); |
| } |
| if (n & 8) { |
| *(u32 *)(d + 0) = *(u32 *)(s + 0); |
| *(u32 *)(d + 4) = *(u32 *)(s + 4); |
| d += 8; |
| s += 8; |
| } |
| if (n & 4) { |
| *(u32 *)(d + 0) = *(u32 *)(s + 0); |
| d += 4; |
| s += 4; |
| } |
| if (n & 2) { |
| *d++ = *s++; |
| *d++ = *s++; |
| } |
| if (n & 1) { |
| *d = *s; |
| } |
| return dest; |
| } |
| |
| if (n >= 32) switch ((sel4runtime_uintptr_t)d % 4) { |
| case 1: |
| w = *(u32 *)s; |
| *d++ = *s++; |
| *d++ = *s++; |
| *d++ = *s++; |
| n -= 3; |
| for (; n >= 17; s += 16, d += 16, n -= 16) { |
| x = *(u32 *)(s + 1); |
| *(u32 *)(d + 0) = (w LS 24) | (x RS 8); |
| w = *(u32 *)(s + 5); |
| *(u32 *)(d + 4) = (x LS 24) | (w RS 8); |
| x = *(u32 *)(s + 9); |
| *(u32 *)(d + 8) = (w LS 24) | (x RS 8); |
| w = *(u32 *)(s + 13); |
| *(u32 *)(d + 12) = (x LS 24) | (w RS 8); |
| } |
| break; |
| case 2: |
| w = *(u32 *)s; |
| *d++ = *s++; |
| *d++ = *s++; |
| n -= 2; |
| for (; n >= 18; s += 16, d += 16, n -= 16) { |
| x = *(u32 *)(s + 2); |
| *(u32 *)(d + 0) = (w LS 16) | (x RS 16); |
| w = *(u32 *)(s + 6); |
| *(u32 *)(d + 4) = (x LS 16) | (w RS 16); |
| x = *(u32 *)(s + 10); |
| *(u32 *)(d + 8) = (w LS 16) | (x RS 16); |
| w = *(u32 *)(s + 14); |
| *(u32 *)(d + 12) = (x LS 16) | (w RS 16); |
| } |
| break; |
| case 3: |
| w = *(u32 *)s; |
| *d++ = *s++; |
| n -= 1; |
| for (; n >= 19; s += 16, d += 16, n -= 16) { |
| x = *(u32 *)(s + 3); |
| *(u32 *)(d + 0) = (w LS 8) | (x RS 24); |
| w = *(u32 *)(s + 7); |
| *(u32 *)(d + 4) = (x LS 8) | (w RS 24); |
| x = *(u32 *)(s + 11); |
| *(u32 *)(d + 8) = (w LS 8) | (x RS 24); |
| w = *(u32 *)(s + 15); |
| *(u32 *)(d + 12) = (x LS 8) | (w RS 24); |
| } |
| break; |
| } |
| if (n & 16) { |
| *d++ = *s++; |
| *d++ = *s++; |
| *d++ = *s++; |
| *d++ = *s++; |
| *d++ = *s++; |
| *d++ = *s++; |
| *d++ = *s++; |
| *d++ = *s++; |
| *d++ = *s++; |
| *d++ = *s++; |
| *d++ = *s++; |
| *d++ = *s++; |
| *d++ = *s++; |
| *d++ = *s++; |
| *d++ = *s++; |
| *d++ = *s++; |
| } |
| if (n & 8) { |
| *d++ = *s++; |
| *d++ = *s++; |
| *d++ = *s++; |
| *d++ = *s++; |
| *d++ = *s++; |
| *d++ = *s++; |
| *d++ = *s++; |
| *d++ = *s++; |
| } |
| if (n & 4) { |
| *d++ = *s++; |
| *d++ = *s++; |
| *d++ = *s++; |
| *d++ = *s++; |
| } |
| if (n & 2) { |
| *d++ = *s++; |
| *d++ = *s++; |
| } |
| if (n & 1) { |
| *d = *s; |
| } |
| return dest; |
| #endif |
| |
| for (; n; n--) { |
| *d++ = *s++; |
| } |
| return dest; |
| } |