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