]>
Commit | Line | Data |
---|---|---|
5d8544e2 | 1 | #include <linux/linkage.h> |
62694797 | 2 | #include <linux/export.h> |
5d8544e2 | 3 | #include <asm/asm.h> |
6dd10d91 | 4 | #include <asm/asm-extable.h> |
5d8544e2 PD |
5 | #include <asm/csr.h> |
6 | ||
5d8544e2 | 7 | .macro fixup op reg addr lbl |
abc71bf0 | 8 | 100: |
5d8544e2 | 9 | \op \reg, \addr |
6dd10d91 | 10 | _asm_extable 100b, \lbl |
5d8544e2 PD |
11 | .endm |
12 | ||
76329c69 | 13 | SYM_FUNC_START(__asm_copy_to_user) |
5d8544e2 PD |
14 | |
15 | /* Enable access to user memory */ | |
16 | li t6, SR_SUM | |
a4c3733d | 17 | csrs CSR_STATUS, t6 |
5d8544e2 | 18 | |
4b05b993 AG |
19 | /* |
20 | * Save the terminal address which will be used to compute the number | |
21 | * of bytes copied in case of a fixup exception. | |
22 | */ | |
23 | add t5, a0, a2 | |
5d8544e2 | 24 | |
5d8544e2 | 25 | /* |
ca6eaaa2 AT |
26 | * Register allocation for code below: |
27 | * a0 - start of uncopied dst | |
28 | * a1 - start of uncopied src | |
29 | * a2 - size | |
30 | * t0 - end of uncopied dst | |
5d8544e2 | 31 | */ |
ca6eaaa2 | 32 | add t0, a0, a2 |
ca6eaaa2 AT |
33 | |
34 | /* | |
35 | * Use byte copy only if too small. | |
ea196c54 | 36 | * SZREG holds 4 for RV32 and 8 for RV64 |
ca6eaaa2 | 37 | */ |
6010d300 | 38 | li a3, 9*SZREG /* size must be larger than size in word_copy */ |
ca6eaaa2 AT |
39 | bltu a2, a3, .Lbyte_copy_tail |
40 | ||
41 | /* | |
ea196c54 | 42 | * Copy first bytes until dst is aligned to word boundary. |
ca6eaaa2 AT |
43 | * a0 - start of dst |
44 | * t1 - start of aligned dst | |
45 | */ | |
46 | addi t1, a0, SZREG-1 | |
47 | andi t1, t1, ~(SZREG-1) | |
48 | /* dst is already aligned, skip */ | |
ea196c54 | 49 | beq a0, t1, .Lskip_align_dst |
5d8544e2 | 50 | 1: |
ca6eaaa2 AT |
51 | /* a5 - one byte for copying data */ |
52 | fixup lb a5, 0(a1), 10f | |
53 | addi a1, a1, 1 /* src */ | |
54 | fixup sb a5, 0(a0), 10f | |
55 | addi a0, a0, 1 /* dst */ | |
56 | bltu a0, t1, 1b /* t1 - start of aligned dst */ | |
57 | ||
ea196c54 | 58 | .Lskip_align_dst: |
ca6eaaa2 AT |
59 | /* |
60 | * Now dst is aligned. | |
61 | * Use shift-copy if src is misaligned. | |
62 | * Use word-copy if both src and dst are aligned because | |
63 | * can not use shift-copy which do not require shifting | |
64 | */ | |
65 | /* a1 - start of src */ | |
66 | andi a3, a1, SZREG-1 | |
67 | bnez a3, .Lshift_copy | |
68 | ||
69 | .Lword_copy: | |
70 | /* | |
71 | * Both src and dst are aligned, unrolled word copy | |
72 | * | |
73 | * a0 - start of aligned dst | |
74 | * a1 - start of aligned src | |
ca6eaaa2 AT |
75 | * t0 - end of aligned dst |
76 | */ | |
6010d300 | 77 | addi t0, t0, -(8*SZREG) /* not to over run */ |
5d8544e2 | 78 | 2: |
ca6eaaa2 AT |
79 | fixup REG_L a4, 0(a1), 10f |
80 | fixup REG_L a5, SZREG(a1), 10f | |
81 | fixup REG_L a6, 2*SZREG(a1), 10f | |
82 | fixup REG_L a7, 3*SZREG(a1), 10f | |
83 | fixup REG_L t1, 4*SZREG(a1), 10f | |
84 | fixup REG_L t2, 5*SZREG(a1), 10f | |
85 | fixup REG_L t3, 6*SZREG(a1), 10f | |
86 | fixup REG_L t4, 7*SZREG(a1), 10f | |
87 | fixup REG_S a4, 0(a0), 10f | |
88 | fixup REG_S a5, SZREG(a0), 10f | |
89 | fixup REG_S a6, 2*SZREG(a0), 10f | |
90 | fixup REG_S a7, 3*SZREG(a0), 10f | |
91 | fixup REG_S t1, 4*SZREG(a0), 10f | |
92 | fixup REG_S t2, 5*SZREG(a0), 10f | |
93 | fixup REG_S t3, 6*SZREG(a0), 10f | |
94 | fixup REG_S t4, 7*SZREG(a0), 10f | |
95 | addi a0, a0, 8*SZREG | |
96 | addi a1, a1, 8*SZREG | |
97 | bltu a0, t0, 2b | |
98 | ||
6010d300 | 99 | addi t0, t0, 8*SZREG /* revert to original value */ |
ca6eaaa2 AT |
100 | j .Lbyte_copy_tail |
101 | ||
102 | .Lshift_copy: | |
103 | ||
104 | /* | |
105 | * Word copy with shifting. | |
106 | * For misaligned copy we still perform aligned word copy, but | |
107 | * we need to use the value fetched from the previous iteration and | |
108 | * do some shifts. | |
ea196c54 | 109 | * This is safe because reading is less than a word size. |
ca6eaaa2 AT |
110 | * |
111 | * a0 - start of aligned dst | |
112 | * a1 - start of src | |
113 | * a3 - a1 & mask:(SZREG-1) | |
114 | * t0 - end of uncopied dst | |
115 | * t1 - end of aligned dst | |
116 | */ | |
117 | /* calculating aligned word boundary for dst */ | |
118 | andi t1, t0, ~(SZREG-1) | |
ea196c54 | 119 | /* Converting unaligned src to aligned src */ |
ca6eaaa2 AT |
120 | andi a1, a1, ~(SZREG-1) |
121 | ||
122 | /* | |
123 | * Calculate shifts | |
124 | * t3 - prev shift | |
125 | * t4 - current shift | |
126 | */ | |
22b5f16f | 127 | slli t3, a3, 3 /* converting bytes in a3 to bits */ |
ca6eaaa2 AT |
128 | li a5, SZREG*8 |
129 | sub t4, a5, t3 | |
130 | ||
ea196c54 | 131 | /* Load the first word to combine with second word */ |
ca6eaaa2 | 132 | fixup REG_L a5, 0(a1), 10f |
5d8544e2 PD |
133 | |
134 | 3: | |
ca6eaaa2 AT |
135 | /* Main shifting copy |
136 | * | |
137 | * a0 - start of aligned dst | |
138 | * a1 - start of aligned src | |
139 | * t1 - end of aligned dst | |
140 | */ | |
141 | ||
142 | /* At least one iteration will be executed */ | |
143 | srl a4, a5, t3 | |
144 | fixup REG_L a5, SZREG(a1), 10f | |
145 | addi a1, a1, SZREG | |
146 | sll a2, a5, t4 | |
147 | or a2, a2, a4 | |
148 | fixup REG_S a2, 0(a0), 10f | |
149 | addi a0, a0, SZREG | |
150 | bltu a0, t1, 3b | |
151 | ||
152 | /* Revert src to original unaligned value */ | |
153 | add a1, a1, a3 | |
154 | ||
155 | .Lbyte_copy_tail: | |
156 | /* | |
157 | * Byte copy anything left. | |
158 | * | |
159 | * a0 - start of remaining dst | |
160 | * a1 - start of remaining src | |
161 | * t0 - end of remaining dst | |
162 | */ | |
ea196c54 | 163 | bgeu a0, t0, .Lout_copy_user /* check if end of copy */ |
ca6eaaa2 AT |
164 | 4: |
165 | fixup lb a5, 0(a1), 10f | |
166 | addi a1, a1, 1 /* src */ | |
167 | fixup sb a5, 0(a0), 10f | |
168 | addi a0, a0, 1 /* dst */ | |
169 | bltu a0, t0, 4b /* t0 - end of dst */ | |
170 | ||
ea196c54 | 171 | .Lout_copy_user: |
5d8544e2 | 172 | /* Disable access to user memory */ |
a4c3733d | 173 | csrc CSR_STATUS, t6 |
ca6eaaa2 | 174 | li a0, 0 |
5d8544e2 | 175 | ret |
9d504f9a JZ |
176 | |
177 | /* Exception fixup code */ | |
178 | 10: | |
179 | /* Disable access to user memory */ | |
c08b4848 | 180 | csrc CSR_STATUS, t6 |
4b05b993 | 181 | sub a0, t5, a0 |
9d504f9a | 182 | ret |
76329c69 | 183 | SYM_FUNC_END(__asm_copy_to_user) |
4d47ce15 | 184 | EXPORT_SYMBOL(__asm_copy_to_user) |
76329c69 | 185 | SYM_FUNC_ALIAS(__asm_copy_from_user, __asm_copy_to_user) |
4d47ce15 | 186 | EXPORT_SYMBOL(__asm_copy_from_user) |
5d8544e2 PD |
187 | |
188 | ||
76329c69 | 189 | SYM_FUNC_START(__clear_user) |
5d8544e2 PD |
190 | |
191 | /* Enable access to user memory */ | |
192 | li t6, SR_SUM | |
a4c3733d | 193 | csrs CSR_STATUS, t6 |
5d8544e2 PD |
194 | |
195 | add a3, a0, a1 | |
196 | addi t0, a0, SZREG-1 | |
197 | andi t1, a3, ~(SZREG-1) | |
198 | andi t0, t0, ~(SZREG-1) | |
199 | /* | |
200 | * a3: terminal address of target region | |
201 | * t0: lowest doubleword-aligned address in target region | |
202 | * t1: highest doubleword-aligned address in target region | |
203 | */ | |
204 | bgeu t0, t1, 2f | |
205 | bltu a0, t0, 4f | |
206 | 1: | |
ebcbd75e | 207 | fixup REG_S, zero, (a0), 11f |
5d8544e2 PD |
208 | addi a0, a0, SZREG |
209 | bltu a0, t1, 1b | |
210 | 2: | |
211 | bltu a0, a3, 5f | |
212 | ||
213 | 3: | |
214 | /* Disable access to user memory */ | |
a4c3733d | 215 | csrc CSR_STATUS, t6 |
5d8544e2 PD |
216 | li a0, 0 |
217 | ret | |
218 | 4: /* Edge case: unalignment */ | |
ebcbd75e | 219 | fixup sb, zero, (a0), 11f |
5d8544e2 PD |
220 | addi a0, a0, 1 |
221 | bltu a0, t0, 4b | |
222 | j 1b | |
223 | 5: /* Edge case: remainder */ | |
ebcbd75e | 224 | fixup sb, zero, (a0), 11f |
5d8544e2 PD |
225 | addi a0, a0, 1 |
226 | bltu a0, a3, 5b | |
227 | j 3b | |
5d8544e2 | 228 | |
9d504f9a | 229 | /* Exception fixup code */ |
ebcbd75e | 230 | 11: |
9d504f9a | 231 | /* Disable access to user memory */ |
c08b4848 | 232 | csrc CSR_STATUS, t6 |
4b05b993 | 233 | sub a0, a3, a0 |
5d8544e2 | 234 | ret |
76329c69 | 235 | SYM_FUNC_END(__clear_user) |
9d504f9a | 236 | EXPORT_SYMBOL(__clear_user) |