From 77575736dd87707cfffa87f14fa789b6c7f04c60 Mon Sep 17 00:00:00 2001 From: Xorg Date: Fri, 27 May 2016 14:02:24 +0200 Subject: [PATCH 01/15] Move code from cpu_msrinfo() in subfunctions --- libcpuid/rdmsr.c | 195 ++++++++++++++++++++++++++--------------------- 1 file changed, 108 insertions(+), 87 deletions(-) diff --git a/libcpuid/rdmsr.c b/libcpuid/rdmsr.c index 3dbf7c0..c05bbb5 100644 --- a/libcpuid/rdmsr.c +++ b/libcpuid/rdmsr.c @@ -485,18 +485,115 @@ static int perfmsr_measure(struct msr_driver_t* handle, int msr) return (int) ((y - x) / (b - a)); } -#ifndef MSRINFO_DEFINED +static double get_info_cur_multiplier(struct msr_driver_t* handle) +{ + int err, cur_clock; + uint64_t r; + static double bclk = 0.0; -#define IA32_THERM_STATUS 0x19C -#define IA32_TEMPERATURE_TARGET 0x1a2 -#define IA32_PACKAGE_THERM_STATUS 0x1b1 -#define MSR_PERF_STATUS 0x198 -#define MSR_TURBO_RATIO_LIMIT 429 + if(cpuid_get_vendor() == VENDOR_INTEL) { + if(!bclk) + bclk = (double) cpu_msrinfo(handle, INFO_BCLK) / 100; + if(bclk > 0) { + cur_clock = cpu_clock_by_ic(10, 4); + if(cur_clock > 0) + return cur_clock / bclk; + } + } + + err = cpu_rdmsr(handle, 0x2a, &r); + if (err) return CPU_INVALID_VALUE; + return (r>>22) & 0x1f; +} + +static double get_info_max_multiplier(struct msr_driver_t* handle) +{ #define PLATFORM_INFO_MSR 206 #define PLATFORM_INFO_MSR_low 8 #define PLATFORM_INFO_MSR_high 15 + int err; + uint64_t val, r; + static int multiplier = 0; + + if(cpuid_get_vendor() == VENDOR_INTEL) { + if(!multiplier) { + cpu_rdmsr_range(handle, PLATFORM_INFO_MSR, PLATFORM_INFO_MSR_high, PLATFORM_INFO_MSR_low, &val); + multiplier = (int) val; + } + if(multiplier > 0) + return multiplier; + } + + err = cpu_rdmsr(handle, 0x198, &r); + if (err) return CPU_INVALID_VALUE; + return (r >> 40) & 0x1f; +} + +static int get_info_temperature(struct msr_driver_t* handle) +{ +#define IA32_THERM_STATUS 0x19C +#define IA32_TEMPERATURE_TARGET 0x1a2 + uint64_t digital_readout, thermal_status, PROCHOT_temp; + + if(cpuid_get_vendor() == VENDOR_INTEL) { + // https://github.com/ajaiantilal/i7z/blob/5023138d7c35c4667c938b853e5ea89737334e92/helper_functions.c#L59 + cpu_rdmsr_range(handle, IA32_THERM_STATUS, 23, 16, &digital_readout); + cpu_rdmsr_range(handle, IA32_THERM_STATUS, 32, 31, &thermal_status); + cpu_rdmsr_range(handle, IA32_TEMPERATURE_TARGET, 23, 16, &PROCHOT_temp); + + // These bits are thermal status : 1 if supported, 0 else + if(thermal_status) + return(PROCHOT_temp - digital_readout); // Temperature is prochot - digital readout + } + + return CPU_INVALID_VALUE; +} + +static double get_info_voltage(struct msr_driver_t* handle) +{ +#define MSR_PERF_STATUS 0x198 #define MSR_PSTATE_S 0xC0010063 #define MSR_PSTATE_0 0xC0010064 + uint64_t val; + + if(cpuid_get_vendor() == VENDOR_INTEL) { + cpu_rdmsr_range(handle, MSR_PERF_STATUS, 47, 32, &val); + double ret = (double) val / (1 << 13); + return (ret > 0) ? ret : CPU_INVALID_VALUE; + } + else if(cpuid_get_vendor() == VENDOR_AMD) { + /* http://support.amd.com/TechDocs/42301_15h_Mod_00h-0Fh_BKDG.pdf + MSRC001_0063[2:0] = CurPstate + MSRC001_00[6B:64][15:9] = CpuVid */ + uint64_t CpuVid; + cpu_rdmsr_range(handle, MSR_PSTATE_S, 2, 0, &val); + if(val <= 7) { // Support 8 P-states + cpu_rdmsr_range(handle, MSR_PSTATE_0 + val, 15, 9, &CpuVid); + return 1.550 - 0.0125 * CpuVid; // 2.4.1.6.3 - Serial VID (SVI) Encodings + } + } + + return CPU_INVALID_VALUE; +} + +static double get_info_bclk(struct msr_driver_t* handle) +{ + static int max_clock = 0, multiplier = 0; + + if(!max_clock) + max_clock = cpu_clock_measure(100, 1); // Return the non-Turbo clock + if(!multiplier) + multiplier = cpu_msrinfo(handle, INFO_MAX_MULTIPLIER) / 100; + if(max_clock > 0 && multiplier > 0) + return (double) max_clock / multiplier; + + return CPU_INVALID_VALUE; +} + +#ifndef MSRINFO_DEFINED + +#define IA32_PACKAGE_THERM_STATUS 0x1b1 +#define MSR_TURBO_RATIO_LIMIT 429 int cpu_rdmsr_range(struct msr_driver_t* handle, uint32_t msr_index, uint8_t highbit, uint8_t lowbit, uint64_t* result) @@ -520,13 +617,6 @@ int cpu_rdmsr_range(struct msr_driver_t* handle, uint32_t msr_index, uint8_t hig int cpu_msrinfo(struct msr_driver_t* handle, cpu_msrinfo_request_t which) { - uint64_t r; - int err, cur_clock; - static int max_clock = 0, multiplier = 0; - static double bclk = 0.0; - uint64_t val; - int digital_readout, thermal_status, PROCHOT_temp; - if (handle == NULL) return set_error(ERR_HANDLE); switch (which) { @@ -535,86 +625,17 @@ int cpu_msrinfo(struct msr_driver_t* handle, cpu_msrinfo_request_t which) case INFO_APERF: return perfmsr_measure(handle, 0xe8); case INFO_CUR_MULTIPLIER: - { - if(cpuid_get_vendor() == VENDOR_INTEL) - { - if(!bclk) - bclk = (double) cpu_msrinfo(handle, INFO_BCLK) / 100; - if(bclk > 0) - { - cur_clock = cpu_clock_by_ic(10, 4); - if(cur_clock > 0) - return (int) (cur_clock / bclk * 100); - } - } - err = cpu_rdmsr(handle, 0x2a, &r); - if (err) return CPU_INVALID_VALUE; - return (int) ((r>>22) & 0x1f) * 100; - } + return (int) get_info_cur_multiplier(handle) * 100; case INFO_MAX_MULTIPLIER: - { - if(cpuid_get_vendor() == VENDOR_INTEL) - { - if(!multiplier) { - cpu_rdmsr_range(handle, PLATFORM_INFO_MSR, PLATFORM_INFO_MSR_high, PLATFORM_INFO_MSR_low, &val); - multiplier = (int) val; - } - if(multiplier > 0) - return multiplier * 100; - } - err = cpu_rdmsr(handle, 0x198, &r); - if (err) return CPU_INVALID_VALUE; - return (int) ((r >> 40) & 0x1f) * 100; - } + return (int) get_info_max_multiplier(handle) * 100; case INFO_TEMPERATURE: - if(cpuid_get_vendor() == VENDOR_INTEL) - { - // https://github.com/ajaiantilal/i7z/blob/5023138d7c35c4667c938b853e5ea89737334e92/helper_functions.c#L59 - - cpu_rdmsr_range(handle, IA32_THERM_STATUS, 23, 16, &digital_readout); - cpu_rdmsr_range(handle, IA32_THERM_STATUS, 32, 31, &thermal_status); - cpu_rdmsr_range(handle, IA32_TEMPERATURE_TARGET, 23, 16, &PROCHOT_temp); - - // These bits are thermal status : 1 if supported, 0 else - if(thermal_status) - return(PROCHOT_temp - digital_readout); // Temperature is prochot - digital readout - } - return CPU_INVALID_VALUE; + return get_info_temperature(handle); case INFO_THROTTLING: return CPU_INVALID_VALUE; case INFO_VOLTAGE: - { - if(cpuid_get_vendor() == VENDOR_INTEL) - { - cpu_rdmsr_range(handle, MSR_PERF_STATUS, 47, 32, &val); - double ret = (double) val / (1 << 13); - return (ret > 0) ? (int) (ret * 100) : CPU_INVALID_VALUE; - } - else if(cpuid_get_vendor() == VENDOR_AMD) - { - /* http://support.amd.com/TechDocs/42301_15h_Mod_00h-0Fh_BKDG.pdf - MSRC001_0063[2:0] = CurPstate - MSRC001_00[6B:64][15:9] = CpuVid */ - uint64_t CpuVid; - cpu_rdmsr_range(handle, MSR_PSTATE_S, 2, 0, &val); - if(val <= 7) { // Support 8 P-states - cpu_rdmsr_range(handle, MSR_PSTATE_0 + val, 15, 9, &CpuVid); - return (int) (1.550 - 0.0125 * CpuVid) * 100; // 2.4.1.6.3 - Serial VID (SVI) Encodings - } - } - return CPU_INVALID_VALUE; - } + return (int) get_info_voltage(handle) * 100; case INFO_BCLK: - { - if(!max_clock) - max_clock = cpu_clock_measure(100, 1); // Return the non-Turbo clock - if(!multiplier) - multiplier = cpu_msrinfo(handle, INFO_MAX_MULTIPLIER) / 100; - if(max_clock > 0 && multiplier > 0) - return (int) ((double) max_clock / multiplier * 100); - - return CPU_INVALID_VALUE; - } + return (int) get_info_bclk(handle) * 100; default: return CPU_INVALID_VALUE; } From 54675046808d050ed880937e20150bbe923078a9 Mon Sep 17 00:00:00 2001 From: Xorg Date: Fri, 3 Jun 2016 15:58:45 +0200 Subject: [PATCH 02/15] Use cpu_ident_internal() in cpu_msrinfo() --- libcpuid/rdmsr.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/libcpuid/rdmsr.c b/libcpuid/rdmsr.c index c05bbb5..905fe6a 100644 --- a/libcpuid/rdmsr.c +++ b/libcpuid/rdmsr.c @@ -29,6 +29,7 @@ #include "libcpuid.h" #include "asm-bits.h" #include "libcpuid_util.h" +#include "libcpuid_internal.h" #include "rdtsc.h" #if defined (__linux__) || defined (__gnu_linux__) @@ -485,7 +486,7 @@ static int perfmsr_measure(struct msr_driver_t* handle, int msr) return (int) ((y - x) / (b - a)); } -static double get_info_cur_multiplier(struct msr_driver_t* handle) +static double get_info_cur_multiplier(struct msr_driver_t* handle, struct internal_id_info_t *internal) { int err, cur_clock; uint64_t r; @@ -506,7 +507,7 @@ static double get_info_cur_multiplier(struct msr_driver_t* handle) return (r>>22) & 0x1f; } -static double get_info_max_multiplier(struct msr_driver_t* handle) +static double get_info_max_multiplier(struct msr_driver_t* handle, struct internal_id_info_t *internal) { #define PLATFORM_INFO_MSR 206 #define PLATFORM_INFO_MSR_low 8 @@ -529,7 +530,7 @@ static double get_info_max_multiplier(struct msr_driver_t* handle) return (r >> 40) & 0x1f; } -static int get_info_temperature(struct msr_driver_t* handle) +static int get_info_temperature(struct msr_driver_t* handle, struct internal_id_info_t *internal) { #define IA32_THERM_STATUS 0x19C #define IA32_TEMPERATURE_TARGET 0x1a2 @@ -549,7 +550,7 @@ static int get_info_temperature(struct msr_driver_t* handle) return CPU_INVALID_VALUE; } -static double get_info_voltage(struct msr_driver_t* handle) +static double get_info_voltage(struct msr_driver_t* handle, struct internal_id_info_t *internal) { #define MSR_PERF_STATUS 0x198 #define MSR_PSTATE_S 0xC0010063 @@ -576,7 +577,7 @@ static double get_info_voltage(struct msr_driver_t* handle) return CPU_INVALID_VALUE; } -static double get_info_bclk(struct msr_driver_t* handle) +static double get_info_bclk(struct msr_driver_t* handle, struct internal_id_info_t *internal) { static int max_clock = 0, multiplier = 0; @@ -617,6 +618,15 @@ int cpu_rdmsr_range(struct msr_driver_t* handle, uint32_t msr_index, uint8_t hig int cpu_msrinfo(struct msr_driver_t* handle, cpu_msrinfo_request_t which) { + struct cpu_raw_data_t raw; + struct cpu_id_t id; + static struct internal_id_info_t internal = { .score = -1 }; + + if(internal.score == -1) { + cpuid_get_raw_data(&raw); + cpu_ident_internal(&raw, &id, &internal); + } + if (handle == NULL) return set_error(ERR_HANDLE); switch (which) { @@ -625,17 +635,17 @@ int cpu_msrinfo(struct msr_driver_t* handle, cpu_msrinfo_request_t which) case INFO_APERF: return perfmsr_measure(handle, 0xe8); case INFO_CUR_MULTIPLIER: - return (int) get_info_cur_multiplier(handle) * 100; + return (int) get_info_cur_multiplier(handle, &internal) * 100; case INFO_MAX_MULTIPLIER: - return (int) get_info_max_multiplier(handle) * 100; + return (int) get_info_max_multiplier(handle, &internal) * 100; case INFO_TEMPERATURE: - return get_info_temperature(handle); + return get_info_temperature(handle, &internal); case INFO_THROTTLING: return CPU_INVALID_VALUE; case INFO_VOLTAGE: - return (int) get_info_voltage(handle) * 100; + return (int) get_info_voltage(handle, &internal) * 100; case INFO_BCLK: - return (int) get_info_bclk(handle) * 100; + return (int) get_info_bclk(handle, &internal) * 100; default: return CPU_INVALID_VALUE; } From 1ef4615d8f06513ea948cb35b007846786ea7670 Mon Sep 17 00:00:00 2001 From: Xorg Date: Sat, 4 Jun 2016 13:16:41 +0200 Subject: [PATCH 03/15] Use cpu_id_t in cpu_msrinfo() It can be useful to have more informations on CPU --- libcpuid/rdmsr.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/libcpuid/rdmsr.c b/libcpuid/rdmsr.c index 905fe6a..19c4236 100644 --- a/libcpuid/rdmsr.c +++ b/libcpuid/rdmsr.c @@ -486,7 +486,8 @@ static int perfmsr_measure(struct msr_driver_t* handle, int msr) return (int) ((y - x) / (b - a)); } -static double get_info_cur_multiplier(struct msr_driver_t* handle, struct internal_id_info_t *internal) +static double get_info_cur_multiplier(struct msr_driver_t* handle, struct cpu_id_t *id, + struct internal_id_info_t *internal) { int err, cur_clock; uint64_t r; @@ -507,7 +508,8 @@ static double get_info_cur_multiplier(struct msr_driver_t* handle, struct intern return (r>>22) & 0x1f; } -static double get_info_max_multiplier(struct msr_driver_t* handle, struct internal_id_info_t *internal) +static double get_info_max_multiplier(struct msr_driver_t* handle, struct cpu_id_t *id, + struct internal_id_info_t *internal) { #define PLATFORM_INFO_MSR 206 #define PLATFORM_INFO_MSR_low 8 @@ -530,7 +532,8 @@ static double get_info_max_multiplier(struct msr_driver_t* handle, struct intern return (r >> 40) & 0x1f; } -static int get_info_temperature(struct msr_driver_t* handle, struct internal_id_info_t *internal) +static int get_info_temperature(struct msr_driver_t* handle, struct cpu_id_t *id, + struct internal_id_info_t *internal) { #define IA32_THERM_STATUS 0x19C #define IA32_TEMPERATURE_TARGET 0x1a2 @@ -550,7 +553,8 @@ static int get_info_temperature(struct msr_driver_t* handle, struct internal_id_ return CPU_INVALID_VALUE; } -static double get_info_voltage(struct msr_driver_t* handle, struct internal_id_info_t *internal) +static double get_info_voltage(struct msr_driver_t* handle, struct cpu_id_t *id, + struct internal_id_info_t *internal) { #define MSR_PERF_STATUS 0x198 #define MSR_PSTATE_S 0xC0010063 @@ -577,7 +581,8 @@ static double get_info_voltage(struct msr_driver_t* handle, struct internal_id_i return CPU_INVALID_VALUE; } -static double get_info_bclk(struct msr_driver_t* handle, struct internal_id_info_t *internal) +static double get_info_bclk(struct msr_driver_t* handle, struct cpu_id_t *id, + struct internal_id_info_t *internal) { static int max_clock = 0, multiplier = 0; @@ -619,33 +624,34 @@ int cpu_rdmsr_range(struct msr_driver_t* handle, uint32_t msr_index, uint8_t hig int cpu_msrinfo(struct msr_driver_t* handle, cpu_msrinfo_request_t which) { struct cpu_raw_data_t raw; - struct cpu_id_t id; + static struct cpu_id_t id; static struct internal_id_info_t internal = { .score = -1 }; - if(internal.score == -1) { + if (handle == NULL) + return set_error(ERR_HANDLE); + + if (internal.score == -1) { cpuid_get_raw_data(&raw); cpu_ident_internal(&raw, &id, &internal); } - if (handle == NULL) - return set_error(ERR_HANDLE); switch (which) { case INFO_MPERF: return perfmsr_measure(handle, 0xe7); case INFO_APERF: return perfmsr_measure(handle, 0xe8); case INFO_CUR_MULTIPLIER: - return (int) get_info_cur_multiplier(handle, &internal) * 100; + return (int) get_info_cur_multiplier(handle, &id, &internal) * 100; case INFO_MAX_MULTIPLIER: - return (int) get_info_max_multiplier(handle, &internal) * 100; + return (int) get_info_max_multiplier(handle, &id, &internal) * 100; case INFO_TEMPERATURE: - return get_info_temperature(handle, &internal); + return get_info_temperature(handle, &id, &internal); case INFO_THROTTLING: return CPU_INVALID_VALUE; case INFO_VOLTAGE: - return (int) get_info_voltage(handle, &internal) * 100; + return (int) get_info_voltage(handle, &id, &internal) * 100; case INFO_BCLK: - return (int) get_info_bclk(handle, &internal) * 100; + return (int) get_info_bclk(handle, &id, &internal) * 100; default: return CPU_INVALID_VALUE; } From 8fc0cc0d4aa4a3e1327ee96d6358533f01277175 Mon Sep 17 00:00:00 2001 From: Xorg Date: Sat, 4 Jun 2016 14:13:24 +0200 Subject: [PATCH 04/15] Use internal code for MSR, replace cpuid_get_vendor() by id->vendor --- libcpuid/rdmsr.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/libcpuid/rdmsr.c b/libcpuid/rdmsr.c index 19c4236..7701629 100644 --- a/libcpuid/rdmsr.c +++ b/libcpuid/rdmsr.c @@ -493,7 +493,12 @@ static double get_info_cur_multiplier(struct msr_driver_t* handle, struct cpu_id uint64_t r; static double bclk = 0.0; - if(cpuid_get_vendor() == VENDOR_INTEL) { + if(id->vendor == VENDOR_INTEL && internal->code.intel == PENTIUM) { + err = cpu_rdmsr(handle, 0x2a, &r); + if (err) return CPU_INVALID_VALUE; + return (r>>22) & 0x1f; + } + else if(id->vendor == VENDOR_INTEL && internal->code.intel != PENTIUM) { if(!bclk) bclk = (double) cpu_msrinfo(handle, INFO_BCLK) / 100; if(bclk > 0) { @@ -503,9 +508,7 @@ static double get_info_cur_multiplier(struct msr_driver_t* handle, struct cpu_id } } - err = cpu_rdmsr(handle, 0x2a, &r); - if (err) return CPU_INVALID_VALUE; - return (r>>22) & 0x1f; + return CPU_INVALID_VALUE; } static double get_info_max_multiplier(struct msr_driver_t* handle, struct cpu_id_t *id, @@ -518,7 +521,12 @@ static double get_info_max_multiplier(struct msr_driver_t* handle, struct cpu_id uint64_t val, r; static int multiplier = 0; - if(cpuid_get_vendor() == VENDOR_INTEL) { + if(id->vendor == VENDOR_INTEL && internal->code.intel == PENTIUM) { + err = cpu_rdmsr(handle, 0x198, &r); + if (err) return CPU_INVALID_VALUE; + return (r >> 40) & 0x1f; + } + else if(id->vendor == VENDOR_INTEL && internal->code.intel != PENTIUM) { if(!multiplier) { cpu_rdmsr_range(handle, PLATFORM_INFO_MSR, PLATFORM_INFO_MSR_high, PLATFORM_INFO_MSR_low, &val); multiplier = (int) val; @@ -527,9 +535,7 @@ static double get_info_max_multiplier(struct msr_driver_t* handle, struct cpu_id return multiplier; } - err = cpu_rdmsr(handle, 0x198, &r); - if (err) return CPU_INVALID_VALUE; - return (r >> 40) & 0x1f; + return CPU_INVALID_VALUE; } static int get_info_temperature(struct msr_driver_t* handle, struct cpu_id_t *id, @@ -539,7 +545,7 @@ static int get_info_temperature(struct msr_driver_t* handle, struct cpu_id_t *id #define IA32_TEMPERATURE_TARGET 0x1a2 uint64_t digital_readout, thermal_status, PROCHOT_temp; - if(cpuid_get_vendor() == VENDOR_INTEL) { + if(id->vendor == VENDOR_INTEL && internal->code.intel != PENTIUM) { // https://github.com/ajaiantilal/i7z/blob/5023138d7c35c4667c938b853e5ea89737334e92/helper_functions.c#L59 cpu_rdmsr_range(handle, IA32_THERM_STATUS, 23, 16, &digital_readout); cpu_rdmsr_range(handle, IA32_THERM_STATUS, 32, 31, &thermal_status); @@ -561,12 +567,12 @@ static double get_info_voltage(struct msr_driver_t* handle, struct cpu_id_t *id, #define MSR_PSTATE_0 0xC0010064 uint64_t val; - if(cpuid_get_vendor() == VENDOR_INTEL) { + if(id->vendor == VENDOR_INTEL) { cpu_rdmsr_range(handle, MSR_PERF_STATUS, 47, 32, &val); double ret = (double) val / (1 << 13); return (ret > 0) ? ret : CPU_INVALID_VALUE; } - else if(cpuid_get_vendor() == VENDOR_AMD) { + else if(id->vendor == VENDOR_AMD) { /* http://support.amd.com/TechDocs/42301_15h_Mod_00h-0Fh_BKDG.pdf MSRC001_0063[2:0] = CurPstate MSRC001_00[6B:64][15:9] = CpuVid */ From 14cfc77b173cefaa716ad8d96726d75b43f9b564 Mon Sep 17 00:00:00 2001 From: Xorg Date: Sat, 4 Jun 2016 17:51:48 +0200 Subject: [PATCH 05/15] Improve/clean code for cpu_msrinfo() * Add AMD and Intel doc links * Use 'return' only if there is no error; on error, the end-function 'return CPU_INVALID_VALUE' is used * Add more comments about MSRs * Simplify a lot of things * Avoid cpu_rdmsr_range() to override cpu_rdmsr() error * Remove int casting in cpu_msrinfo() --- libcpuid/rdmsr.c | 191 ++++++++++++++++++++++++++++++----------------- 1 file changed, 121 insertions(+), 70 deletions(-) diff --git a/libcpuid/rdmsr.c b/libcpuid/rdmsr.c index 7701629..e8461cb 100644 --- a/libcpuid/rdmsr.c +++ b/libcpuid/rdmsr.c @@ -465,6 +465,23 @@ int cpu_msrinfo(struct msr_driver_t* driver, cpu_msrinfo_request_t which) #endif /* Unsupported OS */ +/* Useful links for hackers: +- AMD MSRs: + AMD BIOS and Kernel Developer’s Guide (BKDG) + * AMD Family 10h Processors + http://support.amd.com/TechDocs/31116.pdf + * AMD Family 15h Models 00h-0Fh Processors + http://support.amd.com/TechDocs/42301_15h_Mod_00h-0Fh_BKDG.pdf + * AMD Family 15h Models 30h-3Fh + http://support.amd.com/TechDocs/49125_15h_Models_30h-3Fh_BKDG.pdf + +- Intel MSRs: + Intel® 64 and IA-32 Architectures Software Developer’s Manual + * Volume 3 (3A, 3B, 3C & 3D): System Programming Guide + http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-system-programming-manual-325384.pdf +*/ + + static int rdmsr_supported(void) { struct cpu_id_t* id = get_cached_cpuid(); @@ -489,142 +506,176 @@ static int perfmsr_measure(struct msr_driver_t* handle, int msr) static double get_info_cur_multiplier(struct msr_driver_t* handle, struct cpu_id_t *id, struct internal_id_info_t *internal) { - int err, cur_clock; - uint64_t r; - static double bclk = 0.0; +#define IA32_PERF_STATUS 0x198 + int err; + uint64_t reg; if(id->vendor == VENDOR_INTEL && internal->code.intel == PENTIUM) { - err = cpu_rdmsr(handle, 0x2a, &r); - if (err) return CPU_INVALID_VALUE; - return (r>>22) & 0x1f; + err = cpu_rdmsr(handle, 0x2a, ®); + if (!err) return (reg>>22) & 0x1f; } else if(id->vendor == VENDOR_INTEL && internal->code.intel != PENTIUM) { - if(!bclk) - bclk = (double) cpu_msrinfo(handle, INFO_BCLK) / 100; - if(bclk > 0) { - cur_clock = cpu_clock_by_ic(10, 4); - if(cur_clock > 0) - return cur_clock / bclk; - } + /* Refer links above + Table 35-2. IA-32 Architectural MSRs (Contd.) + IA32_PERF_STATUS[15:0] is Current performance State Value + [7:0] is 0x0, [15:8] looks like current ratio */ + err = cpu_rdmsr_range(handle, IA32_PERF_STATUS, 15, 8, ®); + if (!err) return reg; } return CPU_INVALID_VALUE; +#undef IA32_PERF_STATUS } static double get_info_max_multiplier(struct msr_driver_t* handle, struct cpu_id_t *id, struct internal_id_info_t *internal) { -#define PLATFORM_INFO_MSR 206 -#define PLATFORM_INFO_MSR_low 8 -#define PLATFORM_INFO_MSR_high 15 +#define MSR_TURBO_RATIO_LIMIT 0x1ad int err; - uint64_t val, r; - static int multiplier = 0; + uint64_t reg; if(id->vendor == VENDOR_INTEL && internal->code.intel == PENTIUM) { - err = cpu_rdmsr(handle, 0x198, &r); - if (err) return CPU_INVALID_VALUE; - return (r >> 40) & 0x1f; + err = cpu_rdmsr(handle, 0x198, ®); + if (!err) return (reg >> 40) & 0x1f; } else if(id->vendor == VENDOR_INTEL && internal->code.intel != PENTIUM) { - if(!multiplier) { - cpu_rdmsr_range(handle, PLATFORM_INFO_MSR, PLATFORM_INFO_MSR_high, PLATFORM_INFO_MSR_low, &val); - multiplier = (int) val; - } - if(multiplier > 0) - return multiplier; + /* Refer links above + Table 35-10. Specific MSRs Supported by Intel® Atom™ Processor C2000 Series with CPUID Signature 06_4DH + Table 35-12. MSRs in Next Generation Intel Atom Processors Based on the Goldmont Microarchitecture (Contd.) + Table 35-13. MSRs in Processors Based on Intel® Microarchitecture Code Name Nehalem (Contd.) + Table 35-14. Additional MSRs in Intel® Xeon® Processor 5500 and 3400 Series + Table 35-16. Additional MSRs Supported by Intel Processors (Based on Intel® Microarchitecture Code Name Westmere) + Table 35-19. MSRs Supported by 2nd Generation Intel® Core™ Processors (Intel® microarchitecture code name Sandy Bridge) + Table 35-21. Selected MSRs Supported by Intel® Xeon® Processors E5 Family (based on Sandy Bridge microarchitecture) + Table 35-28. MSRs Supported by 4th Generation Intel® Core™ Processors (Haswell microarchitecture) (Contd.) + Table 35-30. Additional MSRs Supported by Intel® Xeon® Processor E5 v3 Family + Table 35-33. Additional MSRs Supported by Intel® Core™ M Processors and 5th Generation Intel® Core™ Processors + Table 35-34. Additional MSRs Common to Intel® Xeon® Processor D and Intel Xeon Processors E5 v4 Family Based on the Broadwell Microarchitecture + Table 35-37. Additional MSRs Supported by 6th Generation Intel® Core™ Processors Based on Skylake Microarchitecture + Table 35-40. Selected MSRs Supported by Next Generation Intel® Xeon Phi™ Processors with DisplayFamily_DisplayModel Signature 06_57H + MSR_TURBO_RATIO_LIMIT[7:0] is Maximum Ratio Limit for 1C */ + err = cpu_rdmsr_range(handle, MSR_TURBO_RATIO_LIMIT, 7, 0, ®); + if (!err) return reg; } return CPU_INVALID_VALUE; +#undef MSR_TURBO_RATIO_LIMIT } static int get_info_temperature(struct msr_driver_t* handle, struct cpu_id_t *id, struct internal_id_info_t *internal) { -#define IA32_THERM_STATUS 0x19C -#define IA32_TEMPERATURE_TARGET 0x1a2 - uint64_t digital_readout, thermal_status, PROCHOT_temp; +#define IA32_THERM_STATUS 0x19C +#define MSR_TEMPERATURE_TARGET 0x1a2 + int err; + uint64_t DigitalReadout, ReadingValid, TemperatureTarget; if(id->vendor == VENDOR_INTEL && internal->code.intel != PENTIUM) { - // https://github.com/ajaiantilal/i7z/blob/5023138d7c35c4667c938b853e5ea89737334e92/helper_functions.c#L59 - cpu_rdmsr_range(handle, IA32_THERM_STATUS, 23, 16, &digital_readout); - cpu_rdmsr_range(handle, IA32_THERM_STATUS, 32, 31, &thermal_status); - cpu_rdmsr_range(handle, IA32_TEMPERATURE_TARGET, 23, 16, &PROCHOT_temp); + /* Refer links above + Table 35-2. IA-32 Architectural MSRs + IA32_THERM_STATUS[22:16] is Digital Readout + IA32_THERM_STATUS[31] is Reading Valid - // These bits are thermal status : 1 if supported, 0 else - if(thermal_status) - return(PROCHOT_temp - digital_readout); // Temperature is prochot - digital readout + Table 35-6. MSRs Common to the Silvermont Microarchitecture and Newer Microarchitectures for Intel® Atom + Table 35-13. MSRs in Processors Based on Intel® Microarchitecture Code Name Nehalem (Contd.) + Table 35-18. MSRs Supported by Intel® Processors based on Intel® microarchitecture code name Sandy Bridge (Contd.) + Table 35-24. MSRs Supported by Intel® Xeon® Processors E5 v2 Product Family (based on Ivy Bridge-E microarchitecture) (Contd.) + Table 35-34. Additional MSRs Common to Intel® Xeon® Processor D and Intel Xeon Processors E5 v4 Family Based on the Broadwell Microarchitecture + Table 35-40. Selected MSRs Supported by Next Generation Intel® Xeon Phi™ Processors with DisplayFamily_DisplayModel Signature 06_57H + MSR_TEMPERATURE_TARGET[23:16] is Temperature Target */ + err = cpu_rdmsr_range(handle, IA32_THERM_STATUS, 22, 16, &DigitalReadout); + err += cpu_rdmsr_range(handle, IA32_THERM_STATUS, 31, 31, &ReadingValid); + err += cpu_rdmsr_range(handle, MSR_TEMPERATURE_TARGET, 23, 16, &TemperatureTarget); + if(!err && ReadingValid) return TemperatureTarget - DigitalReadout; } return CPU_INVALID_VALUE; +#undef IA32_THERM_STATUS +#undef MSR_TEMPERATURE_TARGET } static double get_info_voltage(struct msr_driver_t* handle, struct cpu_id_t *id, struct internal_id_info_t *internal) { #define MSR_PERF_STATUS 0x198 -#define MSR_PSTATE_S 0xC0010063 -#define MSR_PSTATE_0 0xC0010064 - uint64_t val; +#define MSR_PSTATE_S 0xC0010063 +#define MSR_PSTATE_0 0xC0010064 + int err; + uint64_t reg, CpuVid; if(id->vendor == VENDOR_INTEL) { - cpu_rdmsr_range(handle, MSR_PERF_STATUS, 47, 32, &val); - double ret = (double) val / (1 << 13); - return (ret > 0) ? ret : CPU_INVALID_VALUE; + /* Refer links above + Table 35-18. MSRs Supported by Intel® Processors based on Intel® microarchitecture code name Sandy Bridge (Contd.) + MSR_PERF_STATUS[47:32] is Core Voltage + P-state core voltage can be computed by MSR_PERF_STATUS[37:32] * (float) 1/(2^13). */ + err = cpu_rdmsr_range(handle, MSR_PERF_STATUS, 47, 32, ®); + if (!err) return (double) reg / (1 << 13); } else if(id->vendor == VENDOR_AMD) { - /* http://support.amd.com/TechDocs/42301_15h_Mod_00h-0Fh_BKDG.pdf - MSRC001_0063[2:0] = CurPstate - MSRC001_00[6B:64][15:9] = CpuVid */ - uint64_t CpuVid; - cpu_rdmsr_range(handle, MSR_PSTATE_S, 2, 0, &val); - if(val <= 7) { // Support 8 P-states - cpu_rdmsr_range(handle, MSR_PSTATE_0 + val, 15, 9, &CpuVid); - return 1.550 - 0.0125 * CpuVid; // 2.4.1.6.3 - Serial VID (SVI) Encodings - } + /* Refer links above + MSRC001_00[6B:64][15:9] is CpuVid + MSRC001_0063[2:0] is P-state Status + 2.4.1.6.3 Serial VID (SVI) Encodings: voltage = 1.550V - 0.0125V * SviVid[6:0] */ + err = cpu_rdmsr_range(handle, MSR_PSTATE_S, 2, 0, ®); + err += cpu_rdmsr_range(handle, MSR_PSTATE_0 + reg, 15, 9, &CpuVid); + if (!err && reg <= 7) return 1.550 - 0.0125 * CpuVid; } return CPU_INVALID_VALUE; +#undef MSR_PERF_STATUS +#undef MSR_PSTATE_S +#undef MSR_PSTATE_0 } static double get_info_bclk(struct msr_driver_t* handle, struct cpu_id_t *id, struct internal_id_info_t *internal) { - static int max_clock = 0, multiplier = 0; +#define MSR_PLATFORM_INFO 0xce + int err; + static int clock = 0; + uint64_t reg; - if(!max_clock) - max_clock = cpu_clock_measure(100, 1); // Return the non-Turbo clock - if(!multiplier) - multiplier = cpu_msrinfo(handle, INFO_MAX_MULTIPLIER) / 100; - if(max_clock > 0 && multiplier > 0) - return (double) max_clock / multiplier; + if(clock == 0) + clock = cpu_clock_measure(50, 1); + + if(id->vendor == VENDOR_INTEL) { + /* Refer links above + Table 35-12. MSRs in Next Generation Intel Atom Processors Based on the Goldmont Microarchitecture + Table 35-13. MSRs in Processors Based on Intel® Microarchitecture Code Name Nehalem + Table 35-18. MSRs Supported by Intel® Processors based on Intel® microarchitecture code name Sandy Bridge (Contd.) + Table 35-23. Additional MSRs Supported by 3rd Generation Intel® Core™ Processors (based on Intel® microarchitecture code name Ivy Bridge) + Table 35-24. MSRs Supported by Intel® Xeon® Processors E5 v2 Product Family (based on Ivy Bridge-E microarchitecture) + Table 35-27. Additional MSRs Supported by Processors based on the Haswell or Haswell-E microarchitectures + Table 35-40. Selected MSRs Supported by Next Generation Intel® Xeon Phi™ Processors with DisplayFamily_DisplayModel Signature 06_57H + MSR_PLATFORM_INFO[15:8] is Maximum Non-Turbo Ratio */ + err = cpu_rdmsr_range(handle, MSR_PLATFORM_INFO, 15, 8, ®); + if (!err) return (double) clock / reg; + } return CPU_INVALID_VALUE; +#undef MSR_PLATFORM_INFO } #ifndef MSRINFO_DEFINED -#define IA32_PACKAGE_THERM_STATUS 0x1b1 -#define MSR_TURBO_RATIO_LIMIT 429 - int cpu_rdmsr_range(struct msr_driver_t* handle, uint32_t msr_index, uint8_t highbit, uint8_t lowbit, uint64_t* result) { + int err; const uint8_t bits = highbit - lowbit + 1; if(highbit > 63 || lowbit > highbit) return set_error(ERR_INVRANGE); - if(cpu_rdmsr(handle, msr_index, result)) - return set_error(ERR_HANDLE_R); + err = cpu_rdmsr(handle, msr_index, result); - if(bits < 64) { + if(!err && bits < 64) { /* Show only part of register */ *result >>= lowbit; *result &= (1ULL << bits) - 1; } - return 0; + return err; } int cpu_msrinfo(struct msr_driver_t* handle, cpu_msrinfo_request_t which) @@ -647,17 +698,17 @@ int cpu_msrinfo(struct msr_driver_t* handle, cpu_msrinfo_request_t which) case INFO_APERF: return perfmsr_measure(handle, 0xe8); case INFO_CUR_MULTIPLIER: - return (int) get_info_cur_multiplier(handle, &id, &internal) * 100; + return get_info_cur_multiplier(handle, &id, &internal) * 100; case INFO_MAX_MULTIPLIER: - return (int) get_info_max_multiplier(handle, &id, &internal) * 100; + return get_info_max_multiplier(handle, &id, &internal) * 100; case INFO_TEMPERATURE: return get_info_temperature(handle, &id, &internal); case INFO_THROTTLING: return CPU_INVALID_VALUE; case INFO_VOLTAGE: - return (int) get_info_voltage(handle, &id, &internal) * 100; + return get_info_voltage(handle, &id, &internal) * 100; case INFO_BCLK: - return (int) get_info_bclk(handle, &id, &internal) * 100; + return get_info_bclk(handle, &id, &internal) * 100; default: return CPU_INVALID_VALUE; } From 24cd11fea99f34697e86675e39748e2e3c81e1d5 Mon Sep 17 00:00:00 2001 From: Xorg Date: Sat, 4 Jun 2016 19:50:21 +0200 Subject: [PATCH 06/15] In cpu_msrinfo(), add experimental support for AMD CPUs for INFO_CUR_MULTIPLIER, INFO_MAX_MULTIPLIER and INFO_BCLK get_amd_multipliers() allow to share a maximum of code --- libcpuid/rdmsr.c | 78 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 62 insertions(+), 16 deletions(-) diff --git a/libcpuid/rdmsr.c b/libcpuid/rdmsr.c index e8461cb..ba3302b 100644 --- a/libcpuid/rdmsr.c +++ b/libcpuid/rdmsr.c @@ -481,6 +481,20 @@ int cpu_msrinfo(struct msr_driver_t* driver, cpu_msrinfo_request_t which) http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-system-programming-manual-325384.pdf */ +/* AMD MSRs addresses */ +#define MSR_PSTATE_L 0xC0010061 +#define MSR_PSTATE_S 0xC0010063 +#define MSR_PSTATE_0 0xC0010064 +#define MSR_PSTATE_7 0xC001006B + +/* Intel MSRs addresses */ +#define IA32_PERF_STATUS 0x198 +#define IA32_THERM_STATUS 0x19C +#define MSR_TURBO_RATIO_LIMIT 0x1AD +#define MSR_TEMPERATURE_TARGET 0x1A2 +#define MSR_PERF_STATUS 0x198 +#define MSR_PLATFORM_INFO 0xCE + static int rdmsr_supported(void) { @@ -503,10 +517,34 @@ static int perfmsr_measure(struct msr_driver_t* handle, int msr) return (int) ((y - x) / (b - a)); } +static int get_amd_multipliers(struct msr_driver_t* handle, struct internal_id_info_t *internal, + uint32_t pstate, uint64_t *multiplier) +{ + int err; + uint64_t CpuFid, CpuDid; + double factor = 2.0; + + if (pstate < MSR_PSTATE_0 || MSR_PSTATE_7 < pstate) + return 1; + + /* Refer links above + Table 299: P-state Definitions + MSRC001_00[6B:64][8:6] is CpuDid + MSRC001_00[6B:64][5:0] is CpuFid + APUs -> 100MHz REFCLK + CPUs -> 200MHz REFCLK */ + if (FUSION_C <= internal->code.amd && internal->code.amd <= FUSION_A) + factor = 1.0; + err = cpu_rdmsr_range(handle, pstate, 5, 0, &CpuFid); + err += cpu_rdmsr_range(handle, pstate, 8, 6, &CpuDid); + *multiplier = ((CpuFid + 0x10) / (1 << CpuDid)) / factor; + + return err; +} + static double get_info_cur_multiplier(struct msr_driver_t* handle, struct cpu_id_t *id, struct internal_id_info_t *internal) { -#define IA32_PERF_STATUS 0x198 int err; uint64_t reg; @@ -522,15 +560,20 @@ static double get_info_cur_multiplier(struct msr_driver_t* handle, struct cpu_id err = cpu_rdmsr_range(handle, IA32_PERF_STATUS, 15, 8, ®); if (!err) return reg; } + else if(id->vendor == VENDOR_AMD) { + /* Refer links above + MSRC001_0063[2:0] is CurPstate */ + err = cpu_rdmsr_range(handle, MSR_PSTATE_S, 2, 0, ®); + err += get_amd_multipliers(handle, internal, MSR_PSTATE_0 + reg, ®); + if (!err) return reg; + } return CPU_INVALID_VALUE; -#undef IA32_PERF_STATUS } static double get_info_max_multiplier(struct msr_driver_t* handle, struct cpu_id_t *id, struct internal_id_info_t *internal) { -#define MSR_TURBO_RATIO_LIMIT 0x1ad int err; uint64_t reg; @@ -557,16 +600,21 @@ static double get_info_max_multiplier(struct msr_driver_t* handle, struct cpu_id err = cpu_rdmsr_range(handle, MSR_TURBO_RATIO_LIMIT, 7, 0, ®); if (!err) return reg; } + else if(id->vendor == VENDOR_AMD) { + /* Refer links above + MSRC001_0064 is Pb0 + Pb0 is highest-performance boosted P-state */ + err = get_amd_multipliers(handle, internal, MSR_PSTATE_0, ®); + if (!err) return reg; + } + return CPU_INVALID_VALUE; -#undef MSR_TURBO_RATIO_LIMIT } static int get_info_temperature(struct msr_driver_t* handle, struct cpu_id_t *id, struct internal_id_info_t *internal) { -#define IA32_THERM_STATUS 0x19C -#define MSR_TEMPERATURE_TARGET 0x1a2 int err; uint64_t DigitalReadout, ReadingValid, TemperatureTarget; @@ -590,16 +638,11 @@ static int get_info_temperature(struct msr_driver_t* handle, struct cpu_id_t *id } return CPU_INVALID_VALUE; -#undef IA32_THERM_STATUS -#undef MSR_TEMPERATURE_TARGET } static double get_info_voltage(struct msr_driver_t* handle, struct cpu_id_t *id, struct internal_id_info_t *internal) { -#define MSR_PERF_STATUS 0x198 -#define MSR_PSTATE_S 0xC0010063 -#define MSR_PSTATE_0 0xC0010064 int err; uint64_t reg, CpuVid; @@ -622,15 +665,11 @@ static double get_info_voltage(struct msr_driver_t* handle, struct cpu_id_t *id, } return CPU_INVALID_VALUE; -#undef MSR_PERF_STATUS -#undef MSR_PSTATE_S -#undef MSR_PSTATE_0 } static double get_info_bclk(struct msr_driver_t* handle, struct cpu_id_t *id, struct internal_id_info_t *internal) { -#define MSR_PLATFORM_INFO 0xce int err; static int clock = 0; uint64_t reg; @@ -651,9 +690,16 @@ static double get_info_bclk(struct msr_driver_t* handle, struct cpu_id_t *id, err = cpu_rdmsr_range(handle, MSR_PLATFORM_INFO, 15, 8, ®); if (!err) return (double) clock / reg; } + else if(id->vendor == VENDOR_AMD) { + /* Refer links above + MSRC001_0061[2:0] is CurPstateLimit + CurPstateLimit is highest-performance non-boosted P-state */ + err = cpu_rdmsr_range(handle, MSR_PSTATE_L, 2, 0, ®); + err += get_amd_multipliers(handle, internal, MSR_PSTATE_0 + reg, ®); + if (!err) return (double) clock / reg; + } return CPU_INVALID_VALUE; -#undef MSR_PLATFORM_INFO } #ifndef MSRINFO_DEFINED From eeb7a6f3c70e94cffc0b3cb162044489eca13590 Mon Sep 17 00:00:00 2001 From: Xorg Date: Sat, 4 Jun 2016 20:11:09 +0200 Subject: [PATCH 07/15] Report CPU minimum multiplier (INFO_MIN_MULTIPLIER) in cpu_msrinfo() --- libcpuid/libcpuid.h | 4 +++- libcpuid/rdmsr.c | 39 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/libcpuid/libcpuid.h b/libcpuid/libcpuid.h index ddd59b6..1eb9105 100644 --- a/libcpuid/libcpuid.h +++ b/libcpuid/libcpuid.h @@ -891,10 +891,12 @@ typedef enum { INFO_APERF, /*!< Actual performance frequency clock. This accumulates the core clock counts when the core is active. */ + INFO_MIN_MULTIPLIER, /*!< Minimum CPU:FSB ratio for this CPU, + multiplied by 100. */ INFO_CUR_MULTIPLIER, /*!< Current CPU:FSB ratio, multiplied by 100. e.g., a CPU:FSB value of 18.5 reads as "1850". */ - INFO_MAX_MULTIPLIER, /*!< Maxumum CPU:FSB ratio for this CPU, + INFO_MAX_MULTIPLIER, /*!< Maximum CPU:FSB ratio for this CPU, multiplied by 100. */ INFO_TEMPERATURE, /*!< The current core temperature in Celsius. */ INFO_THROTTLING, /*!< 1 if the current logical processor is diff --git a/libcpuid/rdmsr.c b/libcpuid/rdmsr.c index ba3302b..1794c3d 100644 --- a/libcpuid/rdmsr.c +++ b/libcpuid/rdmsr.c @@ -542,6 +542,39 @@ static int get_amd_multipliers(struct msr_driver_t* handle, struct internal_id_i return err; } +static double get_info_min_multiplier(struct msr_driver_t* handle, struct cpu_id_t *id, + struct internal_id_info_t *internal) +{ + int err; + uint64_t reg; + + if(id->vendor == VENDOR_INTEL && internal->code.intel) { + /* Refer links above + Table 35-12. MSRs in Next Generation Intel Atom Processors Based on the Goldmont Microarchitecture + Table 35-13. MSRs in Processors Based on Intel® Microarchitecture Code Name Nehalem + Table 35-18. MSRs Supported by Intel® Processors based on Intel® microarchitecture code name Sandy Bridge (Contd.) + Table 35-23. Additional MSRs Supported by 3rd Generation Intel® Core™ Processors (based on Intel® microarchitecture code name Ivy Bridge) + Table 35-24. MSRs Supported by Intel® Xeon® Processors E5 v2 Product Family (based on Ivy Bridge-E microarchitecture) + Table 35-27. Additional MSRs Supported by Processors based on the Haswell or Haswell-E microarchitectures + Table 35-34. Additional MSRs Common to Intel® Xeon® Processor D and Intel Xeon Processors E5 v4 Family Based on the Broadwell Microarchitecture + Table 35-40. Selected MSRs Supported by Next Generation Intel® Xeon Phi™ Processors with DisplayFamily_DisplayModel Signature 06_57H + MSR_PLATFORM_INFO[47:40] is Maximum Efficiency Ratio + Maximum Efficiency Ratio is the minimum ratio that the processor can operates */ + err = cpu_rdmsr_range(handle, MSR_PLATFORM_INFO, 47, 40, ®); + if (!err) return reg; + } + else if(id->vendor == VENDOR_AMD) { + /* Refer links above + MSRC001_0061[6:4] is PstateMaxVal + PstateMaxVal is the lowest-performance non-boosted P-state */ + err = cpu_rdmsr_range(handle, MSR_PSTATE_L, 6, 4, ®); + err += get_amd_multipliers(handle, internal, MSR_PSTATE_0 + reg, ®); + if (!err) return reg; + } + + return CPU_INVALID_VALUE; +} + static double get_info_cur_multiplier(struct msr_driver_t* handle, struct cpu_id_t *id, struct internal_id_info_t *internal) { @@ -603,7 +636,7 @@ static double get_info_max_multiplier(struct msr_driver_t* handle, struct cpu_id else if(id->vendor == VENDOR_AMD) { /* Refer links above MSRC001_0064 is Pb0 - Pb0 is highest-performance boosted P-state */ + Pb0 is the highest-performance boosted P-state */ err = get_amd_multipliers(handle, internal, MSR_PSTATE_0, ®); if (!err) return reg; } @@ -693,7 +726,7 @@ static double get_info_bclk(struct msr_driver_t* handle, struct cpu_id_t *id, else if(id->vendor == VENDOR_AMD) { /* Refer links above MSRC001_0061[2:0] is CurPstateLimit - CurPstateLimit is highest-performance non-boosted P-state */ + CurPstateLimit is the highest-performance non-boosted P-state */ err = cpu_rdmsr_range(handle, MSR_PSTATE_L, 2, 0, ®); err += get_amd_multipliers(handle, internal, MSR_PSTATE_0 + reg, ®); if (!err) return (double) clock / reg; @@ -743,6 +776,8 @@ int cpu_msrinfo(struct msr_driver_t* handle, cpu_msrinfo_request_t which) return perfmsr_measure(handle, 0xe7); case INFO_APERF: return perfmsr_measure(handle, 0xe8); + case INFO_MIN_MULTIPLIER: + return get_info_min_multiplier(handle, &id, &internal) * 100; case INFO_CUR_MULTIPLIER: return get_info_cur_multiplier(handle, &id, &internal) * 100; case INFO_MAX_MULTIPLIER: From 9059fb6ff558b03bcb590281a8b60c98cf789322 Mon Sep 17 00:00:00 2001 From: Xorg Date: Sat, 4 Jun 2016 20:31:01 +0200 Subject: [PATCH 08/15] Add INFO_BUS_CLOCK in cpu_msrinfo() as a more generic term (same as INFO_BCLK) BCLK is specific to Intel --- libcpuid/libcpuid.h | 8 +++++--- libcpuid/rdmsr.c | 7 ++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/libcpuid/libcpuid.h b/libcpuid/libcpuid.h index 1eb9105..7ac2adf 100644 --- a/libcpuid/libcpuid.h +++ b/libcpuid/libcpuid.h @@ -902,9 +902,11 @@ typedef enum { INFO_THROTTLING, /*!< 1 if the current logical processor is throttling. 0 if it is running normally. */ INFO_VOLTAGE, /*!< The current core voltage in Volt, - multiplied by 100. */ - INFO_BCLK, /*!< The BCLK (base clock) in MHz, - multiplied by 100. */ + multiplied by 100. */ + INFO_BCLK, /*!< See \ref INFO_BUS_CLOCK. */ + INFO_BUS_CLOCK, /*!< The main bus clock in MHz, + e.g., FSB/QPI/DMI/HT base clock, + multiplied by 100. */ } cpu_msrinfo_request_t; /** diff --git a/libcpuid/rdmsr.c b/libcpuid/rdmsr.c index 1794c3d..f2ba34c 100644 --- a/libcpuid/rdmsr.c +++ b/libcpuid/rdmsr.c @@ -700,8 +700,8 @@ static double get_info_voltage(struct msr_driver_t* handle, struct cpu_id_t *id, return CPU_INVALID_VALUE; } -static double get_info_bclk(struct msr_driver_t* handle, struct cpu_id_t *id, - struct internal_id_info_t *internal) +static double get_info_bus_clock(struct msr_driver_t* handle, struct cpu_id_t *id, + struct internal_id_info_t *internal) { int err; static int clock = 0; @@ -789,7 +789,8 @@ int cpu_msrinfo(struct msr_driver_t* handle, cpu_msrinfo_request_t which) case INFO_VOLTAGE: return get_info_voltage(handle, &id, &internal) * 100; case INFO_BCLK: - return get_info_bclk(handle, &id, &internal) * 100; + case INFO_BUS_CLOCK: + return get_info_bus_clock(handle, &id, &internal) * 100; default: return CPU_INVALID_VALUE; } From e631e62ce6525fc07ec9f71e0b8a8208b27780b4 Mon Sep 17 00:00:00 2001 From: Xorg Date: Sat, 4 Jun 2016 20:36:58 +0200 Subject: [PATCH 09/15] Silent rules in configure.ac Less useless output to easily see warnings --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index feaf147..c8a3066 100644 --- a/configure.ac +++ b/configure.ac @@ -3,6 +3,7 @@ AC_CONFIG_SRCDIR([libcpuid/libcpuid.h]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE([-Wall dist-bzip2 dist-zip foreign]) +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) dnl Versioning scheme shamelessly copied from libexif. dnl Short walkthrough. C means CURRENT, A mean AGE, R means REVISION From cba9a1e19a417754d0cc3c17d152f85b51fcb59b Mon Sep 17 00:00:00 2001 From: Xorg Date: Sat, 4 Jun 2016 20:52:27 +0200 Subject: [PATCH 10/15] Replace hardcoded addresses by define in cpu_msrinfo() --- libcpuid/rdmsr.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/libcpuid/rdmsr.c b/libcpuid/rdmsr.c index f2ba34c..12df95e 100644 --- a/libcpuid/rdmsr.c +++ b/libcpuid/rdmsr.c @@ -488,8 +488,11 @@ int cpu_msrinfo(struct msr_driver_t* driver, cpu_msrinfo_request_t which) #define MSR_PSTATE_7 0xC001006B /* Intel MSRs addresses */ +#define IA32_MPERF 0xE7 +#define IA32_APERF 0xE8 #define IA32_PERF_STATUS 0x198 #define IA32_THERM_STATUS 0x19C +#define MSR_EBL_CR_POWERON 0x2A #define MSR_TURBO_RATIO_LIMIT 0x1AD #define MSR_TEMPERATURE_TARGET 0x1A2 #define MSR_PERF_STATUS 0x198 @@ -582,7 +585,7 @@ static double get_info_cur_multiplier(struct msr_driver_t* handle, struct cpu_id uint64_t reg; if(id->vendor == VENDOR_INTEL && internal->code.intel == PENTIUM) { - err = cpu_rdmsr(handle, 0x2a, ®); + err = cpu_rdmsr(handle, MSR_EBL_CR_POWERON, ®); if (!err) return (reg>>22) & 0x1f; } else if(id->vendor == VENDOR_INTEL && internal->code.intel != PENTIUM) { @@ -611,7 +614,7 @@ static double get_info_max_multiplier(struct msr_driver_t* handle, struct cpu_id uint64_t reg; if(id->vendor == VENDOR_INTEL && internal->code.intel == PENTIUM) { - err = cpu_rdmsr(handle, 0x198, ®); + err = cpu_rdmsr(handle, IA32_PERF_STATUS, ®); if (!err) return (reg >> 40) & 0x1f; } else if(id->vendor == VENDOR_INTEL && internal->code.intel != PENTIUM) { @@ -641,7 +644,6 @@ static double get_info_max_multiplier(struct msr_driver_t* handle, struct cpu_id if (!err) return reg; } - return CPU_INVALID_VALUE; } @@ -773,9 +775,9 @@ int cpu_msrinfo(struct msr_driver_t* handle, cpu_msrinfo_request_t which) switch (which) { case INFO_MPERF: - return perfmsr_measure(handle, 0xe7); + return perfmsr_measure(handle, IA32_MPERF); case INFO_APERF: - return perfmsr_measure(handle, 0xe8); + return perfmsr_measure(handle, IA32_APERF); case INFO_MIN_MULTIPLIER: return get_info_min_multiplier(handle, &id, &internal) * 100; case INFO_CUR_MULTIPLIER: From 240a862c452f4c89ff25f8c4128ea7de6390c1de Mon Sep 17 00:00:00 2001 From: Xorg Date: Sun, 5 Jun 2016 11:07:00 +0200 Subject: [PATCH 11/15] Fix warnings recog_intel.c:589:22: warning: implicit conversion from enumeration type 'enum _common_codes_t' to different enumeration type 'intel_code_t' (aka 'enum _intel_code_t') recog_amd.c:449:9: warning: implicit conversion from enumeration type 'enum _common_codes_t' to different enumeration type 'amd_code_t' (aka 'enum _amd_code_t') --- libcpuid/recog_amd.c | 2 +- libcpuid/recog_intel.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libcpuid/recog_amd.c b/libcpuid/recog_amd.c index d50ad97..058d0a4 100644 --- a/libcpuid/recog_amd.c +++ b/libcpuid/recog_amd.c @@ -446,7 +446,7 @@ static amd_code_t decode_amd_codename_part1(const char *bs) if (match_pattern(bs, "Z-##")) return FUSION_Z; if (match_pattern(bs, "E#-####") || match_pattern(bs, "A#-####")) return FUSION_EA; - return NO_CODE; + return (amd_code_t) NO_CODE; } static void decode_amd_codename(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct internal_id_info_t* internal) diff --git a/libcpuid/recog_intel.c b/libcpuid/recog_intel.c index bc1c34b..0d56d18 100644 --- a/libcpuid/recog_intel.c +++ b/libcpuid/recog_intel.c @@ -586,7 +586,7 @@ static void decode_intel_number_of_cores(struct cpu_raw_data_t* raw, static intel_code_t get_brand_code(struct cpu_id_t* data) { - intel_code_t code = NO_CODE; + intel_code_t code = (intel_code_t) NO_CODE; int i, need_matchtable = 1, core_ix_base = 0; const char* bs = data->brand_str; const char* s; From 8fda5a74f1f8273c1db1b60bcd7250cb9e313a60 Mon Sep 17 00:00:00 2001 From: Xorg Date: Sun, 5 Jun 2016 12:09:59 +0200 Subject: [PATCH 12/15] Generate and install man-pages if Doxygen is installed --- configure.ac | 2 ++ libcpuid/Makefile.am | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/configure.ac b/configure.ac index c8a3066..55f88fb 100644 --- a/configure.ac +++ b/configure.ac @@ -39,6 +39,8 @@ AM_PROG_LIBTOOL AM_CPPFLAGS="$CPPFLAGS" AC_CHECK_HEADERS([stdint.h]) +AC_CHECK_PROGS([DOXYGEN], [doxygen]) +AM_CONDITIONAL([HAVE_DOXYGEN], [test -n "$DOXYGEN"]) AM_LDFLAGS="$LDFLAGS" if test "x$GCC" = "xyes"; then diff --git a/libcpuid/Makefile.am b/libcpuid/Makefile.am index 2710898..e53b7bc 100644 --- a/libcpuid/Makefile.am +++ b/libcpuid/Makefile.am @@ -33,3 +33,29 @@ noinst_HEADERS = \ rdtsc.h EXTRA_DIST += libcpuid.sym libcpuid_vc71.vcproj libcpuid_vc9.vcproj + +if HAVE_DOXYGEN +directory = $(top_srcdir)/libcpuid/docs/man/man3 + +dist_man_MANS = $(directory)/cpu_id_t.3 \ + $(directory)/cpu_list_t.3 \ + $(directory)/cpu_mark_t.3 \ + $(directory)/cpu_raw_data_t.3 \ + $(directory)/libcpuid.3 +$(directory)/cpu_id_t.3: doxyfile.stamp +$(directory)/cpu_list_t.3: doxyfile.stamp +$(directory)/cpu_mark_t.3: doxyfile.stamp +$(directory)/cpu_raw_data_t.3: doxyfile.stamp +$(directory)/libcpuid.3: doxyfile.stamp + +doxyfile.stamp: + $(DOXYGEN) Doxyfile + echo Timestamp > doxyfile.stamp + +CLEANFILES = doxyfile.stamp + +all-local: doxyfile.stamp + +clean-local: + rm -rf $(top_srcdir)/libcpuid/docs +endif From 462ec75c797b61d317fbd76f3b5420048e459620 Mon Sep 17 00:00:00 2001 From: Xorg Date: Sun, 5 Jun 2016 12:19:49 +0200 Subject: [PATCH 13/15] Fix Doxygen warnings, don't warn if undocmented --- libcpuid/Doxyfile.in | 59 +------------------------------------------- libcpuid/libcpuid.h | 8 +++--- 2 files changed, 5 insertions(+), 62 deletions(-) diff --git a/libcpuid/Doxyfile.in b/libcpuid/Doxyfile.in index e698306..f36f738 100644 --- a/libcpuid/Doxyfile.in +++ b/libcpuid/Doxyfile.in @@ -53,16 +53,6 @@ CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English -# This tag can be used to specify the encoding used in the generated output. -# The encoding is not always determined by the language that is chosen, -# but also whether or not the output is meant for Windows or non-Windows users. -# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES -# forces the Windows encoding (this is the default for the Windows binary), -# whereas setting the tag to NO uses a Unix-style encoding (the default for -# all platforms other than Windows). - -USE_WINDOWS_ENCODING = NO - # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). @@ -148,13 +138,6 @@ JAVADOC_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO -# If the DETAILS_AT_TOP tag is set to YES then Doxygen -# will output the detailed description near the top, like JavaDoc. -# If set to NO, the detailed description appears after the member -# documentation. - -DETAILS_AT_TOP = NO - # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. @@ -383,12 +366,6 @@ MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -# in the documentation. The default is NO. - -SHOW_DIRECTORIES = NO - # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from the # version control system). Doxygen will invoke the program by executing (via @@ -418,7 +395,7 @@ WARNINGS = YES # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. -WARN_IF_UNDOCUMENTED = YES +WARN_IF_UNDOCUMENTED = NO # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some @@ -667,12 +644,6 @@ HTML_FOOTER = HTML_STYLESHEET = -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. - -HTML_ALIGN_MEMBERS = YES - # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) @@ -899,18 +870,6 @@ GENERATE_XML = NO XML_OUTPUT = xml -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that @@ -1187,22 +1146,6 @@ DOT_PATH = DOTFILE_DIRS = -# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width -# (in pixels) of the graphs generated by dot. If a graph becomes larger than -# this value, doxygen will try to truncate the graph, so that it fits within -# the specified constraint. Beware that most browsers cannot cope with very -# large images. - -MAX_DOT_GRAPH_WIDTH = 1024 - -# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height -# (in pixels) of the graphs generated by dot. If a graph becomes larger than -# this value, doxygen will try to truncate the graph, so that it fits within -# the specified constraint. Beware that most browsers cannot cope with very -# large images. - -MAX_DOT_GRAPH_HEIGHT = 1024 - # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes diff --git a/libcpuid/libcpuid.h b/libcpuid/libcpuid.h index 7ac2adf..dc1e338 100644 --- a/libcpuid/libcpuid.h +++ b/libcpuid/libcpuid.h @@ -26,10 +26,10 @@ #ifndef __LIBCPUID_H__ #define __LIBCPUID_H__ /** - * @File libcpuid.h - * @Author Veselin Georgiev - * @Date Oct 2008 - * @Version 0.2.2 + * \file libcpuid.h + * \author Veselin Georgiev + * \date Oct 2008 + * \version 0.2.2 * * Version history: * From 023f0307f0a547577d018b23ad193e514c132cdf Mon Sep 17 00:00:00 2001 From: Xorg Date: Sun, 5 Jun 2016 13:16:15 +0200 Subject: [PATCH 14/15] Minor changes for cpu_msrinfo() --- libcpuid/rdmsr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libcpuid/rdmsr.c b/libcpuid/rdmsr.c index 12df95e..632d592 100644 --- a/libcpuid/rdmsr.c +++ b/libcpuid/rdmsr.c @@ -551,7 +551,7 @@ static double get_info_min_multiplier(struct msr_driver_t* handle, struct cpu_id int err; uint64_t reg; - if(id->vendor == VENDOR_INTEL && internal->code.intel) { + if(id->vendor == VENDOR_INTEL) { /* Refer links above Table 35-12. MSRs in Next Generation Intel Atom Processors Based on the Goldmont Microarchitecture Table 35-13. MSRs in Processors Based on Intel® Microarchitecture Code Name Nehalem @@ -653,7 +653,7 @@ static int get_info_temperature(struct msr_driver_t* handle, struct cpu_id_t *id int err; uint64_t DigitalReadout, ReadingValid, TemperatureTarget; - if(id->vendor == VENDOR_INTEL && internal->code.intel != PENTIUM) { + if(id->vendor == VENDOR_INTEL) { /* Refer links above Table 35-2. IA-32 Architectural MSRs IA32_THERM_STATUS[22:16] is Digital Readout @@ -696,7 +696,7 @@ static double get_info_voltage(struct msr_driver_t* handle, struct cpu_id_t *id, 2.4.1.6.3 Serial VID (SVI) Encodings: voltage = 1.550V - 0.0125V * SviVid[6:0] */ err = cpu_rdmsr_range(handle, MSR_PSTATE_S, 2, 0, ®); err += cpu_rdmsr_range(handle, MSR_PSTATE_0 + reg, 15, 9, &CpuVid); - if (!err && reg <= 7) return 1.550 - 0.0125 * CpuVid; + if (!err && MSR_PSTATE_0 + reg <= MSR_PSTATE_7) return 1.550 - 0.0125 * CpuVid; } return CPU_INVALID_VALUE; From ec445b0a545d92aa629709c50af529d841ac95c6 Mon Sep 17 00:00:00 2001 From: Xorg Date: Sun, 5 Jun 2016 14:10:19 +0200 Subject: [PATCH 15/15] Add load_driver() support for GNU/Linux & FreeBSD in cpu_msr_driver_open_core() --- libcpuid/rdmsr.c | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/libcpuid/rdmsr.c b/libcpuid/rdmsr.c index 632d592..4a2fab2 100644 --- a/libcpuid/rdmsr.c +++ b/libcpuid/rdmsr.c @@ -42,6 +42,21 @@ #include struct msr_driver_t { int fd; }; static int rdmsr_supported(void); +static int load_driver(char *msr_path) +{ + const int file_exists = !access(msr_path, F_OK); + const int file_readable = !access(msr_path, R_OK); + + if (file_exists && file_readable) + return 1; + else if (file_exists && !file_readable) + return 0; + else if (getuid() != 0) + return 0; + else + return !system("modprobe msr 2> /dev/null"); +} + struct msr_driver_t* cpu_msr_driver_open(void) { return cpu_msr_driver_open_core(0); @@ -51,7 +66,7 @@ struct msr_driver_t* cpu_msr_driver_open_core(unsigned core_num) { char msr[32]; struct msr_driver_t* handle; - if (core_num >= cpuid_get_total_cpus()) { + if (core_num >= cpuid_get_total_cpus()) { set_error(ERR_INVCNB); return NULL; } @@ -60,6 +75,10 @@ struct msr_driver_t* cpu_msr_driver_open_core(unsigned core_num) return NULL; } sprintf(msr, "/dev/cpu/%u/msr", core_num); + if(!load_driver(msr)) { + set_error(ERR_NO_DRIVER); + return NULL; + } int fd = open(msr, O_RDONLY); if (fd < 0) { if (errno == EIO) { @@ -107,6 +126,21 @@ int cpu_msr_driver_close(struct msr_driver_t* drv) struct msr_driver_t { int fd; }; static int rdmsr_supported(void); +static int load_driver(char *msr_path) +{ + const int file_exists = !access(msr_path, F_OK); + const int file_readable = !access(msr_path, R_OK); + + if (file_exists && file_readable) + return 1; + else if (file_exists && !file_readable) + return 0; + else if (getuid() != 0) + return 0; + else + return !system("kldload -n cpuctl 2> /dev/null"); +} + struct msr_driver_t* cpu_msr_driver_open(void) { return cpu_msr_driver_open_core(0); @@ -125,6 +159,10 @@ struct msr_driver_t* cpu_msr_driver_open_core(unsigned core_num) return NULL; } sprintf(msr, "/dev/cpuctl%u", core_num); + if(!load_driver(msr)) { + set_error(ERR_NO_DRIVER); + return NULL; + } int fd = open(msr, O_RDONLY); if (fd < 0) { if (errno == EIO) {