Hardware/Ring0.cs
author StephaneLenclud
Thu, 18 Apr 2013 23:25:10 +0200
branchMiniDisplay
changeset 444 9b09e2ee0968
parent 379 7af3aaeb42e9
permissions -rw-r--r--
Front View plug-in does not init if no sensor added.
Fixing some format to make strings shorter.
Now trying to start SoundGraphAccess.exe process from same directory.
Packed mode now can display three sensors along with the current time.
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@380
    49
      
moel@380
    50
      // try to create one in the application folder
moel@283
    51
      string fileName = Path.ChangeExtension(
moel@380
    52
        Assembly.GetEntryAssembly().Location, ".sys");
moel@283
    53
      try {
moel@283
    54
        using (FileStream stream = File.Create(fileName)) {
moel@283
    55
          return fileName;
moel@283
    56
        }        
moel@283
    57
      } catch (IOException) { } 
moel@283
    58
        catch (UnauthorizedAccessException) { }
moel@380
    59
moel@380
    60
      // if this failed, try to get a file in the temporary folder
moel@380
    61
      try {
moel@380
    62
        return Path.GetTempFileName();        
moel@380
    63
      } catch (IOException) { 
moel@380
    64
          // some I/O exception
moel@380
    65
      } 
moel@380
    66
      catch (UnauthorizedAccessException) { 
moel@380
    67
        // we do not have the right to create a file in the temp folder
moel@380
    68
      }
moel@380
    69
      catch (NotSupportedException) {
moel@380
    70
        // invalid path format of the TMP system environment variable
moel@380
    71
      }
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
}