mirror of
https://github.com/Dr-Noob/cpufetch
synced 2025-08-31 06:15:08 +00:00
[v1.06][RISCV] Support for fetching mvendorid, marchid and mimpid (#286)
Getting these 3 RISC-V cpuinfo fields allows the detection of microarchitecture (and other information), extending the RISC-V detection capabilities. In particular, this is used here to detect the marchid of Spacemit X60 uarch. This commit also changes how the microarchitecture is fetched (i.e., get_uarch) so that it does not rely only in the uarch field in cpuinfo, but also on the marchid value.
This commit is contained in:
@@ -25,6 +25,7 @@ enum {
|
||||
CPU_VENDOR_RISCV,
|
||||
CPU_VENDOR_SIFIVE,
|
||||
CPU_VENDOR_THEAD,
|
||||
CPU_VENDOR_SPACEMIT,
|
||||
// OTHERS
|
||||
CPU_VENDOR_UNKNOWN,
|
||||
CPU_VENDOR_INVALID
|
||||
|
@@ -101,8 +101,8 @@ struct extensions* get_extensions_from_str(char* str) {
|
||||
return ext;
|
||||
}
|
||||
|
||||
int len = strlen(str);
|
||||
ext->str = ecalloc(len+1, sizeof(char));
|
||||
int len = strlen(str)+1;
|
||||
ext->str = emalloc(len * sizeof(char));
|
||||
strncpy(ext->str, str, sizeof(char) * len);
|
||||
|
||||
// Code inspired in Linux kernel (riscv_fill_hwcap):
|
||||
@@ -157,13 +157,12 @@ struct cpuInfo* get_cpu_info(void) {
|
||||
topo->cach = NULL;
|
||||
cpu->topo = topo;
|
||||
|
||||
char* cpuinfo_str = get_uarch_from_cpuinfo();
|
||||
char* ext_str = get_extensions_from_cpuinfo();
|
||||
cpu->hv = emalloc(sizeof(struct hypervisor));
|
||||
cpu->hv->present = false;
|
||||
cpu->ext = get_extensions_from_str(ext_str);
|
||||
if(cpu->ext->str != NULL && cpu->ext->mask == 0) return NULL;
|
||||
cpu->arch = get_uarch_from_cpuinfo_str(cpuinfo_str, cpu);
|
||||
cpu->arch = get_uarch(cpu);
|
||||
cpu->soc = get_soc(cpu);
|
||||
cpu->freq = get_frequency_info(0);
|
||||
cpu->peak_performance = get_peak_performance(cpu);
|
||||
|
@@ -4,6 +4,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "uarch.h"
|
||||
#include "udev.h"
|
||||
#include "../common/global.h"
|
||||
|
||||
typedef uint32_t MICROARCH;
|
||||
@@ -12,6 +13,7 @@ struct uarch {
|
||||
MICROARCH uarch;
|
||||
char* uarch_str;
|
||||
char* cpuinfo_str;
|
||||
struct riscv_cpuinfo* ci;
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -21,13 +23,20 @@ enum {
|
||||
UARCH_U74,
|
||||
// THEAD
|
||||
UARCH_C906,
|
||||
UARCH_C910
|
||||
UARCH_C910,
|
||||
// SPACEMIT
|
||||
UARCH_X60
|
||||
};
|
||||
|
||||
#define UARCH_START if (false) {}
|
||||
#define CHECK_UARCH(arch, cpu, cpuinfo_str, uarch_str, str, uarch, vendor) \
|
||||
else if (strcmp(cpuinfo_str, uarch_str) == 0) fill_uarch(arch, cpu, str, uarch, vendor);
|
||||
#define UARCH_END else { printBug("Unknown microarchitecture detected: uarch='%s'", cpuinfo_str); fill_uarch(arch, cpu, "Unknown", UARCH_UNKNOWN, CPU_VENDOR_UNKNOWN); }
|
||||
#define UARCH_END else { printWarn("Unknown microarchitecture detected: uarch='%s'", cpuinfo_str); fill_uarch(arch, cpu, "Unknown", UARCH_UNKNOWN, CPU_VENDOR_UNKNOWN); }
|
||||
|
||||
#define ARCHID_START if (false) {}
|
||||
#define CHECK_ARCHID(arch, marchid_val, str, uarch, vendor) \
|
||||
else if (arch->ci->marchid == (unsigned long) marchid_val) fill_uarch(arch, cpu, str, uarch, vendor);
|
||||
#define ARCHID_END else { printWarn("Unknown microarchitecture detected: marchid=0x%.8X", arch->ci->marchid); fill_uarch(arch, cpu, "Unknown", UARCH_UNKNOWN, CPU_VENDOR_UNKNOWN); }
|
||||
|
||||
void fill_uarch(struct uarch* arch, struct cpuInfo* cpu, char* str, MICROARCH u, VENDOR vendor) {
|
||||
arch->uarch = u;
|
||||
@@ -39,14 +48,8 @@ void fill_uarch(struct uarch* arch, struct cpuInfo* cpu, char* str, MICROARCH u,
|
||||
// https://elixir.bootlin.com/linux/latest/source/Documentation/devicetree/bindings/riscv/cpus.yaml
|
||||
// SiFive: https://www.sifive.com/risc-v-core-ip
|
||||
// T-Head: https://www.t-head.cn/product/c906
|
||||
struct uarch* get_uarch_from_cpuinfo_str(char* cpuinfo_str, struct cpuInfo* cpu) {
|
||||
struct uarch* arch = emalloc(sizeof(struct uarch));
|
||||
struct uarch* get_uarch_from_cpuinfo_str(char* cpuinfo_str, struct cpuInfo* cpu, struct uarch* arch) {
|
||||
arch->cpuinfo_str = cpuinfo_str;
|
||||
if(cpuinfo_str == NULL) {
|
||||
printWarn("get_uarch_from_cpuinfo: Unable to detect microarchitecture, cpuinfo_str is NULL");
|
||||
fill_uarch(arch, cpu, "Unknown", UARCH_UNKNOWN, CPU_VENDOR_UNKNOWN);
|
||||
return arch;
|
||||
}
|
||||
|
||||
// U74/U74-MC:
|
||||
// SiFive says that U74-MC is "Multicore: four U74 cores and one S76 core" while
|
||||
@@ -70,6 +73,41 @@ struct uarch* get_uarch_from_cpuinfo_str(char* cpuinfo_str, struct cpuInfo* cpu)
|
||||
return arch;
|
||||
}
|
||||
|
||||
// Use marchid to get the microarchitecture
|
||||
struct uarch* get_uarch_from_riscv_cpuinfo(struct cpuInfo* cpu, struct uarch* arch) {
|
||||
|
||||
ARCHID_START
|
||||
CHECK_ARCHID(arch, 0x8000000058000001, "X60", UARCH_X60, CPU_VENDOR_SPACEMIT) // https://github.com/Dr-Noob/cpufetch/issues/286
|
||||
ARCHID_END
|
||||
|
||||
return arch;
|
||||
}
|
||||
|
||||
struct uarch* get_uarch(struct cpuInfo* cpu) {
|
||||
char* cpuinfo_str = get_uarch_from_cpuinfo();
|
||||
struct uarch* arch = emalloc(sizeof(struct uarch));
|
||||
arch->uarch = UARCH_UNKNOWN;
|
||||
arch->ci = NULL;
|
||||
|
||||
if (cpuinfo_str == NULL) {
|
||||
printWarn("get_uarch_from_cpuinfo: Unable to detect microarchitecture using uarch: cpuinfo_str is NULL");
|
||||
arch->ci = get_riscv_cpuinfo();
|
||||
|
||||
if (arch->ci == NULL || arch->ci->marchid == 0)
|
||||
printWarn("get_riscv_cpuinfo: Unable to get marchid from udev");
|
||||
else
|
||||
arch = get_uarch_from_riscv_cpuinfo(cpu, arch);
|
||||
}
|
||||
else {
|
||||
arch = get_uarch_from_cpuinfo_str(cpuinfo_str, cpu, arch);
|
||||
}
|
||||
|
||||
if (arch->uarch == UARCH_UNKNOWN)
|
||||
fill_uarch(arch, cpu, "Unknown", UARCH_UNKNOWN, CPU_VENDOR_UNKNOWN);
|
||||
|
||||
return arch;
|
||||
}
|
||||
|
||||
char* get_str_uarch(struct cpuInfo* cpu) {
|
||||
return cpu->arch->uarch_str;
|
||||
}
|
||||
|
@@ -9,6 +9,6 @@ struct uarch;
|
||||
char* get_arch_cpuinfo_str(struct cpuInfo* cpu);
|
||||
char* get_str_uarch(struct cpuInfo* cpu);
|
||||
void free_uarch_struct(struct uarch* arch);
|
||||
struct uarch* get_uarch_from_cpuinfo_str(char* cpuinfo_str, struct cpuInfo* cpu);
|
||||
struct uarch* get_uarch(struct cpuInfo* cpu);
|
||||
|
||||
#endif
|
||||
|
@@ -7,6 +7,9 @@
|
||||
#define _PATH_DEVTREE "/proc/device-tree/compatible"
|
||||
#define CPUINFO_UARCH_STR "uarch\t\t: "
|
||||
#define CPUINFO_EXTENSIONS_STR "isa\t\t: "
|
||||
#define CPUINFO_RISCV_MVENDORID "mvendorid\t:"
|
||||
#define CPUINFO_RISCV_MARCHID "marchid\t\t:"
|
||||
#define CPUINFO_RISCV_MIMPID "mimpid\t\t:"
|
||||
#define DEVTREE_HARDWARE_FIELD 0
|
||||
|
||||
char* get_field_from_devtree(int DEVTREE_FIELD) {
|
||||
@@ -75,6 +78,52 @@ char* parse_cpuinfo_field(char* field_str) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned long parse_cpuinfo_field_uint64(char* field_str) {
|
||||
int filelen;
|
||||
char* buf;
|
||||
if((buf = read_file(_PATH_CPUINFO, &filelen)) == NULL) {
|
||||
printWarn("read_file: %s: %s", _PATH_CPUINFO, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* tmp = strstr(buf, field_str);
|
||||
if(tmp == NULL) return 0;
|
||||
tmp += strlen(field_str);
|
||||
|
||||
char* end;
|
||||
errno = 0;
|
||||
unsigned long ret = strtoul(tmp, &end, 16);
|
||||
if (errno != 0) {
|
||||
printWarn("strtoul: %s: %s", strerror(errno), tmp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Creates and fills in the riscv_cpuinfo struct (which contains
|
||||
// mvendorid, marchid and mimpid) using cpuinfo to fetch the values.
|
||||
//
|
||||
// Every RISC-V hart (hardware thread) [1] provides a
|
||||
// marchid (Machine Architecture ID register) CSR that encodes its
|
||||
// base microarchitecture [2]. For more information about
|
||||
// marchid and the rest of values, see [3].
|
||||
// [1] https://groups.google.com/a/groups.riscv.org/g/sw-dev/c/QKjUDjz_vKo
|
||||
// [2] https://github.com/riscv/riscv-isa-manual/blob/main/marchid.md
|
||||
// [3] https://five-embeddev.com/riscv-priv-isa-manual/Priv-v1.12/machine.html#machine-architecture-id-register-marchid
|
||||
struct riscv_cpuinfo *get_riscv_cpuinfo(void) {
|
||||
struct riscv_cpuinfo* ci = emalloc(sizeof(struct riscv_cpuinfo));
|
||||
|
||||
ci->mvendorid = parse_cpuinfo_field_uint64(CPUINFO_RISCV_MVENDORID);
|
||||
ci->marchid = parse_cpuinfo_field_uint64(CPUINFO_RISCV_MARCHID);
|
||||
ci->mimpid = parse_cpuinfo_field_uint64(CPUINFO_RISCV_MIMPID);
|
||||
|
||||
if (ci->mvendorid == 0 && ci->mvendorid == 0 && ci->mvendorid == 0)
|
||||
return NULL;
|
||||
|
||||
return ci;
|
||||
}
|
||||
|
||||
char* get_hardware_from_devtree(void) {
|
||||
return get_field_from_devtree(DEVTREE_HARDWARE_FIELD);
|
||||
}
|
||||
|
@@ -5,8 +5,16 @@
|
||||
|
||||
#define UNKNOWN -1
|
||||
|
||||
// https://elixir.bootlin.com/linux/v6.10.6/source/arch/riscv/include/asm/cpufeature.h#L21
|
||||
struct riscv_cpuinfo {
|
||||
unsigned long mvendorid;
|
||||
unsigned long marchid;
|
||||
unsigned long mimpid;
|
||||
};
|
||||
|
||||
char* get_hardware_from_devtree(void);
|
||||
char* get_uarch_from_cpuinfo(void);
|
||||
char* get_extensions_from_cpuinfo(void);
|
||||
struct riscv_cpuinfo *get_riscv_cpuinfo(void);
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user