Hardware/Ring0.cs
author moel.mich
Sat, 25 Jun 2011 14:46:28 +0000
changeset 304 16a86362c2ca
parent 293 9c1b242b1c63
child 344 3145aadca3d2
permissions -rw-r--r--
Changed the maximum buffer size for double buffering of controls that isn't disposed after each draw call to the size of the screen. This should reduce the memory allocation and disposing on each sensor update. Also page faults are no longer increasing with this change.
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
}