aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/riscv/kernel/cpufeature.c35
1 files changed, 27 insertions, 8 deletions
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index 72c5f6ef56b5..b0df7eff47f7 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -124,8 +124,28 @@ void __init riscv_fill_hwcap(void)
ext_long = true;
/* Multi-letter extension must be delimited */
for (; *isa && *isa != '_'; ++isa)
- if (!islower(*isa) && !isdigit(*isa))
+ if (unlikely(!islower(*isa)
+ && !isdigit(*isa)))
ext_err = true;
+ /* Parse backwards */
+ ext_end = isa;
+ if (unlikely(ext_err))
+ break;
+ if (!isdigit(ext_end[-1]))
+ break;
+ /* Skip the minor version */
+ while (isdigit(*--ext_end))
+ ;
+ if (ext_end[0] != 'p'
+ || !isdigit(ext_end[-1])) {
+ /* Advance it to offset the pre-decrement */
+ ++ext_end;
+ break;
+ }
+ /* Skip the major version */
+ while (isdigit(*--ext_end))
+ ;
+ ++ext_end;
break;
default:
if (unlikely(!islower(*ext))) {
@@ -151,14 +171,13 @@ void __init riscv_fill_hwcap(void)
}
if (*isa != '_')
--isa;
- /*
- * TODO: Full version-aware handling including
- * multi-letter extensions will be added in-future.
- */
- if (ext_err || ext_long)
+
+ if (unlikely(ext_err))
continue;
- this_hwcap |= isa2hwcap[(unsigned char)(*ext)];
- this_isa |= (1UL << (*ext - 'a'));
+ if (!ext_long) {
+ this_hwcap |= isa2hwcap[(unsigned char)(*ext)];
+ this_isa |= (1UL << (*ext - 'a'));
+ }
}
/*