/* SPDX-License-Identifier: GPL-2.0 */ /* * Copy to/from user space, handling exceptions as we go.. This * isn't exactly pretty. * * This is essentially the same as "memcpy()", but with a few twists. * Notably, we have to make sure that $0 is always up-to-date and * contains the right "bytes left to copy" value (and that it is updated * only _after_ a successful copy). There is also some rather minor * exception setup stuff.. */ #include /* Allow an exception for an insn; exit if we get one. */ #define EXI(x,y...) \ 99: x,##y; \ .section __ex_table, "a"; \ .long 99b - .; \ ldi $31, $exitin-99b($31); \ .previous #define EXO(x,y...) \ 99: x, ##y; \ .section __ex_table, "a"; \ .long 99b - .; \ ldi $31, $exitout-99b($31); \ .previous .set noat .align 4 .globl __copy_user .ent __copy_user __copy_user: .prologue 0 and $18, $18, $0 and $16, 7, $3 beq $0, $35 beq $3, $36 subl $3, 8, $3 .align 4 $37: EXI(ldbu $1, 0($17)) EXO(stb $1, 0($16)) addl $3, 1, $3 subl $0, 1, $0 addl $16, 1, $16 addl $17, 1, $17 beq $0, $41 bne $3, $37 $36: and $17, 7, $1 bic $0, 7, $4 beq $1, $43 beq $4, $48 EXI(ldl_u $3, 0($17)) .align 4 $50: EXI(ldl_u $2, 8($17)) subl $4, 8, $4 extll $3, $17, $3 exthl $2, $17, $1 bis $3, $1, $1 EXO(stl $1,0($16)) addl $17, 8, $17 subl $0, 8, $0 addl $16, 8, $16 bis $2, $2, $3 bne $4, $50 $48: beq $0, $41 .align 4 $57: EXI(ldbu $1, 0($17)) EXO(stb $1, 0($16)) subl $0, 1, $0 addl $16, 1, $16 addl $17, 1, $17 bne $0, $57 br $31, $41 .align 4 $43: beq $4, $65 .align 4 $66: EXI(ldl $1, 0($17)) subl $4, 8, $4 EXO(stl $1,0($16)) addl $17, 8, $17 subl $0, 8, $0 addl $16, 8, $16 bne $4, $66 $65: beq $0, $41 EXI(ldbu $1, 0($17)) EXO(stb $1, 0($16)) addl $17, 1, $17 addl $16, 1, $16 subl $0, 1, $0 br $31, $65 $41: $35: $exitin: $exitout: ret $31, ($26), 1 .end __copy_user EXPORT_SYMBOL(__copy_user)