Fixed Issue 387. The new implementation does not try to start a ring 0 driver that already exists, but could not be opened. It tries to delete the driver and install it new. The driver is now stored temporarily in the application folder. The driver is not correctly removed on system shutdown.
3 This Source Code Form is subject to the terms of the Mozilla Public
4 License, v. 2.0. If a copy of the MPL was not distributed with this
5 file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 Copyright (C) 2009-2011 Michael Möller <mmoeller@openhardwaremonitor.org>
12 using System.Collections.Generic;
13 using System.Diagnostics;
14 using System.Globalization;
16 using System.Runtime.InteropServices;
18 using System.Threading;
20 namespace OpenHardwareMonitor.Hardware.CPU {
22 internal sealed class AMD10CPU : AMDCPU {
24 private readonly Sensor coreTemperature;
25 private readonly Sensor[] coreClocks;
26 private readonly Sensor busClock;
28 private const uint PERF_CTL_0 = 0xC0010000;
29 private const uint PERF_CTR_0 = 0xC0010004;
30 private const uint HWCR = 0xC0010015;
31 private const uint P_STATE_0 = 0xC0010064;
32 private const uint COFVID_STATUS = 0xC0010071;
34 private const byte MISCELLANEOUS_CONTROL_FUNCTION = 3;
35 private const ushort FAMILY_10H_MISCELLANEOUS_CONTROL_DEVICE_ID = 0x1203;
36 private const ushort FAMILY_11H_MISCELLANEOUS_CONTROL_DEVICE_ID = 0x1303;
37 private const ushort FAMILY_12H_MISCELLANEOUS_CONTROL_DEVICE_ID = 0x1703;
38 private const ushort FAMILY_14H_MISCELLANEOUS_CONTROL_DEVICE_ID = 0x1703;
39 private const ushort FAMILY_15H_MISCELLANEOUS_CONTROL_DEVICE_ID = 0x1603;
40 private const uint REPORTED_TEMPERATURE_CONTROL_REGISTER = 0xA4;
41 private const uint CLOCK_POWER_TIMING_CONTROL_0_REGISTER = 0xD4;
43 private readonly uint miscellaneousControlAddress;
44 private readonly ushort miscellaneousControlDeviceId;
46 private readonly FileStream temperatureStream;
48 private readonly double timeStampCounterMultiplier;
49 private readonly bool corePerformanceBoostSupport;
51 public AMD10CPU(int processorIndex, CPUID[][] cpuid, ISettings settings)
52 : base(processorIndex, cpuid, settings)
54 // AMD family 1Xh processors support only one temperature sensor
55 coreTemperature = new Sensor(
56 "Core" + (coreCount > 1 ? " #1 - #" + coreCount : ""), 0,
57 SensorType.Temperature, this, new [] {
58 new ParameterDescription("Offset [°C]", "Temperature offset.", 0)
62 case 0x10: miscellaneousControlDeviceId =
63 FAMILY_10H_MISCELLANEOUS_CONTROL_DEVICE_ID; break;
64 case 0x11: miscellaneousControlDeviceId =
65 FAMILY_11H_MISCELLANEOUS_CONTROL_DEVICE_ID; break;
66 case 0x12: miscellaneousControlDeviceId =
67 FAMILY_12H_MISCELLANEOUS_CONTROL_DEVICE_ID; break;
68 case 0x14: miscellaneousControlDeviceId =
69 FAMILY_14H_MISCELLANEOUS_CONTROL_DEVICE_ID; break;
70 case 0x15: miscellaneousControlDeviceId =
71 FAMILY_15H_MISCELLANEOUS_CONTROL_DEVICE_ID; break;
72 default: miscellaneousControlDeviceId = 0; break;
75 // get the pci address for the Miscellaneous Control registers
76 miscellaneousControlAddress = GetPciAddress(
77 MISCELLANEOUS_CONTROL_FUNCTION, miscellaneousControlDeviceId);
79 busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings);
80 coreClocks = new Sensor[coreCount];
81 for (int i = 0; i < coreClocks.Length; i++) {
82 coreClocks[i] = new Sensor(CoreString(i), i + 1, SensorType.Clock,
84 if (HasTimeStampCounter)
85 ActivateSensor(coreClocks[i]);
88 corePerformanceBoostSupport = (cpuid[0][0].ExtData[7, 3] & (1 << 9)) > 0;
90 // set affinity to the first thread for all frequency estimations
91 ulong mask = ThreadAffinity.Set(1UL << cpuid[0][0].Thread);
93 // disable core performance boost
94 uint hwcrEax, hwcrEdx;
95 Ring0.Rdmsr(HWCR, out hwcrEax, out hwcrEdx);
96 if (corePerformanceBoostSupport)
97 Ring0.Wrmsr(HWCR, hwcrEax | (1 << 25), hwcrEdx);
100 Ring0.Rdmsr(PERF_CTL_0, out ctlEax, out ctlEdx);
102 Ring0.Rdmsr(PERF_CTR_0, out ctrEax, out ctrEdx);
104 timeStampCounterMultiplier = estimateTimeStampCounterMultiplier();
106 // restore the performance counter registers
107 Ring0.Wrmsr(PERF_CTL_0, ctlEax, ctlEdx);
108 Ring0.Wrmsr(PERF_CTR_0, ctrEax, ctrEdx);
110 // restore core performance boost
111 if (corePerformanceBoostSupport)
112 Ring0.Wrmsr(HWCR, hwcrEax, hwcrEdx);
114 // restore the thread affinity.
115 ThreadAffinity.Set(mask);
117 // the file reader for lm-sensors support on Linux
118 temperatureStream = null;
119 int p = (int)Environment.OSVersion.Platform;
120 if ((p == 4) || (p == 128)) {
121 string[] devicePaths = Directory.GetDirectories("/sys/class/hwmon/");
122 foreach (string path in devicePaths) {
125 using (StreamReader reader = new StreamReader(path + "/device/name"))
126 name = reader.ReadLine();
127 } catch (IOException) { }
130 temperatureStream = new FileStream(path + "/device/temp1_input",
131 FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
140 private double estimateTimeStampCounterMultiplier() {
141 // preload the function
142 estimateTimeStampCounterMultiplier(0);
143 estimateTimeStampCounterMultiplier(0);
145 // estimate the multiplier
146 List<double> estimate = new List<double>(3);
147 for (int i = 0; i < 3; i++)
148 estimate.Add(estimateTimeStampCounterMultiplier(0.025));
153 private double estimateTimeStampCounterMultiplier(double timeWindow) {
156 // select event "076h CPU Clocks not Halted" and enable the counter
157 Ring0.Wrmsr(PERF_CTL_0,
158 (1 << 22) | // enable performance counter
159 (1 << 17) | // count events in user mode
160 (1 << 16) | // count events in operating-system mode
163 // set the counter to 0
164 Ring0.Wrmsr(PERF_CTR_0, 0, 0);
166 long ticks = (long)(timeWindow * Stopwatch.Frequency);
167 uint lsbBegin, msbBegin, lsbEnd, msbEnd;
169 long timeBegin = Stopwatch.GetTimestamp() +
170 (long)Math.Ceiling(0.001 * ticks);
171 long timeEnd = timeBegin + ticks;
172 while (Stopwatch.GetTimestamp() < timeBegin) { }
173 Ring0.Rdmsr(PERF_CTR_0, out lsbBegin, out msbBegin);
175 while (Stopwatch.GetTimestamp() < timeEnd) { }
176 Ring0.Rdmsr(PERF_CTR_0, out lsbEnd, out msbEnd);
177 Ring0.Rdmsr(COFVID_STATUS, out eax, out edx);
178 double coreMultiplier = GetCoreMultiplier(eax);
180 ulong countBegin = ((ulong)msbBegin << 32) | lsbBegin;
181 ulong countEnd = ((ulong)msbEnd << 32) | lsbEnd;
183 double coreFrequency = 1e-6 *
184 (((double)(countEnd - countBegin)) * Stopwatch.Frequency) /
185 (timeEnd - timeBegin);
187 double busFrequency = coreFrequency / coreMultiplier;
189 return 0.25 * Math.Round(4 * TimeStampCounterFrequency / busFrequency);
192 protected override uint[] GetMSRs() {
193 return new uint[] { PERF_CTL_0, PERF_CTR_0, HWCR, P_STATE_0,
197 public override string GetReport() {
198 StringBuilder r = new StringBuilder();
199 r.Append(base.GetReport());
201 r.Append("Miscellaneous Control Address: 0x");
202 r.AppendLine((miscellaneousControlAddress).ToString("X",
203 CultureInfo.InvariantCulture));
204 r.Append("Time Stamp Counter Multiplier: ");
205 r.AppendLine(timeStampCounterMultiplier.ToString(
206 CultureInfo.InvariantCulture));
207 if (family == 0x14) {
209 Ring0.ReadPciConfig(miscellaneousControlAddress,
210 CLOCK_POWER_TIMING_CONTROL_0_REGISTER, out value);
211 r.Append("PCI Register D18F3xD4: ");
212 r.AppendLine(value.ToString("X8", CultureInfo.InvariantCulture));
219 private double GetCoreMultiplier(uint cofvidEax) {
224 // 8:6 CpuDid: current core divisor ID
225 // 5:0 CpuFid: current core frequency ID
226 uint cpuDid = (cofvidEax >> 6) & 7;
227 uint cpuFid = cofvidEax & 0x1F;
228 return 0.5 * (cpuFid + 0x10) / (1 << (int)cpuDid);
231 // 8:4 CpuFid: current CPU core frequency ID
232 // 3:0 CpuDid: current CPU core divisor ID
233 uint cpuFid = (cofvidEax >> 4) & 0x1F;
234 uint cpuDid = cofvidEax & 0xF;
237 case 0: divisor = 1; break;
238 case 1: divisor = 1.5; break;
239 case 2: divisor = 2; break;
240 case 3: divisor = 3; break;
241 case 4: divisor = 4; break;
242 case 5: divisor = 6; break;
243 case 6: divisor = 8; break;
244 case 7: divisor = 12; break;
245 case 8: divisor = 16; break;
246 default: divisor = 1; break;
248 return (cpuFid + 0x10) / divisor;
251 // 8:4: current CPU core divisor ID most significant digit
252 // 3:0: current CPU core divisor ID least significant digit
253 uint divisorIdMSD = (cofvidEax >> 4) & 0x1F;
254 uint divisorIdLSD = cofvidEax & 0xF;
256 Ring0.ReadPciConfig(miscellaneousControlAddress,
257 CLOCK_POWER_TIMING_CONTROL_0_REGISTER, out value);
258 uint frequencyId = value & 0x1F;
259 return (frequencyId + 0x10) /
260 (divisorIdMSD + (divisorIdLSD * 0.25) + 1);
267 private string ReadFirstLine(Stream stream) {
268 StringBuilder sb = new StringBuilder();
270 stream.Seek(0, SeekOrigin.Begin);
271 int b = stream.ReadByte();
272 while (b != -1 && b != 10) {
274 b = stream.ReadByte();
277 return sb.ToString();
280 public override void Update() {
283 if (temperatureStream == null) {
284 if (miscellaneousControlAddress != Ring0.InvalidPciAddress) {
286 if (Ring0.ReadPciConfig(miscellaneousControlAddress,
287 REPORTED_TEMPERATURE_CONTROL_REGISTER, out value)) {
288 if (family == 0x15 && (value & 0x30000) == 0x30000) {
289 coreTemperature.Value = ((value >> 21) & 0x7FC) / 8.0f +
290 coreTemperature.Parameters[0].Value - 49;
292 coreTemperature.Value = ((value >> 21) & 0x7FF) / 8.0f +
293 coreTemperature.Parameters[0].Value;
295 ActivateSensor(coreTemperature);
297 DeactivateSensor(coreTemperature);
301 string s = ReadFirstLine(temperatureStream);
303 coreTemperature.Value = 0.001f *
304 long.Parse(s, CultureInfo.InvariantCulture);
305 ActivateSensor(coreTemperature);
307 DeactivateSensor(coreTemperature);
311 if (HasTimeStampCounter) {
312 double newBusClock = 0;
314 for (int i = 0; i < coreClocks.Length; i++) {
318 if (Ring0.RdmsrTx(COFVID_STATUS, out curEax, out curEdx,
319 1UL << cpuid[i][0].Thread))
322 multiplier = GetCoreMultiplier(curEax);
324 coreClocks[i].Value =
325 (float)(multiplier * TimeStampCounterFrequency /
326 timeStampCounterMultiplier);
328 (float)(TimeStampCounterFrequency / timeStampCounterMultiplier);
330 coreClocks[i].Value = (float)TimeStampCounterFrequency;
334 if (newBusClock > 0) {
335 this.busClock.Value = (float)newBusClock;
336 ActivateSensor(this.busClock);
341 public override void Close() {
342 if (temperatureStream != null) {
343 temperatureStream.Close();