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.
     1 /*
     2   
     3   Version: MPL 1.1/GPL 2.0/LGPL 2.1
     4 
     5   The contents of this file are subject to the Mozilla Public License Version
     6   1.1 (the "License"); you may not use this file except in compliance with
     7   the License. You may obtain a copy of the License at
     8  
     9   http://www.mozilla.org/MPL/
    10 
    11   Software distributed under the License is distributed on an "AS IS" basis,
    12   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
    13   for the specific language governing rights and limitations under the License.
    14 
    15   The Original Code is the Open Hardware Monitor code.
    16 
    17   The Initial Developer of the Original Code is 
    18   Michael Möller <m.moeller@gmx.ch>.
    19   Portions created by the Initial Developer are Copyright (C) 2010
    20   the Initial Developer. All Rights Reserved.
    21 
    22   Contributor(s):
    23 
    24   Alternatively, the contents of this file may be used under the terms of
    25   either the GNU General Public License Version 2 or later (the "GPL"), or
    26   the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
    27   in which case the provisions of the GPL or the LGPL are applicable instead
    28   of those above. If you wish to allow use of your version of this file only
    29   under the terms of either the GPL or the LGPL, and not to allow others to
    30   use your version of this file under the terms of the MPL, indicate your
    31   decision by deleting the provisions above and replace them with the notice
    32   and other provisions required by the GPL or the LGPL. If you do not delete
    33   the provisions above, a recipient may use your version of this file under
    34   the terms of any one of the MPL, the GPL or the LGPL.
    35  
    36 */
    37 
    38 using System;
    39 using System.IO;
    40 using System.Reflection;
    41 using System.Runtime.InteropServices;
    42 using System.Threading;
    43 
    44 namespace OpenHardwareMonitor.Hardware {
    45   internal static class Ring0 {
    46 
    47     private static KernelDriver driver;
    48     private static Mutex isaBusMutex;
    49 
    50     private const uint OLS_TYPE = 40000;
    51     private static IOControlCode
    52       IOCTL_OLS_GET_REFCOUNT = new IOControlCode(OLS_TYPE, 0x801,
    53         IOControlCode.Access.Any),
    54       IOCTL_OLS_GET_DRIVER_VERSION = new IOControlCode(OLS_TYPE, 0x800,
    55         IOControlCode.Access.Any),
    56       IOCTL_OLS_READ_MSR = new IOControlCode(OLS_TYPE, 0x821,
    57         IOControlCode.Access.Any),
    58       IOCTL_OLS_WRITE_MSR = new IOControlCode(OLS_TYPE, 0x822, 
    59         IOControlCode.Access.Any),
    60       IOCTL_OLS_READ_IO_PORT_BYTE = new IOControlCode(OLS_TYPE, 0x833,
    61         IOControlCode.Access.Read),
    62       IOCTL_OLS_WRITE_IO_PORT_BYTE = new IOControlCode(OLS_TYPE, 0x836, 
    63         IOControlCode.Access.Write),
    64       IOCTL_OLS_READ_PCI_CONFIG = new IOControlCode(OLS_TYPE, 0x851, 
    65         IOControlCode.Access.Read),
    66       IOCTL_OLS_WRITE_PCI_CONFIG = new IOControlCode(OLS_TYPE, 0x852,
    67         IOControlCode.Access.Write);
    68 
    69     private static bool ExtractDriver(string fileName) {
    70       string resourceName = "OpenHardwareMonitor.Hardware." +
    71         (IntPtr.Size == 4 ? "WinRing0.sys" : "WinRing0x64.sys");
    72 
    73       string[] names =
    74         Assembly.GetExecutingAssembly().GetManifestResourceNames();
    75       byte[] buffer = null;
    76       for (int i = 0; i < names.Length; i++) {
    77         if (names[i].Replace('\\', '.') == resourceName) {
    78           using (Stream stream = Assembly.GetExecutingAssembly().
    79             GetManifestResourceStream(names[i])) 
    80           {
    81               buffer = new byte[stream.Length];
    82               stream.Read(buffer, 0, buffer.Length);
    83           }
    84         }
    85       }
    86 
    87       if (buffer == null)
    88         return false;
    89 
    90       using (FileStream target = new FileStream(fileName, FileMode.Create)) {
    91         target.Write(buffer, 0, buffer.Length);
    92       }
    93 
    94       return true;
    95     }
    96 
    97     public static void Open() {
    98       if (driver != null)
    99         return;
   100      
   101       driver = new KernelDriver("WinRing0_1_2_0");
   102       driver.Open();
   103 
   104       if (!driver.IsOpen) {
   105         string fileName = Path.GetTempFileName();
   106         if (ExtractDriver(fileName)) {
   107 
   108           driver.Install(fileName);
   109           File.Delete(fileName);
   110 
   111           driver.Open();
   112 
   113           if (!driver.IsOpen)
   114             driver.Delete();
   115         }
   116       }
   117 
   118       if (!driver.IsOpen) 
   119         driver = null;
   120 
   121       isaBusMutex = new Mutex(false, "Access_ISABUS.HTP.Method");
   122     }
   123 
   124     public static bool IsOpen {
   125       get { return driver != null; }
   126     }
   127 
   128     public static void Close() {
   129       if (driver == null)
   130         return;
   131 
   132       uint refCount = 0;
   133       driver.DeviceIOControl(IOCTL_OLS_GET_REFCOUNT, null, ref refCount);
   134 
   135       driver.Close();
   136 
   137       if (refCount <= 1)
   138         driver.Delete();
   139 
   140       driver = null;
   141 
   142       isaBusMutex.Close(); 
   143     }
   144 
   145     public static bool WaitIsaBusMutex(int millisecondsTimeout) {
   146       try {
   147         return isaBusMutex.WaitOne(millisecondsTimeout, false);
   148       } catch (AbandonedMutexException) { return false; } 
   149         catch (InvalidOperationException) { return false; }
   150     }
   151 
   152     public static void ReleaseIsaBusMutex() {
   153       isaBusMutex.ReleaseMutex();
   154     }
   155 
   156     public static bool Rdmsr(uint index, out uint eax, out uint edx) {
   157       if (driver == null) {
   158         eax = 0;
   159         edx = 0;
   160         return false;
   161       }
   162 
   163       ulong buffer = 0;
   164       bool result = driver.DeviceIOControl(IOCTL_OLS_READ_MSR, index,
   165         ref buffer);
   166 
   167       edx = (uint)((buffer >> 32) & 0xFFFFFFFF);
   168       eax = (uint)(buffer & 0xFFFFFFFF);
   169       return result;
   170     }
   171 
   172     public static bool RdmsrTx(uint index, out uint eax, out uint edx,
   173       UIntPtr threadAffinityMask) 
   174     {
   175       IntPtr thread = NativeMethods.GetCurrentThread();
   176       UIntPtr mask = NativeMethods.SetThreadAffinityMask(thread, 
   177         threadAffinityMask);
   178 
   179       bool result = Rdmsr(index, out eax, out edx);
   180 
   181       NativeMethods.SetThreadAffinityMask(thread, mask);
   182       return result;
   183     }
   184 
   185     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   186     private struct WrmsrInput {
   187       public uint Register;
   188       public ulong Value;
   189     }
   190 
   191     public static bool Wrmsr(uint index, uint eax, uint edx) {
   192       if (driver == null)
   193         return false;
   194 
   195       WrmsrInput input = new WrmsrInput();
   196       input.Register = index;
   197       input.Value = ((ulong)edx << 32) | eax;
   198 
   199       return driver.DeviceIOControl(IOCTL_OLS_WRITE_MSR, input);
   200     }
   201 
   202     public static byte ReadIoPort(uint port) {
   203       if (driver == null)
   204         return 0;
   205 
   206       uint value = 0;
   207       driver.DeviceIOControl(IOCTL_OLS_READ_IO_PORT_BYTE, port, ref value);
   208 
   209       return (byte)(value & 0xFF);
   210     }
   211 
   212     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   213     private struct WriteIoPortInput {
   214       public uint PortNumber;
   215       public byte Value;
   216     }
   217 
   218     public static void WriteIoPort(uint port, byte value) {
   219       if (driver == null)
   220         return;
   221 
   222       WriteIoPortInput input = new WriteIoPortInput();
   223       input.PortNumber = port;
   224       input.Value = value;
   225 
   226       driver.DeviceIOControl(IOCTL_OLS_WRITE_IO_PORT_BYTE, input);
   227     }
   228 
   229     public const uint InvalidPciAddress = 0xFFFFFFFF;
   230 
   231     public static uint GetPciAddress(byte bus, byte device, byte function) {
   232       return
   233         (uint)(((bus & 0xFF) << 8) | ((device & 0x1F) << 3) | (function & 7));
   234     }
   235 
   236     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   237     private struct ReadPciConfigInput {
   238       public uint PciAddress;
   239       public uint RegAddress;
   240     }
   241 
   242     public static bool ReadPciConfig(uint pciAddress, uint regAddress, 
   243       out uint value) 
   244     {
   245       if (driver == null || (regAddress & 3) != 0) {
   246         value = 0;
   247         return false;
   248       }
   249 
   250       ReadPciConfigInput input = new ReadPciConfigInput();
   251       input.PciAddress = pciAddress;
   252       input.RegAddress = regAddress;
   253 
   254       value = 0;
   255       return driver.DeviceIOControl(IOCTL_OLS_READ_PCI_CONFIG, input, 
   256         ref value);
   257     }
   258 
   259     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   260     private struct WritePciConfigInput {
   261       public uint PciAddress;
   262       public uint RegAddress;
   263       public uint Value;
   264     }
   265 
   266     public static bool WritePciConfig(uint pciAddress, uint regAddress, 
   267       uint value) 
   268     {
   269       if (driver == null || (regAddress & 3) != 0)
   270         return false;
   271 
   272       WritePciConfigInput input = new WritePciConfigInput();
   273       input.PciAddress = pciAddress;
   274       input.RegAddress = regAddress;
   275       input.Value = value;
   276 
   277       return driver.DeviceIOControl(IOCTL_OLS_WRITE_PCI_CONFIG, input);
   278     }
   279 
   280     private static class NativeMethods {
   281       private const string KERNEL = "kernel32.dll";
   282 
   283       [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   284       public static extern UIntPtr
   285         SetThreadAffinityMask(IntPtr handle, UIntPtr mask);
   286 
   287       [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   288       public static extern IntPtr GetCurrentThread();
   289     }
   290   }
   291 }