| #include <linux/linkage.h> | 
 | #include <asm-generic/export.h> | 
 | #include <asm/asm.h> | 
 | #include <asm/asm-extable.h> | 
 | #include <asm/csr.h> | 
 |  | 
 | 	.macro fixup op reg addr lbl | 
 | 100: | 
 | 	\op \reg, \addr | 
 | 	_asm_extable	100b, \lbl | 
 | 	.endm | 
 |  | 
 | ENTRY(__asm_copy_to_user) | 
 | ENTRY(__asm_copy_from_user) | 
 |  | 
 | 	/* Enable access to user memory */ | 
 | 	li t6, SR_SUM | 
 | 	csrs CSR_STATUS, t6 | 
 |  | 
 | 	/* | 
 | 	 * Save the terminal address which will be used to compute the number | 
 | 	 * of bytes copied in case of a fixup exception. | 
 | 	 */ | 
 | 	add	t5, a0, a2 | 
 |  | 
 | 	/* | 
 | 	 * Register allocation for code below: | 
 | 	 * a0 - start of uncopied dst | 
 | 	 * a1 - start of uncopied src | 
 | 	 * a2 - size | 
 | 	 * t0 - end of uncopied dst | 
 | 	 */ | 
 | 	add	t0, a0, a2 | 
 |  | 
 | 	/* | 
 | 	 * Use byte copy only if too small. | 
 | 	 * SZREG holds 4 for RV32 and 8 for RV64 | 
 | 	 */ | 
 | 	li	a3, 9*SZREG /* size must be larger than size in word_copy */ | 
 | 	bltu	a2, a3, .Lbyte_copy_tail | 
 |  | 
 | 	/* | 
 | 	 * Copy first bytes until dst is aligned to word boundary. | 
 | 	 * a0 - start of dst | 
 | 	 * t1 - start of aligned dst | 
 | 	 */ | 
 | 	addi	t1, a0, SZREG-1 | 
 | 	andi	t1, t1, ~(SZREG-1) | 
 | 	/* dst is already aligned, skip */ | 
 | 	beq	a0, t1, .Lskip_align_dst | 
 | 1: | 
 | 	/* a5 - one byte for copying data */ | 
 | 	fixup lb      a5, 0(a1), 10f | 
 | 	addi	a1, a1, 1	/* src */ | 
 | 	fixup sb      a5, 0(a0), 10f | 
 | 	addi	a0, a0, 1	/* dst */ | 
 | 	bltu	a0, t1, 1b	/* t1 - start of aligned dst */ | 
 |  | 
 | .Lskip_align_dst: | 
 | 	/* | 
 | 	 * Now dst is aligned. | 
 | 	 * Use shift-copy if src is misaligned. | 
 | 	 * Use word-copy if both src and dst are aligned because | 
 | 	 * can not use shift-copy which do not require shifting | 
 | 	 */ | 
 | 	/* a1 - start of src */ | 
 | 	andi	a3, a1, SZREG-1 | 
 | 	bnez	a3, .Lshift_copy | 
 |  | 
 | .Lword_copy: | 
 |         /* | 
 | 	 * Both src and dst are aligned, unrolled word copy | 
 | 	 * | 
 | 	 * a0 - start of aligned dst | 
 | 	 * a1 - start of aligned src | 
 | 	 * t0 - end of aligned dst | 
 | 	 */ | 
 | 	addi	t0, t0, -(8*SZREG) /* not to over run */ | 
 | 2: | 
 | 	fixup REG_L   a4,        0(a1), 10f | 
 | 	fixup REG_L   a5,    SZREG(a1), 10f | 
 | 	fixup REG_L   a6,  2*SZREG(a1), 10f | 
 | 	fixup REG_L   a7,  3*SZREG(a1), 10f | 
 | 	fixup REG_L   t1,  4*SZREG(a1), 10f | 
 | 	fixup REG_L   t2,  5*SZREG(a1), 10f | 
 | 	fixup REG_L   t3,  6*SZREG(a1), 10f | 
 | 	fixup REG_L   t4,  7*SZREG(a1), 10f | 
 | 	fixup REG_S   a4,        0(a0), 10f | 
 | 	fixup REG_S   a5,    SZREG(a0), 10f | 
 | 	fixup REG_S   a6,  2*SZREG(a0), 10f | 
 | 	fixup REG_S   a7,  3*SZREG(a0), 10f | 
 | 	fixup REG_S   t1,  4*SZREG(a0), 10f | 
 | 	fixup REG_S   t2,  5*SZREG(a0), 10f | 
 | 	fixup REG_S   t3,  6*SZREG(a0), 10f | 
 | 	fixup REG_S   t4,  7*SZREG(a0), 10f | 
 | 	addi	a0, a0, 8*SZREG | 
 | 	addi	a1, a1, 8*SZREG | 
 | 	bltu	a0, t0, 2b | 
 |  | 
 | 	addi	t0, t0, 8*SZREG /* revert to original value */ | 
 | 	j	.Lbyte_copy_tail | 
 |  | 
 | .Lshift_copy: | 
 |  | 
 | 	/* | 
 | 	 * Word copy with shifting. | 
 | 	 * For misaligned copy we still perform aligned word copy, but | 
 | 	 * we need to use the value fetched from the previous iteration and | 
 | 	 * do some shifts. | 
 | 	 * This is safe because reading is less than a word size. | 
 | 	 * | 
 | 	 * a0 - start of aligned dst | 
 | 	 * a1 - start of src | 
 | 	 * a3 - a1 & mask:(SZREG-1) | 
 | 	 * t0 - end of uncopied dst | 
 | 	 * t1 - end of aligned dst | 
 | 	 */ | 
 | 	/* calculating aligned word boundary for dst */ | 
 | 	andi	t1, t0, ~(SZREG-1) | 
 | 	/* Converting unaligned src to aligned src */ | 
 | 	andi	a1, a1, ~(SZREG-1) | 
 |  | 
 | 	/* | 
 | 	 * Calculate shifts | 
 | 	 * t3 - prev shift | 
 | 	 * t4 - current shift | 
 | 	 */ | 
 | 	slli	t3, a3, 3 /* converting bytes in a3 to bits */ | 
 | 	li	a5, SZREG*8 | 
 | 	sub	t4, a5, t3 | 
 |  | 
 | 	/* Load the first word to combine with second word */ | 
 | 	fixup REG_L   a5, 0(a1), 10f | 
 |  | 
 | 3: | 
 | 	/* Main shifting copy | 
 | 	 * | 
 | 	 * a0 - start of aligned dst | 
 | 	 * a1 - start of aligned src | 
 | 	 * t1 - end of aligned dst | 
 | 	 */ | 
 |  | 
 | 	/* At least one iteration will be executed */ | 
 | 	srl	a4, a5, t3 | 
 | 	fixup REG_L   a5, SZREG(a1), 10f | 
 | 	addi	a1, a1, SZREG | 
 | 	sll	a2, a5, t4 | 
 | 	or	a2, a2, a4 | 
 | 	fixup REG_S   a2, 0(a0), 10f | 
 | 	addi	a0, a0, SZREG | 
 | 	bltu	a0, t1, 3b | 
 |  | 
 | 	/* Revert src to original unaligned value  */ | 
 | 	add	a1, a1, a3 | 
 |  | 
 | .Lbyte_copy_tail: | 
 | 	/* | 
 | 	 * Byte copy anything left. | 
 | 	 * | 
 | 	 * a0 - start of remaining dst | 
 | 	 * a1 - start of remaining src | 
 | 	 * t0 - end of remaining dst | 
 | 	 */ | 
 | 	bgeu	a0, t0, .Lout_copy_user  /* check if end of copy */ | 
 | 4: | 
 | 	fixup lb      a5, 0(a1), 10f | 
 | 	addi	a1, a1, 1	/* src */ | 
 | 	fixup sb      a5, 0(a0), 10f | 
 | 	addi	a0, a0, 1	/* dst */ | 
 | 	bltu	a0, t0, 4b	/* t0 - end of dst */ | 
 |  | 
 | .Lout_copy_user: | 
 | 	/* Disable access to user memory */ | 
 | 	csrc CSR_STATUS, t6 | 
 | 	li	a0, 0 | 
 | 	ret | 
 |  | 
 | 	/* Exception fixup code */ | 
 | 10: | 
 | 	/* Disable access to user memory */ | 
 | 	csrc CSR_STATUS, t6 | 
 | 	sub a0, t5, a0 | 
 | 	ret | 
 | ENDPROC(__asm_copy_to_user) | 
 | ENDPROC(__asm_copy_from_user) | 
 | EXPORT_SYMBOL(__asm_copy_to_user) | 
 | EXPORT_SYMBOL(__asm_copy_from_user) | 
 |  | 
 |  | 
 | ENTRY(__clear_user) | 
 |  | 
 | 	/* Enable access to user memory */ | 
 | 	li t6, SR_SUM | 
 | 	csrs CSR_STATUS, 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 CSR_STATUS, 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 | 
 |  | 
 | 	/* Exception fixup code */ | 
 | 11: | 
 | 	/* Disable access to user memory */ | 
 | 	csrc CSR_STATUS, t6 | 
 | 	sub a0, a3, a0 | 
 | 	ret | 
 | ENDPROC(__clear_user) | 
 | EXPORT_SYMBOL(__clear_user) |