git: 88b4d124efc5 - main - riscv: Rework CPU identification (first part)

From: Mitchell Horne <mhorne_at_FreeBSD.org>
Date: Tue, 23 May 2023 13:23:19 UTC
The branch main has been updated by mhorne:

URL: https://cgit.FreeBSD.org/src/commit/?id=88b4d124efc5a2d45660551fe0750acc0be6d3cd

commit 88b4d124efc5a2d45660551fe0750acc0be6d3cd
Author:     Mitchell Horne <mhorne@FreeBSD.org>
AuthorDate: 2023-05-22 23:48:41 +0000
Commit:     Mitchell Horne <mhorne@FreeBSD.org>
CommitDate: 2023-05-23 13:00:25 +0000

    riscv: Rework CPU identification (first part)
    
    Make better use of the RISC-V identification CSRs: mvendorid, marchid,
    and mimpid. This code was written before these registers were
    well-specified, or even available to the kernel. It currently fails to
    recognize any CPU or platform.
    
    Per the privileged specification, mvendorid contains the JEDEC vendor ID,
    or zero.
    
    The marchid register denotes the CPU microarchitecture. This is either
    one of the globally allocated open-source implementation IDs, or the
    field has a custom encoding. Therefore, for known vendors (SiFive) we
    can also maintain a list of known marchid values. If we can not give a
    name to the CPU but marchid is non-zero, then just print its value in
    the report.
    
    The mimpid (implementation ID) could be used in the future to more
    uniquely identify the micro-architecture, but it really remains to be
    seen how it gets used. For now we just print its value.
    
    Thank you to Danjel Qyteza <danq1222@gmail.com> who submitted an early
    version of this change to me, although it has been almost entirely
    rewritten.
    
    MFC after:      2 weeks
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D39809
---
 sys/riscv/include/cpu.h    |  45 +++++++++-------
 sys/riscv/riscv/identcpu.c | 128 ++++++++++++++++++++++++++-------------------
 2 files changed, 101 insertions(+), 72 deletions(-)

diff --git a/sys/riscv/include/cpu.h b/sys/riscv/include/cpu.h
index ee7b1111af56..b33e34d350fb 100644
--- a/sys/riscv/include/cpu.h
+++ b/sys/riscv/include/cpu.h
@@ -52,27 +52,36 @@
 #ifdef _KERNEL
 
 /*
- * 0x0000         CPU ID unimplemented
- * 0x0001         UC Berkeley Rocket repo
- * 0x0002­0x7FFE  Reserved for open-source repos
- * 0x7FFF         Reserved for extension
- * 0x8000         Reserved for anonymous source
- * 0x8001­0xFFFE  Reserved for proprietary implementations
- * 0xFFFF         Reserved for extension
+ * Core manufacturer IDs, as reported by the mvendorid CSR.
  */
+#define	MVENDORID_UNIMPL	0x0
+#define	MVENDORID_SIFIVE	0x489
+#define	MVENDORID_THEAD		0x5b7
 
-#define	CPU_IMPL_SHIFT		0
-#define	CPU_IMPL_MASK		(0xffff << CPU_IMPL_SHIFT)
-#define	CPU_IMPL(mimpid)	((mimpid & CPU_IMPL_MASK) >> CPU_IMPL_SHIFT)
-#define	CPU_IMPL_UNIMPLEMEN	0x0
-#define	CPU_IMPL_UCB_ROCKET	0x1
+/*
+ * Micro-architecture ID register, marchid.
+ *
+ * IDs for open-source implementations are allocated globally. Commercial IDs
+ * will have the most-significant bit set.
+ */
+#define	MARCHID_UNIMPL		0x0
+#define	MARCHID_MSB		(1ul << (XLEN - 1))
+#define	MARCHID_OPENSOURCE(v)	(v)
+#define	MARCHID_COMMERCIAL(v)	(MARCHID_MSB | (v))
+#define	MARCHID_IS_OPENSOURCE(m) (((m) & MARCHID_MSB) == 0)
+
+/*
+ * Open-source marchid values.
+ *
+ * https://github.com/riscv/riscv-isa-manual/blob/master/marchid.md
+ */
+#define	MARCHID_UCB_ROCKET	MARCHID_OPENSOURCE(1)
+#define	MARCHID_UCB_BOOM	MARCHID_OPENSOURCE(2)
+#define	MARCHID_UCB_SPIKE	MARCHID_OPENSOURCE(5)
+#define	MARCHID_UCAM_RVBS	MARCHID_OPENSOURCE(10)
 
-#define	CPU_PART_SHIFT		62
-#define	CPU_PART_MASK		(0x3ul << CPU_PART_SHIFT)
-#define	CPU_PART(misa)		((misa & CPU_PART_MASK) >> CPU_PART_SHIFT)
-#define	CPU_PART_RV32		0x1
-#define	CPU_PART_RV64		0x2
-#define	CPU_PART_RV128		0x3
+/* SiFive marchid values */
+#define	MARCHID_SIFIVE_U7	MARCHID_COMMERCIAL(7)
 
 extern char btext[];
 extern char etext[];
diff --git a/sys/riscv/riscv/identcpu.c b/sys/riscv/riscv/identcpu.c
index c57a22c1b51a..9b2330ee7051 100644
--- a/sys/riscv/riscv/identcpu.c
+++ b/sys/riscv/riscv/identcpu.c
@@ -67,42 +67,47 @@ register_t marchid;	/* The architecture ID */
 register_t mimpid;	/* The implementation ID */
 
 struct cpu_desc {
-	u_int		cpu_impl;
-	u_int		cpu_part_num;
-	const char	*cpu_impl_name;
-	const char	*cpu_part_name;
+	const char	*cpu_mvendor_name;
+	const char	*cpu_march_name;
 };
 
 struct cpu_desc cpu_desc[MAXCPU];
 
-struct cpu_parts {
-	u_int		part_id;
-	const char	*part_name;
+/*
+ * Micro-architecture tables.
+ */
+struct marchid_entry {
+	register_t	march_id;
+	const char	*march_name;
 };
-#define	CPU_PART_NONE	{ -1, "Unknown Processor" }
 
-struct cpu_implementers {
-	u_int			impl_id;
-	const char		*impl_name;
+#define	MARCHID_END	{ -1ul, NULL }
+
+/* Open-source RISC-V architecture IDs; globally allocated. */
+static const struct marchid_entry global_marchids[] = {
+	{ MARCHID_UCB_ROCKET,	"UC Berkeley Rocket"		},
+	{ MARCHID_UCB_BOOM,	"UC Berkeley Boom"		},
+	{ MARCHID_UCB_SPIKE,	"UC Berkeley Spike"		},
+	{ MARCHID_UCAM_RVBS,	"University of Cambridge RVBS"	},
+	MARCHID_END
 };
-#define	CPU_IMPLEMENTER_NONE	{ 0, "Unknown Implementer" }
 
-/*
- * CPU base
- */
-static const struct cpu_parts cpu_parts_std[] = {
-	{ CPU_PART_RV32,	"RV32" },
-	{ CPU_PART_RV64,	"RV64" },
-	{ CPU_PART_RV128,	"RV128" },
-	CPU_PART_NONE,
+static const struct marchid_entry sifive_marchids[] = {
+	{ MARCHID_SIFIVE_U7,	"6/7/P200/X200-Series Processor" },
+	MARCHID_END
 };
 
 /*
- * Implementers table.
+ * Known CPU vendor/manufacturer table.
  */
-const struct cpu_implementers cpu_implementers[] = {
-	{ CPU_IMPL_UCB_ROCKET,	"UC Berkeley Rocket" },
-	CPU_IMPLEMENTER_NONE,
+static const struct {
+	register_t			mvendor_id;
+	const char			*mvendor_name;
+	const struct marchid_entry	*marchid_table;
+} mvendor_ids[] = {
+	{ MVENDORID_UNIMPL,	"Unspecified",		NULL		},
+	{ MVENDORID_SIFIVE,	"SiFive",		sifive_marchids	},
+	{ MVENDORID_THEAD,	"T-Head",		NULL		},
 };
 
 /*
@@ -319,48 +324,63 @@ fill_elf_hwcap(void *dummy __unused)
 SYSINIT(identcpu, SI_SUB_CPU, SI_ORDER_ANY, fill_elf_hwcap, NULL);
 #endif
 
-void
-identify_cpu(void)
+static void
+identify_cpu_ids(struct cpu_desc *desc)
 {
-	const struct cpu_parts *cpu_partsp;
-	uint32_t part_id;
-	uint32_t impl_id;
-	uint64_t misa;
-	u_int cpu;
-	size_t i;
-
-	cpu_partsp = NULL;
+	const struct marchid_entry *table = NULL;
+	int i;
 
-	/* TODO: can we get misa somewhere ? */
-	misa = 0;
+	desc->cpu_mvendor_name = "Unknown";
+	desc->cpu_march_name = "Unknown";
 
-	cpu = PCPU_GET(cpuid);
-
-	impl_id	= CPU_IMPL(mimpid);
-	for (i = 0; i < nitems(cpu_implementers); i++) {
-		if (impl_id == cpu_implementers[i].impl_id ||
-		    cpu_implementers[i].impl_id == 0) {
-			cpu_desc[cpu].cpu_impl = impl_id;
-			cpu_desc[cpu].cpu_impl_name = cpu_implementers[i].impl_name;
-			cpu_partsp = cpu_parts_std;
+	/*
+	 * Search for a recognized vendor, and possibly obtain the secondary
+	 * table for marchid lookup.
+	 */
+	for (i = 0; i < nitems(mvendor_ids); i++) {
+		if (mvendorid == mvendor_ids[i].mvendor_id) {
+			desc->cpu_mvendor_name = mvendor_ids[i].mvendor_name;
+			table = mvendor_ids[i].marchid_table;
 			break;
 		}
 	}
 
-	part_id = CPU_PART(misa);
-	for (i = 0; &cpu_partsp[i] != NULL; i++) {
-		if (part_id == cpu_partsp[i].part_id ||
-		    cpu_partsp[i].part_id == -1) {
-			cpu_desc[cpu].cpu_part_num = part_id;
-			cpu_desc[cpu].cpu_part_name = cpu_partsp[i].part_name;
+	if (marchid == MARCHID_UNIMPL) {
+		desc->cpu_march_name = "Unspecified";
+		return;
+	}
+
+	if (MARCHID_IS_OPENSOURCE(marchid)) {
+		table = global_marchids;
+	} else if (table == NULL)
+		return;
+
+	for (i = 0; table[i].march_name != NULL; i++) {
+		if (marchid == table[i].march_id) {
+			desc->cpu_march_name = table[i].march_name;
 			break;
 		}
 	}
+}
+
+void
+identify_cpu(void)
+{
+	struct cpu_desc *desc;
+	u_int cpu, hart;
+
+	cpu = PCPU_GET(cpuid);
+	hart = PCPU_GET(hart);
+	desc = &cpu_desc[cpu];
+
+	identify_cpu_ids(desc);
 
 	/* Print details for boot CPU or if we want verbose output */
 	if (cpu == 0 || bootverbose) {
-		printf("CPU(%d): %s %s\n", cpu,
-		    cpu_desc[cpu].cpu_impl_name,
-		    cpu_desc[cpu].cpu_part_name);
+		/* Summary line. */
+		printf("CPU %-3u: Vendor=%s Core=%s (Hart %u)\n", cpu,
+		    desc->cpu_mvendor_name, desc->cpu_march_name, hart);
+
+		printf("  marchid=%#lx, mimpid=%#lx\n", marchid, mimpid);
 	}
 }