A piece of fixup code is currently shared by __copy_user and __clear_user. It first disables the access to user-space memory and then returns the "n" argument, which represents #(bytes not processed). However,__copy_user's "n" is in register a2, while __clear_user's in a1, and thus it causes errors for programs like setdomainname02 testcase in LTP. This patch fixes this issue by separating their fixup code and returning the right value for the kernel to handle a relative fault properly. Signed-off-by: Alan Kao <alankao@andestech.com> Cc: Greentime Hu <greentime@andestech.com> Cc: Zong Li <zong@andestech.com> Cc: Vincent Chen <vincentc@andestech.com> Signed-off-by: Palmer Dabbelt <palmer@sifive.com>
123 lines
2.1 KiB
ArmAsm
123 lines
2.1 KiB
ArmAsm
#include <linux/linkage.h>
|
|
#include <asm/asm.h>
|
|
#include <asm/csr.h>
|
|
|
|
.altmacro
|
|
.macro fixup op reg addr lbl
|
|
LOCAL _epc
|
|
_epc:
|
|
\op \reg, \addr
|
|
.section __ex_table,"a"
|
|
.balign RISCV_SZPTR
|
|
RISCV_PTR _epc, \lbl
|
|
.previous
|
|
.endm
|
|
|
|
ENTRY(__copy_user)
|
|
|
|
/* Enable access to user memory */
|
|
li t6, SR_SUM
|
|
csrs sstatus, t6
|
|
|
|
add a3, a1, a2
|
|
/* Use word-oriented copy only if low-order bits match */
|
|
andi t0, a0, SZREG-1
|
|
andi t1, a1, SZREG-1
|
|
bne t0, t1, 2f
|
|
|
|
addi t0, a1, SZREG-1
|
|
andi t1, a3, ~(SZREG-1)
|
|
andi t0, t0, ~(SZREG-1)
|
|
/*
|
|
* a3: terminal address of source region
|
|
* t0: lowest XLEN-aligned address in source
|
|
* t1: highest XLEN-aligned address in source
|
|
*/
|
|
bgeu t0, t1, 2f
|
|
bltu a1, t0, 4f
|
|
1:
|
|
fixup REG_L, t2, (a1), 10f
|
|
fixup REG_S, t2, (a0), 10f
|
|
addi a1, a1, SZREG
|
|
addi a0, a0, SZREG
|
|
bltu a1, t1, 1b
|
|
2:
|
|
bltu a1, a3, 5f
|
|
|
|
3:
|
|
/* Disable access to user memory */
|
|
csrc sstatus, t6
|
|
li a0, 0
|
|
ret
|
|
4: /* Edge case: unalignment */
|
|
fixup lbu, t2, (a1), 10f
|
|
fixup sb, t2, (a0), 10f
|
|
addi a1, a1, 1
|
|
addi a0, a0, 1
|
|
bltu a1, t0, 4b
|
|
j 1b
|
|
5: /* Edge case: remainder */
|
|
fixup lbu, t2, (a1), 10f
|
|
fixup sb, t2, (a0), 10f
|
|
addi a1, a1, 1
|
|
addi a0, a0, 1
|
|
bltu a1, a3, 5b
|
|
j 3b
|
|
ENDPROC(__copy_user)
|
|
|
|
|
|
ENTRY(__clear_user)
|
|
|
|
/* Enable access to user memory */
|
|
li t6, SR_SUM
|
|
csrs sstatus, t6
|
|
|
|
add a3, a0, a1
|
|
addi t0, a0, SZREG-1
|
|
andi t1, a3, ~(SZREG-1)
|
|
andi t0, t0, ~(SZREG-1)
|
|
/*
|
|
* a3: terminal address of target region
|
|
* t0: lowest doubleword-aligned address in target region
|
|
* t1: highest doubleword-aligned address in target region
|
|
*/
|
|
bgeu t0, t1, 2f
|
|
bltu a0, t0, 4f
|
|
1:
|
|
fixup REG_S, zero, (a0), 11f
|
|
addi a0, a0, SZREG
|
|
bltu a0, t1, 1b
|
|
2:
|
|
bltu a0, a3, 5f
|
|
|
|
3:
|
|
/* Disable access to user memory */
|
|
csrc sstatus, t6
|
|
li a0, 0
|
|
ret
|
|
4: /* Edge case: unalignment */
|
|
fixup sb, zero, (a0), 11f
|
|
addi a0, a0, 1
|
|
bltu a0, t0, 4b
|
|
j 1b
|
|
5: /* Edge case: remainder */
|
|
fixup sb, zero, (a0), 11f
|
|
addi a0, a0, 1
|
|
bltu a0, a3, 5b
|
|
j 3b
|
|
ENDPROC(__clear_user)
|
|
|
|
.section .fixup,"ax"
|
|
.balign 4
|
|
/* Fixup code for __copy_user(10) and __clear_user(11) */
|
|
10:
|
|
/* Disable access to user memory */
|
|
csrs sstatus, t6
|
|
mv a0, a2
|
|
ret
|
|
11:
|
|
csrs sstatus, t6
|
|
mv a0, a1
|
|
ret
|
|
.previous
|