[RFC PATCH 3/3] riscv: Full parser for "riscv,isa" strings
Tsukasa OI
research_trasio at irq.a4lg.com
Sat Nov 20 00:54:00 PST 2021
This commit implements full parser for "riscv,isa" strings.
We haven't determined how do we represent multi-letter and/or versioned
extensions in the ISA bitmap yet. So, this commit handles only single-
letter extensions with no respect to version numbers (as before).
Nevertheless, it can be a foundation for our future work.
Note that major version of -1 represents non-versioned extension
(in many cases, they should be handled as 1 with some exceptions).
Signed-off-by: Tsukasa OI <research_trasio at irq.a4lg.com>
---
arch/riscv/kernel/cpufeature.c | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index e0d051516746..6012a1bb1d20 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -60,6 +60,22 @@ bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, int bit)
}
EXPORT_SYMBOL_GPL(__riscv_isa_extension_available);
+static inline int _decimal_part_to_uint(const char *s, unsigned int *res)
+{
+ unsigned int value = 0, d;
+
+ if (!isdigit(*s))
+ return -EINVAL;
+ do {
+ d = *s - '0';
+ if (value > (UINT_MAX - d) / 10)
+ return -ERANGE;
+ value = value * 10 + d;
+ } while (isdigit(*++s));
+ *res = value;
+ return 0;
+}
+
void __init riscv_fill_hwcap(void)
{
struct device_node *node;
@@ -100,6 +116,10 @@ void __init riscv_fill_hwcap(void)
#endif
for (; *isa; ++isa) {
const char *ext = isa;
+ const char *ext_end = isa + 1;
+ const char *ext_nstr;
+ unsigned int ext_major = -1; /* default */
+ unsigned int ext_minor = 0;
int ext_err = 0;
bool ext_long = false;
@@ -113,6 +133,7 @@ void __init riscv_fill_hwcap(void)
ext_long = true;
while ('a' <= *isa && *isa <= 'z')
++isa;
+ ext_end = isa;
break;
}
if (isdigit(*isa)) {
@@ -120,14 +141,25 @@ void __init riscv_fill_hwcap(void)
do {
while (isdigit(*++isa))
;
+ if (_decimal_part_to_uint(ext_nstr,
+ &ext_major) || ext_major == -1) {
+ ext_err = 1;
+ break;
+ }
if (*isa != 'p')
break;
if (!isdigit(*++isa)) {
ext_err = 2;
break;
}
+ ext_nstr = isa;
while (isdigit(*++isa))
;
+ if (_decimal_part_to_uint(ext_nstr,
+ &ext_minor)) {
+ ext_err = 3;
+ break;
+ }
} while (0);
}
if (*isa != '_')
--
2.32.0
More information about the linux-riscv
mailing list