[PATCH v2] lscpu: RISC-V: Print ISA information in summary

Sunil V L <[email protected]>
Newsgroups org.kernel.vger.util-linux
Message-ID <[email protected]>
The ISA information for RISC-V is important for understanding the
different extensions supported by the CPU. Print the ISA information in
the summary, with the Base ISA and single-letter extensions at the
beginning, followed by multi-letter extensions sorted in alphabetical
order. The information is the same as the cpuinfo information, except
that underscores are replaced by spaces and multi-letter extensions are
simply sorted instead of following any ISA string ordering rule.

The sample output below shows the difference between cpuinfo and lscpu.

cpuinfo output:
isa             : rv64imafdch_zicbom_zicboz_zicntr_zicsr_zifencei_zihintntl_zihintpause_zihpm_zawrs_zfa_zba_zbb_zbc_zbs_smaia_ssaia_sstc

lscpu output:
ISA:                rv64imafdch smaia ssaia sstc zawrs zba zbb zbc zbs zfa zicbom zicboz zicntr zicsr zifencei zihintntl zihintpause zihpm

Signed-off-by: Sunil V L <[email protected]>
---
Changes in v2:
	1) Format the ISA string instead of simply printing the same
	   from cpuinfo. (Feedback from Andrew Jones).
---
 sys-utils/Makemodule.am   |  1 +
 sys-utils/lscpu-cputype.c |  1 +
 sys-utils/lscpu-riscv.c   | 57 +++++++++++++++++++++++++++++++++++++++
 sys-utils/lscpu.c         |  5 ++++
 sys-utils/lscpu.h         |  2 ++
 sys-utils/meson.build     |  1 +
 6 files changed, 67 insertions(+)
 create mode 100644 sys-utils/lscpu-riscv.c

diff --git a/sys-utils/Makemodule.am b/sys-utils/Makemodule.am
index 922cce5c5..1055312db 100644
--- a/sys-utils/Makemodule.am
+++ b/sys-utils/Makemodule.am
@@ -461,6 +461,7 @@ lscpu_SOURCES = sys-utils/lscpu.c \
 		sys-utils/lscpu-virt.c \
 		sys-utils/lscpu-arm.c \
 		sys-utils/lscpu-dmi.c \
+		sys-utils/lscpu-riscv.c \
 		sys-utils/lscpu.h
 lscpu_LDADD = $(LDADD) libcommon.la libsmartcols.la $(RTAS_LIBS)
 lscpu_CFLAGS = $(AM_CFLAGS) -I$(ul_libsmartcols_incdir)
diff --git a/sys-utils/lscpu-cputype.c b/sys-utils/lscpu-cputype.c
index 739dd99c5..bdb33ac78 100644
--- a/sys-utils/lscpu-cputype.c
+++ b/sys-utils/lscpu-cputype.c
@@ -233,6 +233,7 @@ static const struct cpuinfo_pattern type_patterns[] =
 	DEF_PAT_CPUTYPE( "family",		PAT_FAMILY,	family),
 	DEF_PAT_CPUTYPE( "features",		PAT_FEATURES,	flags),		/* s390 */
 	DEF_PAT_CPUTYPE( "flags",		PAT_FLAGS,	flags),		/* x86 */
+	DEF_PAT_CPUTYPE( "isa",			PAT_ISA,	isa),		/* riscv */
 	DEF_PAT_CPUTYPE( "marchid",		PAT_FAMILY,	family),	/* riscv */
 	DEF_PAT_CPUTYPE( "max thread id",	PAT_MAX_THREAD_ID, mtid),	/* s390 */
 	DEF_PAT_CPUTYPE( "mimpid",		PAT_MODEL,	model),		/* riscv */
diff --git a/sys-utils/lscpu-riscv.c b/sys-utils/lscpu-riscv.c
new file mode 100644
index 000000000..62f1ad7ab
--- /dev/null
+++ b/sys-utils/lscpu-riscv.c
@@ -0,0 +1,57 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Copyright (C) 2025 Ventana Micro Systems Inc.
+ *
+ */
+#include "lscpu.h"
+#include "strutils.h"
+#include "strv.h"
+
+static int riscv_cmp_func(const void *a, const void *b)
+{
+	return strcmp(*(const char **)a, *(const char **)b);
+}
+
+bool is_riscv(struct lscpu_cputype *ct)
+{
+	const char *base_isa[] = {"rv32", "rv64", "rv128"};
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(base_isa); i++) {
+		if (!strncasecmp(ct->isa, base_isa[i], strlen(base_isa[i])))
+			return true;
+	}
+
+	return false;
+}
+
+/*
+ * Reformat the isa string, but the length stays the same.
+ */
+void lscpu_format_isa_riscv(struct lscpu_cputype *ct)
+{
+	char **split;
+	size_t i;
+
+	split = strv_split(ct->isa, "_");
+
+	/* Sort multi-letter extensions alphabetically */
+	if (strv_length(split) > 1)
+		qsort(&split[1], strv_length(split) - 1, sizeof(char *), riscv_cmp_func);
+
+	/* Keep Base ISA and single-letter extensions at the start */
+	strcpy(ct->isa, split[0]);
+
+	for (i = 1; i < strv_length(split); i++) {
+		strcat(ct->isa, " ");
+		strcat(ct->isa, split[i]);
+	}
+
+	strv_free(split);
+}
diff --git a/sys-utils/lscpu.c b/sys-utils/lscpu.c
index ffec37206..7b2f28e5e 100644
--- a/sys-utils/lscpu.c
+++ b/sys-utils/lscpu.c
@@ -954,6 +954,11 @@ print_summary_cputype(struct lscpu_cxt *cxt,
 
 	if (ct->flags)
 		add_summary_s(tb, sec, _("Flags:"), ct->flags);
+
+	if (ct->isa && is_riscv(ct)) {
+		lscpu_format_isa_riscv(ct);
+		add_summary_s(tb, sec, _("ISA:"), ct->isa);
+	}
 }
 
 /*
diff --git a/sys-utils/lscpu.h b/sys-utils/lscpu.h
index 459fea84d..bd7b64cc5 100644
--- a/sys-utils/lscpu.h
+++ b/sys-utils/lscpu.h
@@ -278,6 +278,7 @@ struct lscpu_cxt {
 		 CPU_ISSET_S((_cpu)->logical_id, (_cxt)->setsize, (_cxt)->present))
 
 int is_arm(struct lscpu_cxt *cxt);
+bool is_riscv(struct lscpu_cputype *ct);
 
 struct lscpu_cputype *lscpu_new_cputype(void);
 void lscpu_ref_cputype(struct lscpu_cputype *ct);
@@ -320,6 +321,7 @@ int lscpu_create_cpus(struct lscpu_cxt *cxt, cpu_set_t *cpuset, size_t setsize);
 struct lscpu_cpu *lscpu_cpus_loopup_by_type(struct lscpu_cxt *cxt, struct lscpu_cputype *ct);
 
 void lscpu_decode_arm(struct lscpu_cxt *cxt);
+void lscpu_format_isa_riscv(struct lscpu_cputype *ct);
 
 int lookup(char *line, char *pattern, char **value);
 
diff --git a/sys-utils/meson.build b/sys-utils/meson.build
index 2fdcc6393..d9817f922 100644
--- a/sys-utils/meson.build
+++ b/sys-utils/meson.build
@@ -184,6 +184,7 @@ lscpu_sources = files(
   'lscpu-virt.c',
   'lscpu-arm.c',
   'lscpu-dmi.c',
+  'lscpu-riscv.c',
 )
 lscpu_manadocs = files('lscpu.1.adoc')
 
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.