1 /* 2 * Copyright (c) 2017 Imagination Technologies. 3 * 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer 14 * in the documentation and/or other materials provided with 15 * the distribution. 16 * * Neither the name of Imagination Technologies nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <string.h> 34 35 #define op_t unsigned long int 36 37 #if !defined(UNALIGNED_INSTR_SUPPORT) 38 /* does target have unaligned lw/ld/ualw/uald instructions? */ 39 #define UNALIGNED_INSTR_SUPPORT 0 40 #if __mips_isa_rev < 6 && !__mips1 41 #undef UNALIGNED_INSTR_SUPPORT 42 #define UNALIGNED_INSTR_SUPPORT 1 43 #endif 44 #endif 45 46 #if !defined(HW_UNALIGNED_SUPPORT) 47 /* Does target have hardware support for unaligned accesses? */ 48 #define HW_UNALIGNED_SUPPORT 0 49 #if __mips_isa_rev >= 6 50 #undef HW_UNALIGNED_SUPPORT 51 #define HW_UNALIGNED_SUPPORT 1 52 #endif 53 #endif 54 55 #if __mips64 56 typedef struct 57 { 58 op_t B0:8, B1:8, B2:8, B3:8, B4:8, B5:8, B6:8, B7:8; 59 } bits_t; 60 #else 61 typedef struct 62 { 63 op_t B0:8, B1:8, B2:8, B3:8; 64 } bits_t; 65 #endif 66 67 typedef union 68 { 69 op_t v; 70 bits_t b; 71 } bitfields_t; 72 73 #if !HW_UNALIGNED_SUPPORT && UNALIGNED_INSTR_SUPPORT 74 /* for MIPS GCC, there are no unaligned builtins - so this struct forces 75 the compiler to treat the pointer access as unaligned. */ 76 struct ulw 77 { 78 op_t uli; 79 } __attribute__ ((packed)); 80 #endif /* !HW_UNALIGNED_SUPPORT && UNALIGNED_INSTR_SUPPORT */ 81 82 #define DO_BYTE(i, ptdst) { \ 83 *(ptdst+i) = a.b.B##i; \ 84 if(a.b.B##i == '\0') \ 85 return ret; \ 86 } 87 88 #if __mips64 89 #define DO_BYTES(val, dst) { \ 90 bitfields_t a; \ 91 char *tdst = (char *)(dst); \ 92 a.v = val; \ 93 DO_BYTE(0, tdst) \ 94 DO_BYTE(1, tdst) \ 95 DO_BYTE(2, tdst) \ 96 DO_BYTE(3, tdst) \ 97 DO_BYTE(4, tdst) \ 98 DO_BYTE(5, tdst) \ 99 DO_BYTE(6, tdst) \ 100 DO_BYTE(7, tdst) \ 101 } 102 #else 103 #define DO_BYTES(val, dst) { \ 104 bitfields_t a; \ 105 char *tdst = (char *)(dst); \ 106 a.v = val; \ 107 DO_BYTE(0, tdst) \ 108 DO_BYTE(1, tdst) \ 109 DO_BYTE(2, tdst) \ 110 DO_BYTE(3, tdst) \ 111 } 112 #endif 113 114 #define DO_WORD_ALIGNED(dst, src) { \ 115 op_t val = *(src); \ 116 if ((((val - mask_1) & ~val) & mask_128) != 0) { \ 117 DO_BYTES(val, dst); \ 118 } else *(dst) = val; \ 119 } 120 121 #if !HW_UNALIGNED_SUPPORT 122 #if UNALIGNED_INSTR_SUPPORT 123 #define DO_WORD_UNALIGNED(dst, src) { \ 124 op_t val = *(src); \ 125 if ((((val - mask_1) & ~val) & mask_128) != 0) { \ 126 DO_BYTES(val, dst); \ 127 } else { \ 128 struct ulw *a = (struct ulw *)(dst); \ 129 a->uli = val; \ 130 } \ 131 } 132 #else 133 #define DO_WORD_UNALIGNED(dst, src) { \ 134 op_t val = *(src); \ 135 if ((((val - mask_1) & ~val) & mask_128) != 0) { \ 136 DO_BYTES(val, dst); \ 137 } else { \ 138 char *pdst = (char *) dst; \ 139 const char *psrc = (const char *) src; \ 140 for (; (*pdst = *psrc) != '\0'; ++psrc, ++pdst); \ 141 return ret; \ 142 } \ 143 } 144 #endif /* UNALIGNED_INSTR_SUPPORT */ 145 146 #define PROCESS_UNALIGNED_WORDS(a, b) { \ 147 while (1) { \ 148 DO_WORD_UNALIGNED(a, b); \ 149 DO_WORD_UNALIGNED(a + 1, b + 1); \ 150 DO_WORD_UNALIGNED(a + 2, b + 2); \ 151 DO_WORD_UNALIGNED(a + 3, b + 3); \ 152 a += 4; \ 153 b += 4; \ 154 } \ 155 } 156 #endif /* HW_UNALIGNED_SUPPORT */ 157 158 #define PROCESS_ALIGNED_WORDS(a, b) { \ 159 while (1) { \ 160 DO_WORD_ALIGNED(a, b); \ 161 DO_WORD_ALIGNED(a + 1, b + 1); \ 162 DO_WORD_ALIGNED(a + 2, b + 2); \ 163 DO_WORD_ALIGNED(a + 3, b + 3); \ 164 a += 4; \ 165 b += 4; \ 166 } \ 167 } 168 169 char * 170 strcpy (char *to, const char *from) __overloadable 171 { 172 char *ret = to; 173 op_t mask_1, mask_128; 174 const op_t *src; 175 op_t *dst; 176 177 for (; (*to = *from) != '\0' && ((size_t) from % sizeof (op_t)) != 0; ++from, ++to); 178 179 if(*to != '\0') { 180 __asm__ volatile ( 181 "li %0, 0x01010101 \n\t" 182 : "=r" (mask_1) 183 ); 184 #if __mips64 185 mask_1 |= mask_1 << 32; 186 #endif 187 mask_128 = mask_1 << 7; 188 189 src = (const op_t *) from; 190 dst = (op_t *) to; 191 192 #if HW_UNALIGNED_SUPPORT 193 PROCESS_ALIGNED_WORDS(dst, src); 194 #else 195 if (((unsigned long) dst) % sizeof (op_t) == 0) { 196 PROCESS_ALIGNED_WORDS(dst, src); 197 } else { 198 PROCESS_UNALIGNED_WORDS(dst, src); 199 } 200 #endif 201 } 202 203 return ret; 204 } 205