linux/arch/parisc/lib/lusercopy.S
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0-or-later */
   2/*
   3 *    User Space Access Routines
   4 *
   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>
  11 */
  12
  13/*
  14 * These routines still have plenty of room for optimization
  15 * (word & doubleword load/store, dual issue, store hints, etc.).
  16 */
  17
  18/*
  19 * The following routines assume that space register 3 (sr3) contains
  20 * the space id associated with the current users address space.
  21 */
  22
  23
  24        .text
  25        
  26#include <asm/assembly.h>
  27#include <asm/errno.h>
  28#include <linux/linkage.h>
  29
  30        /*
  31         * unsigned long lclear_user(void *to, unsigned long n)
  32         *
  33         * Returns 0 for success.
  34         * otherwise, returns number of bytes not transferred.
  35         */
  36
  37ENTRY_CFI(lclear_user)
  38        comib,=,n   0,%r25,$lclu_done
  39$lclu_loop:
  40        addib,<>    -1,%r25,$lclu_loop
  411:      stbs,ma     %r0,1(%sr3,%r26)
  42
  43$lclu_done:
  44        bv          %r0(%r2)
  45        copy        %r25,%r28
  46
  472:      b           $lclu_done
  48        ldo         1(%r25),%r25
  49
  50        ASM_EXCEPTIONTABLE_ENTRY(1b,2b)
  51ENDPROC_CFI(lclear_user)
  52
  53
  54/*
  55 * unsigned long pa_memcpy(void *dstp, const void *srcp, unsigned long len)
  56 *
  57 * Inputs:
  58 * - sr1 already contains space of source region
  59 * - sr2 already contains space of destination region
  60 *
  61 * Returns:
  62 * - number of bytes that could not be copied.
  63 *   On success, this will be zero.
  64 *
  65 * This code is based on a C-implementation of a copy routine written by
  66 * Randolph Chung, which in turn was derived from the glibc.
  67 *
  68 * Several strategies are tried to try to get the best performance for various
  69 * conditions. In the optimal case, we copy by loops that copy 32- or 16-bytes
  70 * at a time using general registers.  Unaligned copies are handled either by
  71 * aligning the destination and then using shift-and-write method, or in a few
  72 * cases by falling back to a byte-at-a-time copy.
  73 *
  74 * Testing with various alignments and buffer sizes shows that this code is
  75 * often >10x faster than a simple byte-at-a-time copy, even for strangely
  76 * aligned operands. It is interesting to note that the glibc version of memcpy
  77 * (written in C) is actually quite fast already. This routine is able to beat
  78 * it by 30-40% for aligned copies because of the loop unrolling, but in some
  79 * cases the glibc version is still slightly faster. This lends more
  80 * credibility that gcc can generate very good code as long as we are careful.
  81 *
  82 * Possible optimizations:
  83 * - add cache prefetching
  84 * - try not to use the post-increment address modifiers; they may create
  85 *   additional interlocks. Assumption is that those were only efficient on old
  86 *   machines (pre PA8000 processors)
  87 */
  88
  89        dst = arg0
  90        src = arg1
  91        len = arg2
  92        end = arg3
  93        t1  = r19
  94        t2  = r20
  95        t3  = r21
  96        t4  = r22
  97        srcspc = sr1
  98        dstspc = sr2
  99
 100        t0 = r1
 101        a1 = t1
 102        a2 = t2
 103        a3 = t3
 104        a0 = t4
 105
 106        save_src = ret0
 107        save_dst = ret1
 108        save_len = r31
 109
 110ENTRY_CFI(pa_memcpy)
 111        /* Last destination address */
 112        add     dst,len,end
 113
 114        /* short copy with less than 16 bytes? */
 115        cmpib,COND(>>=),n 15,len,.Lbyte_loop
 116
 117        /* same alignment? */
 118        xor     src,dst,t0
 119        extru   t0,31,2,t1
 120        cmpib,<>,n  0,t1,.Lunaligned_copy
 121
 122#ifdef CONFIG_64BIT
 123        /* only do 64-bit copies if we can get aligned. */
 124        extru   t0,31,3,t1
 125        cmpib,<>,n  0,t1,.Lalign_loop32
 126
 127        /* loop until we are 64-bit aligned */
 128.Lalign_loop64:
 129        extru   dst,31,3,t1
 130        cmpib,=,n       0,t1,.Lcopy_loop_16_start
 13120:     ldb,ma  1(srcspc,src),t1
 13221:     stb,ma  t1,1(dstspc,dst)
 133        b       .Lalign_loop64
 134        ldo     -1(len),len
 135
 136        ASM_EXCEPTIONTABLE_ENTRY(20b,.Lcopy_done)
 137        ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done)
 138
 139.Lcopy_loop_16_start:
 140        ldi     31,t0
 141.Lcopy_loop_16:
 142        cmpb,COND(>>=),n t0,len,.Lword_loop
 143
 14410:     ldd     0(srcspc,src),t1
 14511:     ldd     8(srcspc,src),t2
 146        ldo     16(src),src
 14712:     std,ma  t1,8(dstspc,dst)
 14813:     std,ma  t2,8(dstspc,dst)
 14914:     ldd     0(srcspc,src),t1
 15015:     ldd     8(srcspc,src),t2
 151        ldo     16(src),src
 15216:     std,ma  t1,8(dstspc,dst)
 15317:     std,ma  t2,8(dstspc,dst)
 154
 155        ASM_EXCEPTIONTABLE_ENTRY(10b,.Lcopy_done)
 156        ASM_EXCEPTIONTABLE_ENTRY(11b,.Lcopy16_fault)
 157        ASM_EXCEPTIONTABLE_ENTRY(12b,.Lcopy_done)
 158        ASM_EXCEPTIONTABLE_ENTRY(13b,.Lcopy_done)
 159        ASM_EXCEPTIONTABLE_ENTRY(14b,.Lcopy_done)
 160        ASM_EXCEPTIONTABLE_ENTRY(15b,.Lcopy16_fault)
 161        ASM_EXCEPTIONTABLE_ENTRY(16b,.Lcopy_done)
 162        ASM_EXCEPTIONTABLE_ENTRY(17b,.Lcopy_done)
 163
 164        b       .Lcopy_loop_16
 165        ldo     -32(len),len
 166
 167.Lword_loop:
 168        cmpib,COND(>>=),n 3,len,.Lbyte_loop
 16920:     ldw,ma  4(srcspc,src),t1
 17021:     stw,ma  t1,4(dstspc,dst)
 171        b       .Lword_loop
 172        ldo     -4(len),len
 173
 174        ASM_EXCEPTIONTABLE_ENTRY(20b,.Lcopy_done)
 175        ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done)
 176
 177#endif /* CONFIG_64BIT */
 178
 179        /* loop until we are 32-bit aligned */
 180.Lalign_loop32:
 181        extru   dst,31,2,t1
 182        cmpib,=,n       0,t1,.Lcopy_loop_8
 18320:     ldb,ma  1(srcspc,src),t1
 18421:     stb,ma  t1,1(dstspc,dst)
 185        b       .Lalign_loop32
 186        ldo     -1(len),len
 187
 188        ASM_EXCEPTIONTABLE_ENTRY(20b,.Lcopy_done)
 189        ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done)
 190
 191
 192.Lcopy_loop_8:
 193        cmpib,COND(>>=),n 15,len,.Lbyte_loop
 194
 19510:     ldw     0(srcspc,src),t1
 19611:     ldw     4(srcspc,src),t2
 19712:     stw,ma  t1,4(dstspc,dst)
 19813:     stw,ma  t2,4(dstspc,dst)
 19914:     ldw     8(srcspc,src),t1
 20015:     ldw     12(srcspc,src),t2
 201        ldo     16(src),src
 20216:     stw,ma  t1,4(dstspc,dst)
 20317:     stw,ma  t2,4(dstspc,dst)
 204
 205        ASM_EXCEPTIONTABLE_ENTRY(10b,.Lcopy_done)
 206        ASM_EXCEPTIONTABLE_ENTRY(11b,.Lcopy8_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,.Lcopy8_fault)
 211        ASM_EXCEPTIONTABLE_ENTRY(16b,.Lcopy_done)
 212        ASM_EXCEPTIONTABLE_ENTRY(17b,.Lcopy_done)
 213
 214        b       .Lcopy_loop_8
 215        ldo     -16(len),len
 216
 217.Lbyte_loop:
 218        cmpclr,COND(<>) len,%r0,%r0
 219        b,n     .Lcopy_done
 22020:     ldb     0(srcspc,src),t1
 221        ldo     1(src),src
 22221:     stb,ma  t1,1(dstspc,dst)
 223        b       .Lbyte_loop
 224        ldo     -1(len),len
 225
 226        ASM_EXCEPTIONTABLE_ENTRY(20b,.Lcopy_done)
 227        ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done)
 228
 229.Lcopy_done:
 230        bv      %r0(%r2)
 231        sub     end,dst,ret0
 232
 233
 234        /* src and dst are not aligned the same way. */
 235        /* need to go the hard way */
 236.Lunaligned_copy:
 237        /* align until dst is 32bit-word-aligned */
 238        extru   dst,31,2,t1
 239        cmpib,=,n       0,t1,.Lcopy_dstaligned
 24020:     ldb     0(srcspc,src),t1
 241        ldo     1(src),src
 24221:     stb,ma  t1,1(dstspc,dst)
 243        b       .Lunaligned_copy
 244        ldo     -1(len),len
 245
 246        ASM_EXCEPTIONTABLE_ENTRY(20b,.Lcopy_done)
 247        ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done)
 248
 249.Lcopy_dstaligned:
 250
 251        /* store src, dst and len in safe place */
 252        copy    src,save_src
 253        copy    dst,save_dst
 254        copy    len,save_len
 255
 256        /* len now needs give number of words to copy */
 257        SHRREG  len,2,len
 258
 259        /*
 260         * Copy from a not-aligned src to an aligned dst using shifts.
 261         * Handles 4 words per loop.
 262         */
 263
 264        depw,z src,28,2,t0
 265        subi 32,t0,t0
 266        mtsar t0
 267        extru len,31,2,t0
 268        cmpib,= 2,t0,.Lcase2
 269        /* Make src aligned by rounding it down.  */
 270        depi 0,31,2,src
 271
 272        cmpiclr,<> 3,t0,%r0
 273        b,n .Lcase3
 274        cmpiclr,<> 1,t0,%r0
 275        b,n .Lcase1
 276.Lcase0:
 277        cmpb,COND(=) %r0,len,.Lcda_finish
 278        nop
 279
 2801:      ldw,ma 4(srcspc,src), a3
 281        ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
 2821:      ldw,ma 4(srcspc,src), a0
 283        ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
 284        b,n .Ldo3
 285.Lcase1:
 2861:      ldw,ma 4(srcspc,src), a2
 287        ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
 2881:      ldw,ma 4(srcspc,src), a3
 289        ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
 290        ldo -1(len),len
 291        cmpb,COND(=),n %r0,len,.Ldo0
 292.Ldo4:
 2931:      ldw,ma 4(srcspc,src), a0
 294        ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
 295        shrpw a2, a3, %sar, t0
 2961:      stw,ma t0, 4(dstspc,dst)
 297        ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcopy_done)
 298.Ldo3:
 2991:      ldw,ma 4(srcspc,src), a1
 300        ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
 301        shrpw a3, a0, %sar, t0
 3021:      stw,ma t0, 4(dstspc,dst)
 303        ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcopy_done)
 304.Ldo2:
 3051:      ldw,ma 4(srcspc,src), a2
 306        ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
 307        shrpw a0, a1, %sar, t0
 3081:      stw,ma t0, 4(dstspc,dst)
 309        ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcopy_done)
 310.Ldo1:
 3111:      ldw,ma 4(srcspc,src), a3
 312        ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
 313        shrpw a1, a2, %sar, t0
 3141:      stw,ma t0, 4(dstspc,dst)
 315        ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcopy_done)
 316        ldo -4(len),len
 317        cmpb,COND(<>) %r0,len,.Ldo4
 318        nop
 319.Ldo0:
 320        shrpw a2, a3, %sar, t0
 3211:      stw,ma t0, 4(dstspc,dst)
 322        ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcopy_done)
 323
 324.Lcda_rdfault:
 325.Lcda_finish:
 326        /* calculate new src, dst and len and jump to byte-copy loop */
 327        sub     dst,save_dst,t0
 328        add     save_src,t0,src
 329        b       .Lbyte_loop
 330        sub     save_len,t0,len
 331
 332.Lcase3:
 3331:      ldw,ma 4(srcspc,src), a0
 334        ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
 3351:      ldw,ma 4(srcspc,src), a1
 336        ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
 337        b .Ldo2
 338        ldo 1(len),len
 339.Lcase2:
 3401:      ldw,ma 4(srcspc,src), a1
 341        ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
 3421:      ldw,ma 4(srcspc,src), a2
 343        ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
 344        b .Ldo1
 345        ldo 2(len),len
 346
 347
 348        /* fault exception fixup handlers: */
 349#ifdef CONFIG_64BIT
 350.Lcopy16_fault:
 351        b       .Lcopy_done
 35210:     std,ma  t1,8(dstspc,dst)
 353        ASM_EXCEPTIONTABLE_ENTRY(10b,.Lcopy_done)
 354#endif
 355
 356.Lcopy8_fault:
 357        b       .Lcopy_done
 35810:     stw,ma  t1,4(dstspc,dst)
 359        ASM_EXCEPTIONTABLE_ENTRY(10b,.Lcopy_done)
 360ENDPROC_CFI(pa_memcpy)
 361
 362        .end
 363