diff options
Diffstat (limited to 'arch/mips/lib/memcpy.S')
-rw-r--r-- | arch/mips/lib/memcpy.S | 158 |
1 files changed, 89 insertions, 69 deletions
diff --git a/arch/mips/lib/memcpy.S b/arch/mips/lib/memcpy.S index c5c40dad0bbf..ab9f04641640 100644 --- a/arch/mips/lib/memcpy.S +++ b/arch/mips/lib/memcpy.S | |||
@@ -10,6 +10,7 @@ | |||
10 | * Copyright (C) 2002 Broadcom, Inc. | 10 | * Copyright (C) 2002 Broadcom, Inc. |
11 | * memcpy/copy_user author: Mark Vandevoorde | 11 | * memcpy/copy_user author: Mark Vandevoorde |
12 | * Copyright (C) 2007 Maciej W. Rozycki | 12 | * Copyright (C) 2007 Maciej W. Rozycki |
13 | * Copyright (C) 2014 Imagination Technologies Ltd. | ||
13 | * | 14 | * |
14 | * Mnemonic names for arguments to memcpy/__copy_user | 15 | * Mnemonic names for arguments to memcpy/__copy_user |
15 | */ | 16 | */ |
@@ -85,8 +86,22 @@ | |||
85 | * they're not protected. | 86 | * they're not protected. |
86 | */ | 87 | */ |
87 | 88 | ||
88 | #define EXC(inst_reg,addr,handler) \ | 89 | /* Instruction type */ |
89 | 9: inst_reg, addr; \ | 90 | #define LD_INSN 1 |
91 | #define ST_INSN 2 | ||
92 | |||
93 | /* | ||
94 | * Wrapper to add an entry in the exception table | ||
95 | * in case the insn causes a memory exception. | ||
96 | * Arguments: | ||
97 | * insn : Load/store instruction | ||
98 | * type : Instruction type | ||
99 | * reg : Register | ||
100 | * addr : Address | ||
101 | * handler : Exception handler | ||
102 | */ | ||
103 | #define EXC(insn, type, reg, addr, handler) \ | ||
104 | 9: insn reg, addr; \ | ||
90 | .section __ex_table,"a"; \ | 105 | .section __ex_table,"a"; \ |
91 | PTR 9b, handler; \ | 106 | PTR 9b, handler; \ |
92 | .previous | 107 | .previous |
@@ -100,12 +115,13 @@ | |||
100 | 115 | ||
101 | #ifdef USE_DOUBLE | 116 | #ifdef USE_DOUBLE |
102 | 117 | ||
103 | #define LOAD ld | 118 | #define LOADK ld /* No exception */ |
104 | #define LOADL ldl | 119 | #define LOAD(reg, addr, handler) EXC(ld, LD_INSN, reg, addr, handler) |
105 | #define LOADR ldr | 120 | #define LOADL(reg, addr, handler) EXC(ldl, LD_INSN, reg, addr, handler) |
106 | #define STOREL sdl | 121 | #define LOADR(reg, addr, handler) EXC(ldr, LD_INSN, reg, addr, handler) |
107 | #define STORER sdr | 122 | #define STOREL(reg, addr, handler) EXC(sdl, ST_INSN, reg, addr, handler) |
108 | #define STORE sd | 123 | #define STORER(reg, addr, handler) EXC(sdr, ST_INSN, reg, addr, handler) |
124 | #define STORE(reg, addr, handler) EXC(sd, ST_INSN, reg, addr, handler) | ||
109 | #define ADD daddu | 125 | #define ADD daddu |
110 | #define SUB dsubu | 126 | #define SUB dsubu |
111 | #define SRL dsrl | 127 | #define SRL dsrl |
@@ -136,12 +152,13 @@ | |||
136 | 152 | ||
137 | #else | 153 | #else |
138 | 154 | ||
139 | #define LOAD lw | 155 | #define LOADK lw /* No exception */ |
140 | #define LOADL lwl | 156 | #define LOAD(reg, addr, handler) EXC(lw, LD_INSN, reg, addr, handler) |
141 | #define LOADR lwr | 157 | #define LOADL(reg, addr, handler) EXC(lwl, LD_INSN, reg, addr, handler) |
142 | #define STOREL swl | 158 | #define LOADR(reg, addr, handler) EXC(lwr, LD_INSN, reg, addr, handler) |
143 | #define STORER swr | 159 | #define STOREL(reg, addr, handler) EXC(swl, ST_INSN, reg, addr, handler) |
144 | #define STORE sw | 160 | #define STORER(reg, addr, handler) EXC(swr, ST_INSN, reg, addr, handler) |
161 | #define STORE(reg, addr, handler) EXC(sw, ST_INSN, reg, addr, handler) | ||
145 | #define ADD addu | 162 | #define ADD addu |
146 | #define SUB subu | 163 | #define SUB subu |
147 | #define SRL srl | 164 | #define SRL srl |
@@ -154,6 +171,9 @@ | |||
154 | 171 | ||
155 | #endif /* USE_DOUBLE */ | 172 | #endif /* USE_DOUBLE */ |
156 | 173 | ||
174 | #define LOADB(reg, addr, handler) EXC(lb, LD_INSN, reg, addr, handler) | ||
175 | #define STOREB(reg, addr, handler) EXC(sb, ST_INSN, reg, addr, handler) | ||
176 | |||
157 | #ifdef CONFIG_CPU_LITTLE_ENDIAN | 177 | #ifdef CONFIG_CPU_LITTLE_ENDIAN |
158 | #define LDFIRST LOADR | 178 | #define LDFIRST LOADR |
159 | #define LDREST LOADL | 179 | #define LDREST LOADL |
@@ -243,25 +263,25 @@ __copy_user_common: | |||
243 | .align 4 | 263 | .align 4 |
244 | 1: | 264 | 1: |
245 | R10KCBARRIER(0(ra)) | 265 | R10KCBARRIER(0(ra)) |
246 | EXC( LOAD t0, UNIT(0)(src), .Ll_exc) | 266 | LOAD(t0, UNIT(0)(src), .Ll_exc) |
247 | EXC( LOAD t1, UNIT(1)(src), .Ll_exc_copy) | 267 | LOAD(t1, UNIT(1)(src), .Ll_exc_copy) |
248 | EXC( LOAD t2, UNIT(2)(src), .Ll_exc_copy) | 268 | LOAD(t2, UNIT(2)(src), .Ll_exc_copy) |
249 | EXC( LOAD t3, UNIT(3)(src), .Ll_exc_copy) | 269 | LOAD(t3, UNIT(3)(src), .Ll_exc_copy) |
250 | SUB len, len, 8*NBYTES | 270 | SUB len, len, 8*NBYTES |
251 | EXC( LOAD t4, UNIT(4)(src), .Ll_exc_copy) | 271 | LOAD(t4, UNIT(4)(src), .Ll_exc_copy) |
252 | EXC( LOAD t7, UNIT(5)(src), .Ll_exc_copy) | 272 | LOAD(t7, UNIT(5)(src), .Ll_exc_copy) |
253 | EXC( STORE t0, UNIT(0)(dst), .Ls_exc_p8u) | 273 | STORE(t0, UNIT(0)(dst), .Ls_exc_p8u) |
254 | EXC( STORE t1, UNIT(1)(dst), .Ls_exc_p7u) | 274 | STORE(t1, UNIT(1)(dst), .Ls_exc_p7u) |
255 | EXC( LOAD t0, UNIT(6)(src), .Ll_exc_copy) | 275 | LOAD(t0, UNIT(6)(src), .Ll_exc_copy) |
256 | EXC( LOAD t1, UNIT(7)(src), .Ll_exc_copy) | 276 | LOAD(t1, UNIT(7)(src), .Ll_exc_copy) |
257 | ADD src, src, 8*NBYTES | 277 | ADD src, src, 8*NBYTES |
258 | ADD dst, dst, 8*NBYTES | 278 | ADD dst, dst, 8*NBYTES |
259 | EXC( STORE t2, UNIT(-6)(dst), .Ls_exc_p6u) | 279 | STORE(t2, UNIT(-6)(dst), .Ls_exc_p6u) |
260 | EXC( STORE t3, UNIT(-5)(dst), .Ls_exc_p5u) | 280 | STORE(t3, UNIT(-5)(dst), .Ls_exc_p5u) |
261 | EXC( STORE t4, UNIT(-4)(dst), .Ls_exc_p4u) | 281 | STORE(t4, UNIT(-4)(dst), .Ls_exc_p4u) |
262 | EXC( STORE t7, UNIT(-3)(dst), .Ls_exc_p3u) | 282 | STORE(t7, UNIT(-3)(dst), .Ls_exc_p3u) |
263 | EXC( STORE t0, UNIT(-2)(dst), .Ls_exc_p2u) | 283 | STORE(t0, UNIT(-2)(dst), .Ls_exc_p2u) |
264 | EXC( STORE t1, UNIT(-1)(dst), .Ls_exc_p1u) | 284 | STORE(t1, UNIT(-1)(dst), .Ls_exc_p1u) |
265 | PREF( 0, 8*32(src) ) | 285 | PREF( 0, 8*32(src) ) |
266 | PREF( 1, 8*32(dst) ) | 286 | PREF( 1, 8*32(dst) ) |
267 | bne len, rem, 1b | 287 | bne len, rem, 1b |
@@ -278,17 +298,17 @@ EXC( STORE t1, UNIT(-1)(dst), .Ls_exc_p1u) | |||
278 | /* | 298 | /* |
279 | * len >= 4*NBYTES | 299 | * len >= 4*NBYTES |
280 | */ | 300 | */ |
281 | EXC( LOAD t0, UNIT(0)(src), .Ll_exc) | 301 | LOAD( t0, UNIT(0)(src), .Ll_exc) |
282 | EXC( LOAD t1, UNIT(1)(src), .Ll_exc_copy) | 302 | LOAD( t1, UNIT(1)(src), .Ll_exc_copy) |
283 | EXC( LOAD t2, UNIT(2)(src), .Ll_exc_copy) | 303 | LOAD( t2, UNIT(2)(src), .Ll_exc_copy) |
284 | EXC( LOAD t3, UNIT(3)(src), .Ll_exc_copy) | 304 | LOAD( t3, UNIT(3)(src), .Ll_exc_copy) |
285 | SUB len, len, 4*NBYTES | 305 | SUB len, len, 4*NBYTES |
286 | ADD src, src, 4*NBYTES | 306 | ADD src, src, 4*NBYTES |
287 | R10KCBARRIER(0(ra)) | 307 | R10KCBARRIER(0(ra)) |
288 | EXC( STORE t0, UNIT(0)(dst), .Ls_exc_p4u) | 308 | STORE(t0, UNIT(0)(dst), .Ls_exc_p4u) |
289 | EXC( STORE t1, UNIT(1)(dst), .Ls_exc_p3u) | 309 | STORE(t1, UNIT(1)(dst), .Ls_exc_p3u) |
290 | EXC( STORE t2, UNIT(2)(dst), .Ls_exc_p2u) | 310 | STORE(t2, UNIT(2)(dst), .Ls_exc_p2u) |
291 | EXC( STORE t3, UNIT(3)(dst), .Ls_exc_p1u) | 311 | STORE(t3, UNIT(3)(dst), .Ls_exc_p1u) |
292 | .set reorder /* DADDI_WAR */ | 312 | .set reorder /* DADDI_WAR */ |
293 | ADD dst, dst, 4*NBYTES | 313 | ADD dst, dst, 4*NBYTES |
294 | beqz len, .Ldone | 314 | beqz len, .Ldone |
@@ -301,10 +321,10 @@ EXC( STORE t3, UNIT(3)(dst), .Ls_exc_p1u) | |||
301 | nop | 321 | nop |
302 | 1: | 322 | 1: |
303 | R10KCBARRIER(0(ra)) | 323 | R10KCBARRIER(0(ra)) |
304 | EXC( LOAD t0, 0(src), .Ll_exc) | 324 | LOAD(t0, 0(src), .Ll_exc) |
305 | ADD src, src, NBYTES | 325 | ADD src, src, NBYTES |
306 | SUB len, len, NBYTES | 326 | SUB len, len, NBYTES |
307 | EXC( STORE t0, 0(dst), .Ls_exc_p1u) | 327 | STORE(t0, 0(dst), .Ls_exc_p1u) |
308 | .set reorder /* DADDI_WAR */ | 328 | .set reorder /* DADDI_WAR */ |
309 | ADD dst, dst, NBYTES | 329 | ADD dst, dst, NBYTES |
310 | bne rem, len, 1b | 330 | bne rem, len, 1b |
@@ -326,10 +346,10 @@ EXC( STORE t0, 0(dst), .Ls_exc_p1u) | |||
326 | ADD t1, dst, len # t1 is just past last byte of dst | 346 | ADD t1, dst, len # t1 is just past last byte of dst |
327 | li bits, 8*NBYTES | 347 | li bits, 8*NBYTES |
328 | SLL rem, len, 3 # rem = number of bits to keep | 348 | SLL rem, len, 3 # rem = number of bits to keep |
329 | EXC( LOAD t0, 0(src), .Ll_exc) | 349 | LOAD(t0, 0(src), .Ll_exc) |
330 | SUB bits, bits, rem # bits = number of bits to discard | 350 | SUB bits, bits, rem # bits = number of bits to discard |
331 | SHIFT_DISCARD t0, t0, bits | 351 | SHIFT_DISCARD t0, t0, bits |
332 | EXC( STREST t0, -1(t1), .Ls_exc) | 352 | STREST(t0, -1(t1), .Ls_exc) |
333 | jr ra | 353 | jr ra |
334 | move len, zero | 354 | move len, zero |
335 | .Ldst_unaligned: | 355 | .Ldst_unaligned: |
@@ -343,13 +363,13 @@ EXC( STREST t0, -1(t1), .Ls_exc) | |||
343 | * Set match = (src and dst have same alignment) | 363 | * Set match = (src and dst have same alignment) |
344 | */ | 364 | */ |
345 | #define match rem | 365 | #define match rem |
346 | EXC( LDFIRST t3, FIRST(0)(src), .Ll_exc) | 366 | LDFIRST(t3, FIRST(0)(src), .Ll_exc) |
347 | ADD t2, zero, NBYTES | 367 | ADD t2, zero, NBYTES |
348 | EXC( LDREST t3, REST(0)(src), .Ll_exc_copy) | 368 | LDREST(t3, REST(0)(src), .Ll_exc_copy) |
349 | SUB t2, t2, t1 # t2 = number of bytes copied | 369 | SUB t2, t2, t1 # t2 = number of bytes copied |
350 | xor match, t0, t1 | 370 | xor match, t0, t1 |
351 | R10KCBARRIER(0(ra)) | 371 | R10KCBARRIER(0(ra)) |
352 | EXC( STFIRST t3, FIRST(0)(dst), .Ls_exc) | 372 | STFIRST(t3, FIRST(0)(dst), .Ls_exc) |
353 | beq len, t2, .Ldone | 373 | beq len, t2, .Ldone |
354 | SUB len, len, t2 | 374 | SUB len, len, t2 |
355 | ADD dst, dst, t2 | 375 | ADD dst, dst, t2 |
@@ -370,24 +390,24 @@ EXC( STFIRST t3, FIRST(0)(dst), .Ls_exc) | |||
370 | * are to the same unit (unless src is aligned, but it's not). | 390 | * are to the same unit (unless src is aligned, but it's not). |
371 | */ | 391 | */ |
372 | R10KCBARRIER(0(ra)) | 392 | R10KCBARRIER(0(ra)) |
373 | EXC( LDFIRST t0, FIRST(0)(src), .Ll_exc) | 393 | LDFIRST(t0, FIRST(0)(src), .Ll_exc) |
374 | EXC( LDFIRST t1, FIRST(1)(src), .Ll_exc_copy) | 394 | LDFIRST(t1, FIRST(1)(src), .Ll_exc_copy) |
375 | SUB len, len, 4*NBYTES | 395 | SUB len, len, 4*NBYTES |
376 | EXC( LDREST t0, REST(0)(src), .Ll_exc_copy) | 396 | LDREST(t0, REST(0)(src), .Ll_exc_copy) |
377 | EXC( LDREST t1, REST(1)(src), .Ll_exc_copy) | 397 | LDREST(t1, REST(1)(src), .Ll_exc_copy) |
378 | EXC( LDFIRST t2, FIRST(2)(src), .Ll_exc_copy) | 398 | LDFIRST(t2, FIRST(2)(src), .Ll_exc_copy) |
379 | EXC( LDFIRST t3, FIRST(3)(src), .Ll_exc_copy) | 399 | LDFIRST(t3, FIRST(3)(src), .Ll_exc_copy) |
380 | EXC( LDREST t2, REST(2)(src), .Ll_exc_copy) | 400 | LDREST(t2, REST(2)(src), .Ll_exc_copy) |
381 | EXC( LDREST t3, REST(3)(src), .Ll_exc_copy) | 401 | LDREST(t3, REST(3)(src), .Ll_exc_copy) |
382 | PREF( 0, 9*32(src) ) # 0 is PREF_LOAD (not streamed) | 402 | PREF( 0, 9*32(src) ) # 0 is PREF_LOAD (not streamed) |
383 | ADD src, src, 4*NBYTES | 403 | ADD src, src, 4*NBYTES |
384 | #ifdef CONFIG_CPU_SB1 | 404 | #ifdef CONFIG_CPU_SB1 |
385 | nop # improves slotting | 405 | nop # improves slotting |
386 | #endif | 406 | #endif |
387 | EXC( STORE t0, UNIT(0)(dst), .Ls_exc_p4u) | 407 | STORE(t0, UNIT(0)(dst), .Ls_exc_p4u) |
388 | EXC( STORE t1, UNIT(1)(dst), .Ls_exc_p3u) | 408 | STORE(t1, UNIT(1)(dst), .Ls_exc_p3u) |
389 | EXC( STORE t2, UNIT(2)(dst), .Ls_exc_p2u) | 409 | STORE(t2, UNIT(2)(dst), .Ls_exc_p2u) |
390 | EXC( STORE t3, UNIT(3)(dst), .Ls_exc_p1u) | 410 | STORE(t3, UNIT(3)(dst), .Ls_exc_p1u) |
391 | PREF( 1, 9*32(dst) ) # 1 is PREF_STORE (not streamed) | 411 | PREF( 1, 9*32(dst) ) # 1 is PREF_STORE (not streamed) |
392 | .set reorder /* DADDI_WAR */ | 412 | .set reorder /* DADDI_WAR */ |
393 | ADD dst, dst, 4*NBYTES | 413 | ADD dst, dst, 4*NBYTES |
@@ -401,11 +421,11 @@ EXC( STORE t3, UNIT(3)(dst), .Ls_exc_p1u) | |||
401 | nop | 421 | nop |
402 | 1: | 422 | 1: |
403 | R10KCBARRIER(0(ra)) | 423 | R10KCBARRIER(0(ra)) |
404 | EXC( LDFIRST t0, FIRST(0)(src), .Ll_exc) | 424 | LDFIRST(t0, FIRST(0)(src), .Ll_exc) |
405 | EXC( LDREST t0, REST(0)(src), .Ll_exc_copy) | 425 | LDREST(t0, REST(0)(src), .Ll_exc_copy) |
406 | ADD src, src, NBYTES | 426 | ADD src, src, NBYTES |
407 | SUB len, len, NBYTES | 427 | SUB len, len, NBYTES |
408 | EXC( STORE t0, 0(dst), .Ls_exc_p1u) | 428 | STORE(t0, 0(dst), .Ls_exc_p1u) |
409 | .set reorder /* DADDI_WAR */ | 429 | .set reorder /* DADDI_WAR */ |
410 | ADD dst, dst, NBYTES | 430 | ADD dst, dst, NBYTES |
411 | bne len, rem, 1b | 431 | bne len, rem, 1b |
@@ -418,10 +438,10 @@ EXC( STORE t0, 0(dst), .Ls_exc_p1u) | |||
418 | /* 0 < len < NBYTES */ | 438 | /* 0 < len < NBYTES */ |
419 | R10KCBARRIER(0(ra)) | 439 | R10KCBARRIER(0(ra)) |
420 | #define COPY_BYTE(N) \ | 440 | #define COPY_BYTE(N) \ |
421 | EXC( lb t0, N(src), .Ll_exc); \ | 441 | LOADB(t0, N(src), .Ll_exc); \ |
422 | SUB len, len, 1; \ | 442 | SUB len, len, 1; \ |
423 | beqz len, .Ldone; \ | 443 | beqz len, .Ldone; \ |
424 | EXC( sb t0, N(dst), .Ls_exc_p1) | 444 | STOREB(t0, N(dst), .Ls_exc_p1) |
425 | 445 | ||
426 | COPY_BYTE(0) | 446 | COPY_BYTE(0) |
427 | COPY_BYTE(1) | 447 | COPY_BYTE(1) |
@@ -431,10 +451,10 @@ EXC( sb t0, N(dst), .Ls_exc_p1) | |||
431 | COPY_BYTE(4) | 451 | COPY_BYTE(4) |
432 | COPY_BYTE(5) | 452 | COPY_BYTE(5) |
433 | #endif | 453 | #endif |
434 | EXC( lb t0, NBYTES-2(src), .Ll_exc) | 454 | LOADB(t0, NBYTES-2(src), .Ll_exc) |
435 | SUB len, len, 1 | 455 | SUB len, len, 1 |
436 | jr ra | 456 | jr ra |
437 | EXC( sb t0, NBYTES-2(dst), .Ls_exc_p1) | 457 | STOREB(t0, NBYTES-2(dst), .Ls_exc_p1) |
438 | .Ldone: | 458 | .Ldone: |
439 | jr ra | 459 | jr ra |
440 | nop | 460 | nop |
@@ -451,11 +471,11 @@ EXC( sb t0, NBYTES-2(dst), .Ls_exc_p1) | |||
451 | * | 471 | * |
452 | * Assumes src < THREAD_BUADDR($28) | 472 | * Assumes src < THREAD_BUADDR($28) |
453 | */ | 473 | */ |
454 | LOAD t0, TI_TASK($28) | 474 | LOADK t0, TI_TASK($28) |
455 | nop | 475 | nop |
456 | LOAD t0, THREAD_BUADDR(t0) | 476 | LOADK t0, THREAD_BUADDR(t0) |
457 | 1: | 477 | 1: |
458 | EXC( lb t1, 0(src), .Ll_exc) | 478 | LOADB(t1, 0(src), .Ll_exc) |
459 | ADD src, src, 1 | 479 | ADD src, src, 1 |
460 | sb t1, 0(dst) # can't fault -- we're copy_from_user | 480 | sb t1, 0(dst) # can't fault -- we're copy_from_user |
461 | .set reorder /* DADDI_WAR */ | 481 | .set reorder /* DADDI_WAR */ |
@@ -463,9 +483,9 @@ EXC( lb t1, 0(src), .Ll_exc) | |||
463 | bne src, t0, 1b | 483 | bne src, t0, 1b |
464 | .set noreorder | 484 | .set noreorder |
465 | .Ll_exc: | 485 | .Ll_exc: |
466 | LOAD t0, TI_TASK($28) | 486 | LOADK t0, TI_TASK($28) |
467 | nop | 487 | nop |
468 | LOAD t0, THREAD_BUADDR(t0) # t0 is just past last good address | 488 | LOADK t0, THREAD_BUADDR(t0) # t0 is just past last good address |
469 | nop | 489 | nop |
470 | SUB len, AT, t0 # len number of uncopied bytes | 490 | SUB len, AT, t0 # len number of uncopied bytes |
471 | bnez t6, .Ldone /* Skip the zeroing part if inatomic */ | 491 | bnez t6, .Ldone /* Skip the zeroing part if inatomic */ |