1*4882a593Smuzhiyun/* 2*4882a593Smuzhiyun * arch/xtensa/lib/strncpy_user.S 3*4882a593Smuzhiyun * 4*4882a593Smuzhiyun * This file is subject to the terms and conditions of the GNU General 5*4882a593Smuzhiyun * Public License. See the file "COPYING" in the main directory of 6*4882a593Smuzhiyun * this archive for more details. 7*4882a593Smuzhiyun * 8*4882a593Smuzhiyun * Returns: -EFAULT if exception before terminator, N if the entire 9*4882a593Smuzhiyun * buffer filled, else strlen. 10*4882a593Smuzhiyun * 11*4882a593Smuzhiyun * Copyright (C) 2002 Tensilica Inc. 12*4882a593Smuzhiyun */ 13*4882a593Smuzhiyun 14*4882a593Smuzhiyun#include <linux/errno.h> 15*4882a593Smuzhiyun#include <linux/linkage.h> 16*4882a593Smuzhiyun#include <asm/asmmacro.h> 17*4882a593Smuzhiyun#include <asm/core.h> 18*4882a593Smuzhiyun 19*4882a593Smuzhiyun/* 20*4882a593Smuzhiyun * char *__strncpy_user(char *dst, const char *src, size_t len) 21*4882a593Smuzhiyun */ 22*4882a593Smuzhiyun 23*4882a593Smuzhiyun#ifdef __XTENSA_EB__ 24*4882a593Smuzhiyun# define MASK0 0xff000000 25*4882a593Smuzhiyun# define MASK1 0x00ff0000 26*4882a593Smuzhiyun# define MASK2 0x0000ff00 27*4882a593Smuzhiyun# define MASK3 0x000000ff 28*4882a593Smuzhiyun#else 29*4882a593Smuzhiyun# define MASK0 0x000000ff 30*4882a593Smuzhiyun# define MASK1 0x0000ff00 31*4882a593Smuzhiyun# define MASK2 0x00ff0000 32*4882a593Smuzhiyun# define MASK3 0xff000000 33*4882a593Smuzhiyun#endif 34*4882a593Smuzhiyun 35*4882a593Smuzhiyun# Register use 36*4882a593Smuzhiyun# a0/ return address 37*4882a593Smuzhiyun# a1/ stack pointer 38*4882a593Smuzhiyun# a2/ return value 39*4882a593Smuzhiyun# a3/ src 40*4882a593Smuzhiyun# a4/ len 41*4882a593Smuzhiyun# a5/ mask0 42*4882a593Smuzhiyun# a6/ mask1 43*4882a593Smuzhiyun# a7/ mask2 44*4882a593Smuzhiyun# a8/ mask3 45*4882a593Smuzhiyun# a9/ tmp 46*4882a593Smuzhiyun# a10/ tmp 47*4882a593Smuzhiyun# a11/ dst 48*4882a593Smuzhiyun# a12/ tmp 49*4882a593Smuzhiyun 50*4882a593Smuzhiyun.text 51*4882a593SmuzhiyunENTRY(__strncpy_user) 52*4882a593Smuzhiyun 53*4882a593Smuzhiyun abi_entry_default 54*4882a593Smuzhiyun # a2/ dst, a3/ src, a4/ len 55*4882a593Smuzhiyun mov a11, a2 # leave dst in return value register 56*4882a593Smuzhiyun beqz a4, .Lret # if len is zero 57*4882a593Smuzhiyun movi a5, MASK0 # mask for byte 0 58*4882a593Smuzhiyun movi a6, MASK1 # mask for byte 1 59*4882a593Smuzhiyun movi a7, MASK2 # mask for byte 2 60*4882a593Smuzhiyun movi a8, MASK3 # mask for byte 3 61*4882a593Smuzhiyun bbsi.l a3, 0, .Lsrc1mod2 # if only 8-bit aligned 62*4882a593Smuzhiyun bbsi.l a3, 1, .Lsrc2mod4 # if only 16-bit aligned 63*4882a593Smuzhiyun.Lsrcaligned: # return here when src is word-aligned 64*4882a593Smuzhiyun srli a12, a4, 2 # number of loop iterations with 4B per loop 65*4882a593Smuzhiyun movi a9, 3 66*4882a593Smuzhiyun bnone a11, a9, .Laligned 67*4882a593Smuzhiyun j .Ldstunaligned 68*4882a593Smuzhiyun 69*4882a593Smuzhiyun.Lsrc1mod2: # src address is odd 70*4882a593SmuzhiyunEX(11f) l8ui a9, a3, 0 # get byte 0 71*4882a593Smuzhiyun addi a3, a3, 1 # advance src pointer 72*4882a593SmuzhiyunEX(10f) s8i a9, a11, 0 # store byte 0 73*4882a593Smuzhiyun beqz a9, .Lret # if byte 0 is zero 74*4882a593Smuzhiyun addi a11, a11, 1 # advance dst pointer 75*4882a593Smuzhiyun addi a4, a4, -1 # decrement len 76*4882a593Smuzhiyun beqz a4, .Lret # if len is zero 77*4882a593Smuzhiyun bbci.l a3, 1, .Lsrcaligned # if src is now word-aligned 78*4882a593Smuzhiyun 79*4882a593Smuzhiyun.Lsrc2mod4: # src address is 2 mod 4 80*4882a593SmuzhiyunEX(11f) l8ui a9, a3, 0 # get byte 0 81*4882a593Smuzhiyun /* 1-cycle interlock */ 82*4882a593SmuzhiyunEX(10f) s8i a9, a11, 0 # store byte 0 83*4882a593Smuzhiyun beqz a9, .Lret # if byte 0 is zero 84*4882a593Smuzhiyun addi a11, a11, 1 # advance dst pointer 85*4882a593Smuzhiyun addi a4, a4, -1 # decrement len 86*4882a593Smuzhiyun beqz a4, .Lret # if len is zero 87*4882a593SmuzhiyunEX(11f) l8ui a9, a3, 1 # get byte 0 88*4882a593Smuzhiyun addi a3, a3, 2 # advance src pointer 89*4882a593SmuzhiyunEX(10f) s8i a9, a11, 0 # store byte 0 90*4882a593Smuzhiyun beqz a9, .Lret # if byte 0 is zero 91*4882a593Smuzhiyun addi a11, a11, 1 # advance dst pointer 92*4882a593Smuzhiyun addi a4, a4, -1 # decrement len 93*4882a593Smuzhiyun bnez a4, .Lsrcaligned # if len is nonzero 94*4882a593Smuzhiyun.Lret: 95*4882a593Smuzhiyun sub a2, a11, a2 # compute strlen 96*4882a593Smuzhiyun abi_ret_default 97*4882a593Smuzhiyun 98*4882a593Smuzhiyun/* 99*4882a593Smuzhiyun * dst is word-aligned, src is word-aligned 100*4882a593Smuzhiyun */ 101*4882a593Smuzhiyun .align 4 # 1 mod 4 alignment for LOOPNEZ 102*4882a593Smuzhiyun .byte 0 # (0 mod 4 alignment for LBEG) 103*4882a593Smuzhiyun.Laligned: 104*4882a593Smuzhiyun#if XCHAL_HAVE_LOOPS 105*4882a593Smuzhiyun loopnez a12, .Loop1done 106*4882a593Smuzhiyun#else 107*4882a593Smuzhiyun beqz a12, .Loop1done 108*4882a593Smuzhiyun slli a12, a12, 2 109*4882a593Smuzhiyun add a12, a12, a11 # a12 = end of last 4B chunck 110*4882a593Smuzhiyun#endif 111*4882a593Smuzhiyun.Loop1: 112*4882a593SmuzhiyunEX(11f) l32i a9, a3, 0 # get word from src 113*4882a593Smuzhiyun addi a3, a3, 4 # advance src pointer 114*4882a593Smuzhiyun bnone a9, a5, .Lz0 # if byte 0 is zero 115*4882a593Smuzhiyun bnone a9, a6, .Lz1 # if byte 1 is zero 116*4882a593Smuzhiyun bnone a9, a7, .Lz2 # if byte 2 is zero 117*4882a593SmuzhiyunEX(10f) s32i a9, a11, 0 # store word to dst 118*4882a593Smuzhiyun bnone a9, a8, .Lz3 # if byte 3 is zero 119*4882a593Smuzhiyun addi a11, a11, 4 # advance dst pointer 120*4882a593Smuzhiyun#if !XCHAL_HAVE_LOOPS 121*4882a593Smuzhiyun blt a11, a12, .Loop1 122*4882a593Smuzhiyun#endif 123*4882a593Smuzhiyun 124*4882a593Smuzhiyun.Loop1done: 125*4882a593Smuzhiyun bbci.l a4, 1, .L100 126*4882a593Smuzhiyun # copy 2 bytes 127*4882a593SmuzhiyunEX(11f) l16ui a9, a3, 0 128*4882a593Smuzhiyun addi a3, a3, 2 # advance src pointer 129*4882a593Smuzhiyun#ifdef __XTENSA_EB__ 130*4882a593Smuzhiyun bnone a9, a7, .Lz0 # if byte 2 is zero 131*4882a593Smuzhiyun bnone a9, a8, .Lz1 # if byte 3 is zero 132*4882a593Smuzhiyun#else 133*4882a593Smuzhiyun bnone a9, a5, .Lz0 # if byte 0 is zero 134*4882a593Smuzhiyun bnone a9, a6, .Lz1 # if byte 1 is zero 135*4882a593Smuzhiyun#endif 136*4882a593SmuzhiyunEX(10f) s16i a9, a11, 0 137*4882a593Smuzhiyun addi a11, a11, 2 # advance dst pointer 138*4882a593Smuzhiyun.L100: 139*4882a593Smuzhiyun bbci.l a4, 0, .Lret 140*4882a593SmuzhiyunEX(11f) l8ui a9, a3, 0 141*4882a593Smuzhiyun /* slot */ 142*4882a593SmuzhiyunEX(10f) s8i a9, a11, 0 143*4882a593Smuzhiyun beqz a9, .Lret # if byte is zero 144*4882a593Smuzhiyun addi a11, a11, 1-3 # advance dst ptr 1, but also cancel 145*4882a593Smuzhiyun # the effect of adding 3 in .Lz3 code 146*4882a593Smuzhiyun /* fall thru to .Lz3 and "retw" */ 147*4882a593Smuzhiyun 148*4882a593Smuzhiyun.Lz3: # byte 3 is zero 149*4882a593Smuzhiyun addi a11, a11, 3 # advance dst pointer 150*4882a593Smuzhiyun sub a2, a11, a2 # compute strlen 151*4882a593Smuzhiyun abi_ret_default 152*4882a593Smuzhiyun.Lz0: # byte 0 is zero 153*4882a593Smuzhiyun#ifdef __XTENSA_EB__ 154*4882a593Smuzhiyun movi a9, 0 155*4882a593Smuzhiyun#endif /* __XTENSA_EB__ */ 156*4882a593SmuzhiyunEX(10f) s8i a9, a11, 0 157*4882a593Smuzhiyun sub a2, a11, a2 # compute strlen 158*4882a593Smuzhiyun abi_ret_default 159*4882a593Smuzhiyun.Lz1: # byte 1 is zero 160*4882a593Smuzhiyun#ifdef __XTENSA_EB__ 161*4882a593Smuzhiyun extui a9, a9, 16, 16 162*4882a593Smuzhiyun#endif /* __XTENSA_EB__ */ 163*4882a593SmuzhiyunEX(10f) s16i a9, a11, 0 164*4882a593Smuzhiyun addi a11, a11, 1 # advance dst pointer 165*4882a593Smuzhiyun sub a2, a11, a2 # compute strlen 166*4882a593Smuzhiyun abi_ret_default 167*4882a593Smuzhiyun.Lz2: # byte 2 is zero 168*4882a593Smuzhiyun#ifdef __XTENSA_EB__ 169*4882a593Smuzhiyun extui a9, a9, 16, 16 170*4882a593Smuzhiyun#endif /* __XTENSA_EB__ */ 171*4882a593SmuzhiyunEX(10f) s16i a9, a11, 0 172*4882a593Smuzhiyun movi a9, 0 173*4882a593SmuzhiyunEX(10f) s8i a9, a11, 2 174*4882a593Smuzhiyun addi a11, a11, 2 # advance dst pointer 175*4882a593Smuzhiyun sub a2, a11, a2 # compute strlen 176*4882a593Smuzhiyun abi_ret_default 177*4882a593Smuzhiyun 178*4882a593Smuzhiyun .align 4 # 1 mod 4 alignment for LOOPNEZ 179*4882a593Smuzhiyun .byte 0 # (0 mod 4 alignment for LBEG) 180*4882a593Smuzhiyun.Ldstunaligned: 181*4882a593Smuzhiyun/* 182*4882a593Smuzhiyun * for now just use byte copy loop 183*4882a593Smuzhiyun */ 184*4882a593Smuzhiyun#if XCHAL_HAVE_LOOPS 185*4882a593Smuzhiyun loopnez a4, .Lunalignedend 186*4882a593Smuzhiyun#else 187*4882a593Smuzhiyun beqz a4, .Lunalignedend 188*4882a593Smuzhiyun add a12, a11, a4 # a12 = ending address 189*4882a593Smuzhiyun#endif /* XCHAL_HAVE_LOOPS */ 190*4882a593Smuzhiyun.Lnextbyte: 191*4882a593SmuzhiyunEX(11f) l8ui a9, a3, 0 192*4882a593Smuzhiyun addi a3, a3, 1 193*4882a593SmuzhiyunEX(10f) s8i a9, a11, 0 194*4882a593Smuzhiyun beqz a9, .Lunalignedend 195*4882a593Smuzhiyun addi a11, a11, 1 196*4882a593Smuzhiyun#if !XCHAL_HAVE_LOOPS 197*4882a593Smuzhiyun blt a11, a12, .Lnextbyte 198*4882a593Smuzhiyun#endif 199*4882a593Smuzhiyun 200*4882a593Smuzhiyun.Lunalignedend: 201*4882a593Smuzhiyun sub a2, a11, a2 # compute strlen 202*4882a593Smuzhiyun abi_ret_default 203*4882a593Smuzhiyun 204*4882a593SmuzhiyunENDPROC(__strncpy_user) 205*4882a593Smuzhiyun 206*4882a593Smuzhiyun .section .fixup, "ax" 207*4882a593Smuzhiyun .align 4 208*4882a593Smuzhiyun 209*4882a593Smuzhiyun /* For now, just return -EFAULT. Future implementations might 210*4882a593Smuzhiyun * like to clear remaining kernel space, like the fixup 211*4882a593Smuzhiyun * implementation in memset(). Thus, we differentiate between 212*4882a593Smuzhiyun * load/store fixups. */ 213*4882a593Smuzhiyun 214*4882a593Smuzhiyun10: 215*4882a593Smuzhiyun11: 216*4882a593Smuzhiyun movi a2, -EFAULT 217*4882a593Smuzhiyun abi_ret_default 218