uaccess.S 5.1 KB
Newer Older
1
#include <linux/linkage.h>
2
#include <asm-generic/export.h>
3
#include <asm/asm.h>
4
#include <asm/asm-extable.h>
5 6 7
#include <asm/csr.h>

	.macro fixup op reg addr lbl
8
100:
9
	\op \reg, \addr
10
	_asm_extable	100b, \lbl
11 12
	.endm

13 14
ENTRY(__asm_copy_to_user)
ENTRY(__asm_copy_from_user)
15 16 17

	/* Enable access to user memory */
	li t6, SR_SUM
18
	csrs CSR_STATUS, t6
19

20 21
	/* Save for return value */
	mv	t5, a2
22 23

	/*
24 25 26 27 28
	 * Register allocation for code below:
	 * a0 - start of uncopied dst
	 * a1 - start of uncopied src
	 * a2 - size
	 * t0 - end of uncopied dst
29
	 */
30 31 32 33
	add	t0, a0, a2

	/*
	 * Use byte copy only if too small.
34
	 * SZREG holds 4 for RV32 and 8 for RV64
35
	 */
36
	li	a3, 9*SZREG /* size must be larger than size in word_copy */
37 38 39
	bltu	a2, a3, .Lbyte_copy_tail

	/*
40
	 * Copy first bytes until dst is aligned to word boundary.
41 42 43 44 45 46
	 * a0 - start of dst
	 * t1 - start of aligned dst
	 */
	addi	t1, a0, SZREG-1
	andi	t1, t1, ~(SZREG-1)
	/* dst is already aligned, skip */
47
	beq	a0, t1, .Lskip_align_dst
48
1:
49 50 51 52 53 54 55
	/* 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 */

56
.Lskip_align_dst:
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
	/*
	 * 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
	 */
75
	addi	t0, t0, -(8*SZREG) /* not to over run */
76
2:
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
	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

97
	addi	t0, t0, 8*SZREG /* revert to original value */
98 99 100 101 102 103 104 105 106
	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.
107
	 * This is safe because reading is less than a word size.
108 109 110 111 112 113 114 115 116
	 *
	 * 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)
117
	/* Converting unaligned src to aligned src */
118 119 120 121 122 123 124
	andi	a1, a1, ~(SZREG-1)

	/*
	 * Calculate shifts
	 * t3 - prev shift
	 * t4 - current shift
	 */
125
	slli	t3, a3, 3 /* converting bytes in a3 to bits */
126 127 128
	li	a5, SZREG*8
	sub	t4, a5, t3

129
	/* Load the first word to combine with second word */
130
	fixup REG_L   a5, 0(a1), 10f
131 132

3:
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
	/* 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
	 */
161
	bgeu	a0, t0, .Lout_copy_user  /* check if end of copy */
162 163 164 165 166 167 168
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 */

169
.Lout_copy_user:
170
	/* Disable access to user memory */
171
	csrc CSR_STATUS, t6
172
	li	a0, 0
173
	ret
174 175 176 177

	/* Exception fixup code */
10:
	/* Disable access to user memory */
178
	csrc CSR_STATUS, t6
179 180
	mv a0, t5
	ret
181 182
ENDPROC(__asm_copy_to_user)
ENDPROC(__asm_copy_from_user)
183 184
EXPORT_SYMBOL(__asm_copy_to_user)
EXPORT_SYMBOL(__asm_copy_from_user)
185 186 187 188 189 190


ENTRY(__clear_user)

	/* Enable access to user memory */
	li t6, SR_SUM
191
	csrs CSR_STATUS, t6
192 193 194 195 196 197 198 199 200 201 202 203 204

	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:
205
	fixup REG_S, zero, (a0), 11f
206 207 208 209 210 211 212
	addi a0, a0, SZREG
	bltu a0, t1, 1b
2:
	bltu a0, a3, 5f

3:
	/* Disable access to user memory */
213
	csrc CSR_STATUS, t6
214 215 216
	li a0, 0
	ret
4: /* Edge case: unalignment */
217
	fixup sb, zero, (a0), 11f
218 219 220 221
	addi a0, a0, 1
	bltu a0, t0, 4b
	j 1b
5: /* Edge case: remainder */
222
	fixup sb, zero, (a0), 11f
223 224 225 226
	addi a0, a0, 1
	bltu a0, a3, 5b
	j 3b

227
	/* Exception fixup code */
228
11:
229
	/* Disable access to user memory */
230
	csrc CSR_STATUS, t6
231
	mv a0, a1
232
	ret
233 234
ENDPROC(__clear_user)
EXPORT_SYMBOL(__clear_user)