Hardware/Ring0.cs
author moel.mich
Thu, 07 Jul 2011 21:53:09 +0000
changeset 309 65a1ae21325d
parent 293 9c1b242b1c63
child 344 3145aadca3d2
permissions -rw-r--r--
Added fan control for Nvidia GPUs based on a patch by Christian Valli?res.
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@285
    42
using System.Security.AccessControl;
moel@236
    43
using System.Threading;
moel@254
    44
using System.Text;
moel@236
    45
moel@236
    46
namespace OpenHardwareMonitor.Hardware {
moel@236
    47
  internal static class Ring0 {
moel@236
    48
moel@236
    49
    private static KernelDriver driver;
moel@281
    50
    private static string fileName;
moel@236
    51
    private static Mutex isaBusMutex;
moel@254
    52
    private static readonly StringBuilder report = new StringBuilder();
moel@236
    53
moel@236
    54
    private const uint OLS_TYPE = 40000;
moel@236
    55
    private static IOControlCode
moel@236
    56
      IOCTL_OLS_GET_REFCOUNT = new IOControlCode(OLS_TYPE, 0x801,
moel@236
    57
        IOControlCode.Access.Any),
moel@236
    58
      IOCTL_OLS_GET_DRIVER_VERSION = new IOControlCode(OLS_TYPE, 0x800,
moel@236
    59
        IOControlCode.Access.Any),
moel@236
    60
      IOCTL_OLS_READ_MSR = new IOControlCode(OLS_TYPE, 0x821,
moel@236
    61
        IOControlCode.Access.Any),
moel@236
    62
      IOCTL_OLS_WRITE_MSR = new IOControlCode(OLS_TYPE, 0x822, 
moel@236
    63
        IOControlCode.Access.Any),
moel@236
    64
      IOCTL_OLS_READ_IO_PORT_BYTE = new IOControlCode(OLS_TYPE, 0x833,
moel@236
    65
        IOControlCode.Access.Read),
moel@236
    66
      IOCTL_OLS_WRITE_IO_PORT_BYTE = new IOControlCode(OLS_TYPE, 0x836, 
moel@236
    67
        IOControlCode.Access.Write),
moel@236
    68
      IOCTL_OLS_READ_PCI_CONFIG = new IOControlCode(OLS_TYPE, 0x851, 
moel@236
    69
        IOControlCode.Access.Read),
moel@236
    70
      IOCTL_OLS_WRITE_PCI_CONFIG = new IOControlCode(OLS_TYPE, 0x852,
moel@279
    71
        IOControlCode.Access.Write),
moel@279
    72
      IOCTL_OLS_READ_MEMORY = new IOControlCode(OLS_TYPE, 0x841,
moel@279
    73
        IOControlCode.Access.Read);
moel@236
    74
moel@283
    75
    private static string GetTempFileName() {
moel@283
    76
moel@283
    77
      // try to get a file in the temporary folder
moel@283
    78
      try {
moel@283
    79
        return Path.GetTempFileName();        
moel@293
    80
      } catch (IOException) { 
moel@293
    81
          // some I/O exception
moel@293
    82
        } 
moel@293
    83
        catch (UnauthorizedAccessException) { 
moel@293
    84
          // we do not have the right to create a file in the temp folder
moel@293
    85
        }
moel@293
    86
        catch (NotSupportedException) {
moel@293
    87
          // invalid path format of the TMP system environment variable
moel@293
    88
        }
moel@283
    89
moel@283
    90
      // if this failed, we try to create one in the application folder
moel@283
    91
      string fileName = Path.ChangeExtension(
moel@283
    92
        Assembly.GetExecutingAssembly().Location, ".sys");
moel@283
    93
      try {
moel@283
    94
        using (FileStream stream = File.Create(fileName)) {
moel@283
    95
          return fileName;
moel@283
    96
        }        
moel@283
    97
      } catch (IOException) { } 
moel@283
    98
        catch (UnauthorizedAccessException) { }
moel@283
    99
     
moel@283
   100
      return null;
moel@283
   101
    }
moel@283
   102
moel@236
   103
    private static bool ExtractDriver(string fileName) {
moel@236
   104
      string resourceName = "OpenHardwareMonitor.Hardware." +
moel@236
   105
        (IntPtr.Size == 4 ? "WinRing0.sys" : "WinRing0x64.sys");
moel@236
   106
moel@236
   107
      string[] names =
moel@236
   108
        Assembly.GetExecutingAssembly().GetManifestResourceNames();
moel@236
   109
      byte[] buffer = null;
moel@236
   110
      for (int i = 0; i < names.Length; i++) {
moel@236
   111
        if (names[i].Replace('\\', '.') == resourceName) {
moel@236
   112
          using (Stream stream = Assembly.GetExecutingAssembly().
moel@236
   113
            GetManifestResourceStream(names[i])) 
moel@236
   114
          {
moel@236
   115
              buffer = new byte[stream.Length];
moel@236
   116
              stream.Read(buffer, 0, buffer.Length);
moel@236
   117
          }
moel@236
   118
        }
moel@236
   119
      }
moel@236
   120
moel@236
   121
      if (buffer == null)
moel@236
   122
        return false;
moel@236
   123
moel@294
   124
      try {
moel@294
   125
        using (FileStream target = new FileStream(fileName, FileMode.Create)) {
moel@294
   126
          target.Write(buffer, 0, buffer.Length);
moel@294
   127
        }
moel@294
   128
      } catch (IOException) { 
moel@294
   129
        // for example there is not enough space on the disk
moel@294
   130
        return false; 
moel@236
   131
      }
moel@236
   132
moel@236
   133
      return true;
moel@236
   134
    }
moel@236
   135
moel@236
   136
    public static void Open() {
moel@254
   137
      // no implementation for unix systems
moel@238
   138
      int p = (int)Environment.OSVersion.Platform;
moel@238
   139
      if ((p == 4) || (p == 128))
moel@238
   140
        return;  
moel@238
   141
      
moel@236
   142
      if (driver != null)
moel@236
   143
        return;
moel@254
   144
moel@254
   145
      // clear the current report
moel@254
   146
      report.Length = 0;
moel@236
   147
     
moel@236
   148
      driver = new KernelDriver("WinRing0_1_2_0");
moel@236
   149
      driver.Open();
moel@236
   150
moel@236
   151
      if (!driver.IsOpen) {
moel@255
   152
        // driver is not loaded, try to reinstall and open
moel@255
   153
moel@255
   154
        driver.Delete();
moel@283
   155
        fileName = GetTempFileName();
moel@283
   156
        if (fileName != null && ExtractDriver(fileName)) {
moel@254
   157
          if (driver.Install(fileName)) {
moel@254
   158
            driver.Open();
moel@236
   159
moel@254
   160
            if (!driver.IsOpen) {
moel@254
   161
              driver.Delete();
moel@254
   162
              report.AppendLine("Status: Opening driver failed");
moel@254
   163
            }
moel@254
   164
          } else {
moel@283
   165
            report.AppendLine("Status: Installing driver \"" +
moel@283
   166
              fileName + "\" failed" +
moel@255
   167
              (File.Exists(fileName) ? " and file exists" : ""));
moel@254
   168
            report.AppendLine();
moel@254
   169
            report.Append("Exception: " + Marshal.GetExceptionForHR(
moel@254
   170
              Marshal.GetHRForLastWin32Error()).Message);
moel@254
   171
          }
moel@254
   172
        } else {
moel@283
   173
          report.AppendLine("Status: Extracting driver failed");
moel@236
   174
        }
moel@281
   175
moel@281
   176
        try {
moel@281
   177
          // try to delte the driver file
moel@281
   178
          if (File.Exists(fileName))
moel@281
   179
            File.Delete(fileName);
moel@281
   180
          fileName = null;
moel@281
   181
        } catch (IOException) { } 
moel@281
   182
          catch (UnauthorizedAccessException) { }
moel@236
   183
      }
moel@236
   184
moel@236
   185
      if (!driver.IsOpen) 
moel@236
   186
        driver = null;
moel@236
   187
moel@285
   188
      string mutexName = "Global\\Access_ISABUS.HTP.Method";
moel@285
   189
      try {
moel@285
   190
        isaBusMutex = new Mutex(false, mutexName);
moel@285
   191
      } catch (UnauthorizedAccessException) {
moel@285
   192
        try {
moel@285
   193
          isaBusMutex = Mutex.OpenExisting(mutexName, MutexRights.Synchronize);
moel@285
   194
        } catch { }
moel@285
   195
      }
moel@236
   196
    }
moel@236
   197
moel@236
   198
    public static bool IsOpen {
moel@236
   199
      get { return driver != null; }
moel@236
   200
    }
moel@236
   201
moel@236
   202
    public static void Close() {
moel@236
   203
      if (driver == null)
moel@236
   204
        return;
moel@236
   205
moel@236
   206
      uint refCount = 0;
moel@236
   207
      driver.DeviceIOControl(IOCTL_OLS_GET_REFCOUNT, null, ref refCount);
moel@236
   208
moel@236
   209
      driver.Close();
moel@236
   210
moel@236
   211
      if (refCount <= 1)
moel@236
   212
        driver.Delete();
moel@236
   213
moel@236
   214
      driver = null;
moel@236
   215
moel@285
   216
      if (isaBusMutex != null) {
moel@285
   217
        isaBusMutex.Close();
moel@285
   218
        isaBusMutex = null;
moel@285
   219
      }
moel@281
   220
moel@281
   221
      // try to delete temporary driver file again if failed during open
moel@281
   222
      if (fileName != null && File.Exists(fileName)) {
moel@281
   223
        try {
moel@281
   224
          File.Delete(fileName);
moel@281
   225
          fileName = null;
moel@281
   226
        } catch (IOException) { } 
moel@281
   227
          catch (UnauthorizedAccessException) { }
moel@281
   228
      }
moel@236
   229
    }
moel@236
   230
moel@254
   231
    public static string GetReport() {
moel@254
   232
      if (report.Length > 0) {
moel@256
   233
        StringBuilder r = new StringBuilder();
moel@256
   234
        r.AppendLine("Ring0");
moel@256
   235
        r.AppendLine();
moel@256
   236
        r.Append(report);
moel@256
   237
        r.AppendLine();
moel@256
   238
        return r.ToString();
moel@254
   239
      } else
moel@254
   240
        return null;
moel@254
   241
    }
moel@254
   242
moel@236
   243
    public static bool WaitIsaBusMutex(int millisecondsTimeout) {
moel@285
   244
      if (isaBusMutex == null)
moel@285
   245
        return true;
moel@236
   246
      try {
moel@236
   247
        return isaBusMutex.WaitOne(millisecondsTimeout, false);
moel@236
   248
      } catch (AbandonedMutexException) { return false; } 
moel@236
   249
        catch (InvalidOperationException) { return false; }
moel@236
   250
    }
moel@236
   251
moel@236
   252
    public static void ReleaseIsaBusMutex() {
moel@285
   253
      if (isaBusMutex == null)
moel@285
   254
        return;
moel@236
   255
      isaBusMutex.ReleaseMutex();
moel@236
   256
    }
moel@236
   257
moel@236
   258
    public static bool Rdmsr(uint index, out uint eax, out uint edx) {
moel@236
   259
      if (driver == null) {
moel@236
   260
        eax = 0;
moel@236
   261
        edx = 0;
moel@236
   262
        return false;
moel@236
   263
      }
moel@236
   264
moel@236
   265
      ulong buffer = 0;
moel@236
   266
      bool result = driver.DeviceIOControl(IOCTL_OLS_READ_MSR, index,
moel@236
   267
        ref buffer);
moel@236
   268
moel@236
   269
      edx = (uint)((buffer >> 32) & 0xFFFFFFFF);
moel@236
   270
      eax = (uint)(buffer & 0xFFFFFFFF);
moel@236
   271
      return result;
moel@236
   272
    }
moel@236
   273
moel@236
   274
    public static bool RdmsrTx(uint index, out uint eax, out uint edx,
moel@238
   275
      ulong threadAffinityMask) 
moel@236
   276
    {
moel@238
   277
      ulong mask = ThreadAffinity.Set(threadAffinityMask);
moel@236
   278
moel@236
   279
      bool result = Rdmsr(index, out eax, out edx);
moel@236
   280
moel@238
   281
      ThreadAffinity.Set(mask);
moel@236
   282
      return result;
moel@236
   283
    }
moel@236
   284
moel@236
   285
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@236
   286
    private struct WrmsrInput {
moel@236
   287
      public uint Register;
moel@236
   288
      public ulong Value;
moel@236
   289
    }
moel@236
   290
moel@236
   291
    public static bool Wrmsr(uint index, uint eax, uint edx) {
moel@236
   292
      if (driver == null)
moel@236
   293
        return false;
moel@236
   294
moel@236
   295
      WrmsrInput input = new WrmsrInput();
moel@236
   296
      input.Register = index;
moel@236
   297
      input.Value = ((ulong)edx << 32) | eax;
moel@236
   298
moel@236
   299
      return driver.DeviceIOControl(IOCTL_OLS_WRITE_MSR, input);
moel@236
   300
    }
moel@236
   301
moel@236
   302
    public static byte ReadIoPort(uint port) {
moel@236
   303
      if (driver == null)
moel@236
   304
        return 0;
moel@236
   305
moel@236
   306
      uint value = 0;
moel@236
   307
      driver.DeviceIOControl(IOCTL_OLS_READ_IO_PORT_BYTE, port, ref value);
moel@236
   308
moel@236
   309
      return (byte)(value & 0xFF);
moel@236
   310
    }
moel@236
   311
moel@236
   312
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@236
   313
    private struct WriteIoPortInput {
moel@236
   314
      public uint PortNumber;
moel@236
   315
      public byte Value;
moel@236
   316
    }
moel@236
   317
moel@236
   318
    public static void WriteIoPort(uint port, byte value) {
moel@236
   319
      if (driver == null)
moel@236
   320
        return;
moel@236
   321
moel@236
   322
      WriteIoPortInput input = new WriteIoPortInput();
moel@236
   323
      input.PortNumber = port;
moel@236
   324
      input.Value = value;
moel@236
   325
moel@236
   326
      driver.DeviceIOControl(IOCTL_OLS_WRITE_IO_PORT_BYTE, input);
moel@236
   327
    }
moel@236
   328
moel@236
   329
    public const uint InvalidPciAddress = 0xFFFFFFFF;
moel@236
   330
moel@236
   331
    public static uint GetPciAddress(byte bus, byte device, byte function) {
moel@236
   332
      return
moel@236
   333
        (uint)(((bus & 0xFF) << 8) | ((device & 0x1F) << 3) | (function & 7));
moel@236
   334
    }
moel@236
   335
moel@236
   336
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@236
   337
    private struct ReadPciConfigInput {
moel@236
   338
      public uint PciAddress;
moel@236
   339
      public uint RegAddress;
moel@236
   340
    }
moel@236
   341
moel@236
   342
    public static bool ReadPciConfig(uint pciAddress, uint regAddress, 
moel@236
   343
      out uint value) 
moel@236
   344
    {
moel@236
   345
      if (driver == null || (regAddress & 3) != 0) {
moel@236
   346
        value = 0;
moel@236
   347
        return false;
moel@236
   348
      }
moel@236
   349
moel@236
   350
      ReadPciConfigInput input = new ReadPciConfigInput();
moel@236
   351
      input.PciAddress = pciAddress;
moel@236
   352
      input.RegAddress = regAddress;
moel@236
   353
moel@236
   354
      value = 0;
moel@236
   355
      return driver.DeviceIOControl(IOCTL_OLS_READ_PCI_CONFIG, input, 
moel@236
   356
        ref value);
moel@236
   357
    }
moel@236
   358
moel@236
   359
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@236
   360
    private struct WritePciConfigInput {
moel@236
   361
      public uint PciAddress;
moel@236
   362
      public uint RegAddress;
moel@236
   363
      public uint Value;
moel@236
   364
    }
moel@236
   365
moel@236
   366
    public static bool WritePciConfig(uint pciAddress, uint regAddress, 
moel@236
   367
      uint value) 
moel@236
   368
    {
moel@236
   369
      if (driver == null || (regAddress & 3) != 0)
moel@236
   370
        return false;
moel@236
   371
moel@236
   372
      WritePciConfigInput input = new WritePciConfigInput();
moel@236
   373
      input.PciAddress = pciAddress;
moel@236
   374
      input.RegAddress = regAddress;
moel@236
   375
      input.Value = value;
moel@236
   376
moel@236
   377
      return driver.DeviceIOControl(IOCTL_OLS_WRITE_PCI_CONFIG, input);
moel@236
   378
    }
moel@279
   379
moel@279
   380
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@279
   381
    private struct ReadMemoryInput {
moel@279
   382
      public ulong address;
moel@279
   383
      public uint unitSize;
moel@279
   384
      public uint count;
moel@279
   385
    }
moel@279
   386
moel@279
   387
    public static bool ReadMemory<T>(ulong address, ref T buffer) {
moel@279
   388
      if (driver == null) {
moel@279
   389
        return false;
moel@279
   390
      }
moel@279
   391
moel@279
   392
      ReadMemoryInput input = new ReadMemoryInput();
moel@279
   393
      input.address = address;
moel@279
   394
      input.unitSize = 1;
moel@279
   395
      input.count = (uint)Marshal.SizeOf(buffer);
moel@279
   396
moel@279
   397
      return driver.DeviceIOControl(IOCTL_OLS_READ_MEMORY, input,
moel@279
   398
        ref buffer);
moel@279
   399
    }
moel@236
   400
  }
moel@236
   401
}