1 #include <linux/linkage.h>
2 #include <linux/export.h>
4 #include <asm/asm-extable.h>
7 #include <asm/alternative-macros.h>
9 .macro fixup op reg addr lbl
12 _asm_extable 100b, \lbl
15 SYM_FUNC_START(__asm_copy_to_user)
16 #ifdef CONFIG_RISCV_ISA_V
17 ALTERNATIVE("j fallback_scalar_usercopy", "nop", 0, RISCV_ISA_EXT_ZVE32X, CONFIG_RISCV_ISA_V)
18 REG_L t0, riscv_v_usercopy_threshold
19 bltu a2, t0, fallback_scalar_usercopy
20 tail enter_vector_usercopy
22 SYM_FUNC_START(fallback_scalar_usercopy)
24 /* Enable access to user memory */
29 * Save the terminal address which will be used to compute the number
30 * of bytes copied in case of a fixup exception.
35 * Register allocation for code below:
36 * a0 - start of uncopied dst
37 * a1 - start of uncopied src
39 * t0 - end of uncopied dst
44 * Use byte copy only if too small.
45 * SZREG holds 4 for RV32 and 8 for RV64
47 li a3, 9*SZREG-1 /* size must >= (word_copy stride + SZREG-1) */
48 bltu a2, a3, .Lbyte_copy_tail
51 * Copy first bytes until dst is aligned to word boundary.
53 * t1 - start of aligned dst
56 andi t1, t1, ~(SZREG-1)
57 /* dst is already aligned, skip */
58 beq a0, t1, .Lskip_align_dst
60 /* a5 - one byte for copying data */
61 fixup lb a5, 0(a1), 10f
62 addi a1, a1, 1 /* src */
63 fixup sb a5, 0(a0), 10f
64 addi a0, a0, 1 /* dst */
65 bltu a0, t1, 1b /* t1 - start of aligned dst */
70 * Use shift-copy if src is misaligned.
71 * Use word-copy if both src and dst are aligned because
72 * can not use shift-copy which do not require shifting
74 /* a1 - start of src */
80 * Both src and dst are aligned, unrolled word copy
82 * a0 - start of aligned dst
83 * a1 - start of aligned src
84 * t0 - end of aligned dst
86 addi t0, t0, -(8*SZREG) /* not to over run */
88 fixup REG_L a4, 0(a1), 10f
89 fixup REG_L a5, SZREG(a1), 10f
90 fixup REG_L a6, 2*SZREG(a1), 10f
91 fixup REG_L a7, 3*SZREG(a1), 10f
92 fixup REG_L t1, 4*SZREG(a1), 10f
93 fixup REG_L t2, 5*SZREG(a1), 10f
94 fixup REG_L t3, 6*SZREG(a1), 10f
95 fixup REG_L t4, 7*SZREG(a1), 10f
96 fixup REG_S a4, 0(a0), 10f
97 fixup REG_S a5, SZREG(a0), 10f
98 fixup REG_S a6, 2*SZREG(a0), 10f
99 fixup REG_S a7, 3*SZREG(a0), 10f
100 fixup REG_S t1, 4*SZREG(a0), 10f
101 fixup REG_S t2, 5*SZREG(a0), 10f
102 fixup REG_S t3, 6*SZREG(a0), 10f
103 fixup REG_S t4, 7*SZREG(a0), 10f
108 addi t0, t0, 8*SZREG /* revert to original value */
114 * Word copy with shifting.
115 * For misaligned copy we still perform aligned word copy, but
116 * we need to use the value fetched from the previous iteration and
118 * This is safe because reading is less than a word size.
120 * a0 - start of aligned dst
122 * a3 - a1 & mask:(SZREG-1)
123 * t0 - end of uncopied dst
124 * t1 - end of aligned dst
126 /* calculating aligned word boundary for dst */
127 andi t1, t0, ~(SZREG-1)
128 /* Converting unaligned src to aligned src */
129 andi a1, a1, ~(SZREG-1)
136 slli t3, a3, 3 /* converting bytes in a3 to bits */
140 /* Load the first word to combine with second word */
141 fixup REG_L a5, 0(a1), 10f
144 /* Main shifting copy
146 * a0 - start of aligned dst
147 * a1 - start of aligned src
148 * t1 - end of aligned dst
151 /* At least one iteration will be executed */
153 fixup REG_L a5, SZREG(a1), 10f
157 fixup REG_S a2, 0(a0), 10f
161 /* Revert src to original unaligned value */
166 * Byte copy anything left.
168 * a0 - start of remaining dst
169 * a1 - start of remaining src
170 * t0 - end of remaining dst
172 bgeu a0, t0, .Lout_copy_user /* check if end of copy */
174 fixup lb a5, 0(a1), 10f
175 addi a1, a1, 1 /* src */
176 fixup sb a5, 0(a0), 10f
177 addi a0, a0, 1 /* dst */
178 bltu a0, t0, 4b /* t0 - end of dst */
181 /* Disable access to user memory */
186 /* Exception fixup code */
188 /* Disable access to user memory */
192 SYM_FUNC_END(__asm_copy_to_user)
193 SYM_FUNC_END(fallback_scalar_usercopy)
194 EXPORT_SYMBOL(__asm_copy_to_user)
195 SYM_FUNC_ALIAS(__asm_copy_from_user, __asm_copy_to_user)
196 EXPORT_SYMBOL(__asm_copy_from_user)
199 SYM_FUNC_START(__clear_user)
201 /* Enable access to user memory */
207 andi t1, a3, ~(SZREG-1)
208 andi t0, t0, ~(SZREG-1)
210 * a3: terminal address of target region
211 * t0: lowest doubleword-aligned address in target region
212 * t1: highest doubleword-aligned address in target region
217 fixup REG_S, zero, (a0), 11f
224 /* Disable access to user memory */
228 4: /* Edge case: unalignment */
229 fixup sb, zero, (a0), 11f
233 5: /* Edge case: remainder */
234 fixup sb, zero, (a0), 11f
239 /* Exception fixup code */
241 /* Disable access to user memory */
245 SYM_FUNC_END(__clear_user)
246 EXPORT_SYMBOL(__clear_user)