| 1 | /*
|
| 2 | * This file is subject to the terms and conditions of the GNU General Public
|
| 3 | * License. See the file "COPYING" in the main directory of this archive
|
| 4 | * for more details.
|
| 5 | *
|
| 6 | * Unified implementation of memcpy, memmove and the __copy_user backend.
|
| 7 | *
|
| 8 | * Copyright (C) 1998, 99, 2000, 01, 2002 Ralf Baechle (ralf@gnu.org)
|
| 9 | * Copyright (C) 1999, 2000, 01, 2002 Silicon Graphics, Inc.
|
| 10 | * Copyright (C) 2002 Broadcom, Inc.
|
| 11 | * memcpy/copy_user author: Mark Vandevoorde
|
| 12 | * Copyright (C) 2007 Maciej W. Rozycki
|
| 13 | * Copyright (C) 2014 Imagination Technologies Ltd.
|
| 14 | *
|
| 15 | * Mnemonic names for arguments to memcpy/__copy_user
|
| 16 | */
|
| 17 |
|
| 18 | /*
|
| 19 | * Hack to resolve longstanding prefetch issue
|
| 20 | *
|
| 21 | * Prefetching may be fatal on some systems if we're prefetching beyond the
|
| 22 | * end of memory on some systems. It's also a seriously bad idea on non
|
| 23 | * dma-coherent systems.
|
| 24 | */
|
| 25 | |
| 26 | |
| 27 | |
| 28 | |
| 29 | |
| 30 | |
| 31 | |
| 32 | |
| 33 | |
| 34 |
|
| 35 | |
| 36 | |
| 37 | |
| 38 | |
| 39 |
|
| 40 | |
| 41 | |
| 42 | |
| 43 |
|
| 44 | /*
|
| 45 | * Spec
|
| 46 | *
|
| 47 | * memcpy copies len bytes from src to dst and sets v0 to dst.
|
| 48 | * It assumes that
|
| 49 | * - src and dst don't overlap
|
| 50 | * - src is readable
|
| 51 | * - dst is writable
|
| 52 | * memcpy uses the standard calling convention
|
| 53 | *
|
| 54 | * __copy_user copies up to len bytes from src to dst and sets a2 (len) to
|
| 55 | * the number of uncopied bytes due to an exception caused by a read or write.
|
| 56 | * __copy_user assumes that src and dst don't overlap, and that the call is
|
| 57 | * implementing one of the following:
|
| 58 | * copy_to_user
|
| 59 | * - src is readable (no exceptions when reading src)
|
| 60 | * copy_from_user
|
| 61 | * - dst is writable (no exceptions when writing dst)
|
| 62 | * __copy_user uses a non-standard calling convention; see
|
| 63 | * include/asm-mips/uaccess.h
|
| 64 | *
|
| 65 | * When an exception happens on a load, the handler must
|
| 66 | |
| 67 | * leaking information to user mode programs.
|
| 68 | */
|
| 69 |
|
| 70 | /*
|
| 71 | * Implementation
|
| 72 | */
|
| 73 |
|
| 74 | /*
|
| 75 | * The exception handler for loads requires that:
|
| 76 | * 1- AT contain the address of the byte just past the end of the source
|
| 77 | * of the copy,
|
| 78 | * 2- src_entry <= src < AT, and
|
| 79 | * 3- (dst - src) == (dst_entry - src_entry),
|
| 80 | * The _entry suffix denotes values when __copy_user was called.
|
| 81 | *
|
| 82 | * (1) is set up up by uaccess.h and maintained by not writing AT in copy_user
|
| 83 | * (2) is met by incrementing src by the number of bytes copied
|
| 84 | * (3) is met by not doing loads between a pair of increments of dst and src
|
| 85 | *
|
| 86 | * The exception handlers for stores adjust len (if necessary) and return.
|
| 87 | * These handlers do not need to overwrite any data.
|
| 88 | *
|
| 89 | * For __rmemcpy and memmove an exception is always a kernel bug, therefore
|
| 90 | * they're not protected.
|
| 91 | */
|
| 92 |
|
| 93 | /* Instruction type */
|
| 94 | #define LD_INSN 1
|
| 95 | #define ST_INSN 2
|
| 96 | /* Pretech type */
|
| 97 | #define SRC_PREFETCH 1
|
| 98 | #define DST_PREFETCH 2
|
| 99 | #define LEGACY_MODE 1
|
| 100 | #define EVA_MODE 2
|
| 101 | #define USEROP 1
|
| 102 | #define KERNELOP 2
|
| 103 |
|
| 104 | /*
|
| 105 | * Wrapper to add an entry in the exception table
|
| 106 | * in case the insn causes a memory exception.
|
| 107 | * Arguments:
|
| 108 | * insn : Load/store instruction
|
| 109 | * type : Instruction type
|
| 110 | * reg : Register
|
| 111 | * addr : Address
|
| 112 | * handler : Exception handler
|
| 113 | */
|
| 114 |
|
| 115 | #define EXC(insn, type, reg, addr, handler) \
|
| 116 | .if \mode == LEGACY_MODE; \
|
| 117 | 9: insn reg, addr; \
|
| 118 | .section __ex_table,"a"; \
|
| 119 | PTR_WD 9b, handler; \
|
| 120 | .previous; \
|
| 121 | /* This is assembled in EVA mode */ \
|
| 122 | .else; \
|
| 123 | /* If loading from user or storing to user */ \
|
| 124 | .if ((\from == USEROP) && (type == LD_INSN)) || \
|
| 125 | ((\to == USEROP) && (type == ST_INSN)); \
|
| 126 | 9: __BUILD_EVA_INSN(insn##e, reg, addr); \
|
| 127 | .section __ex_table,"a"; \
|
| 128 | PTR_WD 9b, handler; \
|
| 129 | .previous; \
|
| 130 | .else; \
|
| 131 | /* \
|
| 132 | * Still in EVA, but no need for \
|
| 133 | * exception handler or EVA insn \
|
| 134 | */ \
|
| 135 | insn reg, addr; \
|
| 136 | .endif; \
|
| 137 | .endif
|
| 138 |
|
| 139 | /*
|
| 140 | * Only on the 64-bit kernel we can made use of 64-bit registers.
|
| 141 | */
|
| 142 | #ifdef CONFIG_64BIT
|
| 143 | #define USE_DOUBLE
|
| 144 | #endif
|
| 145 |
|
| 146 | #ifdef USE_DOUBLE
|
| 147 |
|
| 148 | #define LOADK ld /* No exception */
|
| 149 | #define LOAD(reg, addr, handler) EXC(ld, LD_INSN, reg, addr, handler)
|
| 150 | #define LOADL(reg, addr, handler) EXC(ldl, LD_INSN, reg, addr, handler)
|
| 151 | #define LOADR(reg, addr, handler) EXC(ldr, LD_INSN, reg, addr, handler)
|
| 152 | #define STOREL(reg, addr, handler) EXC(sdl, ST_INSN, reg, addr, handler)
|
| 153 | #define STORER(reg, addr, handler) EXC(sdr, ST_INSN, reg, addr, handler)
|
| 154 | #define STORE(reg, addr, handler) EXC(sd, ST_INSN, reg, addr, handler)
|
| 155 | #define ADD daddu
|
| 156 | #define SUB dsubu
|
| 157 | #define SRL dsrl
|
| 158 | #define SRA dsra
|
| 159 | #define SLL dsll
|
| 160 | #define SLLV dsllv
|
| 161 | #define SRLV dsrlv
|
| 162 | #define NBYTES 8
|
| 163 | #define LOG_NBYTES 3
|
| 164 |
|
| 165 | /*
|
| 166 | * As we are sharing code base with the mips32 tree (which use the o32 ABI
|
| 167 | * register definitions). We need to redefine the register definitions from
|
| 168 | * the n64 ABI register naming to the o32 ABI register naming.
|
| 169 | */
|
| 170 | #undef t0
|
| 171 | #undef t1
|
| 172 | #undef t2
|
| 173 | #undef t3
|
| 174 | #define t0 $8
|
| 175 | #define t1 $9
|
| 176 | #define t2 $10
|
| 177 | #define t3 $11
|
| 178 | #define t4 $12
|
| 179 | #define t5 $13
|
| 180 | #define t6 $14
|
| 181 | #define t7 $15
|
| 182 |
|
| 183 | #else
|
| 184 |
|
| 185 | #define LOADK lw /* No exception */
|
| 186 | #define LOAD(reg, addr, handler) EXC(lw, LD_INSN, reg, addr, handler)
|
| 187 | #define LOADL(reg, addr, handler) EXC(lwl, LD_INSN, reg, addr, handler)
|
| 188 | #define LOADR(reg, addr, handler) EXC(lwr, LD_INSN, reg, addr, handler)
|
| 189 | #define STOREL(reg, addr, handler) EXC(swl, ST_INSN, reg, addr, handler)
|
| 190 | #define STORER(reg, addr, handler) EXC(swr, ST_INSN, reg, addr, handler)
|
| 191 | #define STORE(reg, addr, handler) EXC(sw, ST_INSN, reg, addr, handler)
|
| 192 | #define ADD addu
|
| 193 | #define SUB subu
|
| 194 | #define SRL srl
|
| 195 | #define SLL sll
|
| 196 | #define SRA sra
|
| 197 | #define SLLV sllv
|
| 198 | #define SRLV srlv
|
| 199 | #define NBYTES 4
|
| 200 | #define LOG_NBYTES 2
|
| 201 |
|
| 202 | #endif /* USE_DOUBLE */
|
| 203 |
|
| 204 | #define LOADB(reg, addr, handler) EXC(lb, LD_INSN, reg, addr, handler)
|
| 205 | #define STOREB(reg, addr, handler) EXC(sb, ST_INSN, reg, addr, handler)
|
| 206 |
|
| 207 | #ifdef CONFIG_CPU_HAS_PREFETCH
|
| 208 | # define _PREF(hint, addr, type) \
|
| 209 | .if \mode == LEGACY_MODE; \
|
| 210 | kernel_pref(hint, addr); \
|
| 211 | .else; \
|
| 212 | .if ((\from == USEROP) && (type == SRC_PREFETCH)) || \
|
| 213 | ((\to == USEROP) && (type == DST_PREFETCH)); \
|
| 214 | /* \
|
| 215 | * PREFE has only 9 bits for the offset \
|
| 216 | * compared to PREF which has 16, so it may \
|
| 217 | * need to use the $at register but this \
|
| 218 | * register should remain intact because it's \
|
| 219 | * used later on. Therefore use $v1. \
|
| 220 | */ \
|
| 221 | .set at=v1; \
|
| 222 | user_pref(hint, addr); \
|
| 223 | .set noat; \
|
| 224 | .else; \
|
| 225 | kernel_pref(hint, addr); \
|
| 226 | .endif; \
|
| 227 | .endif
|
| 228 | |
| 229 | |
| 230 | |
| 231 |
|
| 232 | |
| 233 | |
| 234 |
|
| 235 | |
| 236 | |
| 237 | |
| 238 | |
| 239 | |
| 240 | |
| 241 | |
| 242 | |
| 243 | |
| 244 | |
| 245 | |
| 246 | |
| 247 | |
| 248 |
|
| 249 | |
| 250 | |
| 251 | |
| 252 |
|
| 253 | |
| 254 |
|
| 255 | .text
|
| 256 | .set noreorder
|
| 257 | |
| 258 | .set noat
|
| 259 | |
| 260 | .set at=v1
|
| 261 | |
| 262 |
|
| 263 | .align 5
|
| 264 |
|
| 265 | /*
|
| 266 | * Macro to build the __copy_user common code
|
| 267 | * Arguments:
|
| 268 | * mode : LEGACY_MODE or EVA_MODE
|
| 269 | * from : Source operand. USEROP or KERNELOP
|
| 270 | * to : Destination operand. USEROP or KERNELOP
|
| 271 | */
|
| 272 | .macro __BUILD_COPY_USER mode, from, to
|
| 273 |
|
| 274 | /* initialize __memcpy if this the first time we execute this macro */
|
| 275 | .ifnotdef __memcpy
|
| 276 | .set __memcpy, 1
|
| 277 | .endif
|
| 278 |
|
| 279 | /*
|
| 280 | * Note: dst & src may be unaligned, len may be 0
|
| 281 | * Temps
|
| 282 | */
|
| 283 | |
| 284 |
|
| 285 | R10KCBARRIER(0(ra))
|
| 286 | /*
|
| 287 | * The "issue break"s below are very approximate.
|
| 288 | * Issue delays for dcache fills will perturb the schedule, as will
|
| 289 | * load queue full replay traps, etc.
|
| 290 | *
|
| 291 | * If len < NBYTES use byte operations.
|
| 292 | */
|
| 293 | PREFS( 0, 0(src) )
|
| 294 | PREFD( 1, 0(dst) )
|
| 295 | sltu t2, len, NBYTES
|
| 296 | and t1, dst, ADDRMASK
|
| 297 | PREFS( 0, 1*32(src) )
|
| 298 | PREFD( 1, 1*32(dst) )
|
| 299 | bnez t2, .Lcopy_bytes_checklen\@
|
| 300 | and t0, src, ADDRMASK
|
| 301 | PREFS( 0, 2*32(src) )
|
| 302 | PREFD( 1, 2*32(dst) )
|
| 303 | |
| 304 | bnez t1, .Ldst_unaligned\@
|
| 305 | nop
|
| 306 | bnez t0, .Lsrc_unaligned_dst_aligned\@
|
| 307 | |
| 308 | or t0, t0, t1
|
| 309 | bnez t0, .Lcopy_unaligned_bytes\@
|
| 310 | |
| 311 | /*
|
| 312 | * use delay slot for fall-through
|
| 313 | * src and dst are aligned; need to compute rem
|
| 314 | */
|
| 315 | .Lboth_aligned\@:
|
| 316 | SRL t0, len, LOG_NBYTES+3 |
| 317 | beqz t0, .Lcleanup_both_aligned\@ |
| 318 | and rem, len, (8*NBYTES-1) |
| 319 | PREFS( 0, 3*32(src) )
|
| 320 | PREFD( 1, 3*32(dst) )
|
| 321 | .align 4
|
| 322 | 1:
|
| 323 | R10KCBARRIER(0(ra))
|
| 324 | LOAD(t0, UNIT(0)(src), .Ll_exc\@)
|
| 325 | LOAD(t1, UNIT(1)(src), .Ll_exc_copy\@)
|
| 326 | LOAD(t2, UNIT(2)(src), .Ll_exc_copy\@)
|
| 327 | LOAD(t3, UNIT(3)(src), .Ll_exc_copy\@)
|
| 328 | SUB len, len, 8*NBYTES
|
| 329 | LOAD(t4, UNIT(4)(src), .Ll_exc_copy\@)
|
| 330 | LOAD(t7, UNIT(5)(src), .Ll_exc_copy\@)
|
| 331 | STORE(t0, UNIT(0)(dst), .Ls_exc_p8u\@)
|
| 332 | STORE(t1, UNIT(1)(dst), .Ls_exc_p7u\@)
|
| 333 | LOAD(t0, UNIT(6)(src), .Ll_exc_copy\@)
|
| 334 | LOAD(t1, UNIT(7)(src), .Ll_exc_copy\@)
|
| 335 | ADD src, src, 8*NBYTES
|
| 336 | ADD dst, dst, 8*NBYTES
|
| 337 | STORE(t2, UNIT(-6)(dst), .Ls_exc_p6u\@)
|
| 338 | STORE(t3, UNIT(-5)(dst), .Ls_exc_p5u\@)
|
| 339 | STORE(t4, UNIT(-4)(dst), .Ls_exc_p4u\@)
|
| 340 | STORE(t7, UNIT(-3)(dst), .Ls_exc_p3u\@)
|
| 341 | STORE(t0, UNIT(-2)(dst), .Ls_exc_p2u\@)
|
| 342 | STORE(t1, UNIT(-1)(dst), .Ls_exc_p1u\@)
|
| 343 | PREFS( 0, 8*32(src) )
|
| 344 | PREFD( 1, 8*32(dst) )
|
| 345 | bne len, rem, 1b
|
| 346 | nop
|
| 347 |
|
| 348 | /*
|
| 349 | * len == rem == the number of bytes left to copy < 8*NBYTES
|
| 350 | */
|
| 351 | .Lcleanup_both_aligned\@:
|
| 352 | beqz len, .Ldone\@
|
| 353 | sltu t0, len, 4*NBYTES
|
| 354 | bnez t0, .Lless_than_4units\@
|
| 355 | and rem, len, (NBYTES-1) |
| 356 | /*
|
| 357 | * len >= 4*NBYTES
|
| 358 | */
|
| 359 | LOAD( t0, UNIT(0)(src), .Ll_exc\@)
|
| 360 | LOAD( t1, UNIT(1)(src), .Ll_exc_copy\@)
|
| 361 | LOAD( t2, UNIT(2)(src), .Ll_exc_copy\@)
|
| 362 | LOAD( t3, UNIT(3)(src), .Ll_exc_copy\@)
|
| 363 | SUB len, len, 4*NBYTES
|
| 364 | ADD src, src, 4*NBYTES
|
| 365 | R10KCBARRIER(0(ra))
|
| 366 | STORE(t0, UNIT(0)(dst), .Ls_exc_p4u\@)
|
| 367 | STORE(t1, UNIT(1)(dst), .Ls_exc_p3u\@)
|
| 368 | STORE(t2, UNIT(2)(dst), .Ls_exc_p2u\@)
|
| 369 | STORE(t3, UNIT(3)(dst), .Ls_exc_p1u\@)
|
| 370 | .set reorder /* DADDI_WAR */
|
| 371 | ADD dst, dst, 4*NBYTES
|
| 372 | beqz len, .Ldone\@
|
| 373 | .set noreorder
|
| 374 | .Lless_than_4units\@:
|
| 375 | /*
|
| 376 | * rem = len % NBYTES
|
| 377 | */
|
| 378 | beq rem, len, .Lcopy_bytes\@
|
| 379 | nop
|
| 380 | 1:
|
| 381 | R10KCBARRIER(0(ra))
|
| 382 | LOAD(t0, 0(src), .Ll_exc\@)
|
| 383 | ADD src, src, NBYTES
|
| 384 | SUB len, len, NBYTES
|
| 385 | STORE(t0, 0(dst), .Ls_exc_p1u\@)
|
| 386 | .set reorder /* DADDI_WAR */
|
| 387 | ADD dst, dst, NBYTES
|
| 388 | bne rem, len, 1b
|
| 389 | .set noreorder
|
| 390 |
|
| 391 | |
| 392 | /*
|
| 393 | * src and dst are aligned, need to copy rem bytes (rem < NBYTES)
|
| 394 | * A loop would do only a byte at a time with possible branch
|
| 395 | * mispredicts. Can't do an explicit LOAD dst,mask,or,STORE
|
| 396 | * because can't assume read-access to dst. Instead, use
|
| 397 | * STREST dst, which doesn't require read access to dst.
|
| 398 | *
|
| 399 | * This code should perform better than a simple loop on modern,
|
| 400 | * wide-issue mips processors because the code has fewer branches and
|
| 401 | * more instruction-level parallelism.
|
| 402 | */
|
| 403 | #define bits t2
|
| 404 | beqz len, .Ldone\@
|
| 405 | ADD t1, dst, len # t1 is just past last byte of dst
|
| 406 | li bits, 8*NBYTES
|
| 407 | SLL rem, len, 3 # rem = number of bits to keep
|
| 408 | LOAD(t0, 0(src), .Ll_exc\@)
|
| 409 | SUB bits, bits, rem # bits = number of bits to discard
|
| 410 | SHIFT_DISCARD t0, t0, bits
|
| 411 | STREST(t0, -1(t1), .Ls_exc\@)
|
| 412 | jr ra
|
| 413 | move len, zero
|
| 414 | .Ldst_unaligned\@:
|
| 415 | /*
|
| 416 | * dst is unaligned
|
| 417 | * t0 = src & ADDRMASK
|
| 418 | * t1 = dst & ADDRMASK; T1 > 0
|
| 419 | * len >= NBYTES
|
| 420 | *
|
| 421 | * Copy enough bytes to align dst
|
| 422 | * Set match = (src and dst have same alignment)
|
| 423 | */
|
| 424 | #define match rem
|
| 425 | LDFIRST(t3, FIRST(0)(src), .Ll_exc\@)
|
| 426 | ADD t2, zero, NBYTES
|
| 427 | LDREST(t3, REST(0)(src), .Ll_exc_copy\@)
|
| 428 | SUB t2, t2, t1 # t2 = number of bytes copied
|
| 429 | xor match, t0, t1
|
| 430 | R10KCBARRIER(0(ra))
|
| 431 | STFIRST(t3, FIRST(0)(dst), .Ls_exc\@)
|
| 432 | beq len, t2, .Ldone\@
|
| 433 | SUB len, len, t2
|
| 434 | ADD dst, dst, t2
|
| 435 | beqz match, .Lboth_aligned\@
|
| 436 | ADD src, src, t2
|
| 437 |
|
| 438 | .Lsrc_unaligned_dst_aligned\@:
|
| 439 | SRL t0, len, LOG_NBYTES+2 # +2 for 4 units/iter
|
| 440 | PREFS( 0, 3*32(src) )
|
| 441 | beqz t0, .Lcleanup_src_unaligned\@
|
| 442 | and rem, len, (4*NBYTES-1) # rem = len % 4*NBYTES
|
| 443 | PREFD( 1, 3*32(dst) )
|
| 444 | 1:
|
| 445 | /*
|
| 446 | * Avoid consecutive LD*'s to the same register since some mips
|
| 447 | * implementations can't issue them in the same cycle.
|
| 448 | * It's OK to load FIRST(N+1) before REST(N) because the two addresses
|
| 449 | * are to the same unit (unless src is aligned, but it's not).
|
| 450 | */
|
| 451 | R10KCBARRIER(0(ra))
|
| 452 | LDFIRST(t0, FIRST(0)(src), .Ll_exc\@)
|
| 453 | LDFIRST(t1, FIRST(1)(src), .Ll_exc_copy\@)
|
| 454 | SUB len, len, 4*NBYTES
|
| 455 | LDREST(t0, REST(0)(src), .Ll_exc_copy\@)
|
| 456 | LDREST(t1, REST(1)(src), .Ll_exc_copy\@)
|
| 457 | LDFIRST(t2, FIRST(2)(src), .Ll_exc_copy\@)
|
| 458 | LDFIRST(t3, FIRST(3)(src), .Ll_exc_copy\@)
|
| 459 | LDREST(t2, REST(2)(src), .Ll_exc_copy\@)
|
| 460 | LDREST(t3, REST(3)(src), .Ll_exc_copy\@)
|
| 461 | PREFS( 0, 9*32(src) ) # 0 is PREF_LOAD (not streamed)
|
| 462 | ADD src, src, 4*NBYTES
|
| 463 | #ifdef CONFIG_CPU_SB1
|
| 464 | nop # improves slotting
|
| 465 | #endif
|
| 466 | STORE(t0, UNIT(0)(dst), .Ls_exc_p4u\@)
|
| 467 | STORE(t1, UNIT(1)(dst), .Ls_exc_p3u\@)
|
| 468 | STORE(t2, UNIT(2)(dst), .Ls_exc_p2u\@)
|
| 469 | STORE(t3, UNIT(3)(dst), .Ls_exc_p1u\@)
|
| 470 | PREFD( 1, 9*32(dst) ) # 1 is PREF_STORE (not streamed)
|
| 471 | .set reorder /* DADDI_WAR */
|
| 472 | ADD dst, dst, 4*NBYTES
|
| 473 | bne len, rem, 1b
|
| 474 | .set noreorder
|
| 475 |
|
| 476 | .Lcleanup_src_unaligned\@:
|
| 477 | beqz len, .Ldone\@
|
| 478 | and rem, len, NBYTES-1 # rem = len % NBYTES
|
| 479 | beq rem, len, .Lcopy_bytes\@
|
| 480 | nop
|
| 481 | 1:
|
| 482 | R10KCBARRIER(0(ra))
|
| 483 | LDFIRST(t0, FIRST(0)(src), .Ll_exc\@)
|
| 484 | LDREST(t0, REST(0)(src), .Ll_exc_copy\@)
|
| 485 | ADD src, src, NBYTES
|
| 486 | SUB len, len, NBYTES
|
| 487 | STORE(t0, 0(dst), .Ls_exc_p1u\@)
|
| 488 | .set reorder /* DADDI_WAR */
|
| 489 | ADD dst, dst, NBYTES
|
| 490 | bne len, rem, 1b
|
| 491 | .set noreorder
|
| 492 |
|
| 493 | #endif /* !CONFIG_CPU_NO_LOAD_STORE_LR */
|
| 494 | .Lcopy_bytes_checklen\@:
|
| 495 | beqz len, .Ldone\@
|
| 496 | nop
|
| 497 | .Lcopy_bytes\@:
|
| 498 | /* 0 < len < NBYTES */
|
| 499 | R10KCBARRIER(0(ra))
|
| 500 | #define COPY_BYTE(N) \
|
| 501 | LOADB(t0, N(src), .Ll_exc\@); \
|
| 502 | SUB len, len, 1; \
|
| 503 | beqz len, .Ldone\@; \
|
| 504 | STOREB(t0, N(dst), .Ls_exc_p1\@)
|
| 505 |
|
| 506 | COPY_BYTE(0)
|
| 507 | COPY_BYTE(1)
|
| 508 | #ifdef USE_DOUBLE
|
| 509 | COPY_BYTE(2)
|
| 510 | COPY_BYTE(3)
|
| 511 | COPY_BYTE(4)
|
| 512 | COPY_BYTE(5)
|
| 513 | #endif
|
| 514 | LOADB(t0, NBYTES-2(src), .Ll_exc\@)
|
| 515 | SUB len, len, 1
|
| 516 | jr ra
|
| 517 | STOREB(t0, NBYTES-2(dst), .Ls_exc_p1\@)
|
| 518 | .Ldone\@:
|
| 519 | jr ra
|
| 520 | nop
|
| 521 |
|
| 522 | #ifdef CONFIG_CPU_NO_LOAD_STORE_LR
|
| 523 | .Lcopy_unaligned_bytes\@:
|
| 524 | 1:
|
| 525 | COPY_BYTE(0)
|
| 526 | COPY_BYTE(1)
|
| 527 | COPY_BYTE(2)
|
| 528 | COPY_BYTE(3)
|
| 529 | COPY_BYTE(4)
|
| 530 | COPY_BYTE(5)
|
| 531 | COPY_BYTE(6)
|
| 532 | COPY_BYTE(7)
|
| 533 | ADD src, src, 8
|
| 534 | b 1b
|
| 535 | ADD dst, dst, 8
|
| 536 | #endif /* CONFIG_CPU_NO_LOAD_STORE_LR */
|
| 537 | .if __memcpy == 1
|
| 538 | END(memcpy)
|
| 539 | .set __memcpy, 0
|
| 540 | .endif
|
| 541 |
|
| 542 | .Ll_exc_copy\@:
|
| 543 | /*
|
| 544 | * Copy bytes from src until faulting load address (or until a
|
| 545 | * lb faults)
|
| 546 | *
|
| 547 | * When reached by a faulting LDFIRST/LDREST, THREAD_BUADDR($28)
|
| 548 | * may be more than a byte beyond the last address.
|
| 549 | * Hence, the lb below may get an exception.
|
| 550 | *
|
| 551 | * Assumes src < THREAD_BUADDR($28)
|
| 552 | */
|
| 553 | LOADK t0, TI_TASK($28)
|
| 554 | nop
|
| 555 | LOADK t0, THREAD_BUADDR(t0)
|
| 556 | 1:
|
| 557 | LOADB(t1, 0(src), .Ll_exc\@)
|
| 558 | ADD src, src, 1
|
| 559 | sb t1, 0(dst) # can't fault -- we're copy_from_user
|
| 560 | .set reorder /* DADDI_WAR */
|
| 561 | ADD dst, dst, 1
|
| 562 | bne src, t0, 1b
|
| 563 | .set noreorder
|
| 564 | .Ll_exc\@:
|
| 565 | LOADK t0, TI_TASK($28)
|
| 566 | nop
|
| 567 | LOADK t0, THREAD_BUADDR(t0) # t0 is just past last good address
|
| 568 | nop
|
| 569 | SUB len, AT, t0 # len number of uncopied bytes
|
| 570 | jr ra
|
| 571 | nop
|
| 572 |
|
| 573 | #define SEXC(n) \
|
| 574 | .set reorder; /* DADDI_WAR */ \
|
| 575 | .Ls_exc_p ## n ## u\@: \
|
| 576 | ADD len, len, n*NBYTES; \
|
| 577 | jr ra; \
|
| 578 | .set noreorder
|
| 579 |
|
| 580 | SEXC(8)
|
| 581 | SEXC(7)
|
| 582 | SEXC(6)
|
| 583 | SEXC(5)
|
| 584 | SEXC(4)
|
| 585 | SEXC(3)
|
| 586 | SEXC(2)
|
| 587 | SEXC(1)
|
| 588 |
|
| 589 | .Ls_exc_p1\@:
|
| 590 | .set reorder /* DADDI_WAR */
|
| 591 | ADD len, len, 1
|
| 592 | jr ra
|
| 593 | .set noreorder
|
| 594 | .Ls_exc\@:
|
| 595 | jr ra
|
| 596 | nop
|
| 597 | .endm
|
| 598 |
|
| 599 | #ifndef CONFIG_HAVE_PLAT_MEMCPY
|
| 600 | .align 5
|
| 601 | LEAF(memmove)
|
| 602 | EXPORT_SYMBOL(memmove)
|
| 603 | ADD t0, a0, a2
|
| 604 | ADD t1, a1, a2
|
| 605 | sltu t0, a1, t0 # dst + len <= src -> memcpy
|
| 606 | sltu t1, a0, t1 # dst >= src + len -> memcpy
|
| 607 | and t0, t1
|
| 608 | beqz t0, .L__memcpy
|
| 609 | move v0, a0 /* return value */
|
| 610 | beqz a2, .Lr_out
|
| 611 | END(memmove)
|
| 612 |
|
| 613 | /* fall through to __rmemcpy */
|
| 614 | LEAF(__rmemcpy) /* a0=dst a1=src a2=len */
|
| 615 | sltu t0, a1, a0
|
| 616 | beqz t0, .Lr_end_bytes_up # src >= dst
|
| 617 | nop
|
| 618 | ADD a0, a2 # dst = dst + len
|
| 619 | ADD a1, a2 # src = src + len
|
| 620 |
|
| 621 | .Lr_end_bytes:
|
| 622 | R10KCBARRIER(0(ra))
|
| 623 | lb t0, -1(a1)
|
| 624 | SUB a2, a2, 0x1
|
| 625 | sb t0, -1(a0)
|
| 626 | SUB a1, a1, 0x1
|
| 627 | .set reorder /* DADDI_WAR */
|
| 628 | SUB a0, a0, 0x1
|
| 629 | bnez a2, .Lr_end_bytes
|
| 630 | .set noreorder
|
| 631 |
|
| 632 | .Lr_out:
|
| 633 | jr ra
|
| 634 | move a2, zero
|
| 635 |
|
| 636 | .Lr_end_bytes_up:
|
| 637 | R10KCBARRIER(0(ra))
|
| 638 | lb t0, (a1)
|
| 639 | SUB a2, a2, 0x1
|
| 640 | sb t0, (a0)
|
| 641 | ADD a1, a1, 0x1
|
| 642 | .set reorder /* DADDI_WAR */
|
| 643 | ADD a0, a0, 0x1
|
| 644 | bnez a2, .Lr_end_bytes_up
|
| 645 | .set noreorder
|
| 646 |
|
| 647 | jr ra
|
| 648 | move a2, zero
|
| 649 | END(__rmemcpy)
|
| 650 |
|
| 651 | /*
|
| 652 | * A combined memcpy/__copy_user
|
| 653 | * __copy_user sets len to 0 for success; else to an upper bound of
|
| 654 | * the number of uncopied bytes.
|
| 655 | * memcpy sets v0 to dst.
|
| 656 | */
|
| 657 | .align 5
|
| 658 | LEAF(memcpy) /* a0=dst a1=src a2=len */
|
| 659 | EXPORT_SYMBOL(memcpy)
|
| 660 | move v0, dst /* return value */
|
| 661 | .L__memcpy:
|
| 662 | #ifndef CONFIG_EVA
|
| 663 | FEXPORT(__raw_copy_from_user)
|
| 664 | EXPORT_SYMBOL(__raw_copy_from_user)
|
| 665 | FEXPORT(__raw_copy_to_user)
|
| 666 | EXPORT_SYMBOL(__raw_copy_to_user)
|
| 667 | #endif
|
| 668 | /* Legacy Mode, user <-> user */
|
| 669 | __BUILD_COPY_USER LEGACY_MODE USEROP USEROP
|
| 670 |
|
| 671 | #endif
|
| 672 |
|
| 673 | #ifdef CONFIG_EVA
|
| 674 |
|
| 675 | /*
|
| 676 | * For EVA we need distinct symbols for reading and writing to user space.
|
| 677 | * This is because we need to use specific EVA instructions to perform the
|
| 678 | * virtual <-> physical translation when a virtual address is actually in user
|
| 679 | * space
|
| 680 | */
|
| 681 |
|
| 682 | /*
|
| 683 | * __copy_from_user (EVA)
|
| 684 | */
|
| 685 |
|
| 686 | LEAF(__raw_copy_from_user)
|
| 687 | EXPORT_SYMBOL(__raw_copy_from_user)
|
| 688 | __BUILD_COPY_USER EVA_MODE USEROP KERNELOP
|
| 689 | END(__raw_copy_from_user)
|
| 690 |
|
| 691 |
|
| 692 |
|
| 693 | /*
|
| 694 | * __copy_to_user (EVA)
|
| 695 | */
|
| 696 |
|
| 697 | LEAF(__raw_copy_to_user)
|
| 698 | EXPORT_SYMBOL(__raw_copy_to_user)
|
| 699 | __BUILD_COPY_USER EVA_MODE KERNELOP USEROP
|
| 700 | END(__raw_copy_to_user)
|
| 701 |
|
| 702 | #endif
|