/* SPDX-License-Identifier: GPL-2.0-only */12/*3* Base on arch/riscv/lib/strlen.S4*5* Copyright (C) Feng Jiang <[email protected]>6*/78#include <linux/linkage.h>9#include <asm/asm.h>10#include <asm/alternative-macros.h>11#include <asm/hwcap.h>1213/* size_t strnlen(const char *s, size_t count) */14SYM_FUNC_START(strnlen)1516__ALTERNATIVE_CFG("nop", "j strnlen_zbb", 0, RISCV_ISA_EXT_ZBB,17IS_ENABLED(CONFIG_RISCV_ISA_ZBB) && IS_ENABLED(CONFIG_TOOLCHAIN_HAS_ZBB))181920/*21* Returns22* a0 - String length23*24* Parameters25* a0 - String to measure26* a1 - Max length of string27*28* Clobbers29* t0, t1, t230*/31addi t1, a0, -132add t2, a0, a1331:34addi t1, t1, 135beq t1, t2, 2f36lbu t0, 0(t1)37bnez t0, 1b382:39sub a0, t1, a040ret414243/*44* Variant of strnlen using the ZBB extension if available45*/46#if defined(CONFIG_RISCV_ISA_ZBB) && defined(CONFIG_TOOLCHAIN_HAS_ZBB)47strnlen_zbb:4849#ifdef CONFIG_CPU_BIG_ENDIAN50# define CZ clz51# define SHIFT sll52#else53# define CZ ctz54# define SHIFT srl55#endif5657.option push58.option arch,+zbb5960/*61* Returns62* a0 - String length63*64* Parameters65* a0 - String to measure66* a1 - Max length of string67*68* Clobbers69* t0, t1, t2, t3, t470*/7172/* If maxlen is 0, return 0. */73beqz a1, 3f7475/* Number of irrelevant bytes in the first word. */76andi t2, a0, SZREG-17778/* Align pointer. */79andi t0, a0, -SZREG8081li t3, SZREG82sub t3, t3, t283slli t2, t2, 38485/* Aligned boundary. */86add t4, a0, a187andi t4, t4, -SZREG8889/* Get the first word. */90REG_L t1, 0(t0)9192/*93* Shift away the partial data we loaded to remove the irrelevant bytes94* preceding the string with the effect of adding NUL bytes at the95* end of the string's first word.96*/97SHIFT t1, t1, t29899/* Convert non-NUL into 0xff and NUL into 0x00. */100orc.b t1, t1101102/* Convert non-NUL into 0x00 and NUL into 0xff. */103not t1, t1104105/*106* Search for the first set bit (corresponding to a NUL byte in the107* original chunk).108*/109CZ t1, t1110111/*112* The first chunk is special: compare against the number113* of valid bytes in this chunk.114*/115srli a0, t1, 3116117/* Limit the result by maxlen. */118minu a0, a0, a1119120bgtu t3, a0, 2f121122/* Prepare for the word comparison loop. */123addi t2, t0, SZREG124li t3, -1125126/*127* Our critical loop is 4 instructions and processes data in128* 4 byte or 8 byte chunks.129*/130.p2align 31311:132REG_L t1, SZREG(t0)133addi t0, t0, SZREG134orc.b t1, t1135bgeu t0, t4, 4f136beq t1, t3, 1b1374:138not t1, t1139CZ t1, t1140srli t1, t1, 3141142/* Get number of processed bytes. */143sub t2, t0, t2144145/* Add number of characters in the first word. */146add a0, a0, t2147148/* Add number of characters in the last word. */149add a0, a0, t1150151/* Ensure the final result does not exceed maxlen. */152minu a0, a0, a11532:154ret1553:156mv a0, a1157ret158159.option pop160#endif161SYM_FUNC_END(strnlen)162SYM_FUNC_ALIAS(__pi_strnlen, strnlen)163EXPORT_SYMBOL(strnlen)164165166