1*5ba15d41SFeng Jiang/* SPDX-License-Identifier: GPL-2.0-only */ 2*5ba15d41SFeng Jiang 3*5ba15d41SFeng Jiang/* 4*5ba15d41SFeng Jiang * Base on arch/riscv/lib/strlen.S 5*5ba15d41SFeng Jiang * 6*5ba15d41SFeng Jiang * Copyright (C) Feng Jiang <jiangfeng@kylinos.cn> 7*5ba15d41SFeng Jiang */ 8*5ba15d41SFeng Jiang 9*5ba15d41SFeng Jiang#include <linux/linkage.h> 10*5ba15d41SFeng Jiang#include <asm/asm.h> 11*5ba15d41SFeng Jiang#include <asm/alternative-macros.h> 12*5ba15d41SFeng Jiang#include <asm/hwcap.h> 13*5ba15d41SFeng Jiang 14*5ba15d41SFeng Jiang/* size_t strnlen(const char *s, size_t count) */ 15*5ba15d41SFeng JiangSYM_FUNC_START(strnlen) 16*5ba15d41SFeng Jiang 17*5ba15d41SFeng Jiang __ALTERNATIVE_CFG("nop", "j strnlen_zbb", 0, RISCV_ISA_EXT_ZBB, 18*5ba15d41SFeng Jiang IS_ENABLED(CONFIG_RISCV_ISA_ZBB) && IS_ENABLED(CONFIG_TOOLCHAIN_HAS_ZBB)) 19*5ba15d41SFeng Jiang 20*5ba15d41SFeng Jiang 21*5ba15d41SFeng Jiang /* 22*5ba15d41SFeng Jiang * Returns 23*5ba15d41SFeng Jiang * a0 - String length 24*5ba15d41SFeng Jiang * 25*5ba15d41SFeng Jiang * Parameters 26*5ba15d41SFeng Jiang * a0 - String to measure 27*5ba15d41SFeng Jiang * a1 - Max length of string 28*5ba15d41SFeng Jiang * 29*5ba15d41SFeng Jiang * Clobbers 30*5ba15d41SFeng Jiang * t0, t1, t2 31*5ba15d41SFeng Jiang */ 32*5ba15d41SFeng Jiang addi t1, a0, -1 33*5ba15d41SFeng Jiang add t2, a0, a1 34*5ba15d41SFeng Jiang1: 35*5ba15d41SFeng Jiang addi t1, t1, 1 36*5ba15d41SFeng Jiang beq t1, t2, 2f 37*5ba15d41SFeng Jiang lbu t0, 0(t1) 38*5ba15d41SFeng Jiang bnez t0, 1b 39*5ba15d41SFeng Jiang2: 40*5ba15d41SFeng Jiang sub a0, t1, a0 41*5ba15d41SFeng Jiang ret 42*5ba15d41SFeng Jiang 43*5ba15d41SFeng Jiang 44*5ba15d41SFeng Jiang/* 45*5ba15d41SFeng Jiang * Variant of strnlen using the ZBB extension if available 46*5ba15d41SFeng Jiang */ 47*5ba15d41SFeng Jiang#if defined(CONFIG_RISCV_ISA_ZBB) && defined(CONFIG_TOOLCHAIN_HAS_ZBB) 48*5ba15d41SFeng Jiangstrnlen_zbb: 49*5ba15d41SFeng Jiang 50*5ba15d41SFeng Jiang#ifdef CONFIG_CPU_BIG_ENDIAN 51*5ba15d41SFeng Jiang# define CZ clz 52*5ba15d41SFeng Jiang# define SHIFT sll 53*5ba15d41SFeng Jiang#else 54*5ba15d41SFeng Jiang# define CZ ctz 55*5ba15d41SFeng Jiang# define SHIFT srl 56*5ba15d41SFeng Jiang#endif 57*5ba15d41SFeng Jiang 58*5ba15d41SFeng Jiang.option push 59*5ba15d41SFeng Jiang.option arch,+zbb 60*5ba15d41SFeng Jiang 61*5ba15d41SFeng Jiang /* 62*5ba15d41SFeng Jiang * Returns 63*5ba15d41SFeng Jiang * a0 - String length 64*5ba15d41SFeng Jiang * 65*5ba15d41SFeng Jiang * Parameters 66*5ba15d41SFeng Jiang * a0 - String to measure 67*5ba15d41SFeng Jiang * a1 - Max length of string 68*5ba15d41SFeng Jiang * 69*5ba15d41SFeng Jiang * Clobbers 70*5ba15d41SFeng Jiang * t0, t1, t2, t3, t4 71*5ba15d41SFeng Jiang */ 72*5ba15d41SFeng Jiang 73*5ba15d41SFeng Jiang /* If maxlen is 0, return 0. */ 74*5ba15d41SFeng Jiang beqz a1, 3f 75*5ba15d41SFeng Jiang 76*5ba15d41SFeng Jiang /* Number of irrelevant bytes in the first word. */ 77*5ba15d41SFeng Jiang andi t2, a0, SZREG-1 78*5ba15d41SFeng Jiang 79*5ba15d41SFeng Jiang /* Align pointer. */ 80*5ba15d41SFeng Jiang andi t0, a0, -SZREG 81*5ba15d41SFeng Jiang 82*5ba15d41SFeng Jiang li t3, SZREG 83*5ba15d41SFeng Jiang sub t3, t3, t2 84*5ba15d41SFeng Jiang slli t2, t2, 3 85*5ba15d41SFeng Jiang 86*5ba15d41SFeng Jiang /* Aligned boundary. */ 87*5ba15d41SFeng Jiang add t4, a0, a1 88*5ba15d41SFeng Jiang andi t4, t4, -SZREG 89*5ba15d41SFeng Jiang 90*5ba15d41SFeng Jiang /* Get the first word. */ 91*5ba15d41SFeng Jiang REG_L t1, 0(t0) 92*5ba15d41SFeng Jiang 93*5ba15d41SFeng Jiang /* 94*5ba15d41SFeng Jiang * Shift away the partial data we loaded to remove the irrelevant bytes 95*5ba15d41SFeng Jiang * preceding the string with the effect of adding NUL bytes at the 96*5ba15d41SFeng Jiang * end of the string's first word. 97*5ba15d41SFeng Jiang */ 98*5ba15d41SFeng Jiang SHIFT t1, t1, t2 99*5ba15d41SFeng Jiang 100*5ba15d41SFeng Jiang /* Convert non-NUL into 0xff and NUL into 0x00. */ 101*5ba15d41SFeng Jiang orc.b t1, t1 102*5ba15d41SFeng Jiang 103*5ba15d41SFeng Jiang /* Convert non-NUL into 0x00 and NUL into 0xff. */ 104*5ba15d41SFeng Jiang not t1, t1 105*5ba15d41SFeng Jiang 106*5ba15d41SFeng Jiang /* 107*5ba15d41SFeng Jiang * Search for the first set bit (corresponding to a NUL byte in the 108*5ba15d41SFeng Jiang * original chunk). 109*5ba15d41SFeng Jiang */ 110*5ba15d41SFeng Jiang CZ t1, t1 111*5ba15d41SFeng Jiang 112*5ba15d41SFeng Jiang /* 113*5ba15d41SFeng Jiang * The first chunk is special: compare against the number 114*5ba15d41SFeng Jiang * of valid bytes in this chunk. 115*5ba15d41SFeng Jiang */ 116*5ba15d41SFeng Jiang srli a0, t1, 3 117*5ba15d41SFeng Jiang 118*5ba15d41SFeng Jiang /* Limit the result by maxlen. */ 119*5ba15d41SFeng Jiang minu a0, a0, a1 120*5ba15d41SFeng Jiang 121*5ba15d41SFeng Jiang bgtu t3, a0, 2f 122*5ba15d41SFeng Jiang 123*5ba15d41SFeng Jiang /* Prepare for the word comparison loop. */ 124*5ba15d41SFeng Jiang addi t2, t0, SZREG 125*5ba15d41SFeng Jiang li t3, -1 126*5ba15d41SFeng Jiang 127*5ba15d41SFeng Jiang /* 128*5ba15d41SFeng Jiang * Our critical loop is 4 instructions and processes data in 129*5ba15d41SFeng Jiang * 4 byte or 8 byte chunks. 130*5ba15d41SFeng Jiang */ 131*5ba15d41SFeng Jiang .p2align 3 132*5ba15d41SFeng Jiang1: 133*5ba15d41SFeng Jiang REG_L t1, SZREG(t0) 134*5ba15d41SFeng Jiang addi t0, t0, SZREG 135*5ba15d41SFeng Jiang orc.b t1, t1 136*5ba15d41SFeng Jiang bgeu t0, t4, 4f 137*5ba15d41SFeng Jiang beq t1, t3, 1b 138*5ba15d41SFeng Jiang4: 139*5ba15d41SFeng Jiang not t1, t1 140*5ba15d41SFeng Jiang CZ t1, t1 141*5ba15d41SFeng Jiang srli t1, t1, 3 142*5ba15d41SFeng Jiang 143*5ba15d41SFeng Jiang /* Get number of processed bytes. */ 144*5ba15d41SFeng Jiang sub t2, t0, t2 145*5ba15d41SFeng Jiang 146*5ba15d41SFeng Jiang /* Add number of characters in the first word. */ 147*5ba15d41SFeng Jiang add a0, a0, t2 148*5ba15d41SFeng Jiang 149*5ba15d41SFeng Jiang /* Add number of characters in the last word. */ 150*5ba15d41SFeng Jiang add a0, a0, t1 151*5ba15d41SFeng Jiang 152*5ba15d41SFeng Jiang /* Ensure the final result does not exceed maxlen. */ 153*5ba15d41SFeng Jiang minu a0, a0, a1 154*5ba15d41SFeng Jiang2: 155*5ba15d41SFeng Jiang ret 156*5ba15d41SFeng Jiang3: 157*5ba15d41SFeng Jiang mv a0, a1 158*5ba15d41SFeng Jiang ret 159*5ba15d41SFeng Jiang 160*5ba15d41SFeng Jiang.option pop 161*5ba15d41SFeng Jiang#endif 162*5ba15d41SFeng JiangSYM_FUNC_END(strnlen) 163*5ba15d41SFeng JiangSYM_FUNC_ALIAS(__pi_strnlen, strnlen) 164*5ba15d41SFeng JiangEXPORT_SYMBOL(strnlen) 165