root/arch/xtensa/lib/strnlen_user.S

/* [<][>][^][v][top][bottom][index][help] */
   1 /*
   2  *  arch/xtensa/lib/strnlen_user.S
   3  *
   4  *  This file is subject to the terms and conditions of the GNU General
   5  *  Public License.  See the file "COPYING" in the main directory of
   6  *  this archive for more details.
   7  *
   8  *  Returns strnlen, including trailing zero terminator.
   9  *  Zero indicates error.
  10  *
  11  *  Copyright (C) 2002 Tensilica Inc.
  12  */
  13 
  14 #include <linux/linkage.h>
  15 #include <asm/asmmacro.h>
  16 #include <asm/core.h>
  17 
  18 /*
  19  * size_t __strnlen_user(const char *s, size_t len)
  20  */
  21 
  22 #ifdef __XTENSA_EB__
  23 # define MASK0 0xff000000
  24 # define MASK1 0x00ff0000
  25 # define MASK2 0x0000ff00
  26 # define MASK3 0x000000ff
  27 #else
  28 # define MASK0 0x000000ff
  29 # define MASK1 0x0000ff00
  30 # define MASK2 0x00ff0000
  31 # define MASK3 0xff000000
  32 #endif
  33 
  34 # Register use:
  35 #   a2/ src
  36 #   a3/ len
  37 #   a4/ tmp
  38 #   a5/ mask0
  39 #   a6/ mask1
  40 #   a7/ mask2
  41 #   a8/ mask3
  42 #   a9/ tmp
  43 #   a10/ tmp
  44 
  45 .text
  46 ENTRY(__strnlen_user)
  47 
  48         abi_entry_default
  49         # a2/ s, a3/ len
  50         addi    a4, a2, -4      # because we overincrement at the end;
  51                                 # we compensate with load offsets of 4
  52         movi    a5, MASK0       # mask for byte 0
  53         movi    a6, MASK1       # mask for byte 1
  54         movi    a7, MASK2       # mask for byte 2
  55         movi    a8, MASK3       # mask for byte 3
  56         bbsi.l  a2, 0, .L1mod2  # if only  8-bit aligned
  57         bbsi.l  a2, 1, .L2mod4  # if only 16-bit aligned
  58 
  59 /*
  60  * String is word-aligned.
  61  */
  62 .Laligned:
  63         srli    a10, a3, 2      # number of loop iterations with 4B per loop
  64 #if XCHAL_HAVE_LOOPS
  65         loopnez a10, .Ldone
  66 #else
  67         beqz    a10, .Ldone
  68         slli    a10, a10, 2
  69         add     a10, a10, a4    # a10 = end of last 4B chunk
  70 #endif /* XCHAL_HAVE_LOOPS */
  71 .Loop:
  72 EX(10f) l32i    a9, a4, 4               # get next word of string
  73         addi    a4, a4, 4               # advance string pointer
  74         bnone   a9, a5, .Lz0            # if byte 0 is zero
  75         bnone   a9, a6, .Lz1            # if byte 1 is zero
  76         bnone   a9, a7, .Lz2            # if byte 2 is zero
  77         bnone   a9, a8, .Lz3            # if byte 3 is zero
  78 #if !XCHAL_HAVE_LOOPS
  79         blt     a4, a10, .Loop
  80 #endif
  81 
  82 .Ldone:
  83 EX(10f) l32i    a9, a4, 4       # load 4 bytes for remaining checks
  84 
  85         bbci.l  a3, 1, .L100
  86         # check two more bytes (bytes 0, 1 of word)
  87         addi    a4, a4, 2       # advance string pointer
  88         bnone   a9, a5, .Lz0    # if byte 0 is zero
  89         bnone   a9, a6, .Lz1    # if byte 1 is zero
  90 .L100:
  91         bbci.l  a3, 0, .L101
  92         # check one more byte (byte 2 of word)
  93         # Actually, we don't need to check.  Zero or nonzero, we'll add one.
  94         # Do not add an extra one for the NULL terminator since we have
  95         #  exhausted the original len parameter.
  96         addi    a4, a4, 1       # advance string pointer
  97 .L101:
  98         sub     a2, a4, a2      # compute length
  99         abi_ret_default
 100 
 101 # NOTE that in several places below, we point to the byte just after
 102 # the zero byte in order to include the NULL terminator in the count.
 103 
 104 .Lz3:   # byte 3 is zero
 105         addi    a4, a4, 3       # point to zero byte
 106 .Lz0:   # byte 0 is zero
 107         addi    a4, a4, 1       # point just beyond zero byte
 108         sub     a2, a4, a2      # subtract to get length
 109         abi_ret_default
 110 .Lz1:   # byte 1 is zero
 111         addi    a4, a4, 1+1     # point just beyond zero byte
 112         sub     a2, a4, a2      # subtract to get length
 113         abi_ret_default
 114 .Lz2:   # byte 2 is zero
 115         addi    a4, a4, 2+1     # point just beyond zero byte
 116         sub     a2, a4, a2      # subtract to get length
 117         abi_ret_default
 118 
 119 .L1mod2:        # address is odd
 120 EX(10f) l8ui    a9, a4, 4               # get byte 0
 121         addi    a4, a4, 1               # advance string pointer
 122         beqz    a9, .Lz3                # if byte 0 is zero
 123         bbci.l  a4, 1, .Laligned        # if string pointer is now word-aligned
 124 
 125 .L2mod4:        # address is 2 mod 4
 126         addi    a4, a4, 2       # advance ptr for aligned access
 127 EX(10f) l32i    a9, a4, 0       # get word with first two bytes of string
 128         bnone   a9, a7, .Lz2    # if byte 2 (of word, not string) is zero
 129         bany    a9, a8, .Laligned # if byte 3 (of word, not string) is nonzero
 130         # byte 3 is zero
 131         addi    a4, a4, 3+1     # point just beyond zero byte
 132         sub     a2, a4, a2      # subtract to get length
 133         abi_ret_default
 134 
 135 ENDPROC(__strnlen_user)
 136 
 137         .section .fixup, "ax"
 138         .align  4
 139 10:
 140         movi    a2, 0
 141         abi_ret_default

/* [<][>][^][v][top][bottom][index][help] */