b8f7de202d85c0ba6ab871ed20e98b76f85d5282
[oweals/openwrt.git] /
1 From 7e9af733a0be196ed305ec367ea18c13525feb81 Mon Sep 17 00:00:00 2001
2 From: popcornmix <popcornmix@gmail.com>
3 Date: Mon, 28 Nov 2016 16:50:04 +0000
4 Subject: [PATCH 061/454] Improve __copy_to_user and __copy_from_user
5  performance
6
7 Provide a __copy_from_user that uses memcpy. On BCM2708, use
8 optimised memcpy/memmove/memcmp/memset implementations.
9
10 arch/arm: Add mmiocpy/set aliases for memcpy/set
11
12 See: https://github.com/raspberrypi/linux/issues/1082
13
14 copy_from_user: CPU_SW_DOMAIN_PAN compatibility
15
16 The downstream copy_from_user acceleration must also play nice with
17 CONFIG_CPU_SW_DOMAIN_PAN.
18
19 See: https://github.com/raspberrypi/linux/issues/1381
20
21 Signed-off-by: Phil Elwell <phil@raspberrypi.org>
22 ---
23  arch/arm/include/asm/string.h      |   5 +
24  arch/arm/include/asm/uaccess.h     |   3 +
25  arch/arm/lib/Makefile              |  15 +-
26  arch/arm/lib/arm-mem.h             | 159 +++++++++
27  arch/arm/lib/copy_from_user.S      |   4 +-
28  arch/arm/lib/exports_rpi.c         |  37 +++
29  arch/arm/lib/memcmp_rpi.S          | 285 ++++++++++++++++
30  arch/arm/lib/memcpy_rpi.S          |  61 ++++
31  arch/arm/lib/memcpymove.h          | 506 +++++++++++++++++++++++++++++
32  arch/arm/lib/memmove_rpi.S         |  61 ++++
33  arch/arm/lib/memset_rpi.S          | 128 ++++++++
34  arch/arm/lib/uaccess_with_memcpy.c | 120 ++++++-
35  arch/arm/mach-bcm/Kconfig          |   7 +
36  13 files changed, 1385 insertions(+), 6 deletions(-)
37  create mode 100644 arch/arm/lib/arm-mem.h
38  create mode 100644 arch/arm/lib/exports_rpi.c
39  create mode 100644 arch/arm/lib/memcmp_rpi.S
40  create mode 100644 arch/arm/lib/memcpy_rpi.S
41  create mode 100644 arch/arm/lib/memcpymove.h
42  create mode 100644 arch/arm/lib/memmove_rpi.S
43  create mode 100644 arch/arm/lib/memset_rpi.S
44
45 --- a/arch/arm/include/asm/string.h
46 +++ b/arch/arm/include/asm/string.h
47 @@ -39,6 +39,11 @@ static inline void *memset64(uint64_t *p
48         return __memset64(p, v, n * 8, v >> 32);
49  }
50  
51 +#ifdef CONFIG_BCM2835_FAST_MEMCPY
52 +#define __HAVE_ARCH_MEMCMP
53 +extern int memcmp(const void *, const void *, size_t);
54 +#endif
55 +
56  extern void __memzero(void *ptr, __kernel_size_t n);
57  
58  #define memset(p,v,n)                                                  \
59 --- a/arch/arm/include/asm/uaccess.h
60 +++ b/arch/arm/include/asm/uaccess.h
61 @@ -514,6 +514,9 @@ do {                                                                        \
62  extern unsigned long __must_check
63  arm_copy_from_user(void *to, const void __user *from, unsigned long n);
64  
65 +extern unsigned long __must_check
66 +__copy_from_user_std(void *to, const void __user *from, unsigned long n);
67 +
68  static inline unsigned long __must_check
69  raw_copy_from_user(void *to, const void __user *from, unsigned long n)
70  {
71 --- a/arch/arm/lib/Makefile
72 +++ b/arch/arm/lib/Makefile
73 @@ -7,9 +7,8 @@
74  
75  lib-y          := backtrace.o changebit.o csumipv6.o csumpartial.o   \
76                    csumpartialcopy.o csumpartialcopyuser.o clearbit.o \
77 -                  delay.o delay-loop.o findbit.o memchr.o memcpy.o   \
78 -                  memmove.o memset.o memzero.o setbit.o              \
79 -                  strchr.o strrchr.o                                 \
80 +                  delay.o delay-loop.o findbit.o memchr.o memzero.o  \
81 +                  setbit.o strchr.o strrchr.o                        \
82                    testchangebit.o testclearbit.o testsetbit.o        \
83                    ashldi3.o ashrdi3.o lshrdi3.o muldi3.o             \
84                    ucmpdi2.o lib1funcs.o div64.o                      \
85 @@ -19,6 +18,16 @@ lib-y                := backtrace.o changebit.o csumip
86  mmu-y          := clear_user.o copy_page.o getuser.o putuser.o       \
87                    copy_from_user.o copy_to_user.o
88  
89 +# Choose optimised implementations for Raspberry Pi
90 +ifeq ($(CONFIG_BCM2835_FAST_MEMCPY),y)
91 +  CFLAGS_uaccess_with_memcpy.o += -DCOPY_FROM_USER_THRESHOLD=1600
92 +  CFLAGS_uaccess_with_memcpy.o += -DCOPY_TO_USER_THRESHOLD=672
93 +  obj-$(CONFIG_MODULES) += exports_rpi.o
94 +  lib-y        += memcpy_rpi.o memmove_rpi.o memset_rpi.o memcmp_rpi.o
95 +else
96 +  lib-y        += memcpy.o memmove.o memset.o
97 +endif
98 +
99  # using lib_ here won't override already available weak symbols
100  obj-$(CONFIG_UACCESS_WITH_MEMCPY) += uaccess_with_memcpy.o
101  
102 --- /dev/null
103 +++ b/arch/arm/lib/arm-mem.h
104 @@ -0,0 +1,159 @@
105 +/*
106 +Copyright (c) 2013, Raspberry Pi Foundation
107 +Copyright (c) 2013, RISC OS Open Ltd
108 +All rights reserved.
109 +
110 +Redistribution and use in source and binary forms, with or without
111 +modification, are permitted provided that the following conditions are met:
112 +    * Redistributions of source code must retain the above copyright
113 +      notice, this list of conditions and the following disclaimer.
114 +    * Redistributions in binary form must reproduce the above copyright
115 +      notice, this list of conditions and the following disclaimer in the
116 +      documentation and/or other materials provided with the distribution.
117 +    * Neither the name of the copyright holder nor the
118 +      names of its contributors may be used to endorse or promote products
119 +      derived from this software without specific prior written permission.
120 +
121 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
122 +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
123 +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
124 +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
125 +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
126 +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
127 +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
128 +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
129 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
130 +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
131 +*/
132 +
133 +.macro myfunc fname
134 + .func fname
135 + .global fname
136 +fname:
137 +.endm
138 +
139 +.macro preload_leading_step1  backwards, ptr, base
140 +/* If the destination is already 16-byte aligned, then we need to preload
141 + * between 0 and prefetch_distance (inclusive) cache lines ahead so there
142 + * are no gaps when the inner loop starts.
143 + */
144 + .if backwards
145 +        sub     ptr, base, #1
146 +        bic     ptr, ptr, #31
147 + .else
148 +        bic     ptr, base, #31
149 + .endif
150 + .set OFFSET, 0
151 + .rept prefetch_distance+1
152 +        pld     [ptr, #OFFSET]
153 +  .if backwards
154 +   .set OFFSET, OFFSET-32
155 +  .else
156 +   .set OFFSET, OFFSET+32
157 +  .endif
158 + .endr
159 +.endm
160 +
161 +.macro preload_leading_step2  backwards, ptr, base, leading_bytes, tmp
162 +/* However, if the destination is not 16-byte aligned, we may need to
163 + * preload one more cache line than that. The question we need to ask is:
164 + * are the leading bytes more than the amount by which the source
165 + * pointer will be rounded down for preloading, and if so, by how many
166 + * cache lines?
167 + */
168 + .if backwards
169 +/* Here we compare against how many bytes we are into the
170 + * cache line, counting down from the highest such address.
171 + * Effectively, we want to calculate
172 + *     leading_bytes = dst&15
173 + *     cacheline_offset = 31-((src-leading_bytes-1)&31)
174 + *     extra_needed = leading_bytes - cacheline_offset
175 + * and test if extra_needed is <= 0, or rearranging:
176 + *     leading_bytes + (src-leading_bytes-1)&31 <= 31
177 + */
178 +        mov     tmp, base, lsl #32-5
179 +        sbc     tmp, tmp, leading_bytes, lsl #32-5
180 +        adds    tmp, tmp, leading_bytes, lsl #32-5
181 +        bcc     61f
182 +        pld     [ptr, #-32*(prefetch_distance+1)]
183 + .else
184 +/* Effectively, we want to calculate
185 + *     leading_bytes = (-dst)&15
186 + *     cacheline_offset = (src+leading_bytes)&31
187 + *     extra_needed = leading_bytes - cacheline_offset
188 + * and test if extra_needed is <= 0.
189 + */
190 +        mov     tmp, base, lsl #32-5
191 +        add     tmp, tmp, leading_bytes, lsl #32-5
192 +        rsbs    tmp, tmp, leading_bytes, lsl #32-5
193 +        bls     61f
194 +        pld     [ptr, #32*(prefetch_distance+1)]
195 + .endif
196 +61:
197 +.endm
198 +
199 +.macro preload_trailing  backwards, base, remain, tmp
200 +        /* We need either 0, 1 or 2 extra preloads */
201 + .if backwards
202 +        rsb     tmp, base, #0
203 +        mov     tmp, tmp, lsl #32-5
204 + .else
205 +        mov     tmp, base, lsl #32-5
206 + .endif
207 +        adds    tmp, tmp, remain, lsl #32-5
208 +        adceqs  tmp, tmp, #0
209 +        /* The instruction above has two effects: ensures Z is only
210 +         * set if C was clear (so Z indicates that both shifted quantities
211 +         * were 0), and clears C if Z was set (so C indicates that the sum
212 +         * of the shifted quantities was greater and not equal to 32) */
213 +        beq     82f
214 + .if backwards
215 +        sub     tmp, base, #1
216 +        bic     tmp, tmp, #31
217 + .else
218 +        bic     tmp, base, #31
219 + .endif
220 +        bcc     81f
221 + .if backwards
222 +        pld     [tmp, #-32*(prefetch_distance+1)]
223 +81:
224 +        pld     [tmp, #-32*prefetch_distance]
225 + .else
226 +        pld     [tmp, #32*(prefetch_distance+2)]
227 +81:
228 +        pld     [tmp, #32*(prefetch_distance+1)]
229 + .endif
230 +82:
231 +.endm
232 +
233 +.macro preload_all    backwards, narrow_case, shift, base, remain, tmp0, tmp1
234 + .if backwards
235 +        sub     tmp0, base, #1
236 +        bic     tmp0, tmp0, #31
237 +        pld     [tmp0]
238 +        sub     tmp1, base, remain, lsl #shift
239 + .else
240 +        bic     tmp0, base, #31
241 +        pld     [tmp0]
242 +        add     tmp1, base, remain, lsl #shift
243 +        sub     tmp1, tmp1, #1
244 + .endif
245 +        bic     tmp1, tmp1, #31
246 +        cmp     tmp1, tmp0
247 +        beq     92f
248 + .if narrow_case
249 +        /* In this case, all the data fits in either 1 or 2 cache lines */
250 +        pld     [tmp1]
251 + .else
252 +91:
253 +  .if backwards
254 +        sub     tmp0, tmp0, #32
255 +  .else
256 +        add     tmp0, tmp0, #32
257 +  .endif
258 +        cmp     tmp0, tmp1
259 +        pld     [tmp0]
260 +        bne     91b
261 + .endif
262 +92:
263 +.endm
264 --- a/arch/arm/lib/copy_from_user.S
265 +++ b/arch/arm/lib/copy_from_user.S
266 @@ -89,7 +89,8 @@
267  
268         .text
269  
270 -ENTRY(arm_copy_from_user)
271 +ENTRY(__copy_from_user_std)
272 +WEAK(arm_copy_from_user)
273  #ifdef CONFIG_CPU_SPECTRE
274         get_thread_info r3
275         ldr     r3, [r3, #TI_ADDR_LIMIT]
276 @@ -99,6 +100,7 @@ ENTRY(arm_copy_from_user)
277  #include "copy_template.S"
278  
279  ENDPROC(arm_copy_from_user)
280 +ENDPROC(__copy_from_user_std)
281  
282         .pushsection .fixup,"ax"
283         .align 0
284 --- /dev/null
285 +++ b/arch/arm/lib/exports_rpi.c
286 @@ -0,0 +1,37 @@
287 +/**
288 + * Copyright (c) 2014, Raspberry Pi (Trading) Ltd.
289 + *
290 + * Redistribution and use in source and binary forms, with or without
291 + * modification, are permitted provided that the following conditions
292 + * are met:
293 + * 1. Redistributions of source code must retain the above copyright
294 + *    notice, this list of conditions, and the following disclaimer,
295 + *    without modification.
296 + * 2. Redistributions in binary form must reproduce the above copyright
297 + *    notice, this list of conditions and the following disclaimer in the
298 + *    documentation and/or other materials provided with the distribution.
299 + * 3. The names of the above-listed copyright holders may not be used
300 + *    to endorse or promote products derived from this software without
301 + *    specific prior written permission.
302 + *
303 + * ALTERNATIVELY, this software may be distributed under the terms of the
304 + * GNU General Public License ("GPL") version 2, as published by the Free
305 + * Software Foundation.
306 + *
307 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
308 + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
309 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
310 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
311 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
312 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
313 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
314 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
315 + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
316 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
317 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
318 + */
319 +
320 +#include <linux/kernel.h>
321 +#include <linux/module.h>
322 +
323 +EXPORT_SYMBOL(memcmp);
324 --- /dev/null
325 +++ b/arch/arm/lib/memcmp_rpi.S
326 @@ -0,0 +1,285 @@
327 +/*
328 +Copyright (c) 2013, Raspberry Pi Foundation
329 +Copyright (c) 2013, RISC OS Open Ltd
330 +All rights reserved.
331 +
332 +Redistribution and use in source and binary forms, with or without
333 +modification, are permitted provided that the following conditions are met:
334 +    * Redistributions of source code must retain the above copyright
335 +      notice, this list of conditions and the following disclaimer.
336 +    * Redistributions in binary form must reproduce the above copyright
337 +      notice, this list of conditions and the following disclaimer in the
338 +      documentation and/or other materials provided with the distribution.
339 +    * Neither the name of the copyright holder nor the
340 +      names of its contributors may be used to endorse or promote products
341 +      derived from this software without specific prior written permission.
342 +
343 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
344 +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
345 +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
346 +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
347 +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
348 +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
349 +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
350 +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
351 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
352 +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
353 +*/
354 +
355 +#include <linux/linkage.h>
356 +#include "arm-mem.h"
357 +
358 +/* Prevent the stack from becoming executable */
359 +#if defined(__linux__) && defined(__ELF__)
360 +.section .note.GNU-stack,"",%progbits
361 +#endif
362 +
363 +    .text
364 +    .arch armv6
365 +    .object_arch armv4
366 +    .arm
367 +    .altmacro
368 +    .p2align 2
369 +
370 +.macro memcmp_process_head  unaligned
371 + .if unaligned
372 +        ldr     DAT0, [S_1], #4
373 +        ldr     DAT1, [S_1], #4
374 +        ldr     DAT2, [S_1], #4
375 +        ldr     DAT3, [S_1], #4
376 + .else
377 +        ldmia   S_1!, {DAT0, DAT1, DAT2, DAT3}
378 + .endif
379 +        ldmia   S_2!, {DAT4, DAT5, DAT6, DAT7}
380 +.endm
381 +
382 +.macro memcmp_process_tail
383 +        cmp     DAT0, DAT4
384 +        cmpeq   DAT1, DAT5
385 +        cmpeq   DAT2, DAT6
386 +        cmpeq   DAT3, DAT7
387 +        bne     200f
388 +.endm
389 +
390 +.macro memcmp_leading_31bytes
391 +        movs    DAT0, OFF, lsl #31
392 +        ldrmib  DAT0, [S_1], #1
393 +        ldrcsh  DAT1, [S_1], #2
394 +        ldrmib  DAT4, [S_2], #1
395 +        ldrcsh  DAT5, [S_2], #2
396 +        movpl   DAT0, #0
397 +        movcc   DAT1, #0
398 +        movpl   DAT4, #0
399 +        movcc   DAT5, #0
400 +        submi   N, N, #1
401 +        subcs   N, N, #2
402 +        cmp     DAT0, DAT4
403 +        cmpeq   DAT1, DAT5
404 +        bne     200f
405 +        movs    DAT0, OFF, lsl #29
406 +        ldrmi   DAT0, [S_1], #4
407 +        ldrcs   DAT1, [S_1], #4
408 +        ldrcs   DAT2, [S_1], #4
409 +        ldrmi   DAT4, [S_2], #4
410 +        ldmcsia S_2!, {DAT5, DAT6}
411 +        movpl   DAT0, #0
412 +        movcc   DAT1, #0
413 +        movcc   DAT2, #0
414 +        movpl   DAT4, #0
415 +        movcc   DAT5, #0
416 +        movcc   DAT6, #0
417 +        submi   N, N, #4
418 +        subcs   N, N, #8
419 +        cmp     DAT0, DAT4
420 +        cmpeq   DAT1, DAT5
421 +        cmpeq   DAT2, DAT6
422 +        bne     200f
423 +        tst     OFF, #16
424 +        beq     105f
425 +        memcmp_process_head  1
426 +        sub     N, N, #16
427 +        memcmp_process_tail
428 +105:
429 +.endm
430 +
431 +.macro memcmp_trailing_15bytes  unaligned
432 +        movs    N, N, lsl #29
433 + .if unaligned
434 +        ldrcs   DAT0, [S_1], #4
435 +        ldrcs   DAT1, [S_1], #4
436 + .else
437 +        ldmcsia S_1!, {DAT0, DAT1}
438 + .endif
439 +        ldrmi   DAT2, [S_1], #4
440 +        ldmcsia S_2!, {DAT4, DAT5}
441 +        ldrmi   DAT6, [S_2], #4
442 +        movcc   DAT0, #0
443 +        movcc   DAT1, #0
444 +        movpl   DAT2, #0
445 +        movcc   DAT4, #0
446 +        movcc   DAT5, #0
447 +        movpl   DAT6, #0
448 +        cmp     DAT0, DAT4
449 +        cmpeq   DAT1, DAT5
450 +        cmpeq   DAT2, DAT6
451 +        bne     200f
452 +        movs    N, N, lsl #2
453 +        ldrcsh  DAT0, [S_1], #2
454 +        ldrmib  DAT1, [S_1]
455 +        ldrcsh  DAT4, [S_2], #2
456 +        ldrmib  DAT5, [S_2]
457 +        movcc   DAT0, #0
458 +        movpl   DAT1, #0
459 +        movcc   DAT4, #0
460 +        movpl   DAT5, #0
461 +        cmp     DAT0, DAT4
462 +        cmpeq   DAT1, DAT5
463 +        bne     200f
464 +.endm
465 +
466 +.macro memcmp_long_inner_loop  unaligned
467 +110:
468 +        memcmp_process_head  unaligned
469 +        pld     [S_2, #prefetch_distance*32 + 16]
470 +        memcmp_process_tail
471 +        memcmp_process_head  unaligned
472 +        pld     [S_1, OFF]
473 +        memcmp_process_tail
474 +        subs    N, N, #32
475 +        bhs     110b
476 +        /* Just before the final (prefetch_distance+1) 32-byte blocks,
477 +         * deal with final preloads */
478 +        preload_trailing  0, S_1, N, DAT0
479 +        preload_trailing  0, S_2, N, DAT0
480 +        add     N, N, #(prefetch_distance+2)*32 - 16
481 +120:
482 +        memcmp_process_head  unaligned
483 +        memcmp_process_tail
484 +        subs    N, N, #16
485 +        bhs     120b
486 +        /* Trailing words and bytes */
487 +        tst     N, #15
488 +        beq     199f
489 +        memcmp_trailing_15bytes  unaligned
490 +199:    /* Reached end without detecting a difference */
491 +        mov     a1, #0
492 +        setend  le
493 +        pop     {DAT1-DAT6, pc}
494 +.endm
495 +
496 +.macro memcmp_short_inner_loop  unaligned
497 +        subs    N, N, #16     /* simplifies inner loop termination */
498 +        blo     122f
499 +120:
500 +        memcmp_process_head  unaligned
501 +        memcmp_process_tail
502 +        subs    N, N, #16
503 +        bhs     120b
504 +122:    /* Trailing words and bytes */
505 +        tst     N, #15
506 +        beq     199f
507 +        memcmp_trailing_15bytes  unaligned
508 +199:    /* Reached end without detecting a difference */
509 +        mov     a1, #0
510 +        setend  le
511 +        pop     {DAT1-DAT6, pc}
512 +.endm
513 +
514 +/*
515 + * int memcmp(const void *s1, const void *s2, size_t n);
516 + * On entry:
517 + * a1 = pointer to buffer 1
518 + * a2 = pointer to buffer 2
519 + * a3 = number of bytes to compare (as unsigned chars)
520 + * On exit:
521 + * a1 = >0/=0/<0 if s1 >/=/< s2
522 + */
523 +
524 +.set prefetch_distance, 2
525 +
526 +ENTRY(memcmp)
527 +        S_1     .req    a1
528 +        S_2     .req    a2
529 +        N       .req    a3
530 +        DAT0    .req    a4
531 +        DAT1    .req    v1
532 +        DAT2    .req    v2
533 +        DAT3    .req    v3
534 +        DAT4    .req    v4
535 +        DAT5    .req    v5
536 +        DAT6    .req    v6
537 +        DAT7    .req    ip
538 +        OFF     .req    lr
539 +
540 +        push    {DAT1-DAT6, lr}
541 +        setend  be /* lowest-addressed bytes are most significant */
542 +
543 +        /* To preload ahead as we go, we need at least (prefetch_distance+2) 32-byte blocks */
544 +        cmp     N, #(prefetch_distance+3)*32 - 1
545 +        blo     170f
546 +
547 +        /* Long case */
548 +        /* Adjust N so that the decrement instruction can also test for
549 +         * inner loop termination. We want it to stop when there are
550 +         * (prefetch_distance+1) complete blocks to go. */
551 +        sub     N, N, #(prefetch_distance+2)*32
552 +        preload_leading_step1  0, DAT0, S_1
553 +        preload_leading_step1  0, DAT1, S_2
554 +        tst     S_2, #31
555 +        beq     154f
556 +        rsb     OFF, S_2, #0 /* no need to AND with 15 here */
557 +        preload_leading_step2  0, DAT0, S_1, OFF, DAT2
558 +        preload_leading_step2  0, DAT1, S_2, OFF, DAT2
559 +        memcmp_leading_31bytes
560 +154:    /* Second source now cacheline (32-byte) aligned; we have at
561 +         * least one prefetch to go. */
562 +        /* Prefetch offset is best selected such that it lies in the
563 +         * first 8 of each 32 bytes - but it's just as easy to aim for
564 +         * the first one */
565 +        and     OFF, S_1, #31
566 +        rsb     OFF, OFF, #32*prefetch_distance
567 +        tst     S_1, #3
568 +        bne     140f
569 +        memcmp_long_inner_loop  0
570 +140:    memcmp_long_inner_loop  1
571 +
572 +170:    /* Short case */
573 +        teq     N, #0
574 +        beq     199f
575 +        preload_all 0, 0, 0, S_1, N, DAT0, DAT1
576 +        preload_all 0, 0, 0, S_2, N, DAT0, DAT1
577 +        tst     S_2, #3
578 +        beq     174f
579 +172:    subs    N, N, #1
580 +        blo     199f
581 +        ldrb    DAT0, [S_1], #1
582 +        ldrb    DAT4, [S_2], #1
583 +        cmp     DAT0, DAT4
584 +        bne     200f
585 +        tst     S_2, #3
586 +        bne     172b
587 +174:    /* Second source now 4-byte aligned; we have 0 or more bytes to go */
588 +        tst     S_1, #3
589 +        bne     140f
590 +        memcmp_short_inner_loop  0
591 +140:    memcmp_short_inner_loop  1
592 +
593 +200:    /* Difference found: determine sign. */
594 +        movhi   a1, #1
595 +        movlo   a1, #-1
596 +        setend  le
597 +        pop     {DAT1-DAT6, pc}
598 +
599 +        .unreq  S_1
600 +        .unreq  S_2
601 +        .unreq  N
602 +        .unreq  DAT0
603 +        .unreq  DAT1
604 +        .unreq  DAT2
605 +        .unreq  DAT3
606 +        .unreq  DAT4
607 +        .unreq  DAT5
608 +        .unreq  DAT6
609 +        .unreq  DAT7
610 +        .unreq  OFF
611 +ENDPROC(memcmp)
612 --- /dev/null
613 +++ b/arch/arm/lib/memcpy_rpi.S
614 @@ -0,0 +1,61 @@
615 +/*
616 +Copyright (c) 2013, Raspberry Pi Foundation
617 +Copyright (c) 2013, RISC OS Open Ltd
618 +All rights reserved.
619 +
620 +Redistribution and use in source and binary forms, with or without
621 +modification, are permitted provided that the following conditions are met:
622 +    * Redistributions of source code must retain the above copyright
623 +      notice, this list of conditions and the following disclaimer.
624 +    * Redistributions in binary form must reproduce the above copyright
625 +      notice, this list of conditions and the following disclaimer in the
626 +      documentation and/or other materials provided with the distribution.
627 +    * Neither the name of the copyright holder nor the
628 +      names of its contributors may be used to endorse or promote products
629 +      derived from this software without specific prior written permission.
630 +
631 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
632 +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
633 +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
634 +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
635 +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
636 +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
637 +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
638 +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
639 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
640 +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
641 +*/
642 +
643 +#include <linux/linkage.h>
644 +#include "arm-mem.h"
645 +#include "memcpymove.h"
646 +
647 +/* Prevent the stack from becoming executable */
648 +#if defined(__linux__) && defined(__ELF__)
649 +.section .note.GNU-stack,"",%progbits
650 +#endif
651 +
652 +    .text
653 +    .arch armv6
654 +    .object_arch armv4
655 +    .arm
656 +    .altmacro
657 +    .p2align 2
658 +
659 +/*
660 + * void *memcpy(void * restrict s1, const void * restrict s2, size_t n);
661 + * On entry:
662 + * a1 = pointer to destination
663 + * a2 = pointer to source
664 + * a3 = number of bytes to copy
665 + * On exit:
666 + * a1 preserved
667 + */
668 +
669 +.set prefetch_distance, 3
670 +
671 +ENTRY(mmiocpy)
672 +ENTRY(memcpy)
673 +        memcpy  0
674 +ENDPROC(memcpy)
675 +ENDPROC(mmiocpy)
676 --- /dev/null
677 +++ b/arch/arm/lib/memcpymove.h
678 @@ -0,0 +1,506 @@
679 +/*
680 +Copyright (c) 2013, Raspberry Pi Foundation
681 +Copyright (c) 2013, RISC OS Open Ltd
682 +All rights reserved.
683 +
684 +Redistribution and use in source and binary forms, with or without
685 +modification, are permitted provided that the following conditions are met:
686 +    * Redistributions of source code must retain the above copyright
687 +      notice, this list of conditions and the following disclaimer.
688 +    * Redistributions in binary form must reproduce the above copyright
689 +      notice, this list of conditions and the following disclaimer in the
690 +      documentation and/or other materials provided with the distribution.
691 +    * Neither the name of the copyright holder nor the
692 +      names of its contributors may be used to endorse or promote products
693 +      derived from this software without specific prior written permission.
694 +
695 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
696 +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
697 +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
698 +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
699 +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
700 +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
701 +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
702 +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
703 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
704 +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
705 +*/
706 +
707 +.macro unaligned_words  backwards, align, use_pld, words, r0, r1, r2, r3, r4, r5, r6, r7, r8
708 + .if words == 1
709 +  .if backwards
710 +        mov     r1, r0, lsl #32-align*8
711 +        ldr     r0, [S, #-4]!
712 +        orr     r1, r1, r0, lsr #align*8
713 +        str     r1, [D, #-4]!
714 +  .else
715 +        mov     r0, r1, lsr #align*8
716 +        ldr     r1, [S, #4]!
717 +        orr     r0, r0, r1, lsl #32-align*8
718 +        str     r0, [D], #4
719 +  .endif
720 + .elseif words == 2
721 +  .if backwards
722 +        ldr     r1, [S, #-4]!
723 +        mov     r2, r0, lsl #32-align*8
724 +        ldr     r0, [S, #-4]!
725 +        orr     r2, r2, r1, lsr #align*8
726 +        mov     r1, r1, lsl #32-align*8
727 +        orr     r1, r1, r0, lsr #align*8
728 +        stmdb   D!, {r1, r2}
729 +  .else
730 +        ldr     r1, [S, #4]!
731 +        mov     r0, r2, lsr #align*8
732 +        ldr     r2, [S, #4]!
733 +        orr     r0, r0, r1, lsl #32-align*8
734 +        mov     r1, r1, lsr #align*8
735 +        orr     r1, r1, r2, lsl #32-align*8
736 +        stmia   D!, {r0, r1}
737 +  .endif
738 + .elseif words == 4
739 +  .if backwards
740 +        ldmdb   S!, {r2, r3}
741 +        mov     r4, r0, lsl #32-align*8
742 +        ldmdb   S!, {r0, r1}
743 +        orr     r4, r4, r3, lsr #align*8
744 +        mov     r3, r3, lsl #32-align*8
745 +        orr     r3, r3, r2, lsr #align*8
746 +        mov     r2, r2, lsl #32-align*8
747 +        orr     r2, r2, r1, lsr #align*8
748 +        mov     r1, r1, lsl #32-align*8
749 +        orr     r1, r1, r0, lsr #align*8
750 +        stmdb   D!, {r1, r2, r3, r4}
751 +  .else
752 +        ldmib   S!, {r1, r2}
753 +        mov     r0, r4, lsr #align*8
754 +        ldmib   S!, {r3, r4}
755 +        orr     r0, r0, r1, lsl #32-align*8
756 +        mov     r1, r1, lsr #align*8
757 +        orr     r1, r1, r2, lsl #32-align*8
758 +        mov     r2, r2, lsr #align*8
759 +        orr     r2, r2, r3, lsl #32-align*8
760 +        mov     r3, r3, lsr #align*8
761 +        orr     r3, r3, r4, lsl #32-align*8
762 +        stmia   D!, {r0, r1, r2, r3}
763 +  .endif
764 + .elseif words == 8
765 +  .if backwards
766 +        ldmdb   S!, {r4, r5, r6, r7}
767 +        mov     r8, r0, lsl #32-align*8
768 +        ldmdb   S!, {r0, r1, r2, r3}
769 +   .if use_pld
770 +        pld     [S, OFF]
771 +   .endif
772 +        orr     r8, r8, r7, lsr #align*8
773 +        mov     r7, r7, lsl #32-align*8
774 +        orr     r7, r7, r6, lsr #align*8
775 +        mov     r6, r6, lsl #32-align*8
776 +        orr     r6, r6, r5, lsr #align*8
777 +        mov     r5, r5, lsl #32-align*8
778 +        orr     r5, r5, r4, lsr #align*8
779 +        mov     r4, r4, lsl #32-align*8
780 +        orr     r4, r4, r3, lsr #align*8
781 +        mov     r3, r3, lsl #32-align*8
782 +        orr     r3, r3, r2, lsr #align*8
783 +        mov     r2, r2, lsl #32-align*8
784 +        orr     r2, r2, r1, lsr #align*8
785 +        mov     r1, r1, lsl #32-align*8
786 +        orr     r1, r1, r0, lsr #align*8
787 +        stmdb   D!, {r5, r6, r7, r8}
788 +        stmdb   D!, {r1, r2, r3, r4}
789 +  .else
790 +        ldmib   S!, {r1, r2, r3, r4}
791 +        mov     r0, r8, lsr #align*8
792 +        ldmib   S!, {r5, r6, r7, r8}
793 +   .if use_pld
794 +        pld     [S, OFF]
795 +   .endif
796 +        orr     r0, r0, r1, lsl #32-align*8
797 +        mov     r1, r1, lsr #align*8
798 +        orr     r1, r1, r2, lsl #32-align*8
799 +        mov     r2, r2, lsr #align*8
800 +        orr     r2, r2, r3, lsl #32-align*8
801 +        mov     r3, r3, lsr #align*8
802 +        orr     r3, r3, r4, lsl #32-align*8
803 +        mov     r4, r4, lsr #align*8
804 +        orr     r4, r4, r5, lsl #32-align*8
805 +        mov     r5, r5, lsr #align*8
806 +        orr     r5, r5, r6, lsl #32-align*8
807 +        mov     r6, r6, lsr #align*8
808 +        orr     r6, r6, r7, lsl #32-align*8
809 +        mov     r7, r7, lsr #align*8
810 +        orr     r7, r7, r8, lsl #32-align*8
811 +        stmia   D!, {r0, r1, r2, r3}
812 +        stmia   D!, {r4, r5, r6, r7}
813 +  .endif
814 + .endif
815 +.endm
816 +
817 +.macro memcpy_leading_15bytes  backwards, align
818 +        movs    DAT1, DAT2, lsl #31
819 +        sub     N, N, DAT2
820 + .if backwards
821 +        ldrmib  DAT0, [S, #-1]!
822 +        ldrcsh  DAT1, [S, #-2]!
823 +        strmib  DAT0, [D, #-1]!
824 +        strcsh  DAT1, [D, #-2]!
825 + .else
826 +        ldrmib  DAT0, [S], #1
827 +        ldrcsh  DAT1, [S], #2
828 +        strmib  DAT0, [D], #1
829 +        strcsh  DAT1, [D], #2
830 + .endif
831 +        movs    DAT1, DAT2, lsl #29
832 + .if backwards
833 +        ldrmi   DAT0, [S, #-4]!
834 +  .if align == 0
835 +        ldmcsdb S!, {DAT1, DAT2}
836 +  .else
837 +        ldrcs   DAT2, [S, #-4]!
838 +        ldrcs   DAT1, [S, #-4]!
839 +  .endif
840 +        strmi   DAT0, [D, #-4]!
841 +        stmcsdb D!, {DAT1, DAT2}
842 + .else
843 +        ldrmi   DAT0, [S], #4
844 +  .if align == 0
845 +        ldmcsia S!, {DAT1, DAT2}
846 +  .else
847 +        ldrcs   DAT1, [S], #4
848 +        ldrcs   DAT2, [S], #4
849 +  .endif
850 +        strmi   DAT0, [D], #4
851 +        stmcsia D!, {DAT1, DAT2}
852 + .endif
853 +.endm
854 +
855 +.macro memcpy_trailing_15bytes  backwards, align
856 +        movs    N, N, lsl #29
857 + .if backwards
858 +  .if align == 0
859 +        ldmcsdb S!, {DAT0, DAT1}
860 +  .else
861 +        ldrcs   DAT1, [S, #-4]!
862 +        ldrcs   DAT0, [S, #-4]!
863 +  .endif
864 +        ldrmi   DAT2, [S, #-4]!
865 +        stmcsdb D!, {DAT0, DAT1}
866 +        strmi   DAT2, [D, #-4]!
867 + .else
868 +  .if align == 0
869 +        ldmcsia S!, {DAT0, DAT1}
870 +  .else
871 +        ldrcs   DAT0, [S], #4
872 +        ldrcs   DAT1, [S], #4
873 +  .endif
874 +        ldrmi   DAT2, [S], #4
875 +        stmcsia D!, {DAT0, DAT1}
876 +        strmi   DAT2, [D], #4
877 + .endif
878 +        movs    N, N, lsl #2
879 + .if backwards
880 +        ldrcsh  DAT0, [S, #-2]!
881 +        ldrmib  DAT1, [S, #-1]
882 +        strcsh  DAT0, [D, #-2]!
883 +        strmib  DAT1, [D, #-1]
884 + .else
885 +        ldrcsh  DAT0, [S], #2
886 +        ldrmib  DAT1, [S]
887 +        strcsh  DAT0, [D], #2
888 +        strmib  DAT1, [D]
889 + .endif
890 +.endm
891 +
892 +.macro memcpy_long_inner_loop  backwards, align
893 + .if align != 0
894 +  .if backwards
895 +        ldr     DAT0, [S, #-align]!
896 +  .else
897 +        ldr     LAST, [S, #-align]!
898 +  .endif
899 + .endif
900 +110:
901 + .if align == 0
902 +  .if backwards
903 +        ldmdb   S!, {DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, LAST}
904 +        pld     [S, OFF]
905 +        stmdb   D!, {DAT4, DAT5, DAT6, LAST}
906 +        stmdb   D!, {DAT0, DAT1, DAT2, DAT3}
907 +  .else
908 +        ldmia   S!, {DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, LAST}
909 +        pld     [S, OFF]
910 +        stmia   D!, {DAT0, DAT1, DAT2, DAT3}
911 +        stmia   D!, {DAT4, DAT5, DAT6, LAST}
912 +  .endif
913 + .else
914 +        unaligned_words  backwards, align, 1, 8, DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, DAT7, LAST
915 + .endif
916 +        subs    N, N, #32
917 +        bhs     110b
918 +        /* Just before the final (prefetch_distance+1) 32-byte blocks, deal with final preloads */
919 +        preload_trailing  backwards, S, N, OFF
920 +        add     N, N, #(prefetch_distance+2)*32 - 32
921 +120:
922 + .if align == 0
923 +  .if backwards
924 +        ldmdb   S!, {DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, LAST}
925 +        stmdb   D!, {DAT4, DAT5, DAT6, LAST}
926 +        stmdb   D!, {DAT0, DAT1, DAT2, DAT3}
927 +  .else
928 +        ldmia   S!, {DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, LAST}
929 +        stmia   D!, {DAT0, DAT1, DAT2, DAT3}
930 +        stmia   D!, {DAT4, DAT5, DAT6, LAST}
931 +  .endif
932 + .else
933 +        unaligned_words  backwards, align, 0, 8, DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, DAT7, LAST
934 + .endif
935 +        subs    N, N, #32
936 +        bhs     120b
937 +        tst     N, #16
938 + .if align == 0
939 +  .if backwards
940 +        ldmnedb S!, {DAT0, DAT1, DAT2, LAST}
941 +        stmnedb D!, {DAT0, DAT1, DAT2, LAST}
942 +  .else
943 +        ldmneia S!, {DAT0, DAT1, DAT2, LAST}
944 +        stmneia D!, {DAT0, DAT1, DAT2, LAST}
945 +  .endif
946 + .else
947 +        beq     130f
948 +        unaligned_words  backwards, align, 0, 4, DAT0, DAT1, DAT2, DAT3, LAST
949 +130:
950 + .endif
951 +        /* Trailing words and bytes */
952 +        tst      N, #15
953 +        beq      199f
954 + .if align != 0
955 +        add     S, S, #align
956 + .endif
957 +        memcpy_trailing_15bytes  backwards, align
958 +199:
959 +        pop     {DAT3, DAT4, DAT5, DAT6, DAT7}
960 +        pop     {D, DAT1, DAT2, pc}
961 +.endm
962 +
963 +.macro memcpy_medium_inner_loop  backwards, align
964 +120:
965 + .if backwards
966 +  .if align == 0
967 +        ldmdb   S!, {DAT0, DAT1, DAT2, LAST}
968 +  .else
969 +        ldr     LAST, [S, #-4]!
970 +        ldr     DAT2, [S, #-4]!
971 +        ldr     DAT1, [S, #-4]!
972 +        ldr     DAT0, [S, #-4]!
973 +  .endif
974 +        stmdb   D!, {DAT0, DAT1, DAT2, LAST}
975 + .else
976 +  .if align == 0
977 +        ldmia   S!, {DAT0, DAT1, DAT2, LAST}
978 +  .else
979 +        ldr     DAT0, [S], #4
980 +        ldr     DAT1, [S], #4
981 +        ldr     DAT2, [S], #4
982 +        ldr     LAST, [S], #4
983 +  .endif
984 +        stmia   D!, {DAT0, DAT1, DAT2, LAST}
985 + .endif
986 +        subs     N, N, #16
987 +        bhs      120b
988 +        /* Trailing words and bytes */
989 +        tst      N, #15
990 +        beq      199f
991 +        memcpy_trailing_15bytes  backwards, align
992 +199:
993 +        pop     {D, DAT1, DAT2, pc}
994 +.endm
995 +
996 +.macro memcpy_short_inner_loop  backwards, align
997 +        tst     N, #16
998 + .if backwards
999 +  .if align == 0
1000 +        ldmnedb S!, {DAT0, DAT1, DAT2, LAST}
1001 +  .else
1002 +        ldrne   LAST, [S, #-4]!
1003 +        ldrne   DAT2, [S, #-4]!
1004 +        ldrne   DAT1, [S, #-4]!
1005 +        ldrne   DAT0, [S, #-4]!
1006 +  .endif
1007 +        stmnedb D!, {DAT0, DAT1, DAT2, LAST}
1008 + .else
1009 +  .if align == 0
1010 +        ldmneia S!, {DAT0, DAT1, DAT2, LAST}
1011 +  .else
1012 +        ldrne   DAT0, [S], #4
1013 +        ldrne   DAT1, [S], #4
1014 +        ldrne   DAT2, [S], #4
1015 +        ldrne   LAST, [S], #4
1016 +  .endif
1017 +        stmneia D!, {DAT0, DAT1, DAT2, LAST}
1018 + .endif
1019 +        memcpy_trailing_15bytes  backwards, align
1020 +199:
1021 +        pop     {D, DAT1, DAT2, pc}
1022 +.endm
1023 +
1024 +.macro memcpy backwards
1025 +        D       .req    a1
1026 +        S       .req    a2
1027 +        N       .req    a3
1028 +        DAT0    .req    a4
1029 +        DAT1    .req    v1
1030 +        DAT2    .req    v2
1031 +        DAT3    .req    v3
1032 +        DAT4    .req    v4
1033 +        DAT5    .req    v5
1034 +        DAT6    .req    v6
1035 +        DAT7    .req    sl
1036 +        LAST    .req    ip
1037 +        OFF     .req    lr
1038 +
1039 +        .cfi_startproc
1040 +
1041 +        push    {D, DAT1, DAT2, lr}
1042 +
1043 +        .cfi_def_cfa_offset 16
1044 +        .cfi_rel_offset D, 0
1045 +        .cfi_undefined  S
1046 +        .cfi_undefined  N
1047 +        .cfi_undefined  DAT0
1048 +        .cfi_rel_offset DAT1, 4
1049 +        .cfi_rel_offset DAT2, 8
1050 +        .cfi_undefined  LAST
1051 +        .cfi_rel_offset lr, 12
1052 +
1053 + .if backwards
1054 +        add     D, D, N
1055 +        add     S, S, N
1056 + .endif
1057 +
1058 +        /* See if we're guaranteed to have at least one 16-byte aligned 16-byte write */
1059 +        cmp     N, #31
1060 +        blo     170f
1061 +        /* To preload ahead as we go, we need at least (prefetch_distance+2) 32-byte blocks */
1062 +        cmp     N, #(prefetch_distance+3)*32 - 1
1063 +        blo     160f
1064 +
1065 +        /* Long case */
1066 +        push    {DAT3, DAT4, DAT5, DAT6, DAT7}
1067 +
1068 +        .cfi_def_cfa_offset 36
1069 +        .cfi_rel_offset D, 20
1070 +        .cfi_rel_offset DAT1, 24
1071 +        .cfi_rel_offset DAT2, 28
1072 +        .cfi_rel_offset DAT3, 0
1073 +        .cfi_rel_offset DAT4, 4
1074 +        .cfi_rel_offset DAT5, 8
1075 +        .cfi_rel_offset DAT6, 12
1076 +        .cfi_rel_offset DAT7, 16
1077 +        .cfi_rel_offset lr, 32
1078 +
1079 +        /* Adjust N so that the decrement instruction can also test for
1080 +         * inner loop termination. We want it to stop when there are
1081 +         * (prefetch_distance+1) complete blocks to go. */
1082 +        sub     N, N, #(prefetch_distance+2)*32
1083 +        preload_leading_step1  backwards, DAT0, S
1084 + .if backwards
1085 +        /* Bug in GAS: it accepts, but mis-assembles the instruction
1086 +         * ands    DAT2, D, #60, 2
1087 +         * which sets DAT2 to the number of leading bytes until destination is aligned and also clears C (sets borrow)
1088 +         */
1089 +        .word   0xE210513C
1090 +        beq     154f
1091 + .else
1092 +        ands    DAT2, D, #15
1093 +        beq     154f
1094 +        rsb     DAT2, DAT2, #16 /* number of leading bytes until destination aligned */
1095 + .endif
1096 +        preload_leading_step2  backwards, DAT0, S, DAT2, OFF
1097 +        memcpy_leading_15bytes backwards, 1
1098 +154:    /* Destination now 16-byte aligned; we have at least one prefetch as well as at least one 16-byte output block */
1099 +        /* Prefetch offset is best selected such that it lies in the first 8 of each 32 bytes - but it's just as easy to aim for the first one */
1100 + .if backwards
1101 +        rsb     OFF, S, #3
1102 +        and     OFF, OFF, #28
1103 +        sub     OFF, OFF, #32*(prefetch_distance+1)
1104 + .else
1105 +        and     OFF, S, #28
1106 +        rsb     OFF, OFF, #32*prefetch_distance
1107 + .endif
1108 +        movs    DAT0, S, lsl #31
1109 +        bhi     157f
1110 +        bcs     156f
1111 +        bmi     155f
1112 +        memcpy_long_inner_loop  backwards, 0
1113 +155:    memcpy_long_inner_loop  backwards, 1
1114 +156:    memcpy_long_inner_loop  backwards, 2
1115 +157:    memcpy_long_inner_loop  backwards, 3
1116 +
1117 +        .cfi_def_cfa_offset 16
1118 +        .cfi_rel_offset D, 0
1119 +        .cfi_rel_offset DAT1, 4
1120 +        .cfi_rel_offset DAT2, 8
1121 +        .cfi_same_value DAT3
1122 +        .cfi_same_value DAT4
1123 +        .cfi_same_value DAT5
1124 +        .cfi_same_value DAT6
1125 +        .cfi_same_value DAT7
1126 +        .cfi_rel_offset lr, 12
1127 +
1128 +160:    /* Medium case */
1129 +        preload_all  backwards, 0, 0, S, N, DAT2, OFF
1130 +        sub     N, N, #16     /* simplifies inner loop termination */
1131 + .if backwards
1132 +        ands    DAT2, D, #15
1133 +        beq     164f
1134 + .else
1135 +        ands    DAT2, D, #15
1136 +        beq     164f
1137 +        rsb     DAT2, DAT2, #16
1138 + .endif
1139 +        memcpy_leading_15bytes backwards, align
1140 +164:    /* Destination now 16-byte aligned; we have at least one 16-byte output block */
1141 +        tst     S, #3
1142 +        bne     140f
1143 +        memcpy_medium_inner_loop  backwards, 0
1144 +140:    memcpy_medium_inner_loop  backwards, 1
1145 +
1146 +170:    /* Short case, less than 31 bytes, so no guarantee of at least one 16-byte block */
1147 +        teq     N, #0
1148 +        beq     199f
1149 +        preload_all  backwards, 1, 0, S, N, DAT2, LAST
1150 +        tst     D, #3
1151 +        beq     174f
1152 +172:    subs    N, N, #1
1153 +        blo     199f
1154 + .if backwards
1155 +        ldrb    DAT0, [S, #-1]!
1156 +        strb    DAT0, [D, #-1]!
1157 + .else
1158 +        ldrb    DAT0, [S], #1
1159 +        strb    DAT0, [D], #1
1160 + .endif
1161 +        tst     D, #3
1162 +        bne     172b
1163 +174:    /* Destination now 4-byte aligned; we have 0 or more output bytes to go */
1164 +        tst     S, #3
1165 +        bne     140f
1166 +        memcpy_short_inner_loop  backwards, 0
1167 +140:    memcpy_short_inner_loop  backwards, 1
1168 +
1169 +        .cfi_endproc
1170 +
1171 +        .unreq  D
1172 +        .unreq  S
1173 +        .unreq  N
1174 +        .unreq  DAT0
1175 +        .unreq  DAT1
1176 +        .unreq  DAT2
1177 +        .unreq  DAT3
1178 +        .unreq  DAT4
1179 +        .unreq  DAT5
1180 +        .unreq  DAT6
1181 +        .unreq  DAT7
1182 +        .unreq  LAST
1183 +        .unreq  OFF
1184 +.endm
1185 --- /dev/null
1186 +++ b/arch/arm/lib/memmove_rpi.S
1187 @@ -0,0 +1,61 @@
1188 +/*
1189 +Copyright (c) 2013, Raspberry Pi Foundation
1190 +Copyright (c) 2013, RISC OS Open Ltd
1191 +All rights reserved.
1192 +
1193 +Redistribution and use in source and binary forms, with or without
1194 +modification, are permitted provided that the following conditions are met:
1195 +    * Redistributions of source code must retain the above copyright
1196 +      notice, this list of conditions and the following disclaimer.
1197 +    * Redistributions in binary form must reproduce the above copyright
1198 +      notice, this list of conditions and the following disclaimer in the
1199 +      documentation and/or other materials provided with the distribution.
1200 +    * Neither the name of the copyright holder nor the
1201 +      names of its contributors may be used to endorse or promote products
1202 +      derived from this software without specific prior written permission.
1203 +
1204 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
1205 +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1206 +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1207 +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
1208 +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1209 +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1210 +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1211 +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1212 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1213 +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1214 +*/
1215 +
1216 +#include <linux/linkage.h>
1217 +#include "arm-mem.h"
1218 +#include "memcpymove.h"
1219 +
1220 +/* Prevent the stack from becoming executable */
1221 +#if defined(__linux__) && defined(__ELF__)
1222 +.section .note.GNU-stack,"",%progbits
1223 +#endif
1224 +
1225 +    .text
1226 +    .arch armv6
1227 +    .object_arch armv4
1228 +    .arm
1229 +    .altmacro
1230 +    .p2align 2
1231 +
1232 +/*
1233 + * void *memmove(void *s1, const void *s2, size_t n);
1234 + * On entry:
1235 + * a1 = pointer to destination
1236 + * a2 = pointer to source
1237 + * a3 = number of bytes to copy
1238 + * On exit:
1239 + * a1 preserved
1240 + */
1241 +
1242 +.set prefetch_distance, 3
1243 +
1244 +ENTRY(memmove)
1245 +        cmp     a2, a1
1246 +        bpl     memcpy  /* pl works even over -1 - 0 and 0x7fffffff - 0x80000000 boundaries */
1247 +        memcpy  1
1248 +ENDPROC(memmove)
1249 --- /dev/null
1250 +++ b/arch/arm/lib/memset_rpi.S
1251 @@ -0,0 +1,128 @@
1252 +/*
1253 +Copyright (c) 2013, Raspberry Pi Foundation
1254 +Copyright (c) 2013, RISC OS Open Ltd
1255 +All rights reserved.
1256 +
1257 +Redistribution and use in source and binary forms, with or without
1258 +modification, are permitted provided that the following conditions are met:
1259 +    * Redistributions of source code must retain the above copyright
1260 +      notice, this list of conditions and the following disclaimer.
1261 +    * Redistributions in binary form must reproduce the above copyright
1262 +      notice, this list of conditions and the following disclaimer in the
1263 +      documentation and/or other materials provided with the distribution.
1264 +    * Neither the name of the copyright holder nor the
1265 +      names of its contributors may be used to endorse or promote products
1266 +      derived from this software without specific prior written permission.
1267 +
1268 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
1269 +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1270 +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1271 +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
1272 +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1273 +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1274 +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1275 +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1276 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1277 +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1278 +*/
1279 +
1280 +#include <linux/linkage.h>
1281 +#include "arm-mem.h"
1282 +
1283 +/* Prevent the stack from becoming executable */
1284 +#if defined(__linux__) && defined(__ELF__)
1285 +.section .note.GNU-stack,"",%progbits
1286 +#endif
1287 +
1288 +    .text
1289 +    .arch armv6
1290 +    .object_arch armv4
1291 +    .arm
1292 +    .altmacro
1293 +    .p2align 2
1294 +
1295 +/*
1296 + *  void *memset(void *s, int c, size_t n);
1297 + *  On entry:
1298 + *  a1 = pointer to buffer to fill
1299 + *  a2 = byte pattern to fill with (caller-narrowed)
1300 + *  a3 = number of bytes to fill
1301 + *  On exit:
1302 + *  a1 preserved
1303 + */
1304 +ENTRY(mmioset)
1305 +ENTRY(memset)
1306 +ENTRY(__memset32)
1307 +ENTRY(__memset64)
1308 +
1309 +        S       .req    a1
1310 +        DAT0    .req    a2
1311 +        N       .req    a3
1312 +        DAT1    .req    a4
1313 +        DAT2    .req    ip
1314 +        DAT3    .req    lr
1315 +
1316 +        orr     DAT0, DAT0, DAT0, lsl #8
1317 +        push    {S, lr}
1318 +        orr     DAT0, DAT0, DAT0, lsl #16
1319 +        mov     DAT1, DAT0
1320 +
1321 +        /* See if we're guaranteed to have at least one 16-byte aligned 16-byte write */
1322 +        cmp     N, #31
1323 +        blo     170f
1324 +
1325 +161:    sub     N, N, #16     /* simplifies inner loop termination */
1326 +        /* Leading words and bytes */
1327 +        tst     S, #15
1328 +        beq     164f
1329 +        rsb     DAT3, S, #0   /* bits 0-3 = number of leading bytes until aligned */
1330 +        movs    DAT2, DAT3, lsl #31
1331 +        submi   N, N, #1
1332 +        strmib  DAT0, [S], #1
1333 +        subcs   N, N, #2
1334 +        strcsh  DAT0, [S], #2
1335 +        movs    DAT2, DAT3, lsl #29
1336 +        submi   N, N, #4
1337 +        strmi   DAT0, [S], #4
1338 +        subcs   N, N, #8
1339 +        stmcsia S!, {DAT0, DAT1}
1340 +164:    /* Delayed set up of DAT2 and DAT3 so we could use them as scratch registers above */
1341 +        mov     DAT2, DAT0
1342 +        mov     DAT3, DAT0
1343 +        /* Now the inner loop of 16-byte stores */
1344 +165:    stmia   S!, {DAT0, DAT1, DAT2, DAT3}
1345 +        subs    N, N, #16
1346 +        bhs     165b
1347 +166:    /* Trailing words and bytes */
1348 +        movs    N, N, lsl #29
1349 +        stmcsia S!, {DAT0, DAT1}
1350 +        strmi   DAT0, [S], #4
1351 +        movs    N, N, lsl #2
1352 +        strcsh  DAT0, [S], #2
1353 +        strmib  DAT0, [S]
1354 +199:    pop     {S, pc}
1355 +
1356 +170:    /* Short case */
1357 +        mov     DAT2, DAT0
1358 +        mov     DAT3, DAT0
1359 +        tst     S, #3
1360 +        beq     174f
1361 +172:    subs    N, N, #1
1362 +        blo     199b
1363 +        strb    DAT0, [S], #1
1364 +        tst     S, #3
1365 +        bne     172b
1366 +174:    tst     N, #16
1367 +        stmneia S!, {DAT0, DAT1, DAT2, DAT3}
1368 +        b       166b
1369 +
1370 +        .unreq  S
1371 +        .unreq  DAT0
1372 +        .unreq  N
1373 +        .unreq  DAT1
1374 +        .unreq  DAT2
1375 +        .unreq  DAT3
1376 +ENDPROC(__memset64)
1377 +ENDPROC(__memset32)
1378 +ENDPROC(memset)
1379 +ENDPROC(mmioset)
1380 --- a/arch/arm/lib/uaccess_with_memcpy.c
1381 +++ b/arch/arm/lib/uaccess_with_memcpy.c
1382 @@ -22,6 +22,14 @@
1383  #include <asm/current.h>
1384  #include <asm/page.h>
1385  
1386 +#ifndef COPY_FROM_USER_THRESHOLD
1387 +#define COPY_FROM_USER_THRESHOLD 64
1388 +#endif
1389 +
1390 +#ifndef COPY_TO_USER_THRESHOLD
1391 +#define COPY_TO_USER_THRESHOLD 64
1392 +#endif
1393 +
1394  static int
1395  pin_page_for_write(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp)
1396  {
1397 @@ -84,7 +92,44 @@ pin_page_for_write(const void __user *_a
1398         return 1;
1399  }
1400  
1401 -static unsigned long noinline
1402 +static int
1403 +pin_page_for_read(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp)
1404 +{
1405 +       unsigned long addr = (unsigned long)_addr;
1406 +       pgd_t *pgd;
1407 +       pmd_t *pmd;
1408 +       pte_t *pte;
1409 +       pud_t *pud;
1410 +       spinlock_t *ptl;
1411 +
1412 +       pgd = pgd_offset(current->mm, addr);
1413 +       if (unlikely(pgd_none(*pgd) || pgd_bad(*pgd)))
1414 +       {
1415 +               return 0;
1416 +       }
1417 +       pud = pud_offset(pgd, addr);
1418 +       if (unlikely(pud_none(*pud) || pud_bad(*pud)))
1419 +       {
1420 +               return 0;
1421 +       }
1422 +
1423 +       pmd = pmd_offset(pud, addr);
1424 +       if (unlikely(pmd_none(*pmd) || pmd_bad(*pmd)))
1425 +               return 0;
1426 +
1427 +       pte = pte_offset_map_lock(current->mm, pmd, addr, &ptl);
1428 +       if (unlikely(!pte_present(*pte) || !pte_young(*pte))) {
1429 +               pte_unmap_unlock(pte, ptl);
1430 +               return 0;
1431 +       }
1432 +
1433 +       *ptep = pte;
1434 +       *ptlp = ptl;
1435 +
1436 +       return 1;
1437 +}
1438 +
1439 +unsigned long noinline
1440  __copy_to_user_memcpy(void __user *to, const void *from, unsigned long n)
1441  {
1442         unsigned long ua_flags;
1443 @@ -137,6 +182,57 @@ out:
1444         return n;
1445  }
1446  
1447 +unsigned long noinline
1448 +__copy_from_user_memcpy(void *to, const void __user *from, unsigned long n)
1449 +{
1450 +       unsigned long ua_flags;
1451 +       int atomic;
1452 +
1453 +       if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
1454 +               memcpy(to, (const void *)from, n);
1455 +               return 0;
1456 +       }
1457 +
1458 +       /* the mmap semaphore is taken only if not in an atomic context */
1459 +       atomic = in_atomic();
1460 +
1461 +       if (!atomic)
1462 +               down_read(&current->mm->mmap_sem);
1463 +       while (n) {
1464 +               pte_t *pte;
1465 +               spinlock_t *ptl;
1466 +               int tocopy;
1467 +
1468 +               while (!pin_page_for_read(from, &pte, &ptl)) {
1469 +                       char temp;
1470 +                       if (!atomic)
1471 +                               up_read(&current->mm->mmap_sem);
1472 +                       if (__get_user(temp, (char __user *)from))
1473 +                               goto out;
1474 +                       if (!atomic)
1475 +                               down_read(&current->mm->mmap_sem);
1476 +               }
1477 +
1478 +               tocopy = (~(unsigned long)from & ~PAGE_MASK) + 1;
1479 +               if (tocopy > n)
1480 +                       tocopy = n;
1481 +
1482 +               ua_flags = uaccess_save_and_enable();
1483 +               memcpy(to, (const void *)from, tocopy);
1484 +               uaccess_restore(ua_flags);
1485 +               to += tocopy;
1486 +               from += tocopy;
1487 +               n -= tocopy;
1488 +
1489 +               pte_unmap_unlock(pte, ptl);
1490 +       }
1491 +       if (!atomic)
1492 +               up_read(&current->mm->mmap_sem);
1493 +
1494 +out:
1495 +       return n;
1496 +}
1497 +
1498  unsigned long
1499  arm_copy_to_user(void __user *to, const void *from, unsigned long n)
1500  {
1501 @@ -147,7 +243,7 @@ arm_copy_to_user(void __user *to, const
1502          * With frame pointer disabled, tail call optimization kicks in
1503          * as well making this test almost invisible.
1504          */
1505 -       if (n < 64) {
1506 +       if (n < COPY_TO_USER_THRESHOLD) {
1507                 unsigned long ua_flags = uaccess_save_and_enable();
1508                 n = __copy_to_user_std(to, from, n);
1509                 uaccess_restore(ua_flags);
1510 @@ -157,6 +253,26 @@ arm_copy_to_user(void __user *to, const
1511         }
1512         return n;
1513  }
1514 +
1515 +unsigned long __must_check
1516 +arm_copy_from_user(void *to, const void __user *from, unsigned long n)
1517 +{
1518 +       /*
1519 +        * This test is stubbed out of the main function above to keep
1520 +        * the overhead for small copies low by avoiding a large
1521 +        * register dump on the stack just to reload them right away.
1522 +        * With frame pointer disabled, tail call optimization kicks in
1523 +        * as well making this test almost invisible.
1524 +        */
1525 +       if (n < COPY_TO_USER_THRESHOLD) {
1526 +               unsigned long ua_flags = uaccess_save_and_enable();
1527 +               n = __copy_from_user_std(to, from, n);
1528 +               uaccess_restore(ua_flags);
1529 +       } else {
1530 +               n = __copy_from_user_memcpy(to, from, n);
1531 +       }
1532 +       return n;
1533 +}
1534         
1535  static unsigned long noinline
1536  __clear_user_memset(void __user *addr, unsigned long n)
1537 --- a/arch/arm/mach-bcm/Kconfig
1538 +++ b/arch/arm/mach-bcm/Kconfig
1539 @@ -177,6 +177,13 @@ config ARCH_BCM_53573
1540           The base chip is BCM53573 and there are some packaging modifications
1541           like BCM47189 and BCM47452.
1542  
1543 +config BCM2835_FAST_MEMCPY
1544 +       bool "Enable optimized __copy_to_user and __copy_from_user"
1545 +       depends on ARCH_BCM2835 && ARCH_MULTI_V6
1546 +       default y
1547 +       help
1548 +         Optimized versions of __copy_to_user and __copy_from_user for Pi1.
1549 +
1550  config ARCH_BCM_63XX
1551         bool "Broadcom BCM63xx DSL SoC"
1552         depends on ARCH_MULTI_V7