162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * arch/xtensa/lib/strncpy_user.S 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General 562306a36Sopenharmony_ci * Public License. See the file "COPYING" in the main directory of 662306a36Sopenharmony_ci * this archive for more details. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Returns: -EFAULT if exception before terminator, N if the entire 962306a36Sopenharmony_ci * buffer filled, else strlen. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Copyright (C) 2002 Tensilica Inc. 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/errno.h> 1562306a36Sopenharmony_ci#include <linux/linkage.h> 1662306a36Sopenharmony_ci#include <asm/asmmacro.h> 1762306a36Sopenharmony_ci#include <asm/core.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* 2062306a36Sopenharmony_ci * char *__strncpy_user(char *dst, const char *src, size_t len) 2162306a36Sopenharmony_ci */ 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#ifdef __XTENSA_EB__ 2462306a36Sopenharmony_ci# define MASK0 0xff000000 2562306a36Sopenharmony_ci# define MASK1 0x00ff0000 2662306a36Sopenharmony_ci# define MASK2 0x0000ff00 2762306a36Sopenharmony_ci# define MASK3 0x000000ff 2862306a36Sopenharmony_ci#else 2962306a36Sopenharmony_ci# define MASK0 0x000000ff 3062306a36Sopenharmony_ci# define MASK1 0x0000ff00 3162306a36Sopenharmony_ci# define MASK2 0x00ff0000 3262306a36Sopenharmony_ci# define MASK3 0xff000000 3362306a36Sopenharmony_ci#endif 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci# Register use 3662306a36Sopenharmony_ci# a0/ return address 3762306a36Sopenharmony_ci# a1/ stack pointer 3862306a36Sopenharmony_ci# a2/ return value 3962306a36Sopenharmony_ci# a3/ src 4062306a36Sopenharmony_ci# a4/ len 4162306a36Sopenharmony_ci# a5/ mask0 4262306a36Sopenharmony_ci# a6/ mask1 4362306a36Sopenharmony_ci# a7/ mask2 4462306a36Sopenharmony_ci# a8/ mask3 4562306a36Sopenharmony_ci# a9/ tmp 4662306a36Sopenharmony_ci# a10/ tmp 4762306a36Sopenharmony_ci# a11/ dst 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci.text 5062306a36Sopenharmony_ciENTRY(__strncpy_user) 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci abi_entry_default 5362306a36Sopenharmony_ci # a2/ dst, a3/ src, a4/ len 5462306a36Sopenharmony_ci mov a11, a2 # leave dst in return value register 5562306a36Sopenharmony_ci beqz a4, .Lret # if len is zero 5662306a36Sopenharmony_ci movi a5, MASK0 # mask for byte 0 5762306a36Sopenharmony_ci movi a6, MASK1 # mask for byte 1 5862306a36Sopenharmony_ci movi a7, MASK2 # mask for byte 2 5962306a36Sopenharmony_ci movi a8, MASK3 # mask for byte 3 6062306a36Sopenharmony_ci bbsi.l a3, 0, .Lsrc1mod2 # if only 8-bit aligned 6162306a36Sopenharmony_ci bbsi.l a3, 1, .Lsrc2mod4 # if only 16-bit aligned 6262306a36Sopenharmony_ci.Lsrcaligned: # return here when src is word-aligned 6362306a36Sopenharmony_ci srli a10, a4, 2 # number of loop iterations with 4B per loop 6462306a36Sopenharmony_ci movi a9, 3 6562306a36Sopenharmony_ci bnone a11, a9, .Laligned 6662306a36Sopenharmony_ci j .Ldstunaligned 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci.Lsrc1mod2: # src address is odd 6962306a36Sopenharmony_ciEX(11f) l8ui a9, a3, 0 # get byte 0 7062306a36Sopenharmony_ci addi a3, a3, 1 # advance src pointer 7162306a36Sopenharmony_ciEX(10f) s8i a9, a11, 0 # store byte 0 7262306a36Sopenharmony_ci beqz a9, .Lret # if byte 0 is zero 7362306a36Sopenharmony_ci addi a11, a11, 1 # advance dst pointer 7462306a36Sopenharmony_ci addi a4, a4, -1 # decrement len 7562306a36Sopenharmony_ci beqz a4, .Lret # if len is zero 7662306a36Sopenharmony_ci bbci.l a3, 1, .Lsrcaligned # if src is now word-aligned 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci.Lsrc2mod4: # src address is 2 mod 4 7962306a36Sopenharmony_ciEX(11f) l8ui a9, a3, 0 # get byte 0 8062306a36Sopenharmony_ci /* 1-cycle interlock */ 8162306a36Sopenharmony_ciEX(10f) s8i a9, a11, 0 # store byte 0 8262306a36Sopenharmony_ci beqz a9, .Lret # if byte 0 is zero 8362306a36Sopenharmony_ci addi a11, a11, 1 # advance dst pointer 8462306a36Sopenharmony_ci addi a4, a4, -1 # decrement len 8562306a36Sopenharmony_ci beqz a4, .Lret # if len is zero 8662306a36Sopenharmony_ciEX(11f) l8ui a9, a3, 1 # get byte 0 8762306a36Sopenharmony_ci addi a3, a3, 2 # advance src pointer 8862306a36Sopenharmony_ciEX(10f) s8i a9, a11, 0 # store byte 0 8962306a36Sopenharmony_ci beqz a9, .Lret # if byte 0 is zero 9062306a36Sopenharmony_ci addi a11, a11, 1 # advance dst pointer 9162306a36Sopenharmony_ci addi a4, a4, -1 # decrement len 9262306a36Sopenharmony_ci bnez a4, .Lsrcaligned # if len is nonzero 9362306a36Sopenharmony_ci.Lret: 9462306a36Sopenharmony_ci sub a2, a11, a2 # compute strlen 9562306a36Sopenharmony_ci abi_ret_default 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/* 9862306a36Sopenharmony_ci * dst is word-aligned, src is word-aligned 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_ci .align 4 # 1 mod 4 alignment for LOOPNEZ 10162306a36Sopenharmony_ci .byte 0 # (0 mod 4 alignment for LBEG) 10262306a36Sopenharmony_ci.Laligned: 10362306a36Sopenharmony_ci#if XCHAL_HAVE_LOOPS 10462306a36Sopenharmony_ci loopnez a10, .Loop1done 10562306a36Sopenharmony_ci#else 10662306a36Sopenharmony_ci beqz a10, .Loop1done 10762306a36Sopenharmony_ci slli a10, a10, 2 10862306a36Sopenharmony_ci add a10, a10, a11 # a10 = end of last 4B chunck 10962306a36Sopenharmony_ci#endif 11062306a36Sopenharmony_ci.Loop1: 11162306a36Sopenharmony_ciEX(11f) l32i a9, a3, 0 # get word from src 11262306a36Sopenharmony_ci addi a3, a3, 4 # advance src pointer 11362306a36Sopenharmony_ci bnone a9, a5, .Lz0 # if byte 0 is zero 11462306a36Sopenharmony_ci bnone a9, a6, .Lz1 # if byte 1 is zero 11562306a36Sopenharmony_ci bnone a9, a7, .Lz2 # if byte 2 is zero 11662306a36Sopenharmony_ciEX(10f) s32i a9, a11, 0 # store word to dst 11762306a36Sopenharmony_ci bnone a9, a8, .Lz3 # if byte 3 is zero 11862306a36Sopenharmony_ci addi a11, a11, 4 # advance dst pointer 11962306a36Sopenharmony_ci#if !XCHAL_HAVE_LOOPS 12062306a36Sopenharmony_ci blt a11, a10, .Loop1 12162306a36Sopenharmony_ci#endif 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci.Loop1done: 12462306a36Sopenharmony_ci bbci.l a4, 1, .L100 12562306a36Sopenharmony_ci # copy 2 bytes 12662306a36Sopenharmony_ciEX(11f) l16ui a9, a3, 0 12762306a36Sopenharmony_ci addi a3, a3, 2 # advance src pointer 12862306a36Sopenharmony_ci#ifdef __XTENSA_EB__ 12962306a36Sopenharmony_ci bnone a9, a7, .Lz0 # if byte 2 is zero 13062306a36Sopenharmony_ci bnone a9, a8, .Lz1 # if byte 3 is zero 13162306a36Sopenharmony_ci#else 13262306a36Sopenharmony_ci bnone a9, a5, .Lz0 # if byte 0 is zero 13362306a36Sopenharmony_ci bnone a9, a6, .Lz1 # if byte 1 is zero 13462306a36Sopenharmony_ci#endif 13562306a36Sopenharmony_ciEX(10f) s16i a9, a11, 0 13662306a36Sopenharmony_ci addi a11, a11, 2 # advance dst pointer 13762306a36Sopenharmony_ci.L100: 13862306a36Sopenharmony_ci bbci.l a4, 0, .Lret 13962306a36Sopenharmony_ciEX(11f) l8ui a9, a3, 0 14062306a36Sopenharmony_ci /* slot */ 14162306a36Sopenharmony_ciEX(10f) s8i a9, a11, 0 14262306a36Sopenharmony_ci beqz a9, .Lret # if byte is zero 14362306a36Sopenharmony_ci addi a11, a11, 1-3 # advance dst ptr 1, but also cancel 14462306a36Sopenharmony_ci # the effect of adding 3 in .Lz3 code 14562306a36Sopenharmony_ci /* fall thru to .Lz3 and "retw" */ 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci.Lz3: # byte 3 is zero 14862306a36Sopenharmony_ci addi a11, a11, 3 # advance dst pointer 14962306a36Sopenharmony_ci sub a2, a11, a2 # compute strlen 15062306a36Sopenharmony_ci abi_ret_default 15162306a36Sopenharmony_ci.Lz0: # byte 0 is zero 15262306a36Sopenharmony_ci#ifdef __XTENSA_EB__ 15362306a36Sopenharmony_ci movi a9, 0 15462306a36Sopenharmony_ci#endif /* __XTENSA_EB__ */ 15562306a36Sopenharmony_ciEX(10f) s8i a9, a11, 0 15662306a36Sopenharmony_ci sub a2, a11, a2 # compute strlen 15762306a36Sopenharmony_ci abi_ret_default 15862306a36Sopenharmony_ci.Lz1: # byte 1 is zero 15962306a36Sopenharmony_ci#ifdef __XTENSA_EB__ 16062306a36Sopenharmony_ci extui a9, a9, 16, 16 16162306a36Sopenharmony_ci#endif /* __XTENSA_EB__ */ 16262306a36Sopenharmony_ciEX(10f) s16i a9, a11, 0 16362306a36Sopenharmony_ci addi a11, a11, 1 # advance dst pointer 16462306a36Sopenharmony_ci sub a2, a11, a2 # compute strlen 16562306a36Sopenharmony_ci abi_ret_default 16662306a36Sopenharmony_ci.Lz2: # byte 2 is zero 16762306a36Sopenharmony_ci#ifdef __XTENSA_EB__ 16862306a36Sopenharmony_ci extui a9, a9, 16, 16 16962306a36Sopenharmony_ci#endif /* __XTENSA_EB__ */ 17062306a36Sopenharmony_ciEX(10f) s16i a9, a11, 0 17162306a36Sopenharmony_ci movi a9, 0 17262306a36Sopenharmony_ciEX(10f) s8i a9, a11, 2 17362306a36Sopenharmony_ci addi a11, a11, 2 # advance dst pointer 17462306a36Sopenharmony_ci sub a2, a11, a2 # compute strlen 17562306a36Sopenharmony_ci abi_ret_default 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci .align 4 # 1 mod 4 alignment for LOOPNEZ 17862306a36Sopenharmony_ci .byte 0 # (0 mod 4 alignment for LBEG) 17962306a36Sopenharmony_ci.Ldstunaligned: 18062306a36Sopenharmony_ci/* 18162306a36Sopenharmony_ci * for now just use byte copy loop 18262306a36Sopenharmony_ci */ 18362306a36Sopenharmony_ci#if XCHAL_HAVE_LOOPS 18462306a36Sopenharmony_ci loopnez a4, .Lunalignedend 18562306a36Sopenharmony_ci#else 18662306a36Sopenharmony_ci beqz a4, .Lunalignedend 18762306a36Sopenharmony_ci add a10, a11, a4 # a10 = ending address 18862306a36Sopenharmony_ci#endif /* XCHAL_HAVE_LOOPS */ 18962306a36Sopenharmony_ci.Lnextbyte: 19062306a36Sopenharmony_ciEX(11f) l8ui a9, a3, 0 19162306a36Sopenharmony_ci addi a3, a3, 1 19262306a36Sopenharmony_ciEX(10f) s8i a9, a11, 0 19362306a36Sopenharmony_ci beqz a9, .Lunalignedend 19462306a36Sopenharmony_ci addi a11, a11, 1 19562306a36Sopenharmony_ci#if !XCHAL_HAVE_LOOPS 19662306a36Sopenharmony_ci blt a11, a10, .Lnextbyte 19762306a36Sopenharmony_ci#endif 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci.Lunalignedend: 20062306a36Sopenharmony_ci sub a2, a11, a2 # compute strlen 20162306a36Sopenharmony_ci abi_ret_default 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ciENDPROC(__strncpy_user) 20462306a36Sopenharmony_ciEXPORT_SYMBOL(__strncpy_user) 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci .section .fixup, "ax" 20762306a36Sopenharmony_ci .align 4 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* For now, just return -EFAULT. Future implementations might 21062306a36Sopenharmony_ci * like to clear remaining kernel space, like the fixup 21162306a36Sopenharmony_ci * implementation in memset(). Thus, we differentiate between 21262306a36Sopenharmony_ci * load/store fixups. */ 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci10: 21562306a36Sopenharmony_ci11: 21662306a36Sopenharmony_ci movi a2, -EFAULT 21762306a36Sopenharmony_ci abi_ret_default 218