This commit is contained in:
Dr-Noob
2024-09-17 08:49:51 +01:00
parent 2e2e660b97
commit ef1bfa5cc9
5 changed files with 124 additions and 3 deletions

View File

@@ -1044,6 +1044,62 @@ struct system_on_chip* guess_soc_from_devtree(struct system_on_chip* soc) {
DT_END(dt, len) 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 = ".*"' <soc_vendor> | 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 system_on_chip* guess_soc_from_pci(struct system_on_chip* soc, struct cpuInfo* cpu) {
struct pci_devices * pci = get_pci_devices(); struct pci_devices * pci = get_pci_devices();
if (pci == NULL) { if (pci == NULL) {
@@ -1270,6 +1326,11 @@ struct system_on_chip* get_soc(struct cpuInfo* cpu) {
if(soc->vendor == SOC_VENDOR_UNKNOWN) { if(soc->vendor == SOC_VENDOR_UNKNOWN) {
soc = guess_soc_from_pci(soc, cpu); 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__ #elif defined __APPLE__ || __MACH__
soc = guess_soc_apple(soc); 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->vendor = try_match_soc_vendor_name(processor_name_string);
soc->model = SOC_MODEL_UNKNOWN; soc->model = SOC_MODEL_UNKNOWN;
soc->process = UNKNOWN; soc->process = UNKNOWN;
#else #else
if(soc->model == SOC_MODEL_UNKNOWN) { if(soc->model == SOC_MODEL_UNKNOWN) {
// raw_name might not be NULL, but if we were unable to find // raw_name might not be NULL, but if we were unable to find
// the exact SoC, just print "Unkwnown" // the exact SoC, just print "Unkwnown"
soc->raw_name = emalloc(sizeof(char) * (strlen(STRING_UNKNOWN)+1)); soc->raw_name = emalloc(sizeof(char) * (strlen(STRING_UNKNOWN)+1));
snprintf(soc->raw_name, strlen(STRING_UNKNOWN)+1, STRING_UNKNOWN); snprintf(soc->raw_name, strlen(STRING_UNKNOWN)+1, STRING_UNKNOWN);
} }
#endif #endif
return soc; return soc;

View File

@@ -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 #ifdef _WIN32
VENDOR try_match_soc_vendor_name(char* vendor_name) VENDOR try_match_soc_vendor_name(char* vendor_name)
{ {

View File

@@ -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); 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); 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(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 #ifdef _WIN32
VENDOR try_match_soc_vendor_name(char* vendor_name); VENDOR try_match_soc_vendor_name(char* vendor_name);
#endif #endif

View File

@@ -361,3 +361,49 @@ char* get_devtree_compatible(int *filelen) {
return buf; 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;
}

View File

@@ -31,6 +31,11 @@
#define _PATH_CACHE_MAX_LEN 200 #define _PATH_CACHE_MAX_LEN 200
#define _PATH_PACKAGE_MAX_LEN 200 #define _PATH_PACKAGE_MAX_LEN 200
struct devtree {
char* vendor;
char* model;
}
char* read_file(char* path, int* len); char* read_file(char* path, int* len);
long get_max_freq_from_file(uint32_t core); long get_max_freq_from_file(uint32_t core);
long get_min_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); char* get_field_from_cpuinfo(char* CPUINFO_FIELD);
bool is_devtree_compatible(char* str); bool is_devtree_compatible(char* str);
char* get_devtree_compatible(int *filelen); char* get_devtree_compatible(int *filelen);
struct devtree** get_devtree_compatible_struct(int *num_vendors);
#endif #endif