From 14819c350e9939192fd519b858f97f47164e58fc Mon Sep 17 00:00:00 2001 From: Dr-Noob Date: Mon, 3 Apr 2023 12:41:59 +0200 Subject: [PATCH] [v1.03][RISCV] Add basic SoC detection backend --- Makefile | 4 +- src/common/printer.c | 11 +++-- src/riscv/riscv.c | 33 +++++++++++-- src/riscv/riscv.h | 1 + src/riscv/soc.c | 113 ++++++++++++++++++++++++++++++++++++++++++- src/riscv/soc.h | 7 +++ src/riscv/socs.h | 19 ++++++++ src/riscv/udev.c | 44 +++++++++++++++++ src/riscv/udev.h | 10 ++++ 9 files changed, 229 insertions(+), 13 deletions(-) create mode 100644 src/riscv/socs.h create mode 100644 src/riscv/udev.c create mode 100644 src/riscv/udev.h diff --git a/Makefile b/Makefile index dbd9c3c..66e9adb 100644 --- a/Makefile +++ b/Makefile @@ -43,8 +43,8 @@ ifneq ($(OS),Windows_NT) endif else ifeq ($(arch), $(filter $(arch), riscv64 riscv32)) SRC_DIR=src/riscv/ - SOURCE += $(COMMON_SRC) $(SRC_DIR)riscv.c $(SRC_DIR)uarch.c $(SRC_DIR)soc.c - HEADERS += $(COMMON_SRC) $(SRC_DIR)riscv.h $(SRC_DIR)uarch.h $(SRC_DIR)soc.h + SOURCE += $(COMMON_SRC) $(SRC_DIR)riscv.c $(SRC_DIR)uarch.c $(SRC_DIR)soc.c $(SRC_DIR)udev.c + HEADERS += $(COMMON_SRC) $(SRC_DIR)riscv.h $(SRC_DIR)uarch.h $(SRC_DIR)soc.h $(SRC_DIR)udev.h $(SRC_DIR)socs.h CFLAGS += -DARCH_RISCV -Wno-unused-parameter -std=c99 -fstack-protector-all else # Error lines should not be tabulated because Makefile complains about it diff --git a/src/common/printer.c b/src/common/printer.c index da106b0..a5909f2 100644 --- a/src/common/printer.c +++ b/src/common/printer.c @@ -46,7 +46,7 @@ enum { #if defined(ARCH_X86) || defined(ARCH_PPC) ATTRIBUTE_NAME, -#elif ARCH_ARM +#elif defined(ARCH_ARM) || defined(ARCH_RISCV) ATTRIBUTE_SOC, #endif #if defined(ARCH_X86) || defined(ARCH_ARM) @@ -79,7 +79,7 @@ static const char* ATTRIBUTE_FIELDS [] = { "Name:", #elif ARCH_PPC "Part Number:", -#elif ARCH_ARM +#elif defined(ARCH_ARM) || defined(ARCH_RISCV) "SoC:", #endif #if defined(ARCH_X86) || defined(ARCH_ARM) @@ -926,6 +926,8 @@ bool print_cpufetch_riscv(struct cpuInfo* cpu, STYLE s, struct color** cs, struc // Step 1. Retrieve attributes char* uarch = get_str_uarch(cpu); char* manufacturing_process = get_str_process(cpu->soc); + char* soc_name = get_soc_name(cpu->soc); + char* features = get_str_features(cpu); char* max_frequency = get_str_freq(cpu->freq); char* n_cores = get_str_topology(cpu, cpu->topo); @@ -936,10 +938,11 @@ bool print_cpufetch_riscv(struct cpuInfo* cpu, STYLE s, struct color** cs, struc char* pp = get_str_peak_performance(cpu->peak_performance); // Step 2. Set attributes - setAttribute(art,ATTRIBUTE_UARCH,uarch); + setAttribute(art,ATTRIBUTE_SOC,soc_name); setAttribute(art,ATTRIBUTE_TECHNOLOGY,manufacturing_process); - setAttribute(art,ATTRIBUTE_FREQUENCY,max_frequency); + setAttribute(art,ATTRIBUTE_UARCH,uarch); setAttribute(art,ATTRIBUTE_NCORES, n_cores); + setAttribute(art,ATTRIBUTE_FREQUENCY,max_frequency); /*setAttribute(art,ATTRIBUTE_L1i,l1i); setAttribute(art,ATTRIBUTE_L1d,l1d); setAttribute(art,ATTRIBUTE_L2,l2); diff --git a/src/riscv/riscv.c b/src/riscv/riscv.c index 4a3a203..987ee1d 100644 --- a/src/riscv/riscv.c +++ b/src/riscv/riscv.c @@ -5,6 +5,7 @@ #include "../common/global.h" #include "../common/udev.h" +#include "soc.h" struct frequency* get_frequency_info(uint32_t core) { struct frequency* freq = emalloc(sizeof(struct frequency)); @@ -15,23 +16,45 @@ struct frequency* get_frequency_info(uint32_t core) { return freq; } +int64_t get_peak_performance(struct cpuInfo* cpu) { + //First check we have consistent data + if(get_freq(cpu->freq) == UNKNOWN_DATA) { + return -1; + } + + int64_t flops = cpu->topo->total_cores * (get_freq(cpu->freq) * 1000000); + return flops; +} + struct cpuInfo* get_cpu_info(void) { struct cpuInfo* cpu = malloc(sizeof(struct cpuInfo)); //init_cpu_info(cpu); - int ncores = get_ncores_from_cpuinfo(); + struct topology* topo = emalloc(sizeof(struct topology)); + topo->total_cores = get_ncores_from_cpuinfo(); + topo->cach = NULL; + cpu->topo = topo; + cpu->hv = emalloc(sizeof(struct hypervisor)); cpu->hv->present = false; - //cpu->soc = get_soc(); - //cpu->peak_performance = get_peak_performance(cpu); - cpu->peak_performance = 0; + cpu->soc = get_soc(); cpu->freq = get_frequency_info(0); cpu->cpu_vendor = CPU_VENDOR_RISCV; + cpu->peak_performance = get_peak_performance(cpu); return cpu; } +//TODO: Might be worth refactoring with other archs char* get_str_topology(struct cpuInfo* cpu, struct topology* topo) { - return "Many cores"; + uint32_t size = 3+7+1; + char* string = emalloc(sizeof(char)*size); + snprintf(string, size, "%d cores", topo->total_cores); + + return string; +} + +char* get_str_features(struct cpuInfo* cpu) { + return NULL; } void print_debug(struct cpuInfo* cpu) { diff --git a/src/riscv/riscv.h b/src/riscv/riscv.h index 367c56e..e644077 100644 --- a/src/riscv/riscv.h +++ b/src/riscv/riscv.h @@ -5,6 +5,7 @@ struct cpuInfo* get_cpu_info(void); char* get_str_topology(struct cpuInfo* cpu, struct topology* topo); +char* get_str_features(struct cpuInfo* cpu); void print_debug(struct cpuInfo* cpu); #endif diff --git a/src/riscv/soc.c b/src/riscv/soc.c index 6f6f115..45d8a43 100644 --- a/src/riscv/soc.c +++ b/src/riscv/soc.c @@ -1,9 +1,118 @@ #include "soc.h" +#include "socs.h" +#include "udev.h" +#include "../common/global.h" + +#include char* get_str_process(struct system_on_chip* soc) { - return "-1 nm"; + char* str; + + if(soc->process == UNKNOWN) { + str = emalloc(sizeof(char) * (strlen(STRING_UNKNOWN)+1)); + snprintf(str, strlen(STRING_UNKNOWN)+1, STRING_UNKNOWN); + } + else { + str = emalloc(sizeof(char) * 5); + memset(str, 0, sizeof(char) * 5); + snprintf(str, 5, "%dnm", soc->process); + } + return str; } char* get_soc_name(struct system_on_chip* soc) { - return "Unknown"; + if(soc->soc_model == SOC_MODEL_UNKNOWN) + return soc->raw_name; + return soc->soc_name; +} + +static char* soc_trademark_string[] = { + [SOC_VENDOR_SIFIVE] = "SiFive " +}; + +void fill_soc(struct system_on_chip* soc, char* soc_name, SOC soc_model, int32_t process) { + soc->soc_model = soc_model; + soc->soc_vendor = get_soc_vendor_from_soc(soc_model); + soc->process = process; + int len = strlen(soc_name) + strlen(soc_trademark_string[soc->soc_vendor]) + 1; + soc->soc_name = emalloc(sizeof(char) * len); + memset(soc->soc_name, 0, sizeof(char) * len); + sprintf(soc->soc_name, "%s%s", soc_trademark_string[soc->soc_vendor], soc_name); +} + +bool match_soc(struct system_on_chip* soc, char* raw_name, char* expected_name, char* soc_name, SOC soc_model, int32_t process) { + int len1 = strlen(raw_name); + int len2 = strlen(expected_name); + int len = min(len1, len2); + + if(strncmp(raw_name, expected_name, len) != 0) { + return false; + } + else { + fill_soc(soc, soc_name, soc_model, process); + return true; + } +} + +#define SOC_START if (false) {} +#define SOC_EQ(raw_name, expected_name, soc_name, soc_model, soc, process) \ + else if (match_soc(soc, raw_name, expected_name, soc_name, soc_model, process)) return true; +#define SOC_END else { return false; } + +bool match_sifive(char* soc_name, struct system_on_chip* soc) { + char* tmp = soc_name; + + // Dont know if it makes sense in RISC-V + /*if((tmp = strstr(soc_name, "???")) == NULL) + return false;*/ + + //soc->soc_vendor = ??? + + SOC_START + SOC_EQ(tmp, "fu740", "Freedom U740", SOC_SIFIVE_U740, soc, 40) + SOC_END +} + +struct system_on_chip* parse_soc_from_string(struct system_on_chip* soc) { + char* raw_name = soc->raw_name; + match_sifive(raw_name, soc); + return soc; +} + +struct system_on_chip* guess_soc_from_devtree(struct system_on_chip* soc) { + char* tmp = get_hardware_from_devtree(); + + if(tmp != NULL) { + soc->raw_name = tmp; + return parse_soc_from_string(soc); + } + + return soc; +} + +struct system_on_chip* get_soc(void) { + struct system_on_chip* soc = emalloc(sizeof(struct system_on_chip)); + soc->raw_name = NULL; + soc->soc_vendor = SOC_VENDOR_UNKNOWN; + soc->soc_model = SOC_MODEL_UNKNOWN; + soc->process = UNKNOWN; + + soc = guess_soc_from_devtree(soc); + if(soc->soc_vendor == SOC_VENDOR_UNKNOWN) { + if(soc->raw_name != NULL) { + printWarn("SoC detection failed using device tree: Found '%s' string", soc->raw_name); + } + else { + printWarn("SoC detection failed using device tree"); + } + } + + if(soc->soc_model == SOC_MODEL_UNKNOWN) { + // raw_name might not be NULL, but if we were unable to find + // the exact SoC, just print "Unkwnown" + soc->raw_name = emalloc(sizeof(char) * (strlen(STRING_UNKNOWN)+1)); + snprintf(soc->raw_name, strlen(STRING_UNKNOWN)+1, STRING_UNKNOWN); + } + + return soc; } diff --git a/src/riscv/soc.h b/src/riscv/soc.h index 9f55c1b..f71a35b 100644 --- a/src/riscv/soc.h +++ b/src/riscv/soc.h @@ -6,6 +6,11 @@ typedef int32_t SOC; +enum { + SOC_VENDOR_UNKNOWN, + SOC_VENDOR_SIFIVE +}; + struct system_on_chip { SOC soc_model; VENDOR soc_vendor; @@ -14,7 +19,9 @@ struct system_on_chip { char* raw_name; }; +struct system_on_chip* get_soc(void); char* get_soc_name(struct system_on_chip* soc); +//VENDOR get_soc_vendor(struct system_on_chip* soc); char* get_str_process(struct system_on_chip* soc); #endif diff --git a/src/riscv/socs.h b/src/riscv/socs.h new file mode 100644 index 0000000..cf587f6 --- /dev/null +++ b/src/riscv/socs.h @@ -0,0 +1,19 @@ +#ifndef __SOCS__ +#define __SOCS__ + +#include "soc.h" + +// List of supported SOCs +enum { + // SIFIVE + SOC_SIFIVE_U740, + // UNKNOWN + SOC_MODEL_UNKNOWN +}; + +inline static VENDOR get_soc_vendor_from_soc(SOC soc) { + if(soc >= SOC_SIFIVE_U740 && soc <= SOC_SIFIVE_U740) return SOC_VENDOR_SIFIVE; + return SOC_VENDOR_UNKNOWN; +} + +#endif diff --git a/src/riscv/udev.c b/src/riscv/udev.c new file mode 100644 index 0000000..45a52bd --- /dev/null +++ b/src/riscv/udev.c @@ -0,0 +1,44 @@ +#include +#include + +#include "../common/global.h" +#include "udev.h" + +#define _PATH_DEVTREE "/proc/device-tree/compatible" +#define DEVTREE_HARDWARE_FIELD 3 + +// TODO: Works only for DEVTREE_FIELD == DEVTREE_HARDWARE_FIELD +char* get_field_from_devtree(int DEVTREE_FIELD) { + int filelen; + char* buf; + if((buf = read_file(_PATH_DEVTREE, &filelen)) == NULL) { + printWarn("read_file: %s: %s:\n", _PATH_DEVTREE, strerror(errno)); + return NULL; + } + + // Here we would use strstr to find the comma + // However, the device-tree file may contain NULL + // bytes in the middle of the string, which would + // cause strstr to return NULL even when there might + // be an occurence after the NULL byte + int i=0; + char* tmp1 = buf; + do { + tmp1++; + if(*tmp1 == ',') i++; + } while(filelen > (tmp1-buf) && i < DEVTREE_FIELD); + + tmp1++; + if((tmp1-buf) >= filelen) return NULL; + + int strlen = filelen-(tmp1-buf); + char* hardware = emalloc(sizeof(char) * strlen); + memset(hardware, 0, sizeof(char) * strlen); + strncpy(hardware, tmp1, strlen-1); + + return hardware; +} + +char* get_hardware_from_devtree(void) { + return get_field_from_devtree(DEVTREE_HARDWARE_FIELD); +} diff --git a/src/riscv/udev.h b/src/riscv/udev.h new file mode 100644 index 0000000..343489f --- /dev/null +++ b/src/riscv/udev.h @@ -0,0 +1,10 @@ +#ifndef __UDEV_RISCV__ +#define __UDEV_RISCV__ + +#include "../common/udev.h" + +#define UNKNOWN -1 + +char* get_hardware_from_devtree(void); + +#endif