Hardware/Ring0.cs
author moel.mich
Sun, 31 Oct 2010 22:08:47 +0000
changeset 236 763675f19ff4
child 238 bddc6e01840a
permissions -rw-r--r--
Replaced the non-kernel code of WinRing0 with a managed implementation. The new implementation should fix Issue 32 and simplify further work on Issue 46.
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@236
    19
  Portions created by the Initial Developer are Copyright (C) 2010
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@236
    43
moel@236
    44
namespace OpenHardwareMonitor.Hardware {
moel@236
    45
  internal static class Ring0 {
moel@236
    46
moel@236
    47
    private static KernelDriver driver;
moel@236
    48
    private static Mutex isaBusMutex;
moel@236
    49
moel@236
    50
    private const uint OLS_TYPE = 40000;
moel@236
    51
    private static IOControlCode
moel@236
    52
      IOCTL_OLS_GET_REFCOUNT = new IOControlCode(OLS_TYPE, 0x801,
moel@236
    53
        IOControlCode.Access.Any),
moel@236
    54
      IOCTL_OLS_GET_DRIVER_VERSION = new IOControlCode(OLS_TYPE, 0x800,
moel@236
    55
        IOControlCode.Access.Any),
moel@236
    56
      IOCTL_OLS_READ_MSR = new IOControlCode(OLS_TYPE, 0x821,
moel@236
    57
        IOControlCode.Access.Any),
moel@236
    58
      IOCTL_OLS_WRITE_MSR = new IOControlCode(OLS_TYPE, 0x822, 
moel@236
    59
        IOControlCode.Access.Any),
moel@236
    60
      IOCTL_OLS_READ_IO_PORT_BYTE = new IOControlCode(OLS_TYPE, 0x833,
moel@236
    61
        IOControlCode.Access.Read),
moel@236
    62
      IOCTL_OLS_WRITE_IO_PORT_BYTE = new IOControlCode(OLS_TYPE, 0x836, 
moel@236
    63
        IOControlCode.Access.Write),
moel@236
    64
      IOCTL_OLS_READ_PCI_CONFIG = new IOControlCode(OLS_TYPE, 0x851, 
moel@236
    65
        IOControlCode.Access.Read),
moel@236
    66
      IOCTL_OLS_WRITE_PCI_CONFIG = new IOControlCode(OLS_TYPE, 0x852,
moel@236
    67
        IOControlCode.Access.Write);
moel@236
    68
moel@236
    69
    private static bool ExtractDriver(string fileName) {
moel@236
    70
      string resourceName = "OpenHardwareMonitor.Hardware." +
moel@236
    71
        (IntPtr.Size == 4 ? "WinRing0.sys" : "WinRing0x64.sys");
moel@236
    72
moel@236
    73
      string[] names =
moel@236
    74
        Assembly.GetExecutingAssembly().GetManifestResourceNames();
moel@236
    75
      byte[] buffer = null;
moel@236
    76
      for (int i = 0; i < names.Length; i++) {
moel@236
    77
        if (names[i].Replace('\\', '.') == resourceName) {
moel@236
    78
          using (Stream stream = Assembly.GetExecutingAssembly().
moel@236
    79
            GetManifestResourceStream(names[i])) 
moel@236
    80
          {
moel@236
    81
              buffer = new byte[stream.Length];
moel@236
    82
              stream.Read(buffer, 0, buffer.Length);
moel@236
    83
          }
moel@236
    84
        }
moel@236
    85
      }
moel@236
    86
moel@236
    87
      if (buffer == null)
moel@236
    88
        return false;
moel@236
    89
moel@236
    90
      using (FileStream target = new FileStream(fileName, FileMode.Create)) {
moel@236
    91
        target.Write(buffer, 0, buffer.Length);
moel@236
    92
      }
moel@236
    93
moel@236
    94
      return true;
moel@236
    95
    }
moel@236
    96
moel@236
    97
    public static void Open() {
moel@236
    98
      if (driver != null)
moel@236
    99
        return;
moel@236
   100
     
moel@236
   101
      driver = new KernelDriver("WinRing0_1_2_0");
moel@236
   102
      driver.Open();
moel@236
   103
moel@236
   104
      if (!driver.IsOpen) {
moel@236
   105
        string fileName = Path.GetTempFileName();
moel@236
   106
        if (ExtractDriver(fileName)) {
moel@236
   107
moel@236
   108
          driver.Install(fileName);
moel@236
   109
          File.Delete(fileName);
moel@236
   110
moel@236
   111
          driver.Open();
moel@236
   112
moel@236
   113
          if (!driver.IsOpen)
moel@236
   114
            driver.Delete();
moel@236
   115
        }
moel@236
   116
      }
moel@236
   117
moel@236
   118
      if (!driver.IsOpen) 
moel@236
   119
        driver = null;
moel@236
   120
moel@236
   121
      isaBusMutex = new Mutex(false, "Access_ISABUS.HTP.Method");
moel@236
   122
    }
moel@236
   123
moel@236
   124
    public static bool IsOpen {
moel@236
   125
      get { return driver != null; }
moel@236
   126
    }
moel@236
   127
moel@236
   128
    public static void Close() {
moel@236
   129
      if (driver == null)
moel@236
   130
        return;
moel@236
   131
moel@236
   132
      uint refCount = 0;
moel@236
   133
      driver.DeviceIOControl(IOCTL_OLS_GET_REFCOUNT, null, ref refCount);
moel@236
   134
moel@236
   135
      driver.Close();
moel@236
   136
moel@236
   137
      if (refCount <= 1)
moel@236
   138
        driver.Delete();
moel@236
   139
moel@236
   140
      driver = null;
moel@236
   141
moel@236
   142
      isaBusMutex.Close(); 
moel@236
   143
    }
moel@236
   144
moel@236
   145
    public static bool WaitIsaBusMutex(int millisecondsTimeout) {
moel@236
   146
      try {
moel@236
   147
        return isaBusMutex.WaitOne(millisecondsTimeout, false);
moel@236
   148
      } catch (AbandonedMutexException) { return false; } 
moel@236
   149
        catch (InvalidOperationException) { return false; }
moel@236
   150
    }
moel@236
   151
moel@236
   152
    public static void ReleaseIsaBusMutex() {
moel@236
   153
      isaBusMutex.ReleaseMutex();
moel@236
   154
    }
moel@236
   155
moel@236
   156
    public static bool Rdmsr(uint index, out uint eax, out uint edx) {
moel@236
   157
      if (driver == null) {
moel@236
   158
        eax = 0;
moel@236
   159
        edx = 0;
moel@236
   160
        return false;
moel@236
   161
      }
moel@236
   162
moel@236
   163
      ulong buffer = 0;
moel@236
   164
      bool result = driver.DeviceIOControl(IOCTL_OLS_READ_MSR, index,
moel@236
   165
        ref buffer);
moel@236
   166
moel@236
   167
      edx = (uint)((buffer >> 32) & 0xFFFFFFFF);
moel@236
   168
      eax = (uint)(buffer & 0xFFFFFFFF);
moel@236
   169
      return result;
moel@236
   170
    }
moel@236
   171
moel@236
   172
    public static bool RdmsrTx(uint index, out uint eax, out uint edx,
moel@236
   173
      UIntPtr threadAffinityMask) 
moel@236
   174
    {
moel@236
   175
      IntPtr thread = NativeMethods.GetCurrentThread();
moel@236
   176
      UIntPtr mask = NativeMethods.SetThreadAffinityMask(thread, 
moel@236
   177
        threadAffinityMask);
moel@236
   178
moel@236
   179
      bool result = Rdmsr(index, out eax, out edx);
moel@236
   180
moel@236
   181
      NativeMethods.SetThreadAffinityMask(thread, mask);
moel@236
   182
      return result;
moel@236
   183
    }
moel@236
   184
moel@236
   185
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@236
   186
    private struct WrmsrInput {
moel@236
   187
      public uint Register;
moel@236
   188
      public ulong Value;
moel@236
   189
    }
moel@236
   190
moel@236
   191
    public static bool Wrmsr(uint index, uint eax, uint edx) {
moel@236
   192
      if (driver == null)
moel@236
   193
        return false;
moel@236
   194
moel@236
   195
      WrmsrInput input = new WrmsrInput();
moel@236
   196
      input.Register = index;
moel@236
   197
      input.Value = ((ulong)edx << 32) | eax;
moel@236
   198
moel@236
   199
      return driver.DeviceIOControl(IOCTL_OLS_WRITE_MSR, input);
moel@236
   200
    }
moel@236
   201
moel@236
   202
    public static byte ReadIoPort(uint port) {
moel@236
   203
      if (driver == null)
moel@236
   204
        return 0;
moel@236
   205
moel@236
   206
      uint value = 0;
moel@236
   207
      driver.DeviceIOControl(IOCTL_OLS_READ_IO_PORT_BYTE, port, ref value);
moel@236
   208
moel@236
   209
      return (byte)(value & 0xFF);
moel@236
   210
    }
moel@236
   211
moel@236
   212
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@236
   213
    private struct WriteIoPortInput {
moel@236
   214
      public uint PortNumber;
moel@236
   215
      public byte Value;
moel@236
   216
    }
moel@236
   217
moel@236
   218
    public static void WriteIoPort(uint port, byte value) {
moel@236
   219
      if (driver == null)
moel@236
   220
        return;
moel@236
   221
moel@236
   222
      WriteIoPortInput input = new WriteIoPortInput();
moel@236
   223
      input.PortNumber = port;
moel@236
   224
      input.Value = value;
moel@236
   225
moel@236
   226
      driver.DeviceIOControl(IOCTL_OLS_WRITE_IO_PORT_BYTE, input);
moel@236
   227
    }
moel@236
   228
moel@236
   229
    public const uint InvalidPciAddress = 0xFFFFFFFF;
moel@236
   230
moel@236
   231
    public static uint GetPciAddress(byte bus, byte device, byte function) {
moel@236
   232
      return
moel@236
   233
        (uint)(((bus & 0xFF) << 8) | ((device & 0x1F) << 3) | (function & 7));
moel@236
   234
    }
moel@236
   235
moel@236
   236
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@236
   237
    private struct ReadPciConfigInput {
moel@236
   238
      public uint PciAddress;
moel@236
   239
      public uint RegAddress;
moel@236
   240
    }
moel@236
   241
moel@236
   242
    public static bool ReadPciConfig(uint pciAddress, uint regAddress, 
moel@236
   243
      out uint value) 
moel@236
   244
    {
moel@236
   245
      if (driver == null || (regAddress & 3) != 0) {
moel@236
   246
        value = 0;
moel@236
   247
        return false;
moel@236
   248
      }
moel@236
   249
moel@236
   250
      ReadPciConfigInput input = new ReadPciConfigInput();
moel@236
   251
      input.PciAddress = pciAddress;
moel@236
   252
      input.RegAddress = regAddress;
moel@236
   253
moel@236
   254
      value = 0;
moel@236
   255
      return driver.DeviceIOControl(IOCTL_OLS_READ_PCI_CONFIG, input, 
moel@236
   256
        ref value);
moel@236
   257
    }
moel@236
   258
moel@236
   259
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@236
   260
    private struct WritePciConfigInput {
moel@236
   261
      public uint PciAddress;
moel@236
   262
      public uint RegAddress;
moel@236
   263
      public uint Value;
moel@236
   264
    }
moel@236
   265
moel@236
   266
    public static bool WritePciConfig(uint pciAddress, uint regAddress, 
moel@236
   267
      uint value) 
moel@236
   268
    {
moel@236
   269
      if (driver == null || (regAddress & 3) != 0)
moel@236
   270
        return false;
moel@236
   271
moel@236
   272
      WritePciConfigInput input = new WritePciConfigInput();
moel@236
   273
      input.PciAddress = pciAddress;
moel@236
   274
      input.RegAddress = regAddress;
moel@236
   275
      input.Value = value;
moel@236
   276
moel@236
   277
      return driver.DeviceIOControl(IOCTL_OLS_WRITE_PCI_CONFIG, input);
moel@236
   278
    }
moel@236
   279
moel@236
   280
    private static class NativeMethods {
moel@236
   281
      private const string KERNEL = "kernel32.dll";
moel@236
   282
moel@236
   283
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@236
   284
      public static extern UIntPtr
moel@236
   285
        SetThreadAffinityMask(IntPtr handle, UIntPtr mask);
moel@236
   286
moel@236
   287
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@236
   288
      public static extern IntPtr GetCurrentThread();
moel@236
   289
    }
moel@236
   290
  }
moel@236
   291
}