Hardware/Ring0.cs
author moel.mich
Tue, 15 Mar 2011 17:55:11 +0000
changeset 259 d83e927ee9d2
parent 256 6dc6410489f4
child 279 6bce967ba1b5
permissions -rw-r--r--
Fixed Issue 165.
     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, "Global\\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         StringBuilder r = new StringBuilder();
   172         r.AppendLine("Ring0");
   173         r.AppendLine();
   174         r.Append(report);
   175         r.AppendLine();
   176         return r.ToString();
   177       } else
   178         return null;
   179     }
   180 
   181     public static bool WaitIsaBusMutex(int millisecondsTimeout) {
   182       try {
   183         return isaBusMutex.WaitOne(millisecondsTimeout, false);
   184       } catch (AbandonedMutexException) { return false; } 
   185         catch (InvalidOperationException) { return false; }
   186     }
   187 
   188     public static void ReleaseIsaBusMutex() {
   189       isaBusMutex.ReleaseMutex();
   190     }
   191 
   192     public static bool Rdmsr(uint index, out uint eax, out uint edx) {
   193       if (driver == null) {
   194         eax = 0;
   195         edx = 0;
   196         return false;
   197       }
   198 
   199       ulong buffer = 0;
   200       bool result = driver.DeviceIOControl(IOCTL_OLS_READ_MSR, index,
   201         ref buffer);
   202 
   203       edx = (uint)((buffer >> 32) & 0xFFFFFFFF);
   204       eax = (uint)(buffer & 0xFFFFFFFF);
   205       return result;
   206     }
   207 
   208     public static bool RdmsrTx(uint index, out uint eax, out uint edx,
   209       ulong threadAffinityMask) 
   210     {
   211       ulong mask = ThreadAffinity.Set(threadAffinityMask);
   212 
   213       bool result = Rdmsr(index, out eax, out edx);
   214 
   215       ThreadAffinity.Set(mask);
   216       return result;
   217     }
   218 
   219     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   220     private struct WrmsrInput {
   221       public uint Register;
   222       public ulong Value;
   223     }
   224 
   225     public static bool Wrmsr(uint index, uint eax, uint edx) {
   226       if (driver == null)
   227         return false;
   228 
   229       WrmsrInput input = new WrmsrInput();
   230       input.Register = index;
   231       input.Value = ((ulong)edx << 32) | eax;
   232 
   233       return driver.DeviceIOControl(IOCTL_OLS_WRITE_MSR, input);
   234     }
   235 
   236     public static byte ReadIoPort(uint port) {
   237       if (driver == null)
   238         return 0;
   239 
   240       uint value = 0;
   241       driver.DeviceIOControl(IOCTL_OLS_READ_IO_PORT_BYTE, port, ref value);
   242 
   243       return (byte)(value & 0xFF);
   244     }
   245 
   246     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   247     private struct WriteIoPortInput {
   248       public uint PortNumber;
   249       public byte Value;
   250     }
   251 
   252     public static void WriteIoPort(uint port, byte value) {
   253       if (driver == null)
   254         return;
   255 
   256       WriteIoPortInput input = new WriteIoPortInput();
   257       input.PortNumber = port;
   258       input.Value = value;
   259 
   260       driver.DeviceIOControl(IOCTL_OLS_WRITE_IO_PORT_BYTE, input);
   261     }
   262 
   263     public const uint InvalidPciAddress = 0xFFFFFFFF;
   264 
   265     public static uint GetPciAddress(byte bus, byte device, byte function) {
   266       return
   267         (uint)(((bus & 0xFF) << 8) | ((device & 0x1F) << 3) | (function & 7));
   268     }
   269 
   270     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   271     private struct ReadPciConfigInput {
   272       public uint PciAddress;
   273       public uint RegAddress;
   274     }
   275 
   276     public static bool ReadPciConfig(uint pciAddress, uint regAddress, 
   277       out uint value) 
   278     {
   279       if (driver == null || (regAddress & 3) != 0) {
   280         value = 0;
   281         return false;
   282       }
   283 
   284       ReadPciConfigInput input = new ReadPciConfigInput();
   285       input.PciAddress = pciAddress;
   286       input.RegAddress = regAddress;
   287 
   288       value = 0;
   289       return driver.DeviceIOControl(IOCTL_OLS_READ_PCI_CONFIG, input, 
   290         ref value);
   291     }
   292 
   293     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   294     private struct WritePciConfigInput {
   295       public uint PciAddress;
   296       public uint RegAddress;
   297       public uint Value;
   298     }
   299 
   300     public static bool WritePciConfig(uint pciAddress, uint regAddress, 
   301       uint value) 
   302     {
   303       if (driver == null || (regAddress & 3) != 0)
   304         return false;
   305 
   306       WritePciConfigInput input = new WritePciConfigInput();
   307       input.PciAddress = pciAddress;
   308       input.RegAddress = regAddress;
   309       input.Value = value;
   310 
   311       return driver.DeviceIOControl(IOCTL_OLS_WRITE_PCI_CONFIG, input);
   312     }
   313   }
   314 }