2023-01-14 05:23:00 +08:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
|
|
|
|
|
|
#include <linux/linkage.h>
|
|
|
|
#include <asm/asm.h>
|
2023-01-14 05:23:01 +08:00
|
|
|
#include <asm/alternative-macros.h>
|
2023-02-24 23:46:00 +08:00
|
|
|
#include <asm/hwcap.h>
|
2023-01-14 05:23:00 +08:00
|
|
|
|
|
|
|
/* int strncmp(const char *cs, const char *ct, size_t count) */
|
|
|
|
SYM_FUNC_START(strncmp)
|
2023-01-14 05:23:01 +08:00
|
|
|
|
2023-02-12 10:15:33 +08:00
|
|
|
ALTERNATIVE("nop", "j strncmp_zbb", 0, RISCV_ISA_EXT_ZBB, CONFIG_RISCV_ISA_ZBB)
|
2023-01-14 05:23:01 +08:00
|
|
|
|
2023-01-14 05:23:00 +08:00
|
|
|
/*
|
|
|
|
* Returns
|
|
|
|
* a0 - comparison result, value like strncmp
|
|
|
|
*
|
|
|
|
* Parameters
|
|
|
|
* a0 - string1
|
|
|
|
* a1 - string2
|
|
|
|
* a2 - number of characters to compare
|
|
|
|
*
|
|
|
|
* Clobbers
|
|
|
|
* t0, t1, t2
|
|
|
|
*/
|
|
|
|
li t2, 0
|
|
|
|
1:
|
|
|
|
beq a2, t2, 2f
|
|
|
|
lbu t0, 0(a0)
|
|
|
|
lbu t1, 0(a1)
|
|
|
|
addi a0, a0, 1
|
|
|
|
addi a1, a1, 1
|
|
|
|
bne t0, t1, 3f
|
|
|
|
addi t2, t2, 1
|
|
|
|
bnez t0, 1b
|
|
|
|
2:
|
|
|
|
li a0, 0
|
|
|
|
ret
|
|
|
|
3:
|
|
|
|
/*
|
|
|
|
* strncmp only needs to return (< 0, 0, > 0) values
|
|
|
|
* not necessarily -1, 0, +1
|
|
|
|
*/
|
|
|
|
sub a0, t0, t1
|
|
|
|
ret
|
2023-01-14 05:23:01 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Variant of strncmp using the ZBB extension if available
|
|
|
|
*/
|
|
|
|
#ifdef CONFIG_RISCV_ISA_ZBB
|
|
|
|
strncmp_zbb:
|
|
|
|
|
|
|
|
.option push
|
|
|
|
.option arch,+zbb
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns
|
|
|
|
* a0 - comparison result, like strncmp
|
|
|
|
*
|
|
|
|
* Parameters
|
|
|
|
* a0 - string1
|
|
|
|
* a1 - string2
|
|
|
|
* a2 - number of characters to compare
|
|
|
|
*
|
|
|
|
* Clobbers
|
|
|
|
* t0, t1, t2, t3, t4, t5, t6
|
|
|
|
*/
|
|
|
|
|
|
|
|
or t2, a0, a1
|
|
|
|
li t5, -1
|
|
|
|
and t2, t2, SZREG-1
|
|
|
|
add t4, a0, a2
|
2023-02-09 06:53:28 +08:00
|
|
|
bnez t2, 3f
|
2023-01-14 05:23:01 +08:00
|
|
|
|
|
|
|
/* Adjust limit for fast-path. */
|
|
|
|
andi t6, t4, -SZREG
|
|
|
|
|
|
|
|
/* Main loop for aligned string. */
|
|
|
|
.p2align 3
|
|
|
|
1:
|
riscv, lib: Fix Zbb strncmp
The Zbb optimized strncmp has two parts; a fast path that does XLEN/8B
per iteration, and a slow that does one byte per iteration.
The idea is to compare aligned XLEN chunks for most of strings, and do
the remainder tail in the slow path.
The Zbb strncmp has two issues in the fast path:
Incorrect remainder handling (wrong compare): Assume that the string
length is 9. On 64b systems, the fast path should do one iteration,
and one iteration in the slow path. Instead, both were done in the
fast path, which lead to incorrect results. An example:
strncmp("/dev/vda", "/dev/", 5);
Correct by changing "bgt" to "bge".
Missing NULL checks in the second string: This could lead to incorrect
results for:
strncmp("/dev/vda", "/dev/vda\0", 8);
Correct by adding an additional check.
Fixes: b6fcdb191e36 ("RISC-V: add zbb support to string functions")
Suggested-by: Heiko Stuebner <heiko.stuebner@vrull.eu>
Signed-off-by: Björn Töpel <bjorn@rivosinc.com>
Tested-by: Conor Dooley <conor.dooley@microchip.com>
Tested-by: Guenter Roeck <linux@roeck-us.net>
Link: https://lore.kernel.org/r/20230228184211.1585641-1-bjorn@kernel.org
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
2023-03-01 02:42:10 +08:00
|
|
|
bge a0, t6, 3f
|
2023-01-14 05:23:01 +08:00
|
|
|
REG_L t0, 0(a0)
|
|
|
|
REG_L t1, 0(a1)
|
|
|
|
orc.b t3, t0
|
|
|
|
bne t3, t5, 2f
|
riscv, lib: Fix Zbb strncmp
The Zbb optimized strncmp has two parts; a fast path that does XLEN/8B
per iteration, and a slow that does one byte per iteration.
The idea is to compare aligned XLEN chunks for most of strings, and do
the remainder tail in the slow path.
The Zbb strncmp has two issues in the fast path:
Incorrect remainder handling (wrong compare): Assume that the string
length is 9. On 64b systems, the fast path should do one iteration,
and one iteration in the slow path. Instead, both were done in the
fast path, which lead to incorrect results. An example:
strncmp("/dev/vda", "/dev/", 5);
Correct by changing "bgt" to "bge".
Missing NULL checks in the second string: This could lead to incorrect
results for:
strncmp("/dev/vda", "/dev/vda\0", 8);
Correct by adding an additional check.
Fixes: b6fcdb191e36 ("RISC-V: add zbb support to string functions")
Suggested-by: Heiko Stuebner <heiko.stuebner@vrull.eu>
Signed-off-by: Björn Töpel <bjorn@rivosinc.com>
Tested-by: Conor Dooley <conor.dooley@microchip.com>
Tested-by: Guenter Roeck <linux@roeck-us.net>
Link: https://lore.kernel.org/r/20230228184211.1585641-1-bjorn@kernel.org
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
2023-03-01 02:42:10 +08:00
|
|
|
orc.b t3, t1
|
|
|
|
bne t3, t5, 2f
|
2023-01-14 05:23:01 +08:00
|
|
|
addi a0, a0, SZREG
|
|
|
|
addi a1, a1, SZREG
|
|
|
|
beq t0, t1, 1b
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Words don't match, and no null byte in the first
|
|
|
|
* word. Get bytes in big-endian order and compare.
|
|
|
|
*/
|
|
|
|
#ifndef CONFIG_CPU_BIG_ENDIAN
|
|
|
|
rev8 t0, t0
|
|
|
|
rev8 t1, t1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Synthesize (t0 >= t1) ? 1 : -1 in a branchless sequence. */
|
|
|
|
sltu a0, t0, t1
|
|
|
|
neg a0, a0
|
|
|
|
ori a0, a0, 1
|
|
|
|
ret
|
|
|
|
|
|
|
|
2:
|
|
|
|
/*
|
|
|
|
* Found a null byte.
|
|
|
|
* If words don't match, fall back to simple loop.
|
|
|
|
*/
|
|
|
|
bne t0, t1, 3f
|
|
|
|
|
|
|
|
/* Otherwise, strings are equal. */
|
|
|
|
li a0, 0
|
|
|
|
ret
|
|
|
|
|
|
|
|
/* Simple loop for misaligned strings. */
|
|
|
|
.p2align 3
|
2023-02-09 06:53:28 +08:00
|
|
|
3:
|
|
|
|
bge a0, t4, 5f
|
2023-01-14 05:23:01 +08:00
|
|
|
lbu t0, 0(a0)
|
|
|
|
lbu t1, 0(a1)
|
|
|
|
addi a0, a0, 1
|
|
|
|
addi a1, a1, 1
|
2023-02-09 06:53:28 +08:00
|
|
|
bne t0, t1, 4f
|
|
|
|
bnez t0, 3b
|
2023-01-14 05:23:01 +08:00
|
|
|
|
2023-02-09 06:53:28 +08:00
|
|
|
4:
|
2023-01-14 05:23:01 +08:00
|
|
|
sub a0, t0, t1
|
|
|
|
ret
|
|
|
|
|
2023-02-09 06:53:28 +08:00
|
|
|
5:
|
2023-01-14 05:23:01 +08:00
|
|
|
li a0, 0
|
|
|
|
ret
|
|
|
|
|
|
|
|
.option pop
|
|
|
|
#endif
|
2023-01-14 05:23:00 +08:00
|
|
|
SYM_FUNC_END(strncmp)
|