18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * arch/xtensa/lib/strncpy_user.S 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General 58c2ecf20Sopenharmony_ci * Public License. See the file "COPYING" in the main directory of 68c2ecf20Sopenharmony_ci * this archive for more details. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Returns: -EFAULT if exception before terminator, N if the entire 98c2ecf20Sopenharmony_ci * buffer filled, else strlen. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Copyright (C) 2002 Tensilica Inc. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/errno.h> 158c2ecf20Sopenharmony_ci#include <linux/linkage.h> 168c2ecf20Sopenharmony_ci#include <asm/asmmacro.h> 178c2ecf20Sopenharmony_ci#include <asm/core.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* 208c2ecf20Sopenharmony_ci * char *__strncpy_user(char *dst, const char *src, size_t len) 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#ifdef __XTENSA_EB__ 248c2ecf20Sopenharmony_ci# define MASK0 0xff000000 258c2ecf20Sopenharmony_ci# define MASK1 0x00ff0000 268c2ecf20Sopenharmony_ci# define MASK2 0x0000ff00 278c2ecf20Sopenharmony_ci# define MASK3 0x000000ff 288c2ecf20Sopenharmony_ci#else 298c2ecf20Sopenharmony_ci# define MASK0 0x000000ff 308c2ecf20Sopenharmony_ci# define MASK1 0x0000ff00 318c2ecf20Sopenharmony_ci# define MASK2 0x00ff0000 328c2ecf20Sopenharmony_ci# define MASK3 0xff000000 338c2ecf20Sopenharmony_ci#endif 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci# Register use 368c2ecf20Sopenharmony_ci# a0/ return address 378c2ecf20Sopenharmony_ci# a1/ stack pointer 388c2ecf20Sopenharmony_ci# a2/ return value 398c2ecf20Sopenharmony_ci# a3/ src 408c2ecf20Sopenharmony_ci# a4/ len 418c2ecf20Sopenharmony_ci# a5/ mask0 428c2ecf20Sopenharmony_ci# a6/ mask1 438c2ecf20Sopenharmony_ci# a7/ mask2 448c2ecf20Sopenharmony_ci# a8/ mask3 458c2ecf20Sopenharmony_ci# a9/ tmp 468c2ecf20Sopenharmony_ci# a10/ tmp 478c2ecf20Sopenharmony_ci# a11/ dst 488c2ecf20Sopenharmony_ci# a12/ tmp 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci.text 518c2ecf20Sopenharmony_ciENTRY(__strncpy_user) 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci abi_entry_default 548c2ecf20Sopenharmony_ci # a2/ dst, a3/ src, a4/ len 558c2ecf20Sopenharmony_ci mov a11, a2 # leave dst in return value register 568c2ecf20Sopenharmony_ci beqz a4, .Lret # if len is zero 578c2ecf20Sopenharmony_ci movi a5, MASK0 # mask for byte 0 588c2ecf20Sopenharmony_ci movi a6, MASK1 # mask for byte 1 598c2ecf20Sopenharmony_ci movi a7, MASK2 # mask for byte 2 608c2ecf20Sopenharmony_ci movi a8, MASK3 # mask for byte 3 618c2ecf20Sopenharmony_ci bbsi.l a3, 0, .Lsrc1mod2 # if only 8-bit aligned 628c2ecf20Sopenharmony_ci bbsi.l a3, 1, .Lsrc2mod4 # if only 16-bit aligned 638c2ecf20Sopenharmony_ci.Lsrcaligned: # return here when src is word-aligned 648c2ecf20Sopenharmony_ci srli a12, a4, 2 # number of loop iterations with 4B per loop 658c2ecf20Sopenharmony_ci movi a9, 3 668c2ecf20Sopenharmony_ci bnone a11, a9, .Laligned 678c2ecf20Sopenharmony_ci j .Ldstunaligned 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci.Lsrc1mod2: # src address is odd 708c2ecf20Sopenharmony_ciEX(11f) l8ui a9, a3, 0 # get byte 0 718c2ecf20Sopenharmony_ci addi a3, a3, 1 # advance src pointer 728c2ecf20Sopenharmony_ciEX(10f) s8i a9, a11, 0 # store byte 0 738c2ecf20Sopenharmony_ci beqz a9, .Lret # if byte 0 is zero 748c2ecf20Sopenharmony_ci addi a11, a11, 1 # advance dst pointer 758c2ecf20Sopenharmony_ci addi a4, a4, -1 # decrement len 768c2ecf20Sopenharmony_ci beqz a4, .Lret # if len is zero 778c2ecf20Sopenharmony_ci bbci.l a3, 1, .Lsrcaligned # if src is now word-aligned 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci.Lsrc2mod4: # src address is 2 mod 4 808c2ecf20Sopenharmony_ciEX(11f) l8ui a9, a3, 0 # get byte 0 818c2ecf20Sopenharmony_ci /* 1-cycle interlock */ 828c2ecf20Sopenharmony_ciEX(10f) s8i a9, a11, 0 # store byte 0 838c2ecf20Sopenharmony_ci beqz a9, .Lret # if byte 0 is zero 848c2ecf20Sopenharmony_ci addi a11, a11, 1 # advance dst pointer 858c2ecf20Sopenharmony_ci addi a4, a4, -1 # decrement len 868c2ecf20Sopenharmony_ci beqz a4, .Lret # if len is zero 878c2ecf20Sopenharmony_ciEX(11f) l8ui a9, a3, 1 # get byte 0 888c2ecf20Sopenharmony_ci addi a3, a3, 2 # advance src pointer 898c2ecf20Sopenharmony_ciEX(10f) s8i a9, a11, 0 # store byte 0 908c2ecf20Sopenharmony_ci beqz a9, .Lret # if byte 0 is zero 918c2ecf20Sopenharmony_ci addi a11, a11, 1 # advance dst pointer 928c2ecf20Sopenharmony_ci addi a4, a4, -1 # decrement len 938c2ecf20Sopenharmony_ci bnez a4, .Lsrcaligned # if len is nonzero 948c2ecf20Sopenharmony_ci.Lret: 958c2ecf20Sopenharmony_ci sub a2, a11, a2 # compute strlen 968c2ecf20Sopenharmony_ci abi_ret_default 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/* 998c2ecf20Sopenharmony_ci * dst is word-aligned, src is word-aligned 1008c2ecf20Sopenharmony_ci */ 1018c2ecf20Sopenharmony_ci .align 4 # 1 mod 4 alignment for LOOPNEZ 1028c2ecf20Sopenharmony_ci .byte 0 # (0 mod 4 alignment for LBEG) 1038c2ecf20Sopenharmony_ci.Laligned: 1048c2ecf20Sopenharmony_ci#if XCHAL_HAVE_LOOPS 1058c2ecf20Sopenharmony_ci loopnez a12, .Loop1done 1068c2ecf20Sopenharmony_ci#else 1078c2ecf20Sopenharmony_ci beqz a12, .Loop1done 1088c2ecf20Sopenharmony_ci slli a12, a12, 2 1098c2ecf20Sopenharmony_ci add a12, a12, a11 # a12 = end of last 4B chunck 1108c2ecf20Sopenharmony_ci#endif 1118c2ecf20Sopenharmony_ci.Loop1: 1128c2ecf20Sopenharmony_ciEX(11f) l32i a9, a3, 0 # get word from src 1138c2ecf20Sopenharmony_ci addi a3, a3, 4 # advance src pointer 1148c2ecf20Sopenharmony_ci bnone a9, a5, .Lz0 # if byte 0 is zero 1158c2ecf20Sopenharmony_ci bnone a9, a6, .Lz1 # if byte 1 is zero 1168c2ecf20Sopenharmony_ci bnone a9, a7, .Lz2 # if byte 2 is zero 1178c2ecf20Sopenharmony_ciEX(10f) s32i a9, a11, 0 # store word to dst 1188c2ecf20Sopenharmony_ci bnone a9, a8, .Lz3 # if byte 3 is zero 1198c2ecf20Sopenharmony_ci addi a11, a11, 4 # advance dst pointer 1208c2ecf20Sopenharmony_ci#if !XCHAL_HAVE_LOOPS 1218c2ecf20Sopenharmony_ci blt a11, a12, .Loop1 1228c2ecf20Sopenharmony_ci#endif 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci.Loop1done: 1258c2ecf20Sopenharmony_ci bbci.l a4, 1, .L100 1268c2ecf20Sopenharmony_ci # copy 2 bytes 1278c2ecf20Sopenharmony_ciEX(11f) l16ui a9, a3, 0 1288c2ecf20Sopenharmony_ci addi a3, a3, 2 # advance src pointer 1298c2ecf20Sopenharmony_ci#ifdef __XTENSA_EB__ 1308c2ecf20Sopenharmony_ci bnone a9, a7, .Lz0 # if byte 2 is zero 1318c2ecf20Sopenharmony_ci bnone a9, a8, .Lz1 # if byte 3 is zero 1328c2ecf20Sopenharmony_ci#else 1338c2ecf20Sopenharmony_ci bnone a9, a5, .Lz0 # if byte 0 is zero 1348c2ecf20Sopenharmony_ci bnone a9, a6, .Lz1 # if byte 1 is zero 1358c2ecf20Sopenharmony_ci#endif 1368c2ecf20Sopenharmony_ciEX(10f) s16i a9, a11, 0 1378c2ecf20Sopenharmony_ci addi a11, a11, 2 # advance dst pointer 1388c2ecf20Sopenharmony_ci.L100: 1398c2ecf20Sopenharmony_ci bbci.l a4, 0, .Lret 1408c2ecf20Sopenharmony_ciEX(11f) l8ui a9, a3, 0 1418c2ecf20Sopenharmony_ci /* slot */ 1428c2ecf20Sopenharmony_ciEX(10f) s8i a9, a11, 0 1438c2ecf20Sopenharmony_ci beqz a9, .Lret # if byte is zero 1448c2ecf20Sopenharmony_ci addi a11, a11, 1-3 # advance dst ptr 1, but also cancel 1458c2ecf20Sopenharmony_ci # the effect of adding 3 in .Lz3 code 1468c2ecf20Sopenharmony_ci /* fall thru to .Lz3 and "retw" */ 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci.Lz3: # byte 3 is zero 1498c2ecf20Sopenharmony_ci addi a11, a11, 3 # advance dst pointer 1508c2ecf20Sopenharmony_ci sub a2, a11, a2 # compute strlen 1518c2ecf20Sopenharmony_ci abi_ret_default 1528c2ecf20Sopenharmony_ci.Lz0: # byte 0 is zero 1538c2ecf20Sopenharmony_ci#ifdef __XTENSA_EB__ 1548c2ecf20Sopenharmony_ci movi a9, 0 1558c2ecf20Sopenharmony_ci#endif /* __XTENSA_EB__ */ 1568c2ecf20Sopenharmony_ciEX(10f) s8i a9, a11, 0 1578c2ecf20Sopenharmony_ci sub a2, a11, a2 # compute strlen 1588c2ecf20Sopenharmony_ci abi_ret_default 1598c2ecf20Sopenharmony_ci.Lz1: # byte 1 is zero 1608c2ecf20Sopenharmony_ci#ifdef __XTENSA_EB__ 1618c2ecf20Sopenharmony_ci extui a9, a9, 16, 16 1628c2ecf20Sopenharmony_ci#endif /* __XTENSA_EB__ */ 1638c2ecf20Sopenharmony_ciEX(10f) s16i a9, a11, 0 1648c2ecf20Sopenharmony_ci addi a11, a11, 1 # advance dst pointer 1658c2ecf20Sopenharmony_ci sub a2, a11, a2 # compute strlen 1668c2ecf20Sopenharmony_ci abi_ret_default 1678c2ecf20Sopenharmony_ci.Lz2: # byte 2 is zero 1688c2ecf20Sopenharmony_ci#ifdef __XTENSA_EB__ 1698c2ecf20Sopenharmony_ci extui a9, a9, 16, 16 1708c2ecf20Sopenharmony_ci#endif /* __XTENSA_EB__ */ 1718c2ecf20Sopenharmony_ciEX(10f) s16i a9, a11, 0 1728c2ecf20Sopenharmony_ci movi a9, 0 1738c2ecf20Sopenharmony_ciEX(10f) s8i a9, a11, 2 1748c2ecf20Sopenharmony_ci addi a11, a11, 2 # advance dst pointer 1758c2ecf20Sopenharmony_ci sub a2, a11, a2 # compute strlen 1768c2ecf20Sopenharmony_ci abi_ret_default 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci .align 4 # 1 mod 4 alignment for LOOPNEZ 1798c2ecf20Sopenharmony_ci .byte 0 # (0 mod 4 alignment for LBEG) 1808c2ecf20Sopenharmony_ci.Ldstunaligned: 1818c2ecf20Sopenharmony_ci/* 1828c2ecf20Sopenharmony_ci * for now just use byte copy loop 1838c2ecf20Sopenharmony_ci */ 1848c2ecf20Sopenharmony_ci#if XCHAL_HAVE_LOOPS 1858c2ecf20Sopenharmony_ci loopnez a4, .Lunalignedend 1868c2ecf20Sopenharmony_ci#else 1878c2ecf20Sopenharmony_ci beqz a4, .Lunalignedend 1888c2ecf20Sopenharmony_ci add a12, a11, a4 # a12 = ending address 1898c2ecf20Sopenharmony_ci#endif /* XCHAL_HAVE_LOOPS */ 1908c2ecf20Sopenharmony_ci.Lnextbyte: 1918c2ecf20Sopenharmony_ciEX(11f) l8ui a9, a3, 0 1928c2ecf20Sopenharmony_ci addi a3, a3, 1 1938c2ecf20Sopenharmony_ciEX(10f) s8i a9, a11, 0 1948c2ecf20Sopenharmony_ci beqz a9, .Lunalignedend 1958c2ecf20Sopenharmony_ci addi a11, a11, 1 1968c2ecf20Sopenharmony_ci#if !XCHAL_HAVE_LOOPS 1978c2ecf20Sopenharmony_ci blt a11, a12, .Lnextbyte 1988c2ecf20Sopenharmony_ci#endif 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci.Lunalignedend: 2018c2ecf20Sopenharmony_ci sub a2, a11, a2 # compute strlen 2028c2ecf20Sopenharmony_ci abi_ret_default 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ciENDPROC(__strncpy_user) 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci .section .fixup, "ax" 2078c2ecf20Sopenharmony_ci .align 4 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci /* For now, just return -EFAULT. Future implementations might 2108c2ecf20Sopenharmony_ci * like to clear remaining kernel space, like the fixup 2118c2ecf20Sopenharmony_ci * implementation in memset(). Thus, we differentiate between 2128c2ecf20Sopenharmony_ci * load/store fixups. */ 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci10: 2158c2ecf20Sopenharmony_ci11: 2168c2ecf20Sopenharmony_ci movi a2, -EFAULT 2178c2ecf20Sopenharmony_ci abi_ret_default 218