From ef1bfa5cc9659ef18318b8de812cb51eef3b891d Mon Sep 17 00:00:00 2001 From: Dr-Noob Date: Tue, 17 Sep 2024 08:49:51 +0100 Subject: [PATCH] WIP --- src/arm/soc.c | 64 ++++++++++++++++++++++++++++++++++++++++++++--- src/common/soc.c | 10 ++++++++ src/common/soc.h | 1 + src/common/udev.c | 46 ++++++++++++++++++++++++++++++++++ src/common/udev.h | 6 +++++ 5 files changed, 124 insertions(+), 3 deletions(-) diff --git a/src/arm/soc.c b/src/arm/soc.c index 504599d..cc5d2de 100644 --- a/src/arm/soc.c +++ b/src/arm/soc.c @@ -1044,6 +1044,62 @@ struct system_on_chip* guess_soc_from_devtree(struct system_on_chip* soc) { DT_END(dt, len) } +// This function is different from the rest guess_soc_from_xxx, which try infering +// the exact SoC model by matching some string against a list of known values. +// On the other hand, this function will just try to infer the SoC vendor first by +// matching the device tree vendor name (i.e., the first value, before the comma). +// If that is successfull, then it also fills in the SoC name using the string from +// the device tree. +// The critical difference is that this function does not need a LUT to fill in the +// SoC, it just needs to find a known vendor. On the other hand, the detection is +// less powerful since we cannot get the manufacturing process, and the SoC name will +// come directly from the device tree, meaning that it will likely be less precise. +struct system_on_chip* guess_raw_soc_from_devtree(struct system_on_chip* soc) { + int num_vendors; + struct devtree** dt_vendors = get_devtree_compatible_vendors(&num_vendors); + if (dt_vendors == NULL) { + return soc; + } + + typedef struct { + char* compatible; + VENDOR soc_vendor; + } devtreeToVendor; + + // https://elixir.bootlin.com/linux/v6.10.6/source/arch/arm64/boot/dts + // grep -oR --color -E 'compatible = ".*"' | cut -d '=' -f2 | cut -d ',' -f1 | tr -d '"' | sort | uniq -c | sort + // - The following vendors are not included because they dont seem to be present in dts: + // SOC_VENDOR_(KIRIN, KUNPENG, GOOGLE, AMPERE). + // - The commented vendors are not included intentionally, because I prefer updating its LUT manually. + devtreeToVendor socFromDevtree[] = { + // {"qcom", SOC_VENDOR_SNAPDRAGON}, + // {"samsung", SOC_VENDOR_EXYNOS}, + // {"brcm", SOC_VENDOR_BROADCOM}, + // {"apple", SOC_VENDOR_APPLE}, + // {"rockchip", SOC_VENDOR_ROCKCHIP}, + // {"nvidia", SOC_VENDOR_NVIDIA}, + {"mediatek", SOC_VENDOR_MEDIATEK}, + {"fsl", SOC_VENDOR_NXP }, + {"nxp", SOC_VENDOR_NXP }, + {"amlogic", SOC_VENDOR_AMLOGIC }, + {"marvell", SOC_VENDOR_MARVELL }, + {NULL, SOC_VENDOR_UNKNOWN } + }; + + int index = 0; + while (socFromDevtree[index].compatible != 0x0) { + for (int i=0; i < num_vendors; i++) { + if (strcmp(socFromDevtree[index].compatible, dt_vendors[i]->vendor) == 0) { + fill_soc_raw(soc, dt_vendors[i]->model, socFromDevtree[index].soc_vendor); + } + } + index++; + } + + printWarn("guess_raw_soc_from_devtree: No device matched the list"); + return soc; +} + struct system_on_chip* guess_soc_from_pci(struct system_on_chip* soc, struct cpuInfo* cpu) { struct pci_devices * pci = get_pci_devices(); if (pci == NULL) { @@ -1270,6 +1326,11 @@ struct system_on_chip* get_soc(struct cpuInfo* cpu) { if(soc->vendor == SOC_VENDOR_UNKNOWN) { soc = guess_soc_from_pci(soc, cpu); } + if (soc->vendor == SOC_VENDOR_UNKNOWN) { + // If we fall here it means all previous functions failed to detect the SoC. + // In such case, try with our last resort. If it also fails, we will just give up + soc = guess_raw_soc_from_devtree(soc); + } } #elif defined __APPLE__ || __MACH__ soc = guess_soc_apple(soc); @@ -1295,16 +1356,13 @@ struct system_on_chip* get_soc(struct cpuInfo* cpu) { soc->vendor = try_match_soc_vendor_name(processor_name_string); soc->model = SOC_MODEL_UNKNOWN; soc->process = UNKNOWN; - #else - if(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); } - #endif return soc; diff --git a/src/common/soc.c b/src/common/soc.c index 5b11263..270c11f 100644 --- a/src/common/soc.c +++ b/src/common/soc.c @@ -79,6 +79,16 @@ void fill_soc(struct system_on_chip* soc, char* soc_name, SOC soc_model, int32_t } } +void fill_soc_raw(struct system_on_chip* soc, char* soc_name, VENDOR vendor) { + soc->model = SOC_MODEL_UNKNOWN; + soc->vendor = vendor; + soc->process = UNK; + + int len = strlen(soc_name) + strlen(soc_trademark_string[soc->vendor]) + 1; + soc->name = emalloc(sizeof(char) * len); + sprintf(soc->name, "%s%s", soc_trademark_string[soc->vendor], soc_name); +} + #ifdef _WIN32 VENDOR try_match_soc_vendor_name(char* vendor_name) { diff --git a/src/common/soc.h b/src/common/soc.h index be9b795..921a7f7 100644 --- a/src/common/soc.h +++ b/src/common/soc.h @@ -51,6 +51,7 @@ VENDOR get_soc_vendor(struct system_on_chip* soc); bool match_soc(struct system_on_chip* soc, char* raw_name, char* expected_name, char* soc_name, SOC soc_model, int32_t process); char* get_str_process(struct system_on_chip* soc); void fill_soc(struct system_on_chip* soc, char* soc_name, SOC soc_model, int32_t process); +void fill_soc_raw(struct system_on_chip* soc, char* soc_name, VENDOR vendor); #ifdef _WIN32 VENDOR try_match_soc_vendor_name(char* vendor_name); #endif diff --git a/src/common/udev.c b/src/common/udev.c index 4683cda..b971da2 100644 --- a/src/common/udev.c +++ b/src/common/udev.c @@ -361,3 +361,49 @@ char* get_devtree_compatible(int *filelen) { return buf; } + +// TODO: +// Returns a list of strings containing the vendors of the compatible +// file from the device tree. In this context, vendor refers to the first +// string of every entry. For instance, given a compatible file with: +// "str1,foo1.str2,foo2" (where . denotes the NULL byte, i.e., the separator), +// then this function will return a list with str1,str2. +struct devtree** get_devtree_compatible_struct(int *num_vendors_ptr) { + int len; + char* dt = get_devtree_compatible(&len); + if (dt == NULL) { + return NULL; + } + + int num_vendors = 0; + char* ptr = dt; + + for (int ptrpos = 0; ptrpos < len; ptrpos = (ptr-dt)) { + ptr = memchr(ptr, '\0', len)+1; + num_vendors++; + } + + struct devtree** vendors = emalloc(sizeof(struct devtree *) * num_vendors); + ptr = dt; + + for (int ptrpos = 0, i = 0; ptrpos < len; ptrpos = (ptr-dt), i++) { + char* comma_ptr = strstr(ptr, ",")-1; + char* end_ptr = memchr(comma_ptr, '\0', ptrpos - len); + + // TODO check NULL + int vendor_str_len = (comma_ptr-ptr)+1; + int model_str_len = (end_ptr-comma_ptr)+1; + + vendors[i] = emalloc(struct devtree); + vendors[i]->vendor = ecalloc(vendor_str_len, sizeof(char)); + vendors[i]->model = ecalloc(model_str_len, sizeof(char)); + + strncpy(vendors[i]->vendor, ptr, vendor_str_len); + strncpy(vendors[i]->model, comma_ptr, model_str_len); + + ptr = memchr(ptr, '\0', len)+1; + } + + *num_vendors_ptr = num_vendors; + return vendors; +} \ No newline at end of file diff --git a/src/common/udev.h b/src/common/udev.h index 92ff1d1..f00b20a 100644 --- a/src/common/udev.h +++ b/src/common/udev.h @@ -31,6 +31,11 @@ #define _PATH_CACHE_MAX_LEN 200 #define _PATH_PACKAGE_MAX_LEN 200 +struct devtree { + char* vendor; + char* model; +} + char* read_file(char* path, int* len); long get_max_freq_from_file(uint32_t core); long get_min_freq_from_file(uint32_t core); @@ -44,5 +49,6 @@ int get_ncores_from_cpuinfo(void); char* get_field_from_cpuinfo(char* CPUINFO_FIELD); bool is_devtree_compatible(char* str); char* get_devtree_compatible(int *filelen); +struct devtree** get_devtree_compatible_struct(int *num_vendors); #endif