1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 * User Space Access Routines
5 * Copyright (C) 2000-2002 Hewlett-Packard (John Marvin)
6 * Copyright (C) 2000 Richard Hirst <rhirst with parisc-linux.org>
7 * Copyright (C) 2001 Matthieu Delahaye <delahaym at esiee.fr>
8 * Copyright (C) 2003 Randolph Chung <tausq with parisc-linux.org>
9 * Copyright (C) 2017 Helge Deller <deller@gmx.de>
10 * Copyright (C) 2017 John David Anglin <dave.anglin@bell.net>
14 * These routines still have plenty of room for optimization
15 * (word & doubleword load/store, dual issue, store hints, etc.).
19 * The following routines assume that space register 3 (sr3) contains
20 * the space id associated with the current users address space.
26 #include <asm/assembly.h>
27 #include <asm/errno.h>
28 #include <linux/linkage.h>
31 * get_sr gets the appropriate space value into
32 * sr1 for kernel/user space access, depending
33 * on the flag stored in the task structure.
38 ldw TI_SEGMENT(%r1),%r22
46 * unsigned long lclear_user(void *to, unsigned long n)
48 * Returns 0 for success.
49 * otherwise, returns number of bytes not transferred.
52 ENTRY_CFI(lclear_user)
53 comib,=,n 0,%r25,$lclu_done
56 addib,<> -1,%r25,$lclu_loop
57 1: stbs,ma %r0,1(%sr1,%r26)
66 ASM_EXCEPTIONTABLE_ENTRY(1b,2b)
67 ENDPROC_CFI(lclear_user)
71 * long lstrnlen_user(char *s, long n)
73 * Returns 0 if exception before zero byte or reaching N,
74 * N+1 if N would be exceeded,
75 * else strlen + 1 (i.e. includes zero byte).
78 ENTRY_CFI(lstrnlen_user)
79 comib,= 0,%r25,$lslen_nzero
82 1: ldbs,ma 1(%sr1,%r26),%r1
84 comib,=,n 0,%r1,$lslen_done
85 addib,<> -1,%r25,$lslen_loop
86 2: ldbs,ma 1(%sr1,%r26),%r1
93 ldo 1(%r26),%r26 /* special case for N == 0 */
96 copy %r24,%r26 /* reset r26 so 0 is returned on fault */
98 ASM_EXCEPTIONTABLE_ENTRY(1b,3b)
99 ASM_EXCEPTIONTABLE_ENTRY(2b,3b)
101 ENDPROC_CFI(lstrnlen_user)
105 * unsigned long pa_memcpy(void *dstp, const void *srcp, unsigned long len)
108 * - sr1 already contains space of source region
109 * - sr2 already contains space of destination region
112 * - number of bytes that could not be copied.
113 * On success, this will be zero.
115 * This code is based on a C-implementation of a copy routine written by
116 * Randolph Chung, which in turn was derived from the glibc.
118 * Several strategies are tried to try to get the best performance for various
119 * conditions. In the optimal case, we copy by loops that copy 32- or 16-bytes
120 * at a time using general registers. Unaligned copies are handled either by
121 * aligning the destination and then using shift-and-write method, or in a few
122 * cases by falling back to a byte-at-a-time copy.
124 * Testing with various alignments and buffer sizes shows that this code is
125 * often >10x faster than a simple byte-at-a-time copy, even for strangely
126 * aligned operands. It is interesting to note that the glibc version of memcpy
127 * (written in C) is actually quite fast already. This routine is able to beat
128 * it by 30-40% for aligned copies because of the loop unrolling, but in some
129 * cases the glibc version is still slightly faster. This lends more
130 * credibility that gcc can generate very good code as long as we are careful.
132 * Possible optimizations:
133 * - add cache prefetching
134 * - try not to use the post-increment address modifiers; they may create
135 * additional interlocks. Assumption is that those were only efficient on old
136 * machines (pre PA8000 processors)
161 /* Last destination address */
164 /* short copy with less than 16 bytes? */
165 cmpib,COND(>>=),n 15,len,.Lbyte_loop
167 /* same alignment? */
170 cmpib,<>,n 0,t1,.Lunaligned_copy
173 /* only do 64-bit copies if we can get aligned. */
175 cmpib,<>,n 0,t1,.Lalign_loop32
177 /* loop until we are 64-bit aligned */
180 cmpib,=,n 0,t1,.Lcopy_loop_16_start
181 20: ldb,ma 1(srcspc,src),t1
182 21: stb,ma t1,1(dstspc,dst)
186 ASM_EXCEPTIONTABLE_ENTRY(20b,.Lcopy_done)
187 ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done)
189 .Lcopy_loop_16_start:
192 cmpb,COND(>>=),n t0,len,.Lword_loop
194 10: ldd 0(srcspc,src),t1
195 11: ldd 8(srcspc,src),t2
197 12: std,ma t1,8(dstspc,dst)
198 13: std,ma t2,8(dstspc,dst)
199 14: ldd 0(srcspc,src),t1
200 15: ldd 8(srcspc,src),t2
202 16: std,ma t1,8(dstspc,dst)
203 17: std,ma t2,8(dstspc,dst)
205 ASM_EXCEPTIONTABLE_ENTRY(10b,.Lcopy_done)
206 ASM_EXCEPTIONTABLE_ENTRY(11b,.Lcopy16_fault)
207 ASM_EXCEPTIONTABLE_ENTRY(12b,.Lcopy_done)
208 ASM_EXCEPTIONTABLE_ENTRY(13b,.Lcopy_done)
209 ASM_EXCEPTIONTABLE_ENTRY(14b,.Lcopy_done)
210 ASM_EXCEPTIONTABLE_ENTRY(15b,.Lcopy16_fault)
211 ASM_EXCEPTIONTABLE_ENTRY(16b,.Lcopy_done)
212 ASM_EXCEPTIONTABLE_ENTRY(17b,.Lcopy_done)
218 cmpib,COND(>>=),n 3,len,.Lbyte_loop
219 20: ldw,ma 4(srcspc,src),t1
220 21: stw,ma t1,4(dstspc,dst)
224 ASM_EXCEPTIONTABLE_ENTRY(20b,.Lcopy_done)
225 ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done)
227 #endif /* CONFIG_64BIT */
229 /* loop until we are 32-bit aligned */
232 cmpib,=,n 0,t1,.Lcopy_loop_8
233 20: ldb,ma 1(srcspc,src),t1
234 21: stb,ma t1,1(dstspc,dst)
238 ASM_EXCEPTIONTABLE_ENTRY(20b,.Lcopy_done)
239 ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done)
243 cmpib,COND(>>=),n 15,len,.Lbyte_loop
245 10: ldw 0(srcspc,src),t1
246 11: ldw 4(srcspc,src),t2
247 12: stw,ma t1,4(dstspc,dst)
248 13: stw,ma t2,4(dstspc,dst)
249 14: ldw 8(srcspc,src),t1
250 15: ldw 12(srcspc,src),t2
252 16: stw,ma t1,4(dstspc,dst)
253 17: stw,ma t2,4(dstspc,dst)
255 ASM_EXCEPTIONTABLE_ENTRY(10b,.Lcopy_done)
256 ASM_EXCEPTIONTABLE_ENTRY(11b,.Lcopy8_fault)
257 ASM_EXCEPTIONTABLE_ENTRY(12b,.Lcopy_done)
258 ASM_EXCEPTIONTABLE_ENTRY(13b,.Lcopy_done)
259 ASM_EXCEPTIONTABLE_ENTRY(14b,.Lcopy_done)
260 ASM_EXCEPTIONTABLE_ENTRY(15b,.Lcopy8_fault)
261 ASM_EXCEPTIONTABLE_ENTRY(16b,.Lcopy_done)
262 ASM_EXCEPTIONTABLE_ENTRY(17b,.Lcopy_done)
268 cmpclr,COND(<>) len,%r0,%r0
270 20: ldb 0(srcspc,src),t1
272 21: stb,ma t1,1(dstspc,dst)
276 ASM_EXCEPTIONTABLE_ENTRY(20b,.Lcopy_done)
277 ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done)
284 /* src and dst are not aligned the same way. */
285 /* need to go the hard way */
287 /* align until dst is 32bit-word-aligned */
289 cmpib,=,n 0,t1,.Lcopy_dstaligned
290 20: ldb 0(srcspc,src),t1
292 21: stb,ma t1,1(dstspc,dst)
296 ASM_EXCEPTIONTABLE_ENTRY(20b,.Lcopy_done)
297 ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done)
301 /* store src, dst and len in safe place */
306 /* len now needs give number of words to copy */
310 * Copy from a not-aligned src to an aligned dst using shifts.
311 * Handles 4 words per loop.
319 /* Make src aligned by rounding it down. */
327 cmpb,COND(=) %r0,len,.Lcda_finish
330 1: ldw,ma 4(srcspc,src), a3
331 ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
332 1: ldw,ma 4(srcspc,src), a0
333 ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
336 1: ldw,ma 4(srcspc,src), a2
337 ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
338 1: ldw,ma 4(srcspc,src), a3
339 ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
341 cmpb,COND(=),n %r0,len,.Ldo0
343 1: ldw,ma 4(srcspc,src), a0
344 ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
345 shrpw a2, a3, %sar, t0
346 1: stw,ma t0, 4(dstspc,dst)
347 ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcopy_done)
349 1: ldw,ma 4(srcspc,src), a1
350 ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
351 shrpw a3, a0, %sar, t0
352 1: stw,ma t0, 4(dstspc,dst)
353 ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcopy_done)
355 1: ldw,ma 4(srcspc,src), a2
356 ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
357 shrpw a0, a1, %sar, t0
358 1: stw,ma t0, 4(dstspc,dst)
359 ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcopy_done)
361 1: ldw,ma 4(srcspc,src), a3
362 ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
363 shrpw a1, a2, %sar, t0
364 1: stw,ma t0, 4(dstspc,dst)
365 ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcopy_done)
367 cmpb,COND(<>) %r0,len,.Ldo4
370 shrpw a2, a3, %sar, t0
371 1: stw,ma t0, 4(dstspc,dst)
372 ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcopy_done)
376 /* calculate new src, dst and len and jump to byte-copy loop */
383 1: ldw,ma 4(srcspc,src), a0
384 ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
385 1: ldw,ma 4(srcspc,src), a1
386 ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
390 1: ldw,ma 4(srcspc,src), a1
391 ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
392 1: ldw,ma 4(srcspc,src), a2
393 ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
398 /* fault exception fixup handlers: */
402 10: std,ma t1,8(dstspc,dst)
403 ASM_EXCEPTIONTABLE_ENTRY(10b,.Lcopy_done)
408 10: stw,ma t1,4(dstspc,dst)
409 ASM_EXCEPTIONTABLE_ENTRY(10b,.Lcopy_done)
410 ENDPROC_CFI(pa_memcpy)