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