af313e5a4f
The copy_in_user primitive does not work as advertised. If the source and target area are available copy_in_user copies one byte too much. If one of the memory areas is not available it does not copy as much data as it can, but up to 257 bytes less. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
212 lines
4.2 KiB
ArmAsm
212 lines
4.2 KiB
ArmAsm
/*
|
|
* arch/s390/lib/uaccess.S
|
|
* __copy_{from|to}_user functions.
|
|
*
|
|
* s390
|
|
* Copyright (C) 2000,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
|
|
* Authors(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
|
|
*
|
|
* These functions have standard call interface
|
|
*/
|
|
|
|
#include <linux/errno.h>
|
|
#include <asm/lowcore.h>
|
|
#include <asm/asm-offsets.h>
|
|
|
|
.text
|
|
.align 4
|
|
.globl __copy_from_user_asm
|
|
# %r2 = to, %r3 = n, %r4 = from
|
|
__copy_from_user_asm:
|
|
slr %r0,%r0
|
|
0: mvcp 0(%r3,%r2),0(%r4),%r0
|
|
jnz 1f
|
|
slr %r2,%r2
|
|
br %r14
|
|
1: la %r2,256(%r2)
|
|
la %r4,256(%r4)
|
|
ahi %r3,-256
|
|
2: mvcp 0(%r3,%r2),0(%r4),%r0
|
|
jnz 1b
|
|
3: slr %r2,%r2
|
|
br %r14
|
|
4: lhi %r0,-4096
|
|
lr %r5,%r4
|
|
slr %r5,%r0
|
|
nr %r5,%r0 # %r5 = (%r4 + 4096) & -4096
|
|
slr %r5,%r4 # %r5 = #bytes to next user page boundary
|
|
clr %r3,%r5 # copy crosses next page boundary ?
|
|
jnh 6f # no, the current page faulted
|
|
# move with the reduced length which is < 256
|
|
5: mvcp 0(%r5,%r2),0(%r4),%r0
|
|
slr %r3,%r5
|
|
6: lr %r2,%r3
|
|
br %r14
|
|
.section __ex_table,"a"
|
|
.long 0b,4b
|
|
.long 2b,4b
|
|
.long 5b,6b
|
|
.previous
|
|
|
|
.align 4
|
|
.text
|
|
.globl __copy_to_user_asm
|
|
# %r2 = from, %r3 = n, %r4 = to
|
|
__copy_to_user_asm:
|
|
slr %r0,%r0
|
|
0: mvcs 0(%r3,%r4),0(%r2),%r0
|
|
jnz 1f
|
|
slr %r2,%r2
|
|
br %r14
|
|
1: la %r2,256(%r2)
|
|
la %r4,256(%r4)
|
|
ahi %r3,-256
|
|
2: mvcs 0(%r3,%r4),0(%r2),%r0
|
|
jnz 1b
|
|
3: slr %r2,%r2
|
|
br %r14
|
|
4: lhi %r0,-4096
|
|
lr %r5,%r4
|
|
slr %r5,%r0
|
|
nr %r5,%r0 # %r5 = (%r4 + 4096) & -4096
|
|
slr %r5,%r4 # %r5 = #bytes to next user page boundary
|
|
clr %r3,%r5 # copy crosses next page boundary ?
|
|
jnh 6f # no, the current page faulted
|
|
# move with the reduced length which is < 256
|
|
5: mvcs 0(%r5,%r4),0(%r2),%r0
|
|
slr %r3,%r5
|
|
6: lr %r2,%r3
|
|
br %r14
|
|
.section __ex_table,"a"
|
|
.long 0b,4b
|
|
.long 2b,4b
|
|
.long 5b,6b
|
|
.previous
|
|
|
|
.align 4
|
|
.text
|
|
.globl __copy_in_user_asm
|
|
# %r2 = from, %r3 = n, %r4 = to
|
|
__copy_in_user_asm:
|
|
ahi %r3,-1
|
|
jo 6f
|
|
sacf 256
|
|
bras %r1,4f
|
|
0: ahi %r3,257
|
|
1: mvc 0(1,%r4),0(%r2)
|
|
la %r2,1(%r2)
|
|
la %r4,1(%r4)
|
|
ahi %r3,-1
|
|
jnz 1b
|
|
2: lr %r2,%r3
|
|
br %r14
|
|
3: mvc 0(256,%r4),0(%r2)
|
|
la %r2,256(%r2)
|
|
la %r4,256(%r4)
|
|
4: ahi %r3,-256
|
|
jnm 3b
|
|
5: ex %r3,4(%r1)
|
|
sacf 0
|
|
6: slr %r2,%r2
|
|
br %r14
|
|
.section __ex_table,"a"
|
|
.long 1b,2b
|
|
.long 3b,0b
|
|
.long 5b,0b
|
|
.previous
|
|
|
|
.align 4
|
|
.text
|
|
.globl __clear_user_asm
|
|
# %r2 = to, %r3 = n
|
|
__clear_user_asm:
|
|
bras %r5,0f
|
|
.long empty_zero_page
|
|
0: l %r5,0(%r5)
|
|
slr %r0,%r0
|
|
1: mvcs 0(%r3,%r2),0(%r5),%r0
|
|
jnz 2f
|
|
slr %r2,%r2
|
|
br %r14
|
|
2: la %r2,256(%r2)
|
|
ahi %r3,-256
|
|
3: mvcs 0(%r3,%r2),0(%r5),%r0
|
|
jnz 2b
|
|
4: slr %r2,%r2
|
|
br %r14
|
|
5: lhi %r0,-4096
|
|
lr %r4,%r2
|
|
slr %r4,%r0
|
|
nr %r4,%r0 # %r4 = (%r2 + 4096) & -4096
|
|
slr %r4,%r2 # %r4 = #bytes to next user page boundary
|
|
clr %r3,%r4 # clear crosses next page boundary ?
|
|
jnh 7f # no, the current page faulted
|
|
# clear with the reduced length which is < 256
|
|
6: mvcs 0(%r4,%r2),0(%r5),%r0
|
|
slr %r3,%r4
|
|
7: lr %r2,%r3
|
|
br %r14
|
|
.section __ex_table,"a"
|
|
.long 1b,5b
|
|
.long 3b,5b
|
|
.long 6b,7b
|
|
.previous
|
|
|
|
.align 4
|
|
.text
|
|
.globl __strncpy_from_user_asm
|
|
# %r2 = count, %r3 = dst, %r4 = src
|
|
__strncpy_from_user_asm:
|
|
lhi %r0,0
|
|
lr %r1,%r4
|
|
la %r4,0(%r4) # clear high order bit from %r4
|
|
la %r2,0(%r2,%r4) # %r2 points to first byte after string
|
|
sacf 256
|
|
0: srst %r2,%r1
|
|
jo 0b
|
|
sacf 0
|
|
lr %r1,%r2
|
|
jh 1f # \0 found in string ?
|
|
ahi %r1,1 # include \0 in copy
|
|
1: slr %r1,%r4 # %r1 = copy length (without \0)
|
|
slr %r2,%r4 # %r2 = return length (including \0)
|
|
2: mvcp 0(%r1,%r3),0(%r4),%r0
|
|
jnz 3f
|
|
br %r14
|
|
3: la %r3,256(%r3)
|
|
la %r4,256(%r4)
|
|
ahi %r1,-256
|
|
mvcp 0(%r1,%r3),0(%r4),%r0
|
|
jnz 3b
|
|
br %r14
|
|
4: sacf 0
|
|
lhi %r2,-EFAULT
|
|
br %r14
|
|
.section __ex_table,"a"
|
|
.long 0b,4b
|
|
.previous
|
|
|
|
.align 4
|
|
.text
|
|
.globl __strnlen_user_asm
|
|
# %r2 = count, %r3 = src
|
|
__strnlen_user_asm:
|
|
lhi %r0,0
|
|
lr %r1,%r3
|
|
la %r3,0(%r3) # clear high order bit from %r4
|
|
la %r2,0(%r2,%r3) # %r2 points to first byte after string
|
|
sacf 256
|
|
0: srst %r2,%r1
|
|
jo 0b
|
|
sacf 0
|
|
ahi %r2,1 # strnlen_user result includes the \0
|
|
# or return count+1 if \0 not found
|
|
slr %r2,%r3
|
|
br %r14
|
|
2: sacf 0
|
|
slr %r2,%r2 # return 0 on exception
|
|
br %r14
|
|
.section __ex_table,"a"
|
|
.long 0b,2b
|
|
.previous
|