Implement get_riscv_cpuinfo. Needs testing and further documentation

This commit is contained in:
Dr-Noob
2024-10-02 08:43:18 +01:00
parent 5194976739
commit 2272423163
8 changed files with 110 additions and 15 deletions

View File

@@ -25,6 +25,7 @@ enum {
CPU_VENDOR_RISCV,
CPU_VENDOR_SIFIVE,
CPU_VENDOR_THEAD,
CPU_VENDOR_SPACEMIT,
// OTHERS
CPU_VENDOR_UNKNOWN,
CPU_VENDOR_INVALID

View File

@@ -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);

View File

@@ -40,7 +40,7 @@ bool match_sipeed(char* soc_name, struct system_on_chip* soc) {
bool match_spacemit(char* soc_name, struct system_on_chip* soc) {
SOC_START
SOC_EQ(soc_name, "k1-x", "X60", SOC_SPACEMIT_X60, soc, 22) // https://github.com/Dr-Noob/cpufetch/issues/286 https://www.spacemit.com/en/spacemit-x60-core/
SOC_EQ(soc_name, "k1-x", "K1", SOC_SPACEMIT_K1, soc, 22) // https://github.com/Dr-Noob/cpufetch/issues/286 https://www.spacemit.com/en/spacemit-x60-core/
SOC_END
}

View File

@@ -14,7 +14,7 @@ enum {
// SIPEED
SOC_SIPEED_LICHEEPI4A,
// SPACEMIT
SOC_SPACEMIT_X60,
SOC_SPACEMIT_K1,
// UNKNOWN
SOC_MODEL_UNKNOWN
};
@@ -24,7 +24,7 @@ inline static VENDOR get_soc_vendor_from_soc(SOC soc) {
if(soc >= SOC_STARFIVE_VF2 && soc <= SOC_STARFIVE_VF2) return SOC_VENDOR_STARFIVE;
if(soc >= SOC_ALLWINNER_D1H && soc <= SOC_ALLWINNER_D1H) return SOC_VENDOR_ALLWINNER;
if(soc >= SOC_SIPEED_LICHEEPI4A && soc <= SOC_SIPEED_LICHEEPI4A) return SOC_VENDOR_SIPEED;
if(soc >= SOC_SPACEMIT_X60 && soc <= SOC_SPACEMIT_X60) return SOC_VENDOR_SPACEMIT;
if(soc >= SOC_SPACEMIT_K1 && soc <= SOC_SPACEMIT_K1) return SOC_VENDOR_SPACEMIT;
return SOC_VENDOR_UNKNOWN;
}

View File

@@ -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;
}
// TODO: Doc
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)
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)
printWarn("get_riscv_cpuinfo: Unable to get cpuinfo 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;
}

View File

@@ -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

View File

@@ -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;
long ret = strtol(tmp, &end, 16);
if(errno != 0) {
printWarn("strtol: %s:\n", strerror(errno));
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);
}

View File

@@ -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