[v0.81][ARM][Refactoring] Refactoring and very basic ARM support

This commit is contained in:
Dr-Noob
2020-11-05 13:44:46 +01:00
parent f4f68287aa
commit 4f1722ead6
11 changed files with 504 additions and 311 deletions

179
src/common/cpu.c Executable file
View File

@@ -0,0 +1,179 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdbool.h>
#include "../common/global.h"
#include "cpu.h"
#ifdef ARCH_X86
#include "../x86/uarch.h"
#elif ARCH_ARM
#include "../arm/uarch.h"
#endif
#define STRING_UNKNOWN "Unknown"
#define STRING_YES "Yes"
#define STRING_NO "No"
#define STRING_NONE "None"
#define STRING_MEGAHERZ "MHz"
#define STRING_GIGAHERZ "GHz"
#define STRING_KILOBYTES "KB"
#define STRING_MEGABYTES "MB"
VENDOR get_cpu_vendor(struct cpuInfo* cpu) {
return cpu->cpu_vendor;
}
uint32_t get_nsockets(struct topology* topo) {
return topo->sockets;
}
int64_t get_freq(struct frequency* freq) {
return freq->max;
}
char* get_str_sockets(struct topology* topo) {
char* string = malloc(sizeof(char) * 2);
int32_t sanity_ret = snprintf(string, 2, "%d", topo->sockets);
if(sanity_ret < 0) {
printBug("get_str_sockets: snprintf returned a negative value for input: '%d'", topo->sockets);
return NULL;
}
return string;
}
char* get_str_cpu_name(struct cpuInfo* cpu) {
return cpu->cpu_name;
}
int32_t get_value_as_smallest_unit(char ** str, uint32_t value) {
int32_t sanity_ret;
*str = malloc(sizeof(char)* 11); //8 for digits, 2 for units
if(value/1024 >= 1024)
sanity_ret = snprintf(*str, 10,"%.4g"STRING_MEGABYTES, (double)value/(1<<20));
else
sanity_ret = snprintf(*str, 10,"%.4g"STRING_KILOBYTES, (double)value/(1<<10));
return sanity_ret;
}
// String functions
char* get_str_cache_two(int32_t cache_size, uint32_t physical_cores) {
// 4 for digits, 2 for units, 2 for ' (', 3 digits, 2 for units and 7 for ' Total)'
uint32_t max_size = 4+2 + 2 + 4+2 + 7 + 1;
int32_t sanity_ret;
char* string = malloc(sizeof(char) * max_size);
char* tmp1;
char* tmp2;
int32_t tmp1_len = get_value_as_smallest_unit(&tmp1, cache_size);
int32_t tmp2_len = get_value_as_smallest_unit(&tmp2, cache_size * physical_cores);
if(tmp1_len < 0) {
printBug("get_value_as_smallest_unit: snprintf returned a negative value for input: %d\n", cache_size);
return NULL;
}
if(tmp2_len < 0) {
printBug("get_value_as_smallest_unit: snprintf returned a negative value for input: %d\n", cache_size * physical_cores);
return NULL;
}
uint32_t size = tmp1_len + 2 + tmp2_len + 7 + 1;
sanity_ret = snprintf(string, size, "%s (%s Total)", tmp1, tmp2);
if(sanity_ret < 0) {
printBug("get_str_cache_two: snprintf returned a negative value for input: '%s' and '%s'\n", tmp1, tmp2);
return NULL;
}
free(tmp1);
free(tmp2);
return string;
}
char* get_str_cache_one(int32_t cache_size) {
// 4 for digits, 2 for units, 2 for ' (', 3 digits, 2 for units and 7 for ' Total)'
uint32_t max_size = 4+2 + 1;
int32_t sanity_ret;
char* string = malloc(sizeof(char) * max_size);
char* tmp;
int32_t tmp_len = get_value_as_smallest_unit(&tmp, cache_size);
if(tmp_len < 0) {
printBug("get_value_as_smallest_unit: snprintf returned a negative value for input: %d", cache_size);
return NULL;
}
uint32_t size = tmp_len + 1;
sanity_ret = snprintf(string, size, "%s", tmp);
if(sanity_ret < 0) {
printBug("get_str_cache_one: snprintf returned a negative value for input: '%s'", tmp);
return NULL;
}
free(tmp);
return string;
}
char* get_str_cache(int32_t cache_size, int32_t num_caches) {
if(num_caches > 1)
return get_str_cache_two(cache_size, num_caches);
else
return get_str_cache_one(cache_size);
}
char* get_str_l1i(struct cache* cach) {
return get_str_cache(cach->L1i->size, cach->L1i->num_caches);
}
char* get_str_l1d(struct cache* cach) {
return get_str_cache(cach->L1d->size, cach->L1d->num_caches);
}
char* get_str_l2(struct cache* cach) {
assert(cach->L2->exists);
return get_str_cache(cach->L2->size, cach->L2->num_caches);
}
char* get_str_l3(struct cache* cach) {
if(!cach->L3->exists)
return NULL;
return get_str_cache(cach->L3->size, cach->L3->num_caches);
}
char* get_str_freq(struct frequency* freq) {
//Max 3 digits and 3 for '(M/G)Hz' plus 1 for '\0'
uint32_t size = (4+3+1);
assert(strlen(STRING_UNKNOWN)+1 <= size);
char* string = malloc(sizeof(char)*size);
if(freq->max == UNKNOWN_FREQ)
snprintf(string,strlen(STRING_UNKNOWN)+1,STRING_UNKNOWN);
else if(freq->max >= 1000)
snprintf(string,size,"%.2f"STRING_GIGAHERZ,(float)(freq->max)/1000);
else
snprintf(string,size,"%.2f"STRING_MEGAHERZ,(float)(freq->max));
return string;
}
void free_cache_struct(struct cache* cach) {
for(int i=0; i < 4; i++) free(cach->cach_arr[i]);
free(cach->cach_arr);
free(cach);
}
void free_freq_struct(struct frequency* freq) {
free(freq);
}
void free_hv_struct(struct hypervisor* hv) {
free(hv);
}
void free_cpuinfo_struct(struct cpuInfo* cpu) {
free_uarch_struct(cpu->arch);
free_hv_struct(cpu->hv);
free(cpu->cpu_name);
free(cpu);
}

View File

@@ -68,6 +68,9 @@ struct cpuInfo {
uint32_t maxLevels;
// Max cpuids extended levels
uint32_t maxExtendedLevels;
#else
// Main ID register
uint32_t midr;
#endif
struct uarch* arch;
@@ -104,4 +107,22 @@ struct topology {
#endif
};
VENDOR get_cpu_vendor(struct cpuInfo* cpu);
uint32_t get_nsockets(struct topology* topo);
int64_t get_freq(struct frequency* freq);
char* get_str_sockets(struct topology* topo);
char* get_str_cpu_name(struct cpuInfo* cpu);
char* get_str_aes(struct cpuInfo* cpu);
char* get_str_sha(struct cpuInfo* cpu);
char* get_str_l1i(struct cache* cach);
char* get_str_l1d(struct cache* cach);
char* get_str_l2(struct cache* cach);
char* get_str_l3(struct cache* cach);
char* get_str_freq(struct frequency* freq);
void free_cache_struct(struct cache* cach);
void free_freq_struct(struct frequency* freq);
void free_cpuinfo_struct(struct cpuInfo* cpu);
#endif

View File

@@ -13,7 +13,7 @@
#include "../arm/midr.h"
#endif
static const char* VERSION = "0.8";
static const char* VERSION = "0.81";
void print_help(char *argv[]) {
#ifdef ARCH_X86

View File

@@ -6,6 +6,7 @@
#include "printer.h"
#include "ascii.h"
#include "../common/global.h"
#include "../common/cpu.h"
#ifdef ARCH_X86
#include "../x86/uarch.h"
@@ -49,8 +50,10 @@ enum {
ATTRIBUTE_SOCKETS,
ATTRIBUTE_NCORES,
ATTRIBUTE_NCORES_DUAL,
#ifdef ARCH_X86
ATTRIBUTE_AVX,
ATTRIBUTE_FMA,
#endif
ATTRIBUTE_L1i,
ATTRIBUTE_L1d,
ATTRIBUTE_L2,
@@ -67,8 +70,10 @@ static const char* ATTRIBUTE_FIELDS [] = {
"Sockets:",
"Cores:",
"Cores (Total):",
#ifdef ARCH_X86
"AVX:",
"FMA:",
#endif
"L1i Size:",
"L1d Size:",
"L2 Size:",
@@ -85,8 +90,10 @@ static const int ATTRIBUTE_LIST[] = {
ATTRIBUTE_SOCKETS,
ATTRIBUTE_NCORES,
ATTRIBUTE_NCORES_DUAL,
#ifdef ARCH_X86
ATTRIBUTE_AVX,
ATTRIBUTE_FMA,
#endif
ATTRIBUTE_L1i,
ATTRIBUTE_L1d,
ATTRIBUTE_L2,
@@ -386,8 +393,12 @@ bool print_cpufetch(struct cpuInfo* cpu, struct cache* cach, struct frequency* f
char* max_frequency = get_str_freq(freq);
char* n_cores = get_str_topology(cpu, topo, false);
char* n_cores_dual = get_str_topology(cpu, topo, true);
#ifdef ARCH_X86
char* avx = get_str_avx(cpu);
char* fma = get_str_fma(cpu);
setAttribute(art,ATTRIBUTE_AVX,avx);
setAttribute(art,ATTRIBUTE_FMA,fma);
#endif
char* l1i = get_str_l1i(topo->cach);
char* l1d = get_str_l1d(topo->cach);
char* l2 = get_str_l2(topo->cach);
@@ -399,8 +410,6 @@ bool print_cpufetch(struct cpuInfo* cpu, struct cache* cach, struct frequency* f
setAttribute(art,ATTRIBUTE_TECHNOLOGY,manufacturing_process);
setAttribute(art,ATTRIBUTE_FREQUENCY,max_frequency);
setAttribute(art,ATTRIBUTE_NCORES,n_cores);
setAttribute(art,ATTRIBUTE_AVX,avx);
setAttribute(art,ATTRIBUTE_FMA,fma);
setAttribute(art,ATTRIBUTE_L1i,l1i);
setAttribute(art,ATTRIBUTE_L1d,l1d);
setAttribute(art,ATTRIBUTE_L2,l2);
@@ -428,8 +437,10 @@ bool print_cpufetch(struct cpuInfo* cpu, struct cache* cach, struct frequency* f
free(sockets);
free(n_cores);
free(n_cores_dual);
#ifdef ARCH_X86
free(avx);
free(fma);
#endif
free(l1i);
free(l1d);
free(l2);

View File

@@ -10,8 +10,8 @@
#ifdef ARCH_X86
#include "../x86/cpuid.h"
#else
#include "../arm/cpuid.h"
#endif
#include "../arm/midr.h"
#endif
#define _PATH_SYS_SYSTEM "/sys/devices/system"
#define _PATH_SYS_CPU _PATH_SYS_SYSTEM"/cpu"
@@ -77,3 +77,145 @@ long get_max_freq_from_file() {
long get_min_freq_from_file() {
return get_freq_from_file(_PATH_FREQUENCY_MIN);
}
#ifdef ARCH_ARM
#define UNKNOWN -1
#define _PATH_CPUINFO "/proc/cpuinfo"
#define CPUINFO_CPU_IMPLEMENTER_STR "CPU implementer\t: "
#define CPUINFO_CPU_ARCHITECTURE_STR "CPU architecture: "
#define CPUINFO_CPU_VARIANT_STR "CPU variant\t: "
#define CPUINFO_CPU_PART_STR "CPU part\t: "
#define CPUINFO_CPU_REVISION_STR "CPU revision\t: "
#define CPUINFO_CPU_STRING "processor"
int get_ncores_from_cpuinfo() {
int fd = open(_PATH_CPUINFO, O_RDONLY);
if(fd == -1) {
perror("open");
return UNKNOWN;
}
//File exists, read it
int bytes_read = 0;
int offset = 0;
int block = 128;
char* buf = malloc(sizeof(char)*DEFAULT_FILE_SIZE);
memset(buf, 0, sizeof(char)*DEFAULT_FILE_SIZE);
while ( (bytes_read = read(fd, buf+offset, block)) > 0 ) {
offset += bytes_read;
}
int ncores = 0;
char* tmp = buf;
do {
tmp++;
ncores++;
tmp = strstr(tmp, CPUINFO_CPU_STRING);
} while(tmp != NULL);
free(buf);
if (close(fd) == -1) {
perror("close");
}
return ncores;
}
long parse_cpuinfo_field(char* buf, char* field_str, int field_base) {
char* tmp = strstr(buf, field_str);
if(tmp == NULL) return -1;
tmp += strlen(field_str);
char* end;
errno = 0;
long ret = strtol(tmp, &end, field_base);
if(errno != 0) {
perror("strtol");
return -1;
}
return ret;
}
// https://developer.arm.com/docs/ddi0595/h/aarch32-system-registers/midr
// https://static.docs.arm.com/ddi0595/h/SysReg_xml_v86A-2020-06.pdf
uint32_t get_midr_from_cpuinfo(uint32_t core) {
int fd = open(_PATH_CPUINFO, O_RDONLY);
if(fd == -1) {
perror("open");
return UNKNOWN;
}
//File exists, read it
int bytes_read = 0;
int offset = 0;
int block = 128;
char* buf = malloc(sizeof(char)*DEFAULT_FILE_SIZE);
memset(buf, 0, sizeof(char)*DEFAULT_FILE_SIZE);
while ( (bytes_read = read(fd, buf+offset, block)) > 0 ) {
offset += bytes_read;
}
char* tmp = buf;
uint32_t current_core = 0;
while(core != current_core && tmp != NULL) {
tmp++;
current_core++;
tmp = strstr(tmp, CPUINFO_CPU_STRING);
}
uint32_t cpu_implementer;
uint32_t cpu_architecture;
uint32_t cpu_variant;
uint32_t cpu_part;
uint32_t cpu_revision;
uint32_t midr = 0;
long ret;
if ((ret = parse_cpuinfo_field(tmp, CPUINFO_CPU_IMPLEMENTER_STR, 16)) < 0) {
printf("Failed parsing cpu_implementer\n");
return 0;
}
cpu_implementer = (uint32_t) ret;
if ((ret = parse_cpuinfo_field(tmp, CPUINFO_CPU_ARCHITECTURE_STR, 10)) < 0) {
printf("Failed parsing cpu_architecture\n");
return 0;
}
cpu_architecture = (uint32_t) 0xF; // Why?
if ((ret = parse_cpuinfo_field(tmp, CPUINFO_CPU_VARIANT_STR, 16)) < 0) {
printf("Failed parsing cpu_variant\n");
return 0;
}
cpu_variant = (uint32_t) ret;
if ((ret = parse_cpuinfo_field(tmp, CPUINFO_CPU_PART_STR, 16)) < 0) {
printf("Failed parsing cpu_part\n");
return 0;
}
cpu_part = (uint32_t) ret;
if ((ret = parse_cpuinfo_field(tmp, CPUINFO_CPU_REVISION_STR, 10)) < 0) {
printf("Failed parsing cpu_revision\n");
return 0;
}
cpu_revision = (uint32_t) ret;
midr = midr_set_implementer(midr, cpu_implementer);
midr = midr_set_variant(midr, cpu_variant);
midr = midr_set_architecture(midr, cpu_architecture);
midr = midr_set_part(midr, cpu_part);
midr = midr_set_revision(midr, cpu_revision);
return midr;
}
#endif /* ARCH_ARM */

View File

@@ -1,7 +1,14 @@
#ifndef __UDEV__
#define __UDEV__
#include <stdint.h>
long get_max_freq_from_file();
long get_min_freq_from_file();
#ifdef ARCH_ARM
int get_ncores_from_cpuinfo();
uint32_t get_midr_from_cpuinfo(uint32_t core);
#endif
#endif