| #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(__asm_copy_to_user) | 
 | ENTRY(__asm_copy_from_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(__asm_copy_to_user) | 
 | ENDPROC(__asm_copy_from_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 |