mirror of
https://github.com/anrieff/libcpuid
synced 2024-11-10 22:59:13 +00:00
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()
This commit is contained in:
parent
8fc0cc0d4a
commit
14cfc77b17
1 changed files with 121 additions and 70 deletions
191
libcpuid/rdmsr.c
191
libcpuid/rdmsr.c
|
@ -465,6 +465,23 @@ int cpu_msrinfo(struct msr_driver_t* driver, cpu_msrinfo_request_t which)
|
||||||
#endif /* Unsupported OS */
|
#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)
|
static int rdmsr_supported(void)
|
||||||
{
|
{
|
||||||
struct cpu_id_t* id = get_cached_cpuid();
|
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,
|
static double get_info_cur_multiplier(struct msr_driver_t* handle, struct cpu_id_t *id,
|
||||||
struct internal_id_info_t *internal)
|
struct internal_id_info_t *internal)
|
||||||
{
|
{
|
||||||
int err, cur_clock;
|
#define IA32_PERF_STATUS 0x198
|
||||||
uint64_t r;
|
int err;
|
||||||
static double bclk = 0.0;
|
uint64_t reg;
|
||||||
|
|
||||||
if(id->vendor == VENDOR_INTEL && internal->code.intel == PENTIUM) {
|
if(id->vendor == VENDOR_INTEL && internal->code.intel == PENTIUM) {
|
||||||
err = cpu_rdmsr(handle, 0x2a, &r);
|
err = cpu_rdmsr(handle, 0x2a, ®);
|
||||||
if (err) return CPU_INVALID_VALUE;
|
if (!err) return (reg>>22) & 0x1f;
|
||||||
return (r>>22) & 0x1f;
|
|
||||||
}
|
}
|
||||||
else if(id->vendor == VENDOR_INTEL && internal->code.intel != PENTIUM) {
|
else if(id->vendor == VENDOR_INTEL && internal->code.intel != PENTIUM) {
|
||||||
if(!bclk)
|
/* Refer links above
|
||||||
bclk = (double) cpu_msrinfo(handle, INFO_BCLK) / 100;
|
Table 35-2. IA-32 Architectural MSRs (Contd.)
|
||||||
if(bclk > 0) {
|
IA32_PERF_STATUS[15:0] is Current performance State Value
|
||||||
cur_clock = cpu_clock_by_ic(10, 4);
|
[7:0] is 0x0, [15:8] looks like current ratio */
|
||||||
if(cur_clock > 0)
|
err = cpu_rdmsr_range(handle, IA32_PERF_STATUS, 15, 8, ®);
|
||||||
return cur_clock / bclk;
|
if (!err) return reg;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return CPU_INVALID_VALUE;
|
return CPU_INVALID_VALUE;
|
||||||
|
#undef IA32_PERF_STATUS
|
||||||
}
|
}
|
||||||
|
|
||||||
static double get_info_max_multiplier(struct msr_driver_t* handle, struct cpu_id_t *id,
|
static double get_info_max_multiplier(struct msr_driver_t* handle, struct cpu_id_t *id,
|
||||||
struct internal_id_info_t *internal)
|
struct internal_id_info_t *internal)
|
||||||
{
|
{
|
||||||
#define PLATFORM_INFO_MSR 206
|
#define MSR_TURBO_RATIO_LIMIT 0x1ad
|
||||||
#define PLATFORM_INFO_MSR_low 8
|
|
||||||
#define PLATFORM_INFO_MSR_high 15
|
|
||||||
int err;
|
int err;
|
||||||
uint64_t val, r;
|
uint64_t reg;
|
||||||
static int multiplier = 0;
|
|
||||||
|
|
||||||
if(id->vendor == VENDOR_INTEL && internal->code.intel == PENTIUM) {
|
if(id->vendor == VENDOR_INTEL && internal->code.intel == PENTIUM) {
|
||||||
err = cpu_rdmsr(handle, 0x198, &r);
|
err = cpu_rdmsr(handle, 0x198, ®);
|
||||||
if (err) return CPU_INVALID_VALUE;
|
if (!err) return (reg >> 40) & 0x1f;
|
||||||
return (r >> 40) & 0x1f;
|
|
||||||
}
|
}
|
||||||
else if(id->vendor == VENDOR_INTEL && internal->code.intel != PENTIUM) {
|
else if(id->vendor == VENDOR_INTEL && internal->code.intel != PENTIUM) {
|
||||||
if(!multiplier) {
|
/* Refer links above
|
||||||
cpu_rdmsr_range(handle, PLATFORM_INFO_MSR, PLATFORM_INFO_MSR_high, PLATFORM_INFO_MSR_low, &val);
|
Table 35-10. Specific MSRs Supported by Intel® Atom™ Processor C2000 Series with CPUID Signature 06_4DH
|
||||||
multiplier = (int) val;
|
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.)
|
||||||
if(multiplier > 0)
|
Table 35-14. Additional MSRs in Intel® Xeon® Processor 5500 and 3400 Series
|
||||||
return multiplier;
|
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;
|
return CPU_INVALID_VALUE;
|
||||||
|
#undef MSR_TURBO_RATIO_LIMIT
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_info_temperature(struct msr_driver_t* handle, struct cpu_id_t *id,
|
static int get_info_temperature(struct msr_driver_t* handle, struct cpu_id_t *id,
|
||||||
struct internal_id_info_t *internal)
|
struct internal_id_info_t *internal)
|
||||||
{
|
{
|
||||||
#define IA32_THERM_STATUS 0x19C
|
#define IA32_THERM_STATUS 0x19C
|
||||||
#define IA32_TEMPERATURE_TARGET 0x1a2
|
#define MSR_TEMPERATURE_TARGET 0x1a2
|
||||||
uint64_t digital_readout, thermal_status, PROCHOT_temp;
|
int err;
|
||||||
|
uint64_t DigitalReadout, ReadingValid, TemperatureTarget;
|
||||||
|
|
||||||
if(id->vendor == VENDOR_INTEL && internal->code.intel != PENTIUM) {
|
if(id->vendor == VENDOR_INTEL && internal->code.intel != PENTIUM) {
|
||||||
// https://github.com/ajaiantilal/i7z/blob/5023138d7c35c4667c938b853e5ea89737334e92/helper_functions.c#L59
|
/* Refer links above
|
||||||
cpu_rdmsr_range(handle, IA32_THERM_STATUS, 23, 16, &digital_readout);
|
Table 35-2. IA-32 Architectural MSRs
|
||||||
cpu_rdmsr_range(handle, IA32_THERM_STATUS, 32, 31, &thermal_status);
|
IA32_THERM_STATUS[22:16] is Digital Readout
|
||||||
cpu_rdmsr_range(handle, IA32_TEMPERATURE_TARGET, 23, 16, &PROCHOT_temp);
|
IA32_THERM_STATUS[31] is Reading Valid
|
||||||
|
|
||||||
// These bits are thermal status : 1 if supported, 0 else
|
Table 35-6. MSRs Common to the Silvermont Microarchitecture and Newer Microarchitectures for Intel® Atom
|
||||||
if(thermal_status)
|
Table 35-13. MSRs in Processors Based on Intel® Microarchitecture Code Name Nehalem (Contd.)
|
||||||
return(PROCHOT_temp - digital_readout); // Temperature is prochot - digital readout
|
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;
|
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,
|
static double get_info_voltage(struct msr_driver_t* handle, struct cpu_id_t *id,
|
||||||
struct internal_id_info_t *internal)
|
struct internal_id_info_t *internal)
|
||||||
{
|
{
|
||||||
#define MSR_PERF_STATUS 0x198
|
#define MSR_PERF_STATUS 0x198
|
||||||
#define MSR_PSTATE_S 0xC0010063
|
#define MSR_PSTATE_S 0xC0010063
|
||||||
#define MSR_PSTATE_0 0xC0010064
|
#define MSR_PSTATE_0 0xC0010064
|
||||||
uint64_t val;
|
int err;
|
||||||
|
uint64_t reg, CpuVid;
|
||||||
|
|
||||||
if(id->vendor == VENDOR_INTEL) {
|
if(id->vendor == VENDOR_INTEL) {
|
||||||
cpu_rdmsr_range(handle, MSR_PERF_STATUS, 47, 32, &val);
|
/* Refer links above
|
||||||
double ret = (double) val / (1 << 13);
|
Table 35-18. MSRs Supported by Intel® Processors based on Intel® microarchitecture code name Sandy Bridge (Contd.)
|
||||||
return (ret > 0) ? ret : CPU_INVALID_VALUE;
|
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) {
|
else if(id->vendor == VENDOR_AMD) {
|
||||||
/* http://support.amd.com/TechDocs/42301_15h_Mod_00h-0Fh_BKDG.pdf
|
/* Refer links above
|
||||||
MSRC001_0063[2:0] = CurPstate
|
MSRC001_00[6B:64][15:9] is CpuVid
|
||||||
MSRC001_00[6B:64][15:9] = CpuVid */
|
MSRC001_0063[2:0] is P-state Status
|
||||||
uint64_t CpuVid;
|
2.4.1.6.3 Serial VID (SVI) Encodings: voltage = 1.550V - 0.0125V * SviVid[6:0] */
|
||||||
cpu_rdmsr_range(handle, MSR_PSTATE_S, 2, 0, &val);
|
err = cpu_rdmsr_range(handle, MSR_PSTATE_S, 2, 0, ®);
|
||||||
if(val <= 7) { // Support 8 P-states
|
err += cpu_rdmsr_range(handle, MSR_PSTATE_0 + reg, 15, 9, &CpuVid);
|
||||||
cpu_rdmsr_range(handle, MSR_PSTATE_0 + val, 15, 9, &CpuVid);
|
if (!err && reg <= 7) return 1.550 - 0.0125 * CpuVid;
|
||||||
return 1.550 - 0.0125 * CpuVid; // 2.4.1.6.3 - Serial VID (SVI) Encodings
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return CPU_INVALID_VALUE;
|
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,
|
static double get_info_bclk(struct msr_driver_t* handle, struct cpu_id_t *id,
|
||||||
struct internal_id_info_t *internal)
|
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)
|
if(clock == 0)
|
||||||
max_clock = cpu_clock_measure(100, 1); // Return the non-Turbo clock
|
clock = cpu_clock_measure(50, 1);
|
||||||
if(!multiplier)
|
|
||||||
multiplier = cpu_msrinfo(handle, INFO_MAX_MULTIPLIER) / 100;
|
if(id->vendor == VENDOR_INTEL) {
|
||||||
if(max_clock > 0 && multiplier > 0)
|
/* Refer links above
|
||||||
return (double) max_clock / multiplier;
|
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;
|
return CPU_INVALID_VALUE;
|
||||||
|
#undef MSR_PLATFORM_INFO
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef MSRINFO_DEFINED
|
#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,
|
int cpu_rdmsr_range(struct msr_driver_t* handle, uint32_t msr_index, uint8_t highbit,
|
||||||
uint8_t lowbit, uint64_t* result)
|
uint8_t lowbit, uint64_t* result)
|
||||||
{
|
{
|
||||||
|
int err;
|
||||||
const uint8_t bits = highbit - lowbit + 1;
|
const uint8_t bits = highbit - lowbit + 1;
|
||||||
|
|
||||||
if(highbit > 63 || lowbit > highbit)
|
if(highbit > 63 || lowbit > highbit)
|
||||||
return set_error(ERR_INVRANGE);
|
return set_error(ERR_INVRANGE);
|
||||||
|
|
||||||
if(cpu_rdmsr(handle, msr_index, result))
|
err = cpu_rdmsr(handle, msr_index, result);
|
||||||
return set_error(ERR_HANDLE_R);
|
|
||||||
|
|
||||||
if(bits < 64) {
|
if(!err && bits < 64) {
|
||||||
/* Show only part of register */
|
/* Show only part of register */
|
||||||
*result >>= lowbit;
|
*result >>= lowbit;
|
||||||
*result &= (1ULL << bits) - 1;
|
*result &= (1ULL << bits) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cpu_msrinfo(struct msr_driver_t* handle, cpu_msrinfo_request_t which)
|
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:
|
case INFO_APERF:
|
||||||
return perfmsr_measure(handle, 0xe8);
|
return perfmsr_measure(handle, 0xe8);
|
||||||
case INFO_CUR_MULTIPLIER:
|
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:
|
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:
|
case INFO_TEMPERATURE:
|
||||||
return get_info_temperature(handle, &id, &internal);
|
return get_info_temperature(handle, &id, &internal);
|
||||||
case INFO_THROTTLING:
|
case INFO_THROTTLING:
|
||||||
return CPU_INVALID_VALUE;
|
return CPU_INVALID_VALUE;
|
||||||
case INFO_VOLTAGE:
|
case INFO_VOLTAGE:
|
||||||
return (int) get_info_voltage(handle, &id, &internal) * 100;
|
return get_info_voltage(handle, &id, &internal) * 100;
|
||||||
case INFO_BCLK:
|
case INFO_BCLK:
|
||||||
return (int) get_info_bclk(handle, &id, &internal) * 100;
|
return get_info_bclk(handle, &id, &internal) * 100;
|
||||||
default:
|
default:
|
||||||
return CPU_INVALID_VALUE;
|
return CPU_INVALID_VALUE;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue