public inbox for linux-hardening@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/5] riscv: optimize string functions and add kunit tests
@ 2026-01-07  2:35 Feng Jiang
  2026-01-07  2:35 ` [PATCH 1/5] lib/string_kunit: add test case for strlen Feng Jiang
                   ` (4 more replies)
  0 siblings, 5 replies; 12+ messages in thread
From: Feng Jiang @ 2026-01-07  2:35 UTC (permalink / raw)
  To: pjw, palmer, aou, alex, kees, andy, jiangfeng, ebiggers,
	martin.petersen, Jason, conor.dooley, samuel.holland, charlie,
	ajones, nathan, linus.walleij
  Cc: linux-riscv, linux-kernel, linux-hardening

This series introduces optimized assembly implementations for several 
string functions on the RISC-V architecture (strnlen, strchr, and strrchr). 
To ensure correctness and prevent regressions, it also extends the 
string_kunit test suite with new cases.

The patchset is organized as follows:
- Patches 1-2: Enhance lib/string_kunit.c with new test cases for 
  strlen and strnlen to establish a baseline for verification.
- Patches 3-5: Provide the RISC-V specific optimized implementations 
  for strnlen, strchr, and strrchr.

Testing:
All patches have been verified using the KUnit framework on QEMU 
virt machine (riscv64). All string-related tests passed.

Changes:
- v1: Initial submission.

---

Feng Jiang (5):
  lib/string_kunit: add test case for strlen
  lib/string_kunit: add test case for strnlen
  riscv: lib: add strnlen implementation
  riscv: lib: add strchr implementation
  riscv: lib: add strrchr implementation

 arch/riscv/include/asm/string.h |   9 ++
 arch/riscv/lib/Makefile         |   3 +
 arch/riscv/lib/strchr.S         |  35 +++++++
 arch/riscv/lib/strnlen.S        | 164 ++++++++++++++++++++++++++++++++
 arch/riscv/lib/strrchr.S        |  37 +++++++
 arch/riscv/purgatory/Makefile   |  11 ++-
 lib/tests/string_kunit.c        |  53 +++++++++++
 7 files changed, 311 insertions(+), 1 deletion(-)
 create mode 100644 arch/riscv/lib/strchr.S
 create mode 100644 arch/riscv/lib/strnlen.S
 create mode 100644 arch/riscv/lib/strrchr.S

-- 
2.25.1


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/5] lib/string_kunit: add test case for strlen
  2026-01-07  2:35 [PATCH 0/5] riscv: optimize string functions and add kunit tests Feng Jiang
@ 2026-01-07  2:35 ` Feng Jiang
  2026-01-07 11:48   ` Andy Shevchenko
  2026-01-07  2:35 ` [PATCH 2/5] lib/string_kunit: add test case for strnlen Feng Jiang
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 12+ messages in thread
From: Feng Jiang @ 2026-01-07  2:35 UTC (permalink / raw)
  To: pjw, palmer, aou, alex, kees, andy, jiangfeng, ebiggers,
	martin.petersen, Jason, conor.dooley, samuel.holland, charlie,
	ajones, nathan, linus.walleij
  Cc: linux-riscv, linux-kernel, linux-hardening

Add a KUnit test for strlen() to verify correctness across
different string lengths and memory alignments.

Signed-off-by: Feng Jiang <jiangfeng@kylinos.cn>
---
 lib/tests/string_kunit.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/lib/tests/string_kunit.c b/lib/tests/string_kunit.c
index f9a8e557ba77..9f4fc72f0886 100644
--- a/lib/tests/string_kunit.c
+++ b/lib/tests/string_kunit.c
@@ -104,6 +104,28 @@ static void string_test_memset64(struct kunit *test)
 	}
 }
 
+static void string_test_strlen(struct kunit *test)
+{
+	char *s;
+	size_t len, offset;
+	const size_t buf_size = 16 + 128 + 1; /* max_offset + max_len + '\0' */
+
+	s = kunit_kzalloc(test, buf_size, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, s);
+
+	memset(s, 'A', buf_size);
+	s[buf_size - 1] = '\0';
+
+	for (offset = 0; offset < 16; offset++) {
+		for (len = 0; len <= 128; len++) {
+			s[offset + len] = '\0';
+			KUNIT_EXPECT_EQ_MSG(test, strlen(s + offset), len,
+				"offset:%zu len:%zu", offset, len);
+			s[offset + len] = 'A';
+		}
+	}
+}
+
 static void string_test_strchr(struct kunit *test)
 {
 	const char *test_string = "abcdefghijkl";
@@ -618,6 +640,7 @@ static struct kunit_case string_test_cases[] = {
 	KUNIT_CASE(string_test_memset16),
 	KUNIT_CASE(string_test_memset32),
 	KUNIT_CASE(string_test_memset64),
+	KUNIT_CASE(string_test_strlen),
 	KUNIT_CASE(string_test_strchr),
 	KUNIT_CASE(string_test_strnchr),
 	KUNIT_CASE(string_test_strspn),
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/5] lib/string_kunit: add test case for strnlen
  2026-01-07  2:35 [PATCH 0/5] riscv: optimize string functions and add kunit tests Feng Jiang
  2026-01-07  2:35 ` [PATCH 1/5] lib/string_kunit: add test case for strlen Feng Jiang
@ 2026-01-07  2:35 ` Feng Jiang
  2026-01-07 11:56   ` Andy Shevchenko
  2026-01-07  2:35 ` [PATCH 3/5] riscv: lib: add strnlen implementation Feng Jiang
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 12+ messages in thread
From: Feng Jiang @ 2026-01-07  2:35 UTC (permalink / raw)
  To: pjw, palmer, aou, alex, kees, andy, jiangfeng, ebiggers,
	martin.petersen, Jason, conor.dooley, samuel.holland, charlie,
	ajones, nathan, linus.walleij
  Cc: linux-riscv, linux-kernel, linux-hardening

Add a KUnit test for strnlen() to verify correctness across
different string lengths and memory alignments.

Signed-off-by: Feng Jiang <jiangfeng@kylinos.cn>
---
 lib/tests/string_kunit.c | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/lib/tests/string_kunit.c b/lib/tests/string_kunit.c
index 9f4fc72f0886..1d08850e439c 100644
--- a/lib/tests/string_kunit.c
+++ b/lib/tests/string_kunit.c
@@ -126,6 +126,35 @@ static void string_test_strlen(struct kunit *test)
 	}
 }
 
+static void string_test_strnlen(struct kunit *test)
+{
+	char *s;
+	size_t len, offset;
+	const size_t buf_size = 16 + 128 + 1; /* max_offset + max_len + '\0' */
+
+	s = kunit_kzalloc(test, buf_size, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, s);
+
+	memset(s, 'A', buf_size);
+	s[buf_size - 1] = '\0';
+
+	for (offset = 0; offset < 16; offset++) {
+		for (len = 0; len <= 128; len++) {
+			s[offset + len] = '\0';
+
+			if (len > 0)
+				KUNIT_EXPECT_EQ(test, strnlen(s + offset, len - 1), len - 1);
+
+			KUNIT_EXPECT_EQ(test, strnlen(s + offset, len), len);
+
+			KUNIT_EXPECT_EQ(test, strnlen(s + offset, len + 1), len);
+			KUNIT_EXPECT_EQ(test, strnlen(s + offset, len + 10), len);
+
+			s[offset + len] = 'A';
+		}
+	}
+}
+
 static void string_test_strchr(struct kunit *test)
 {
 	const char *test_string = "abcdefghijkl";
@@ -641,6 +670,7 @@ static struct kunit_case string_test_cases[] = {
 	KUNIT_CASE(string_test_memset32),
 	KUNIT_CASE(string_test_memset64),
 	KUNIT_CASE(string_test_strlen),
+	KUNIT_CASE(string_test_strnlen),
 	KUNIT_CASE(string_test_strchr),
 	KUNIT_CASE(string_test_strnchr),
 	KUNIT_CASE(string_test_strspn),
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/5] riscv: lib: add strnlen implementation
  2026-01-07  2:35 [PATCH 0/5] riscv: optimize string functions and add kunit tests Feng Jiang
  2026-01-07  2:35 ` [PATCH 1/5] lib/string_kunit: add test case for strlen Feng Jiang
  2026-01-07  2:35 ` [PATCH 2/5] lib/string_kunit: add test case for strnlen Feng Jiang
@ 2026-01-07  2:35 ` Feng Jiang
  2026-01-07  2:35 ` [PATCH 4/5] riscv: lib: add strchr implementation Feng Jiang
  2026-01-07  2:35 ` [PATCH 5/5] riscv: lib: add strrchr implementation Feng Jiang
  4 siblings, 0 replies; 12+ messages in thread
From: Feng Jiang @ 2026-01-07  2:35 UTC (permalink / raw)
  To: pjw, palmer, aou, alex, kees, andy, jiangfeng, ebiggers,
	martin.petersen, Jason, conor.dooley, samuel.holland, charlie,
	ajones, nathan, linus.walleij
  Cc: linux-riscv, linux-kernel, linux-hardening

Add strnlen() implementation for RISC-V with both generic and
Zbb-optimized versions, derived from strlen.S.

Signed-off-by: Feng Jiang <jiangfeng@kylinos.cn>
---
 arch/riscv/include/asm/string.h |   3 +
 arch/riscv/lib/Makefile         |   1 +
 arch/riscv/lib/strnlen.S        | 164 ++++++++++++++++++++++++++++++++
 arch/riscv/purgatory/Makefile   |   5 +-
 4 files changed, 172 insertions(+), 1 deletion(-)
 create mode 100644 arch/riscv/lib/strnlen.S

diff --git a/arch/riscv/include/asm/string.h b/arch/riscv/include/asm/string.h
index 5ba77f60bf0b..16634d67c217 100644
--- a/arch/riscv/include/asm/string.h
+++ b/arch/riscv/include/asm/string.h
@@ -28,6 +28,9 @@ extern asmlinkage __kernel_size_t strlen(const char *);
 
 #define __HAVE_ARCH_STRNCMP
 extern asmlinkage int strncmp(const char *cs, const char *ct, size_t count);
+
+#define __HAVE_ARCH_STRNLEN
+extern asmlinkage __kernel_size_t strnlen(const char *, size_t);
 #endif
 
 /* For those files which don't want to check by kasan. */
diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile
index bbc031124974..0969d8136df0 100644
--- a/arch/riscv/lib/Makefile
+++ b/arch/riscv/lib/Makefile
@@ -7,6 +7,7 @@ ifeq ($(CONFIG_KASAN_GENERIC)$(CONFIG_KASAN_SW_TAGS),)
 lib-y			+= strcmp.o
 lib-y			+= strlen.o
 lib-y			+= strncmp.o
+lib-y			+= strnlen.o
 endif
 lib-y			+= csum.o
 ifeq ($(CONFIG_MMU), y)
diff --git a/arch/riscv/lib/strnlen.S b/arch/riscv/lib/strnlen.S
new file mode 100644
index 000000000000..4af0df9442f1
--- /dev/null
+++ b/arch/riscv/lib/strnlen.S
@@ -0,0 +1,164 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/*
+ * Base on arch/riscv/lib/strlen.S
+ *
+ * Copyright (C) Feng Jiang <jiangfeng@kylinos.cn>
+ */
+
+#include <linux/linkage.h>
+#include <asm/asm.h>
+#include <asm/alternative-macros.h>
+#include <asm/hwcap.h>
+
+/* size_t strnlen(const char *s, size_t count) */
+SYM_FUNC_START(strnlen)
+
+	__ALTERNATIVE_CFG("nop", "j strnlen_zbb", 0, RISCV_ISA_EXT_ZBB,
+		IS_ENABLED(CONFIG_RISCV_ISA_ZBB) && IS_ENABLED(CONFIG_TOOLCHAIN_HAS_ZBB))
+
+
+	/*
+	 * Returns
+	 *   a0 - String length
+	 *
+	 * Parameters
+	 *   a0 - String to measure
+	 *   a1 - Max length of string
+	 *
+	 * Clobbers
+	 *   t0, t1, t2
+	 */
+	addi	t1, a0, -1
+	add	t2, a0, a1
+1:
+	addi	t1, t1, 1
+	beq	t1, t2, 2f
+	lbu	t0, 0(t1)
+	bnez	t0, 1b
+2:
+	sub	a0, t1, a0
+	ret
+
+
+/*
+ * Variant of strnlen using the ZBB extension if available
+ */
+#if defined(CONFIG_RISCV_ISA_ZBB) && defined(CONFIG_TOOLCHAIN_HAS_ZBB)
+strnlen_zbb:
+
+#ifdef CONFIG_CPU_BIG_ENDIAN
+# define CZ	clz
+# define SHIFT	sll
+#else
+# define CZ	ctz
+# define SHIFT	srl
+#endif
+
+.option push
+.option arch,+zbb
+
+	/*
+	 * Returns
+	 *   a0 - String length
+	 *
+	 * Parameters
+	 *   a0 - String to measure
+	 *   a1 - Max length of string
+	 *
+	 * Clobbers
+	 *   t0, t1, t2, t3, t4
+	 */
+
+	/* If maxlen is 0, return 0. */
+	beqz	a1, 3f
+
+	/* Number of irrelevant bytes in the first word. */
+	andi	t2, a0, SZREG-1
+
+	/* Align pointer. */
+	andi	t0, a0, -SZREG
+
+	li	t3, SZREG
+	sub	t3, t3, t2
+	slli	t2, t2, 3
+
+	/* Aligned boundary. */
+	add	t4, a0, a1
+	andi	t4, t4, -SZREG
+
+	/* Get the first word.  */
+	REG_L	t1, 0(t0)
+
+	/*
+	 * Shift away the partial data we loaded to remove the irrelevant bytes
+	 * preceding the string with the effect of adding NUL bytes at the
+	 * end of the string's first word.
+	 */
+	SHIFT	t1, t1, t2
+
+	/* Convert non-NUL into 0xff and NUL into 0x00. */
+	orc.b	t1, t1
+
+	/* Convert non-NUL into 0x00 and NUL into 0xff. */
+	not	t1, t1
+
+	/*
+	 * Search for the first set bit (corresponding to a NUL byte in the
+	 * original chunk).
+	 */
+	CZ	t1, t1
+
+	/*
+	 * The first chunk is special: compare against the number
+	 * of valid bytes in this chunk.
+	 */
+	srli	a0, t1, 3
+
+	/* Limit the result by maxlen. */
+	bleu	a1, a0, 3f
+
+	bgtu	t3, a0, 2f
+
+	/* Prepare for the word comparison loop. */
+	addi	t2, t0, SZREG
+	li	t3, -1
+
+	/*
+	 * Our critical loop is 4 instructions and processes data in
+	 * 4 byte or 8 byte chunks.
+	 */
+	.p2align 3
+1:
+	REG_L	t1, SZREG(t0)
+	addi	t0, t0, SZREG
+	orc.b	t1, t1
+	bgeu	t0, t4, 4f
+	beq	t1, t3, 1b
+4:
+	not	t1, t1
+	CZ	t1, t1
+	srli	t1, t1, 3
+
+	/* Get number of processed bytes. */
+	sub	t2, t0, t2
+
+	/* Add number of characters in the first word.  */
+	add	a0, a0, t2
+
+	/* Add number of characters in the last word.  */
+	add	a0, a0, t1
+
+	/* Ensure the final result does not exceed maxlen. */
+	bgeu	a0, a1, 3f
+2:
+	ret
+3:
+	mv	a0, a1
+	ret
+
+.option pop
+#endif
+SYM_FUNC_END(strnlen)
+SYM_FUNC_ALIAS(__pi_strnlen, strnlen)
+EXPORT_SYMBOL(strnlen)
diff --git a/arch/riscv/purgatory/Makefile b/arch/riscv/purgatory/Makefile
index 530e497ca2f9..d7c0533108be 100644
--- a/arch/riscv/purgatory/Makefile
+++ b/arch/riscv/purgatory/Makefile
@@ -2,7 +2,7 @@
 
 purgatory-y := purgatory.o sha256.o entry.o string.o ctype.o memcpy.o memset.o
 ifeq ($(CONFIG_KASAN_GENERIC)$(CONFIG_KASAN_SW_TAGS),)
-purgatory-y += strcmp.o strlen.o strncmp.o
+purgatory-y += strcmp.o strlen.o strncmp.o strnlen.o
 endif
 
 targets += $(purgatory-y)
@@ -32,6 +32,9 @@ $(obj)/strncmp.o: $(srctree)/arch/riscv/lib/strncmp.S FORCE
 $(obj)/sha256.o: $(srctree)/lib/crypto/sha256.c FORCE
 	$(call if_changed_rule,cc_o_c)
 
+$(obj)/strnlen.o: $(srctree)/arch/riscv/lib/strnlen.S FORCE
+	$(call if_changed_rule,as_o_S)
+
 CFLAGS_sha256.o := -D__DISABLE_EXPORTS -D__NO_FORTIFY
 CFLAGS_string.o := -D__DISABLE_EXPORTS
 CFLAGS_ctype.o := -D__DISABLE_EXPORTS
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 4/5] riscv: lib: add strchr implementation
  2026-01-07  2:35 [PATCH 0/5] riscv: optimize string functions and add kunit tests Feng Jiang
                   ` (2 preceding siblings ...)
  2026-01-07  2:35 ` [PATCH 3/5] riscv: lib: add strnlen implementation Feng Jiang
@ 2026-01-07  2:35 ` Feng Jiang
  2026-01-07  2:35 ` [PATCH 5/5] riscv: lib: add strrchr implementation Feng Jiang
  4 siblings, 0 replies; 12+ messages in thread
From: Feng Jiang @ 2026-01-07  2:35 UTC (permalink / raw)
  To: pjw, palmer, aou, alex, kees, andy, jiangfeng, ebiggers,
	martin.petersen, Jason, conor.dooley, samuel.holland, charlie,
	ajones, nathan, linus.walleij
  Cc: linux-riscv, linux-kernel, linux-hardening

Add a basic assembly implementation of strchr() for RISC-V.
This provides a functional byte-by-byte version as a foundation
for future optimizations.

Signed-off-by: Feng Jiang <jiangfeng@kylinos.cn>
---
 arch/riscv/include/asm/string.h |  3 +++
 arch/riscv/lib/Makefile         |  1 +
 arch/riscv/lib/strchr.S         | 35 +++++++++++++++++++++++++++++++++
 arch/riscv/purgatory/Makefile   |  5 ++++-
 4 files changed, 43 insertions(+), 1 deletion(-)
 create mode 100644 arch/riscv/lib/strchr.S

diff --git a/arch/riscv/include/asm/string.h b/arch/riscv/include/asm/string.h
index 16634d67c217..ca3ade82b124 100644
--- a/arch/riscv/include/asm/string.h
+++ b/arch/riscv/include/asm/string.h
@@ -31,6 +31,9 @@ extern asmlinkage int strncmp(const char *cs, const char *ct, size_t count);
 
 #define __HAVE_ARCH_STRNLEN
 extern asmlinkage __kernel_size_t strnlen(const char *, size_t);
+
+#define __HAVE_ARCH_STRCHR
+extern asmlinkage char *strchr(const char *, int);
 #endif
 
 /* For those files which don't want to check by kasan. */
diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile
index 0969d8136df0..b7f804dce1c3 100644
--- a/arch/riscv/lib/Makefile
+++ b/arch/riscv/lib/Makefile
@@ -8,6 +8,7 @@ lib-y			+= strcmp.o
 lib-y			+= strlen.o
 lib-y			+= strncmp.o
 lib-y			+= strnlen.o
+lib-y			+= strchr.o
 endif
 lib-y			+= csum.o
 ifeq ($(CONFIG_MMU), y)
diff --git a/arch/riscv/lib/strchr.S b/arch/riscv/lib/strchr.S
new file mode 100644
index 000000000000..48c3a9da53e3
--- /dev/null
+++ b/arch/riscv/lib/strchr.S
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/*
+ * Copyright (C) 2025 Feng Jiang <jiangfeng@kylinos.cn>
+ */
+
+#include <linux/linkage.h>
+#include <asm/asm.h>
+
+/* char *strchr(const char *s, int c) */
+SYM_FUNC_START(strchr)
+	/*
+	 * Parameters
+	 *   a0 - The string to be searched
+	 *   a1 - The character to search for
+	 *
+	 * Returns
+	 *   a0 - Address of first occurrence of 'c' or 0
+	 *
+	 * Clobbers
+	 *   t0
+	 */
+	andi	a1, a1, 0xff
+1:
+	lbu	t0, 0(a0)
+	beq	t0, a1, 2f
+	addi	a0, a0, 1
+	bnez	t0, 1b
+	li	a0, 0
+2:
+	ret
+SYM_FUNC_END(strchr)
+
+SYM_FUNC_ALIAS_WEAK(__pi_strchr, strchr)
+EXPORT_SYMBOL(strchr)
diff --git a/arch/riscv/purgatory/Makefile b/arch/riscv/purgatory/Makefile
index d7c0533108be..e7b3d748c913 100644
--- a/arch/riscv/purgatory/Makefile
+++ b/arch/riscv/purgatory/Makefile
@@ -2,7 +2,7 @@
 
 purgatory-y := purgatory.o sha256.o entry.o string.o ctype.o memcpy.o memset.o
 ifeq ($(CONFIG_KASAN_GENERIC)$(CONFIG_KASAN_SW_TAGS),)
-purgatory-y += strcmp.o strlen.o strncmp.o strnlen.o
+purgatory-y += strcmp.o strlen.o strncmp.o strnlen.o strchr.o
 endif
 
 targets += $(purgatory-y)
@@ -35,6 +35,9 @@ $(obj)/sha256.o: $(srctree)/lib/crypto/sha256.c FORCE
 $(obj)/strnlen.o: $(srctree)/arch/riscv/lib/strnlen.S FORCE
 	$(call if_changed_rule,as_o_S)
 
+$(obj)/strchr.o: $(srctree)/arch/riscv/lib/strchr.S FORCE
+	$(call if_changed_rule,as_o_S)
+
 CFLAGS_sha256.o := -D__DISABLE_EXPORTS -D__NO_FORTIFY
 CFLAGS_string.o := -D__DISABLE_EXPORTS
 CFLAGS_ctype.o := -D__DISABLE_EXPORTS
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 5/5] riscv: lib: add strrchr implementation
  2026-01-07  2:35 [PATCH 0/5] riscv: optimize string functions and add kunit tests Feng Jiang
                   ` (3 preceding siblings ...)
  2026-01-07  2:35 ` [PATCH 4/5] riscv: lib: add strchr implementation Feng Jiang
@ 2026-01-07  2:35 ` Feng Jiang
  4 siblings, 0 replies; 12+ messages in thread
From: Feng Jiang @ 2026-01-07  2:35 UTC (permalink / raw)
  To: pjw, palmer, aou, alex, kees, andy, jiangfeng, ebiggers,
	martin.petersen, Jason, conor.dooley, samuel.holland, charlie,
	ajones, nathan, linus.walleij
  Cc: linux-riscv, linux-kernel, linux-hardening

Add a basic assembly implementation of strrchr() for RISC-V.
This provides a functional byte-by-byte version as a foundation
for future optimizations.

Signed-off-by: Feng Jiang <jiangfeng@kylinos.cn>
---
 arch/riscv/include/asm/string.h |  3 +++
 arch/riscv/lib/Makefile         |  1 +
 arch/riscv/lib/strrchr.S        | 37 +++++++++++++++++++++++++++++++++
 arch/riscv/purgatory/Makefile   |  5 ++++-
 4 files changed, 45 insertions(+), 1 deletion(-)
 create mode 100644 arch/riscv/lib/strrchr.S

diff --git a/arch/riscv/include/asm/string.h b/arch/riscv/include/asm/string.h
index ca3ade82b124..764ffe8f6479 100644
--- a/arch/riscv/include/asm/string.h
+++ b/arch/riscv/include/asm/string.h
@@ -34,6 +34,9 @@ extern asmlinkage __kernel_size_t strnlen(const char *, size_t);
 
 #define __HAVE_ARCH_STRCHR
 extern asmlinkage char *strchr(const char *, int);
+
+#define __HAVE_ARCH_STRRCHR
+extern asmlinkage char *strrchr(const char *, int);
 #endif
 
 /* For those files which don't want to check by kasan. */
diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile
index b7f804dce1c3..735d0b665536 100644
--- a/arch/riscv/lib/Makefile
+++ b/arch/riscv/lib/Makefile
@@ -9,6 +9,7 @@ lib-y			+= strlen.o
 lib-y			+= strncmp.o
 lib-y			+= strnlen.o
 lib-y			+= strchr.o
+lib-y			+= strrchr.o
 endif
 lib-y			+= csum.o
 ifeq ($(CONFIG_MMU), y)
diff --git a/arch/riscv/lib/strrchr.S b/arch/riscv/lib/strrchr.S
new file mode 100644
index 000000000000..ac58b20ca21d
--- /dev/null
+++ b/arch/riscv/lib/strrchr.S
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/*
+ * Copyright (C) 2025 Feng Jiang <jiangfeng@kylinos.cn>
+ */
+
+#include <linux/linkage.h>
+#include <asm/asm.h>
+
+/* char *strrchr(const char *s, int c) */
+SYM_FUNC_START(strrchr)
+	/*
+	 * Parameters
+	 *	a0 - The string to be searched
+	 *	a1 - The character to seaerch for
+	 *
+	 * Returns
+	 *	a0 - Address of last occurrence of 'c' or 0
+	 *
+	 * Clobbers
+	 *	t0, t1
+	 */
+	andi	a1, a1, 0xff
+	mv	t1, a0
+	li	a0, 0
+1:
+	lbu	t0, 0(t1)
+	bne	t0, a1, 2f
+	mv	a0, t1
+2:
+	addi	t1, t1, 1
+	bnez	t0, 1b
+	ret
+SYM_FUNC_END(strrchr)
+
+SYM_FUNC_ALIAS_WEAK(__pi_strrchr, strrchr)
+EXPORT_SYMBOL(strrchr)
diff --git a/arch/riscv/purgatory/Makefile b/arch/riscv/purgatory/Makefile
index e7b3d748c913..b0358a78f11a 100644
--- a/arch/riscv/purgatory/Makefile
+++ b/arch/riscv/purgatory/Makefile
@@ -2,7 +2,7 @@
 
 purgatory-y := purgatory.o sha256.o entry.o string.o ctype.o memcpy.o memset.o
 ifeq ($(CONFIG_KASAN_GENERIC)$(CONFIG_KASAN_SW_TAGS),)
-purgatory-y += strcmp.o strlen.o strncmp.o strnlen.o strchr.o
+purgatory-y += strcmp.o strlen.o strncmp.o strnlen.o strchr.o strrchr.o
 endif
 
 targets += $(purgatory-y)
@@ -38,6 +38,9 @@ $(obj)/strnlen.o: $(srctree)/arch/riscv/lib/strnlen.S FORCE
 $(obj)/strchr.o: $(srctree)/arch/riscv/lib/strchr.S FORCE
 	$(call if_changed_rule,as_o_S)
 
+$(obj)/strrchr.o: $(srctree)/arch/riscv/lib/strrchr.S FORCE
+	$(call if_changed_rule,as_o_S)
+
 CFLAGS_sha256.o := -D__DISABLE_EXPORTS -D__NO_FORTIFY
 CFLAGS_string.o := -D__DISABLE_EXPORTS
 CFLAGS_ctype.o := -D__DISABLE_EXPORTS
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/5] lib/string_kunit: add test case for strlen
  2026-01-07  2:35 ` [PATCH 1/5] lib/string_kunit: add test case for strlen Feng Jiang
@ 2026-01-07 11:48   ` Andy Shevchenko
  0 siblings, 0 replies; 12+ messages in thread
From: Andy Shevchenko @ 2026-01-07 11:48 UTC (permalink / raw)
  To: Feng Jiang
  Cc: pjw, palmer, aou, alex, kees, andy, ebiggers, martin.petersen,
	Jason, conor.dooley, samuel.holland, charlie, ajones, nathan,
	linus.walleij, linux-riscv, linux-kernel, linux-hardening

On Wed, Jan 7, 2026 at 4:35 AM Feng Jiang <jiangfeng@kylinos.cn> wrote:
>
> Add a KUnit test for strlen() to verify correctness across
> different string lengths and memory alignments.

I assume you also wanted the optimisation tests, i.e. something that
does random filling and measure two algorithms by execution time.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/5] lib/string_kunit: add test case for strnlen
  2026-01-07  2:35 ` [PATCH 2/5] lib/string_kunit: add test case for strnlen Feng Jiang
@ 2026-01-07 11:56   ` Andy Shevchenko
  2026-01-08  6:53     ` Feng Jiang
  0 siblings, 1 reply; 12+ messages in thread
From: Andy Shevchenko @ 2026-01-07 11:56 UTC (permalink / raw)
  To: Feng Jiang
  Cc: pjw, palmer, aou, alex, kees, andy, ebiggers, martin.petersen,
	Jason, conor.dooley, samuel.holland, charlie, ajones, nathan,
	linus.walleij, linux-riscv, linux-kernel, linux-hardening

On Wed, Jan 7, 2026 at 4:35 AM Feng Jiang <jiangfeng@kylinos.cn> wrote:
>
> Add a KUnit test for strnlen() to verify correctness across
> different string lengths and memory alignments.

Same comment as per patch 1 (it would probably require to call for
arch_strnlen() or something like this).

...

> +       for (offset = 0; offset < 16; offset++) {
> +               for (len = 0; len <= 128; len++) {

You want to define these two limits to avoid the possible issues in
the future if the code gets changed.

> +       }

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/5] lib/string_kunit: add test case for strnlen
  2026-01-07 11:56   ` Andy Shevchenko
@ 2026-01-08  6:53     ` Feng Jiang
  2026-01-08  7:26       ` Andy Shevchenko
  0 siblings, 1 reply; 12+ messages in thread
From: Feng Jiang @ 2026-01-08  6:53 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: pjw, palmer, aou, alex, kees, andy, ebiggers, martin.petersen,
	Jason, conor.dooley, samuel.holland, charlie, ajones, nathan,
	linus.walleij, linux-riscv, linux-kernel, linux-hardening

On 2026/1/7 19:56, Andy Shevchenko wrote:
> On Wed, Jan 7, 2026 at 4:35 AM Feng Jiang <jiangfeng@kylinos.cn> wrote:
>>
>> Add a KUnit test for strnlen() to verify correctness across
>> different string lengths and memory alignments.
> 
> Same comment as per patch 1 (it would probably require to call for
> arch_strnlen() or something like this).

Thanks, makes sense.

I'll add the performance benchmarking (random filling + timing) in V2.

Since string functions are typically exported directly by each architecture
without an arch_ prefix, I'll introduce a generic_strnlen() (based on
lib/string.c) within the test for comparison.

> ...
> 
>> +       for (offset = 0; offset < 16; offset++) {
>> +               for (len = 0; len <= 128; len++) {
> 
> You want to define these two limits to avoid the possible issues in
> the future if the code gets changed.

Got it, will define these limits as macros in V2. Thanks!

-- 
With Best Regards,
Feng Jiang


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/5] lib/string_kunit: add test case for strnlen
  2026-01-08  6:53     ` Feng Jiang
@ 2026-01-08  7:26       ` Andy Shevchenko
  2026-01-08 10:00         ` Feng Jiang
  0 siblings, 1 reply; 12+ messages in thread
From: Andy Shevchenko @ 2026-01-08  7:26 UTC (permalink / raw)
  To: Feng Jiang
  Cc: Andy Shevchenko, pjw, palmer, aou, alex, kees, andy, ebiggers,
	martin.petersen, Jason, conor.dooley, samuel.holland, charlie,
	ajones, nathan, linus.walleij, linux-riscv, linux-kernel,
	linux-hardening

On Thu, Jan 08, 2026 at 02:53:58PM +0800, Feng Jiang wrote:
> On 2026/1/7 19:56, Andy Shevchenko wrote:
> > On Wed, Jan 7, 2026 at 4:35 AM Feng Jiang <jiangfeng@kylinos.cn> wrote:

...

> >> Add a KUnit test for strnlen() to verify correctness across
> >> different string lengths and memory alignments.
> > 
> > Same comment as per patch 1 (it would probably require to call for
> > arch_strnlen() or something like this).
> 
> Thanks, makes sense.
> 
> I'll add the performance benchmarking (random filling + timing) in V2.
> 
> Since string functions are typically exported directly by each architecture
> without an arch_ prefix, I'll introduce a generic_strnlen() (based on
> lib/string.c) within the test for comparison.

Probably you want to make the existing one to have that name and use it inside
the test and in the fallback wrapper. We don't want to have duplicate code, it
is bad from maintenance perspective.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/5] lib/string_kunit: add test case for strnlen
  2026-01-08  7:26       ` Andy Shevchenko
@ 2026-01-08 10:00         ` Feng Jiang
  2026-01-08 10:42           ` Andy Shevchenko
  0 siblings, 1 reply; 12+ messages in thread
From: Feng Jiang @ 2026-01-08 10:00 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Andy Shevchenko, pjw, palmer, aou, alex, kees, andy, ebiggers,
	martin.petersen, Jason, conor.dooley, samuel.holland, charlie,
	ajones, nathan, linus.walleij, linux-riscv, linux-kernel,
	linux-hardening

On 2026/1/8 15:26, Andy Shevchenko wrote:
> On Thu, Jan 08, 2026 at 02:53:58PM +0800, Feng Jiang wrote:
>> On 2026/1/7 19:56, Andy Shevchenko wrote:
>>> On Wed, Jan 7, 2026 at 4:35 AM Feng Jiang <jiangfeng@kylinos.cn> wrote:
> 
> ...
> 
>>>> Add a KUnit test for strnlen() to verify correctness across
>>>> different string lengths and memory alignments.
>>>
>>> Same comment as per patch 1 (it would probably require to call for
>>> arch_strnlen() or something like this).
>>
>> Thanks, makes sense.
>>
>> I'll add the performance benchmarking (random filling + timing) in V2.
>>
>> Since string functions are typically exported directly by each architecture
>> without an arch_ prefix, I'll introduce a generic_strnlen() (based on
>> lib/string.c) within the test for comparison.
> 
> Probably you want to make the existing one to have that name and use it inside
> the test and in the fallback wrapper. We don't want to have duplicate code, it
> is bad from maintenance perspective.
> 

Thanks for the suggestions!

To avoid code duplication, I'll rename the generic implementation in lib/string.c
to __generic_strnlen() and keep the original strnlen() as a wrapper. Then I'll use
the generic one in the KUnit test for comparison.

Does this approach look good to you?

-- 
With Best Regards,
Feng Jiang


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/5] lib/string_kunit: add test case for strnlen
  2026-01-08 10:00         ` Feng Jiang
@ 2026-01-08 10:42           ` Andy Shevchenko
  0 siblings, 0 replies; 12+ messages in thread
From: Andy Shevchenko @ 2026-01-08 10:42 UTC (permalink / raw)
  To: Feng Jiang
  Cc: Andy Shevchenko, pjw, palmer, aou, alex, kees, andy, ebiggers,
	martin.petersen, Jason, conor.dooley, samuel.holland, charlie,
	ajones, nathan, linus.walleij, linux-riscv, linux-kernel,
	linux-hardening

On Thu, Jan 08, 2026 at 06:00:21PM +0800, Feng Jiang wrote:
> On 2026/1/8 15:26, Andy Shevchenko wrote:
> > On Thu, Jan 08, 2026 at 02:53:58PM +0800, Feng Jiang wrote:
> >> On 2026/1/7 19:56, Andy Shevchenko wrote:
> >>> On Wed, Jan 7, 2026 at 4:35 AM Feng Jiang <jiangfeng@kylinos.cn> wrote:

...

> >>>> Add a KUnit test for strnlen() to verify correctness across
> >>>> different string lengths and memory alignments.
> >>>
> >>> Same comment as per patch 1 (it would probably require to call for
> >>> arch_strnlen() or something like this).
> >>
> >> Thanks, makes sense.
> >>
> >> I'll add the performance benchmarking (random filling + timing) in V2.
> >>
> >> Since string functions are typically exported directly by each architecture
> >> without an arch_ prefix, I'll introduce a generic_strnlen() (based on
> >> lib/string.c) within the test for comparison.
> > 
> > Probably you want to make the existing one to have that name and use it inside
> > the test and in the fallback wrapper. We don't want to have duplicate code, it
> > is bad from maintenance perspective.
> 
> Thanks for the suggestions!
> 
> To avoid code duplication, I'll rename the generic implementation in lib/string.c
> to __generic_strnlen() and keep the original strnlen() as a wrapper. Then I'll use
> the generic one in the KUnit test for comparison.
> 
> Does this approach look good to you?

To me, yes. To others, we will know later on when you send a new version.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2026-01-08 10:42 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-07  2:35 [PATCH 0/5] riscv: optimize string functions and add kunit tests Feng Jiang
2026-01-07  2:35 ` [PATCH 1/5] lib/string_kunit: add test case for strlen Feng Jiang
2026-01-07 11:48   ` Andy Shevchenko
2026-01-07  2:35 ` [PATCH 2/5] lib/string_kunit: add test case for strnlen Feng Jiang
2026-01-07 11:56   ` Andy Shevchenko
2026-01-08  6:53     ` Feng Jiang
2026-01-08  7:26       ` Andy Shevchenko
2026-01-08 10:00         ` Feng Jiang
2026-01-08 10:42           ` Andy Shevchenko
2026-01-07  2:35 ` [PATCH 3/5] riscv: lib: add strnlen implementation Feng Jiang
2026-01-07  2:35 ` [PATCH 4/5] riscv: lib: add strchr implementation Feng Jiang
2026-01-07  2:35 ` [PATCH 5/5] riscv: lib: add strrchr implementation Feng Jiang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox