Hardware/Ring0.cs
author moel.mich
Fri, 11 Feb 2011 22:29:26 +0000
changeset 255 a608358af258
parent 254 d8079800a888
child 256 6dc6410489f4
permissions -rw-r--r--
Added code to delete any kernel driver service that can't be opened before reinstalling it.
     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-2011
    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 using System.Text;
    44 
    45 namespace OpenHardwareMonitor.Hardware {
    46   internal static class Ring0 {
    47 
    48     private static KernelDriver driver;
    49     private static Mutex isaBusMutex;
    50     private static readonly StringBuilder report = new StringBuilder();
    51 
    52     private const uint OLS_TYPE = 40000;
    53     private static IOControlCode
    54       IOCTL_OLS_GET_REFCOUNT = new IOControlCode(OLS_TYPE, 0x801,
    55         IOControlCode.Access.Any),
    56       IOCTL_OLS_GET_DRIVER_VERSION = new IOControlCode(OLS_TYPE, 0x800,
    57         IOControlCode.Access.Any),
    58       IOCTL_OLS_READ_MSR = new IOControlCode(OLS_TYPE, 0x821,
    59         IOControlCode.Access.Any),
    60       IOCTL_OLS_WRITE_MSR = new IOControlCode(OLS_TYPE, 0x822, 
    61         IOControlCode.Access.Any),
    62       IOCTL_OLS_READ_IO_PORT_BYTE = new IOControlCode(OLS_TYPE, 0x833,
    63         IOControlCode.Access.Read),
    64       IOCTL_OLS_WRITE_IO_PORT_BYTE = new IOControlCode(OLS_TYPE, 0x836, 
    65         IOControlCode.Access.Write),
    66       IOCTL_OLS_READ_PCI_CONFIG = new IOControlCode(OLS_TYPE, 0x851, 
    67         IOControlCode.Access.Read),
    68       IOCTL_OLS_WRITE_PCI_CONFIG = new IOControlCode(OLS_TYPE, 0x852,
    69         IOControlCode.Access.Write);
    70 
    71     private static bool ExtractDriver(string fileName) {
    72       string resourceName = "OpenHardwareMonitor.Hardware." +
    73         (IntPtr.Size == 4 ? "WinRing0.sys" : "WinRing0x64.sys");
    74 
    75       string[] names =
    76         Assembly.GetExecutingAssembly().GetManifestResourceNames();
    77       byte[] buffer = null;
    78       for (int i = 0; i < names.Length; i++) {
    79         if (names[i].Replace('\\', '.') == resourceName) {
    80           using (Stream stream = Assembly.GetExecutingAssembly().
    81             GetManifestResourceStream(names[i])) 
    82           {
    83               buffer = new byte[stream.Length];
    84               stream.Read(buffer, 0, buffer.Length);
    85           }
    86         }
    87       }
    88 
    89       if (buffer == null)
    90         return false;
    91 
    92       using (FileStream target = new FileStream(fileName, FileMode.Create)) {
    93         target.Write(buffer, 0, buffer.Length);
    94       }
    95 
    96       return true;
    97     }
    98 
    99     public static void Open() {
   100       // no implementation for unix systems
   101       int p = (int)Environment.OSVersion.Platform;
   102       if ((p == 4) || (p == 128))
   103         return;  
   104       
   105       if (driver != null)
   106         return;
   107 
   108       // clear the current report
   109       report.Length = 0;
   110      
   111       driver = new KernelDriver("WinRing0_1_2_0");
   112       driver.Open();
   113 
   114       if (!driver.IsOpen) {
   115         // driver is not loaded, try to reinstall and open
   116 
   117         driver.Delete();
   118         string fileName = Path.GetTempFileName();
   119         if (ExtractDriver(fileName)) {
   120           if (driver.Install(fileName)) {
   121             File.Delete(fileName);
   122             driver.Open();
   123 
   124             if (!driver.IsOpen) {
   125               driver.Delete();
   126               report.AppendLine("Status: Opening driver failed");
   127             }
   128           } else {
   129             report.AppendLine("Status: Installing driver \"" + 
   130               fileName + "\" failed" + 
   131               (File.Exists(fileName) ? " and file exists" : ""));
   132             report.AppendLine();
   133             report.Append("Exception: " + Marshal.GetExceptionForHR(
   134               Marshal.GetHRForLastWin32Error()).Message);
   135           }
   136         } else {
   137           report.AppendLine(
   138             "Status: Extracting driver to \"" + fileName + "\" failed");
   139         }
   140       }
   141 
   142       if (!driver.IsOpen) 
   143         driver = null;
   144 
   145       isaBusMutex = new Mutex(false, "Access_ISABUS.HTP.Method");
   146     }
   147 
   148     public static bool IsOpen {
   149       get { return driver != null; }
   150     }
   151 
   152     public static void Close() {
   153       if (driver == null)
   154         return;
   155 
   156       uint refCount = 0;
   157       driver.DeviceIOControl(IOCTL_OLS_GET_REFCOUNT, null, ref refCount);
   158 
   159       driver.Close();
   160 
   161       if (refCount <= 1)
   162         driver.Delete();
   163 
   164       driver = null;
   165 
   166       isaBusMutex.Close(); 
   167     }
   168 
   169     public static string GetReport() {
   170       if (report.Length > 0) {
   171         report.Insert(0, "Ring0" + Environment.NewLine +
   172           Environment.NewLine);
   173         report.AppendLine();
   174         return report.ToString();
   175       } else
   176         return null;
   177     }
   178 
   179     public static bool WaitIsaBusMutex(int millisecondsTimeout) {
   180       try {
   181         return isaBusMutex.WaitOne(millisecondsTimeout, false);
   182       } catch (AbandonedMutexException) { return false; } 
   183         catch (InvalidOperationException) { return false; }
   184     }
   185 
   186     public static void ReleaseIsaBusMutex() {
   187       isaBusMutex.ReleaseMutex();
   188     }
   189 
   190     public static bool Rdmsr(uint index, out uint eax, out uint edx) {
   191       if (driver == null) {
   192         eax = 0;
   193         edx = 0;
   194         return false;
   195       }
   196 
   197       ulong buffer = 0;
   198       bool result = driver.DeviceIOControl(IOCTL_OLS_READ_MSR, index,
   199         ref buffer);
   200 
   201       edx = (uint)((buffer >> 32) & 0xFFFFFFFF);
   202       eax = (uint)(buffer & 0xFFFFFFFF);
   203       return result;
   204     }
   205 
   206     public static bool RdmsrTx(uint index, out uint eax, out uint edx,
   207       ulong threadAffinityMask) 
   208     {
   209       ulong mask = ThreadAffinity.Set(threadAffinityMask);
   210 
   211       bool result = Rdmsr(index, out eax, out edx);
   212 
   213       ThreadAffinity.Set(mask);
   214       return result;
   215     }
   216 
   217     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   218     private struct WrmsrInput {
   219       public uint Register;
   220       public ulong Value;
   221     }
   222 
   223     public static bool Wrmsr(uint index, uint eax, uint edx) {
   224       if (driver == null)
   225         return false;
   226 
   227       WrmsrInput input = new WrmsrInput();
   228       input.Register = index;
   229       input.Value = ((ulong)edx << 32) | eax;
   230 
   231       return driver.DeviceIOControl(IOCTL_OLS_WRITE_MSR, input);
   232     }
   233 
   234     public static byte ReadIoPort(uint port) {
   235       if (driver == null)
   236         return 0;
   237 
   238       uint value = 0;
   239       driver.DeviceIOControl(IOCTL_OLS_READ_IO_PORT_BYTE, port, ref value);
   240 
   241       return (byte)(value & 0xFF);
   242     }
   243 
   244     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   245     private struct WriteIoPortInput {
   246       public uint PortNumber;
   247       public byte Value;
   248     }
   249 
   250     public static void WriteIoPort(uint port, byte value) {
   251       if (driver == null)
   252         return;
   253 
   254       WriteIoPortInput input = new WriteIoPortInput();
   255       input.PortNumber = port;
   256       input.Value = value;
   257 
   258       driver.DeviceIOControl(IOCTL_OLS_WRITE_IO_PORT_BYTE, input);
   259     }
   260 
   261     public const uint InvalidPciAddress = 0xFFFFFFFF;
   262 
   263     public static uint GetPciAddress(byte bus, byte device, byte function) {
   264       return
   265         (uint)(((bus & 0xFF) << 8) | ((device & 0x1F) << 3) | (function & 7));
   266     }
   267 
   268     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   269     private struct ReadPciConfigInput {
   270       public uint PciAddress;
   271       public uint RegAddress;
   272     }
   273 
   274     public static bool ReadPciConfig(uint pciAddress, uint regAddress, 
   275       out uint value) 
   276     {
   277       if (driver == null || (regAddress & 3) != 0) {
   278         value = 0;
   279         return false;
   280       }
   281 
   282       ReadPciConfigInput input = new ReadPciConfigInput();
   283       input.PciAddress = pciAddress;
   284       input.RegAddress = regAddress;
   285 
   286       value = 0;
   287       return driver.DeviceIOControl(IOCTL_OLS_READ_PCI_CONFIG, input, 
   288         ref value);
   289     }
   290 
   291     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   292     private struct WritePciConfigInput {
   293       public uint PciAddress;
   294       public uint RegAddress;
   295       public uint Value;
   296     }
   297 
   298     public static bool WritePciConfig(uint pciAddress, uint regAddress, 
   299       uint value) 
   300     {
   301       if (driver == null || (regAddress & 3) != 0)
   302         return false;
   303 
   304       WritePciConfigInput input = new WritePciConfigInput();
   305       input.PciAddress = pciAddress;
   306       input.RegAddress = regAddress;
   307       input.Value = value;
   308 
   309       return driver.DeviceIOControl(IOCTL_OLS_WRITE_PCI_CONFIG, input);
   310     }
   311   }
   312 }