Hardware/Ring0.cs
author moel.mich
Sun, 08 May 2011 22:10:13 +0000
changeset 279 6bce967ba1b5
parent 259 d83e927ee9d2
child 281 1c301069cfce
permissions -rw-r--r--
Fixed the bus and core clock reading on AMD family 10h model Ah CPUs. The new "Core Performance Boost" feature of these CPUs resulted in very low accuracy of the bus speed (and as a consequence also an inaccurate TSC multiplier). This fixed Issue 205.
moel@236
     1
/*
moel@236
     2
  
moel@236
     3
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@236
     4
moel@236
     5
  The contents of this file are subject to the Mozilla Public License Version
moel@236
     6
  1.1 (the "License"); you may not use this file except in compliance with
moel@236
     7
  the License. You may obtain a copy of the License at
moel@236
     8
 
moel@236
     9
  http://www.mozilla.org/MPL/
moel@236
    10
moel@236
    11
  Software distributed under the License is distributed on an "AS IS" basis,
moel@236
    12
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@236
    13
  for the specific language governing rights and limitations under the License.
moel@236
    14
moel@236
    15
  The Original Code is the Open Hardware Monitor code.
moel@236
    16
moel@236
    17
  The Initial Developer of the Original Code is 
moel@236
    18
  Michael Möller <m.moeller@gmx.ch>.
moel@254
    19
  Portions created by the Initial Developer are Copyright (C) 2010-2011
moel@236
    20
  the Initial Developer. All Rights Reserved.
moel@236
    21
moel@236
    22
  Contributor(s):
moel@236
    23
moel@236
    24
  Alternatively, the contents of this file may be used under the terms of
moel@236
    25
  either the GNU General Public License Version 2 or later (the "GPL"), or
moel@236
    26
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@236
    27
  in which case the provisions of the GPL or the LGPL are applicable instead
moel@236
    28
  of those above. If you wish to allow use of your version of this file only
moel@236
    29
  under the terms of either the GPL or the LGPL, and not to allow others to
moel@236
    30
  use your version of this file under the terms of the MPL, indicate your
moel@236
    31
  decision by deleting the provisions above and replace them with the notice
moel@236
    32
  and other provisions required by the GPL or the LGPL. If you do not delete
moel@236
    33
  the provisions above, a recipient may use your version of this file under
moel@236
    34
  the terms of any one of the MPL, the GPL or the LGPL.
moel@236
    35
 
moel@236
    36
*/
moel@236
    37
moel@236
    38
using System;
moel@236
    39
using System.IO;
moel@236
    40
using System.Reflection;
moel@236
    41
using System.Runtime.InteropServices;
moel@236
    42
using System.Threading;
moel@254
    43
using System.Text;
moel@236
    44
moel@236
    45
namespace OpenHardwareMonitor.Hardware {
moel@236
    46
  internal static class Ring0 {
moel@236
    47
moel@236
    48
    private static KernelDriver driver;
moel@236
    49
    private static Mutex isaBusMutex;
moel@254
    50
    private static readonly StringBuilder report = new StringBuilder();
moel@236
    51
moel@236
    52
    private const uint OLS_TYPE = 40000;
moel@236
    53
    private static IOControlCode
moel@236
    54
      IOCTL_OLS_GET_REFCOUNT = new IOControlCode(OLS_TYPE, 0x801,
moel@236
    55
        IOControlCode.Access.Any),
moel@236
    56
      IOCTL_OLS_GET_DRIVER_VERSION = new IOControlCode(OLS_TYPE, 0x800,
moel@236
    57
        IOControlCode.Access.Any),
moel@236
    58
      IOCTL_OLS_READ_MSR = new IOControlCode(OLS_TYPE, 0x821,
moel@236
    59
        IOControlCode.Access.Any),
moel@236
    60
      IOCTL_OLS_WRITE_MSR = new IOControlCode(OLS_TYPE, 0x822, 
moel@236
    61
        IOControlCode.Access.Any),
moel@236
    62
      IOCTL_OLS_READ_IO_PORT_BYTE = new IOControlCode(OLS_TYPE, 0x833,
moel@236
    63
        IOControlCode.Access.Read),
moel@236
    64
      IOCTL_OLS_WRITE_IO_PORT_BYTE = new IOControlCode(OLS_TYPE, 0x836, 
moel@236
    65
        IOControlCode.Access.Write),
moel@236
    66
      IOCTL_OLS_READ_PCI_CONFIG = new IOControlCode(OLS_TYPE, 0x851, 
moel@236
    67
        IOControlCode.Access.Read),
moel@236
    68
      IOCTL_OLS_WRITE_PCI_CONFIG = new IOControlCode(OLS_TYPE, 0x852,
moel@279
    69
        IOControlCode.Access.Write),
moel@279
    70
      IOCTL_OLS_READ_MEMORY = new IOControlCode(OLS_TYPE, 0x841,
moel@279
    71
        IOControlCode.Access.Read);
moel@236
    72
moel@236
    73
    private static bool ExtractDriver(string fileName) {
moel@236
    74
      string resourceName = "OpenHardwareMonitor.Hardware." +
moel@236
    75
        (IntPtr.Size == 4 ? "WinRing0.sys" : "WinRing0x64.sys");
moel@236
    76
moel@236
    77
      string[] names =
moel@236
    78
        Assembly.GetExecutingAssembly().GetManifestResourceNames();
moel@236
    79
      byte[] buffer = null;
moel@236
    80
      for (int i = 0; i < names.Length; i++) {
moel@236
    81
        if (names[i].Replace('\\', '.') == resourceName) {
moel@236
    82
          using (Stream stream = Assembly.GetExecutingAssembly().
moel@236
    83
            GetManifestResourceStream(names[i])) 
moel@236
    84
          {
moel@236
    85
              buffer = new byte[stream.Length];
moel@236
    86
              stream.Read(buffer, 0, buffer.Length);
moel@236
    87
          }
moel@236
    88
        }
moel@236
    89
      }
moel@236
    90
moel@236
    91
      if (buffer == null)
moel@236
    92
        return false;
moel@236
    93
moel@236
    94
      using (FileStream target = new FileStream(fileName, FileMode.Create)) {
moel@236
    95
        target.Write(buffer, 0, buffer.Length);
moel@236
    96
      }
moel@236
    97
moel@236
    98
      return true;
moel@236
    99
    }
moel@236
   100
moel@236
   101
    public static void Open() {
moel@254
   102
      // no implementation for unix systems
moel@238
   103
      int p = (int)Environment.OSVersion.Platform;
moel@238
   104
      if ((p == 4) || (p == 128))
moel@238
   105
        return;  
moel@238
   106
      
moel@236
   107
      if (driver != null)
moel@236
   108
        return;
moel@254
   109
moel@254
   110
      // clear the current report
moel@254
   111
      report.Length = 0;
moel@236
   112
     
moel@236
   113
      driver = new KernelDriver("WinRing0_1_2_0");
moel@236
   114
      driver.Open();
moel@236
   115
moel@236
   116
      if (!driver.IsOpen) {
moel@255
   117
        // driver is not loaded, try to reinstall and open
moel@255
   118
moel@255
   119
        driver.Delete();
moel@236
   120
        string fileName = Path.GetTempFileName();
moel@236
   121
        if (ExtractDriver(fileName)) {
moel@254
   122
          if (driver.Install(fileName)) {
moel@254
   123
            File.Delete(fileName);
moel@254
   124
            driver.Open();
moel@236
   125
moel@254
   126
            if (!driver.IsOpen) {
moel@254
   127
              driver.Delete();
moel@254
   128
              report.AppendLine("Status: Opening driver failed");
moel@254
   129
            }
moel@254
   130
          } else {
moel@255
   131
            report.AppendLine("Status: Installing driver \"" + 
moel@255
   132
              fileName + "\" failed" + 
moel@255
   133
              (File.Exists(fileName) ? " and file exists" : ""));
moel@254
   134
            report.AppendLine();
moel@254
   135
            report.Append("Exception: " + Marshal.GetExceptionForHR(
moel@254
   136
              Marshal.GetHRForLastWin32Error()).Message);
moel@254
   137
          }
moel@254
   138
        } else {
moel@254
   139
          report.AppendLine(
moel@254
   140
            "Status: Extracting driver to \"" + fileName + "\" failed");
moel@236
   141
        }
moel@236
   142
      }
moel@236
   143
moel@236
   144
      if (!driver.IsOpen) 
moel@236
   145
        driver = null;
moel@236
   146
moel@259
   147
      isaBusMutex = new Mutex(false, "Global\\Access_ISABUS.HTP.Method");
moel@236
   148
    }
moel@236
   149
moel@236
   150
    public static bool IsOpen {
moel@236
   151
      get { return driver != null; }
moel@236
   152
    }
moel@236
   153
moel@236
   154
    public static void Close() {
moel@236
   155
      if (driver == null)
moel@236
   156
        return;
moel@236
   157
moel@236
   158
      uint refCount = 0;
moel@236
   159
      driver.DeviceIOControl(IOCTL_OLS_GET_REFCOUNT, null, ref refCount);
moel@236
   160
moel@236
   161
      driver.Close();
moel@236
   162
moel@236
   163
      if (refCount <= 1)
moel@236
   164
        driver.Delete();
moel@236
   165
moel@236
   166
      driver = null;
moel@236
   167
moel@236
   168
      isaBusMutex.Close(); 
moel@236
   169
    }
moel@236
   170
moel@254
   171
    public static string GetReport() {
moel@254
   172
      if (report.Length > 0) {
moel@256
   173
        StringBuilder r = new StringBuilder();
moel@256
   174
        r.AppendLine("Ring0");
moel@256
   175
        r.AppendLine();
moel@256
   176
        r.Append(report);
moel@256
   177
        r.AppendLine();
moel@256
   178
        return r.ToString();
moel@254
   179
      } else
moel@254
   180
        return null;
moel@254
   181
    }
moel@254
   182
moel@236
   183
    public static bool WaitIsaBusMutex(int millisecondsTimeout) {
moel@236
   184
      try {
moel@236
   185
        return isaBusMutex.WaitOne(millisecondsTimeout, false);
moel@236
   186
      } catch (AbandonedMutexException) { return false; } 
moel@236
   187
        catch (InvalidOperationException) { return false; }
moel@236
   188
    }
moel@236
   189
moel@236
   190
    public static void ReleaseIsaBusMutex() {
moel@236
   191
      isaBusMutex.ReleaseMutex();
moel@236
   192
    }
moel@236
   193
moel@236
   194
    public static bool Rdmsr(uint index, out uint eax, out uint edx) {
moel@236
   195
      if (driver == null) {
moel@236
   196
        eax = 0;
moel@236
   197
        edx = 0;
moel@236
   198
        return false;
moel@236
   199
      }
moel@236
   200
moel@236
   201
      ulong buffer = 0;
moel@236
   202
      bool result = driver.DeviceIOControl(IOCTL_OLS_READ_MSR, index,
moel@236
   203
        ref buffer);
moel@236
   204
moel@236
   205
      edx = (uint)((buffer >> 32) & 0xFFFFFFFF);
moel@236
   206
      eax = (uint)(buffer & 0xFFFFFFFF);
moel@236
   207
      return result;
moel@236
   208
    }
moel@236
   209
moel@236
   210
    public static bool RdmsrTx(uint index, out uint eax, out uint edx,
moel@238
   211
      ulong threadAffinityMask) 
moel@236
   212
    {
moel@238
   213
      ulong mask = ThreadAffinity.Set(threadAffinityMask);
moel@236
   214
moel@236
   215
      bool result = Rdmsr(index, out eax, out edx);
moel@236
   216
moel@238
   217
      ThreadAffinity.Set(mask);
moel@236
   218
      return result;
moel@236
   219
    }
moel@236
   220
moel@236
   221
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@236
   222
    private struct WrmsrInput {
moel@236
   223
      public uint Register;
moel@236
   224
      public ulong Value;
moel@236
   225
    }
moel@236
   226
moel@236
   227
    public static bool Wrmsr(uint index, uint eax, uint edx) {
moel@236
   228
      if (driver == null)
moel@236
   229
        return false;
moel@236
   230
moel@236
   231
      WrmsrInput input = new WrmsrInput();
moel@236
   232
      input.Register = index;
moel@236
   233
      input.Value = ((ulong)edx << 32) | eax;
moel@236
   234
moel@236
   235
      return driver.DeviceIOControl(IOCTL_OLS_WRITE_MSR, input);
moel@236
   236
    }
moel@236
   237
moel@236
   238
    public static byte ReadIoPort(uint port) {
moel@236
   239
      if (driver == null)
moel@236
   240
        return 0;
moel@236
   241
moel@236
   242
      uint value = 0;
moel@236
   243
      driver.DeviceIOControl(IOCTL_OLS_READ_IO_PORT_BYTE, port, ref value);
moel@236
   244
moel@236
   245
      return (byte)(value & 0xFF);
moel@236
   246
    }
moel@236
   247
moel@236
   248
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@236
   249
    private struct WriteIoPortInput {
moel@236
   250
      public uint PortNumber;
moel@236
   251
      public byte Value;
moel@236
   252
    }
moel@236
   253
moel@236
   254
    public static void WriteIoPort(uint port, byte value) {
moel@236
   255
      if (driver == null)
moel@236
   256
        return;
moel@236
   257
moel@236
   258
      WriteIoPortInput input = new WriteIoPortInput();
moel@236
   259
      input.PortNumber = port;
moel@236
   260
      input.Value = value;
moel@236
   261
moel@236
   262
      driver.DeviceIOControl(IOCTL_OLS_WRITE_IO_PORT_BYTE, input);
moel@236
   263
    }
moel@236
   264
moel@236
   265
    public const uint InvalidPciAddress = 0xFFFFFFFF;
moel@236
   266
moel@236
   267
    public static uint GetPciAddress(byte bus, byte device, byte function) {
moel@236
   268
      return
moel@236
   269
        (uint)(((bus & 0xFF) << 8) | ((device & 0x1F) << 3) | (function & 7));
moel@236
   270
    }
moel@236
   271
moel@236
   272
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@236
   273
    private struct ReadPciConfigInput {
moel@236
   274
      public uint PciAddress;
moel@236
   275
      public uint RegAddress;
moel@236
   276
    }
moel@236
   277
moel@236
   278
    public static bool ReadPciConfig(uint pciAddress, uint regAddress, 
moel@236
   279
      out uint value) 
moel@236
   280
    {
moel@236
   281
      if (driver == null || (regAddress & 3) != 0) {
moel@236
   282
        value = 0;
moel@236
   283
        return false;
moel@236
   284
      }
moel@236
   285
moel@236
   286
      ReadPciConfigInput input = new ReadPciConfigInput();
moel@236
   287
      input.PciAddress = pciAddress;
moel@236
   288
      input.RegAddress = regAddress;
moel@236
   289
moel@236
   290
      value = 0;
moel@236
   291
      return driver.DeviceIOControl(IOCTL_OLS_READ_PCI_CONFIG, input, 
moel@236
   292
        ref value);
moel@236
   293
    }
moel@236
   294
moel@236
   295
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@236
   296
    private struct WritePciConfigInput {
moel@236
   297
      public uint PciAddress;
moel@236
   298
      public uint RegAddress;
moel@236
   299
      public uint Value;
moel@236
   300
    }
moel@236
   301
moel@236
   302
    public static bool WritePciConfig(uint pciAddress, uint regAddress, 
moel@236
   303
      uint value) 
moel@236
   304
    {
moel@236
   305
      if (driver == null || (regAddress & 3) != 0)
moel@236
   306
        return false;
moel@236
   307
moel@236
   308
      WritePciConfigInput input = new WritePciConfigInput();
moel@236
   309
      input.PciAddress = pciAddress;
moel@236
   310
      input.RegAddress = regAddress;
moel@236
   311
      input.Value = value;
moel@236
   312
moel@236
   313
      return driver.DeviceIOControl(IOCTL_OLS_WRITE_PCI_CONFIG, input);
moel@236
   314
    }
moel@279
   315
moel@279
   316
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@279
   317
    private struct ReadMemoryInput {
moel@279
   318
      public ulong address;
moel@279
   319
      public uint unitSize;
moel@279
   320
      public uint count;
moel@279
   321
    }
moel@279
   322
moel@279
   323
    public static bool ReadMemory<T>(ulong address, ref T buffer) {
moel@279
   324
      if (driver == null) {
moel@279
   325
        return false;
moel@279
   326
      }
moel@279
   327
moel@279
   328
      ReadMemoryInput input = new ReadMemoryInput();
moel@279
   329
      input.address = address;
moel@279
   330
      input.unitSize = 1;
moel@279
   331
      input.count = (uint)Marshal.SizeOf(buffer);
moel@279
   332
moel@279
   333
      return driver.DeviceIOControl(IOCTL_OLS_READ_MEMORY, input,
moel@279
   334
        ref buffer);
moel@279
   335
    }
moel@236
   336
  }
moel@236
   337
}