Changeset View
Standalone View
sys/riscv/riscv/identcpu.c
Show First 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD | CTLFLAG_CAPRD, machine, 0, | ||||
"Machine class"); | "Machine class"); | ||||
/* Hardware implementation info. These values may be empty. */ | /* Hardware implementation info. These values may be empty. */ | ||||
register_t mvendorid; /* The CPU's JEDEC vendor ID */ | register_t mvendorid; /* The CPU's JEDEC vendor ID */ | ||||
register_t marchid; /* The architecture ID */ | register_t marchid; /* The architecture ID */ | ||||
register_t mimpid; /* The implementation ID */ | register_t mimpid; /* The implementation ID */ | ||||
struct cpu_desc { | struct cpu_desc { | ||||
u_int cpu_impl; | const char *cpu_mvendor_name; | ||||
u_int cpu_part_num; | const char *cpu_march_name; | ||||
const char *cpu_impl_name; | |||||
const char *cpu_part_name; | |||||
}; | }; | ||||
struct cpu_desc cpu_desc[MAXCPU]; | struct cpu_desc cpu_desc[MAXCPU]; | ||||
struct cpu_parts { | /* | ||||
u_int part_id; | * Micro-architecture tables. | ||||
const char *part_name; | */ | ||||
struct marchid_entry { | |||||
register_t march_id; | |||||
const char *march_name; | |||||
}; | }; | ||||
#define CPU_PART_NONE { -1, "Unknown Processor" } | |||||
struct cpu_implementers { | #define MARCHID_END { -1ul, NULL } | ||||
u_int impl_id; | |||||
const char *impl_name; | /* 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" } | |||||
/* | static const struct marchid_entry sifive_marchids[] = { | ||||
* CPU base | { MARCHID_SIFIVE_U7, "6/7/P200/X200-Series Processor" }, | ||||
jrtc27: What made you choose this rather than U7-series? Is there some official document somewhere that… | |||||
Done Inline ActionsYes, in the U74 Core Complex manual, Appendix B, they describe the encoding of marchid and this is the exact string specified. mhorne: Yes, in the U74 Core Complex manual, Appendix B, they describe the encoding of marchid and this… | |||||
*/ | MARCHID_END | ||||
static const struct cpu_parts cpu_parts_std[] = { | |||||
{ CPU_PART_RV32, "RV32" }, | |||||
{ CPU_PART_RV64, "RV64" }, | |||||
{ CPU_PART_RV128, "RV128" }, | |||||
CPU_PART_NONE, | |||||
}; | }; | ||||
/* | /* | ||||
* Implementers table. | * Known CPU vendor/manufacturer table. | ||||
*/ | */ | ||||
const struct cpu_implementers cpu_implementers[] = { | static const struct { | ||||
{ CPU_IMPL_UCB_ROCKET, "UC Berkeley Rocket" }, | register_t mvendor_id; | ||||
CPU_IMPLEMENTER_NONE, | const char *mvendor_name; | ||||
const struct marchid_entry *marchid_table; | |||||
Done Inline ActionsPerhaps we want a 0 -> "Unspecified", either here or in the function? That distinguishes it from some vendor we don't know about but is specified. Especially since 0 is what you have to use as a non-commercial entity. jrtc27: Perhaps we want a 0 -> "Unspecified", either here or in the function? That distinguishes it… | |||||
} mvendor_ids[] = { | |||||
{ MVENDORID_UNIMPL, "Unspecified", NULL }, | |||||
{ MVENDORID_SIFIVE, "SiFive", sifive_marchids }, | |||||
{ MVENDORID_THEAD, "T-Head", NULL }, | |||||
}; | }; | ||||
/* | /* | ||||
* The ISA string describes the complete set of instructions supported by a | * The ISA string describes the complete set of instructions supported by a | ||||
* RISC-V CPU. The string begins with a small prefix (e.g. rv64) indicating the | * RISC-V CPU. The string begins with a small prefix (e.g. rv64) indicating the | ||||
* base ISA. It is followed first by single-letter ISA extensions, and then | * base ISA. It is followed first by single-letter ISA extensions, and then | ||||
* multi-letter ISA extensions. | * multi-letter ISA extensions. | ||||
* | * | ||||
▲ Show 20 Lines • Show All 200 Lines • ▼ Show 20 Lines | for (node = OF_child(node); node > 0; node = OF_peer(node)) { | ||||
else | else | ||||
elf_hwcap = hwcap; | elf_hwcap = hwcap; | ||||
} | } | ||||
} | } | ||||
SYSINIT(identcpu, SI_SUB_CPU, SI_ORDER_ANY, fill_elf_hwcap, NULL); | SYSINIT(identcpu, SI_SUB_CPU, SI_ORDER_ANY, fill_elf_hwcap, NULL); | ||||
#endif | #endif | ||||
void | static void | ||||
identify_cpu(void) | identify_cpu_ids(struct cpu_desc *desc) | ||||
{ | { | ||||
const struct cpu_parts *cpu_partsp; | const struct marchid_entry *table = NULL; | ||||
uint32_t part_id; | int i; | ||||
uint32_t impl_id; | |||||
uint64_t misa; | |||||
u_int cpu; | |||||
size_t i; | |||||
cpu_partsp = NULL; | desc->cpu_mvendor_name = "Unknown"; | ||||
desc->cpu_march_name = "Unknown"; | |||||
/* TODO: can we get misa somewhere ? */ | /* | ||||
misa = 0; | * Search for a recognized vendor, and possibly obtain the secondary | ||||
* table for marchid lookup. | |||||
cpu = PCPU_GET(cpuid); | */ | ||||
for (i = 0; i < nitems(mvendor_ids); i++) { | |||||
impl_id = CPU_IMPL(mimpid); | if (mvendorid == mvendor_ids[i].mvendor_id) { | ||||
for (i = 0; i < nitems(cpu_implementers); i++) { | desc->cpu_mvendor_name = mvendor_ids[i].mvendor_name; | ||||
if (impl_id == cpu_implementers[i].impl_id || | table = mvendor_ids[i].marchid_table; | ||||
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; | |||||
break; | break; | ||||
} | } | ||||
Not Done Inline ActionsNo T-Head despite the define? jrtc27: No T-Head despite the define? | |||||
Done Inline Actions*shrug* we do not run on it, and I did not chase down any marchid values. Arguably I don't need to add the T-Head vendor entry for the same reason, but I had that information and it will not change. mhorne: *shrug* we do not run on it, and I did not chase down any marchid values. Arguably I don't need… | |||||
} | } | ||||
Done Inline ActionsIn the arm64 world the table stores a pointer to the vendor's parts in the vendor entry rather than splitting them like this, which makes things shorter. Is there a reason you opted not to do that? Doing zero-terminated lists rather than using nitems helps make that less ugly, too. jrtc27: In the arm64 world the table stores a pointer to the vendor's parts in the vendor entry rather… | |||||
Done Inline ActionsEarlier iterations were zero-terminated, and for reasons forgotten I shuffled it around. I agree it is cleaner so I will restore that. mhorne: Earlier iterations were zero-terminated, and for reasons forgotten I shuffled it around. I… | |||||
part_id = CPU_PART(misa); | if (marchid == MARCHID_UNIMPL) { | ||||
for (i = 0; &cpu_partsp[i] != NULL; i++) { | desc->cpu_march_name = "Unspecified"; | ||||
if (part_id == cpu_partsp[i].part_id || | return; | ||||
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_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; | 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 */ | /* Print details for boot CPU or if we want verbose output */ | ||||
if (cpu == 0 || bootverbose) { | if (cpu == 0 || bootverbose) { | ||||
printf("CPU(%d): %s %s\n", cpu, | /* Summary line. */ | ||||
cpu_desc[cpu].cpu_impl_name, | printf("CPU %-3u: Vendor=%s Core=%s (Hart %u)\n", cpu, | ||||
cpu_desc[cpu].cpu_part_name); | desc->cpu_mvendor_name, desc->cpu_march_name, hart); | ||||
printf(" marchid=%#lx, mimpid=%#lx\n", marchid, mimpid); | |||||
Done Inline Actionsarm64 does %3u so things line up nicely when you roll into the multiple digits (provided MAXCPU remains < 1000). arm64 also prints a one-line summary for each core and will print out detailed information if it differs from the previous core (or bootverbose is set), which all seems useful to me. It seems like we should be able to squeeze the basic identification information into a single line like it, too? Then the ISA etc information can be following lines like it does and collapsed when the same for non-bootverbose. In general we should be aligning with other similar ports like arm64 where possible. jrtc27: arm64 does %3u so things line up nicely when you roll into the multiple digits (provided MAXCPU… | |||||
Done Inline ActionsSure, I will play around with the format a bit more. I did not look too much at other identcpu code, purposefully. How this code should look ends up being quite an open-ended problem. I really tried to approach it by assessing the needs and mechanisms of this platform in particular. I think the arm64 print-only-when-different behaviour is superior, so I will work on that. It will be in a future change, though, since this one is really just about printing more complete information than we currently do, based on what is now available. mhorne: Sure, I will play around with the format a bit more.
I did not look too much at other identcpu… | |||||
} | } | ||||
} | } |
What made you choose this rather than U7-series? Is there some official document somewhere that refers to this marchid by this name?