[PATCH 1/2] riscv: allow case-insensitive ISA string parsing

From: Yangyu Chen
Date: Tue Apr 25 2023 - 08:02:18 EST


According to RISC-V ISA specification, the ISA naming strings are case
insensitive. The kernel docs require the riscv,isa string must be all
lowercase to simplify parsing currently. However, this limitation is not
consistent with RISC-V ISA Spec.

This patch modifies the ISA string parser in the kernel to support
case-insensitive ISA string parsing. It replaces `strncmp` with
`strncasecmp`, replaces `islower` with `isalpha`, and wraps the
dereferenced char in the parser with `tolower`.

Signed-off-by: Yangyu Chen <cyy@xxxxxxxxxxxx>
---
arch/riscv/kernel/cpu.c | 6 ++++--
arch/riscv/kernel/cpufeature.c | 20 ++++++++++----------
2 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c
index 8400f0cc9704..531c76079b73 100644
--- a/arch/riscv/kernel/cpu.c
+++ b/arch/riscv/kernel/cpu.c
@@ -4,6 +4,7 @@
*/

#include <linux/cpu.h>
+#include <linux/ctype.h>
#include <linux/init.h>
#include <linux/seq_file.h>
#include <linux/of.h>
@@ -41,7 +42,7 @@ int riscv_of_processor_hartid(struct device_node *node, unsigned long *hart)
pr_warn("CPU with hartid=%lu has no \"riscv,isa\" property\n", *hart);
return -ENODEV;
}
- if (isa[0] != 'r' || isa[1] != 'v') {
+ if (tolower(isa[0]) != 'r' || tolower(isa[1]) != 'v') {
pr_warn("CPU with hartid=%lu has an invalid ISA of \"%s\"\n", *hart, isa);
return -ENODEV;
}
@@ -228,7 +229,8 @@ static void print_isa(struct seq_file *f, const char *isa)

seq_puts(f, "isa\t\t: ");
/* Print the rv[64/32] part */
- seq_write(f, isa, 4);
+ for (i = 0; i < 4; i++)
+ seq_putc(f, tolower(isa[i]));
for (i = 0; i < sizeof(base_riscv_exts); i++) {
if (__riscv_isa_extension_available(NULL, base_riscv_exts[i] - 'a'))
/* Print only enabled the base ISA extensions */
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index 59d58ee0f68d..c01dd144addc 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -120,10 +120,10 @@ void __init riscv_fill_hwcap(void)

temp = isa;
#if IS_ENABLED(CONFIG_32BIT)
- if (!strncmp(isa, "rv32", 4))
+ if (!strncasecmp(isa, "rv32", 4))
isa += 4;
#elif IS_ENABLED(CONFIG_64BIT)
- if (!strncmp(isa, "rv64", 4))
+ if (!strncasecmp(isa, "rv64", 4))
isa += 4;
#endif
/* The riscv,isa DT property must start with rv64 or rv32 */
@@ -135,7 +135,7 @@ void __init riscv_fill_hwcap(void)
const char *ext_end = isa;
bool ext_long = false, ext_err = false;

- switch (*ext) {
+ switch (tolower(*ext)) {
case 's':
/**
* Workaround for invalid single-letter 's' & 'u'(QEMU).
@@ -143,7 +143,7 @@ void __init riscv_fill_hwcap(void)
* not valid ISA extensions. It works until multi-letter
* extension starting with "Su" appears.
*/
- if (ext[-1] != '_' && ext[1] == 'u') {
+ if (ext[-1] != '_' && tolower(ext[1]) == 'u') {
++isa;
ext_err = true;
break;
@@ -154,7 +154,7 @@ void __init riscv_fill_hwcap(void)
ext_long = true;
/* Multi-letter extension must be delimited */
for (; *isa && *isa != '_'; ++isa)
- if (unlikely(!islower(*isa)
+ if (unlikely(!isalpha(*isa)
&& !isdigit(*isa)))
ext_err = true;
/* Parse backwards */
@@ -166,7 +166,7 @@ void __init riscv_fill_hwcap(void)
/* Skip the minor version */
while (isdigit(*--ext_end))
;
- if (ext_end[0] != 'p'
+ if (tolower(ext_end[0]) != 'p'
|| !isdigit(ext_end[-1])) {
/* Advance it to offset the pre-decrement */
++ext_end;
@@ -178,7 +178,7 @@ void __init riscv_fill_hwcap(void)
++ext_end;
break;
default:
- if (unlikely(!islower(*ext))) {
+ if (unlikely(!isalpha(*ext))) {
ext_err = true;
break;
}
@@ -188,7 +188,7 @@ void __init riscv_fill_hwcap(void)
/* Skip the minor version */
while (isdigit(*++isa))
;
- if (*isa != 'p')
+ if (tolower(*isa) != 'p')
break;
if (!isdigit(*++isa)) {
--isa;
@@ -205,7 +205,7 @@ void __init riscv_fill_hwcap(void)
#define SET_ISA_EXT_MAP(name, bit) \
do { \
if ((ext_end - ext == sizeof(name) - 1) && \
- !memcmp(ext, name, sizeof(name) - 1) && \
+ !strncasecmp(ext, name, sizeof(name) - 1) && \
riscv_isa_extension_check(bit)) \
set_bit(bit, this_isa); \
} while (false) \
@@ -213,7 +213,7 @@ void __init riscv_fill_hwcap(void)
if (unlikely(ext_err))
continue;
if (!ext_long) {
- int nr = *ext - 'a';
+ int nr = tolower(*ext) - 'a';

if (riscv_isa_extension_check(nr)) {
this_hwcap |= isa2hwcap[nr];
--
2.40.0