Hardware/Ring0.cs
author moel.mich
Sun, 15 May 2011 16:20:30 +0000
changeset 283 fb88cac4a9aa
parent 281 1c301069cfce
child 285 0820c0558727
permissions -rw-r--r--
Fixed Issue 218.
     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 string fileName;
    50     private static Mutex isaBusMutex;
    51     private static readonly StringBuilder report = new StringBuilder();
    52 
    53     private const uint OLS_TYPE = 40000;
    54     private static IOControlCode
    55       IOCTL_OLS_GET_REFCOUNT = new IOControlCode(OLS_TYPE, 0x801,
    56         IOControlCode.Access.Any),
    57       IOCTL_OLS_GET_DRIVER_VERSION = new IOControlCode(OLS_TYPE, 0x800,
    58         IOControlCode.Access.Any),
    59       IOCTL_OLS_READ_MSR = new IOControlCode(OLS_TYPE, 0x821,
    60         IOControlCode.Access.Any),
    61       IOCTL_OLS_WRITE_MSR = new IOControlCode(OLS_TYPE, 0x822, 
    62         IOControlCode.Access.Any),
    63       IOCTL_OLS_READ_IO_PORT_BYTE = new IOControlCode(OLS_TYPE, 0x833,
    64         IOControlCode.Access.Read),
    65       IOCTL_OLS_WRITE_IO_PORT_BYTE = new IOControlCode(OLS_TYPE, 0x836, 
    66         IOControlCode.Access.Write),
    67       IOCTL_OLS_READ_PCI_CONFIG = new IOControlCode(OLS_TYPE, 0x851, 
    68         IOControlCode.Access.Read),
    69       IOCTL_OLS_WRITE_PCI_CONFIG = new IOControlCode(OLS_TYPE, 0x852,
    70         IOControlCode.Access.Write),
    71       IOCTL_OLS_READ_MEMORY = new IOControlCode(OLS_TYPE, 0x841,
    72         IOControlCode.Access.Read);
    73 
    74     private static string GetTempFileName() {
    75 
    76       // try to get a file in the temporary folder
    77       try {
    78         return Path.GetTempFileName();        
    79       } catch (IOException) { } 
    80         catch (UnauthorizedAccessException) { }
    81 
    82       // if this failed, we try to create one in the application folder
    83       string fileName = Path.ChangeExtension(
    84         Assembly.GetExecutingAssembly().Location, ".sys");
    85       try {
    86         using (FileStream stream = File.Create(fileName)) {
    87           return fileName;
    88         }        
    89       } catch (IOException) { } 
    90         catch (UnauthorizedAccessException) { }
    91      
    92       return null;
    93     }
    94 
    95     private static bool ExtractDriver(string fileName) {
    96       string resourceName = "OpenHardwareMonitor.Hardware." +
    97         (IntPtr.Size == 4 ? "WinRing0.sys" : "WinRing0x64.sys");
    98 
    99       string[] names =
   100         Assembly.GetExecutingAssembly().GetManifestResourceNames();
   101       byte[] buffer = null;
   102       for (int i = 0; i < names.Length; i++) {
   103         if (names[i].Replace('\\', '.') == resourceName) {
   104           using (Stream stream = Assembly.GetExecutingAssembly().
   105             GetManifestResourceStream(names[i])) 
   106           {
   107               buffer = new byte[stream.Length];
   108               stream.Read(buffer, 0, buffer.Length);
   109           }
   110         }
   111       }
   112 
   113       if (buffer == null)
   114         return false;
   115 
   116       using (FileStream target = new FileStream(fileName, FileMode.Create)) {
   117         target.Write(buffer, 0, buffer.Length);
   118       }
   119 
   120       return true;
   121     }
   122 
   123     public static void Open() {
   124       // no implementation for unix systems
   125       int p = (int)Environment.OSVersion.Platform;
   126       if ((p == 4) || (p == 128))
   127         return;  
   128       
   129       if (driver != null)
   130         return;
   131 
   132       // clear the current report
   133       report.Length = 0;
   134      
   135       driver = new KernelDriver("WinRing0_1_2_0");
   136       driver.Open();
   137 
   138       if (!driver.IsOpen) {
   139         // driver is not loaded, try to reinstall and open
   140 
   141         driver.Delete();
   142         fileName = GetTempFileName();
   143         if (fileName != null && ExtractDriver(fileName)) {
   144           if (driver.Install(fileName)) {
   145             driver.Open();
   146 
   147             if (!driver.IsOpen) {
   148               driver.Delete();
   149               report.AppendLine("Status: Opening driver failed");
   150             }
   151           } else {
   152             report.AppendLine("Status: Installing driver \"" +
   153               fileName + "\" failed" +
   154               (File.Exists(fileName) ? " and file exists" : ""));
   155             report.AppendLine();
   156             report.Append("Exception: " + Marshal.GetExceptionForHR(
   157               Marshal.GetHRForLastWin32Error()).Message);
   158           }
   159         } else {
   160           report.AppendLine("Status: Extracting driver failed");
   161         }
   162 
   163         try {
   164           // try to delte the driver file
   165           if (File.Exists(fileName))
   166             File.Delete(fileName);
   167           fileName = null;
   168         } catch (IOException) { } 
   169           catch (UnauthorizedAccessException) { }
   170       }
   171 
   172       if (!driver.IsOpen) 
   173         driver = null;
   174 
   175       isaBusMutex = new Mutex(false, "Global\\Access_ISABUS.HTP.Method");
   176     }
   177 
   178     public static bool IsOpen {
   179       get { return driver != null; }
   180     }
   181 
   182     public static void Close() {
   183       if (driver == null)
   184         return;
   185 
   186       uint refCount = 0;
   187       driver.DeviceIOControl(IOCTL_OLS_GET_REFCOUNT, null, ref refCount);
   188 
   189       driver.Close();
   190 
   191       if (refCount <= 1)
   192         driver.Delete();
   193 
   194       driver = null;
   195 
   196       isaBusMutex.Close();
   197 
   198       // try to delete temporary driver file again if failed during open
   199       if (fileName != null && File.Exists(fileName)) {
   200         try {
   201           File.Delete(fileName);
   202           fileName = null;
   203         } catch (IOException) { } 
   204           catch (UnauthorizedAccessException) { }
   205       }
   206     }
   207 
   208     public static string GetReport() {
   209       if (report.Length > 0) {
   210         StringBuilder r = new StringBuilder();
   211         r.AppendLine("Ring0");
   212         r.AppendLine();
   213         r.Append(report);
   214         r.AppendLine();
   215         return r.ToString();
   216       } else
   217         return null;
   218     }
   219 
   220     public static bool WaitIsaBusMutex(int millisecondsTimeout) {
   221       try {
   222         return isaBusMutex.WaitOne(millisecondsTimeout, false);
   223       } catch (AbandonedMutexException) { return false; } 
   224         catch (InvalidOperationException) { return false; }
   225     }
   226 
   227     public static void ReleaseIsaBusMutex() {
   228       isaBusMutex.ReleaseMutex();
   229     }
   230 
   231     public static bool Rdmsr(uint index, out uint eax, out uint edx) {
   232       if (driver == null) {
   233         eax = 0;
   234         edx = 0;
   235         return false;
   236       }
   237 
   238       ulong buffer = 0;
   239       bool result = driver.DeviceIOControl(IOCTL_OLS_READ_MSR, index,
   240         ref buffer);
   241 
   242       edx = (uint)((buffer >> 32) & 0xFFFFFFFF);
   243       eax = (uint)(buffer & 0xFFFFFFFF);
   244       return result;
   245     }
   246 
   247     public static bool RdmsrTx(uint index, out uint eax, out uint edx,
   248       ulong threadAffinityMask) 
   249     {
   250       ulong mask = ThreadAffinity.Set(threadAffinityMask);
   251 
   252       bool result = Rdmsr(index, out eax, out edx);
   253 
   254       ThreadAffinity.Set(mask);
   255       return result;
   256     }
   257 
   258     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   259     private struct WrmsrInput {
   260       public uint Register;
   261       public ulong Value;
   262     }
   263 
   264     public static bool Wrmsr(uint index, uint eax, uint edx) {
   265       if (driver == null)
   266         return false;
   267 
   268       WrmsrInput input = new WrmsrInput();
   269       input.Register = index;
   270       input.Value = ((ulong)edx << 32) | eax;
   271 
   272       return driver.DeviceIOControl(IOCTL_OLS_WRITE_MSR, input);
   273     }
   274 
   275     public static byte ReadIoPort(uint port) {
   276       if (driver == null)
   277         return 0;
   278 
   279       uint value = 0;
   280       driver.DeviceIOControl(IOCTL_OLS_READ_IO_PORT_BYTE, port, ref value);
   281 
   282       return (byte)(value & 0xFF);
   283     }
   284 
   285     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   286     private struct WriteIoPortInput {
   287       public uint PortNumber;
   288       public byte Value;
   289     }
   290 
   291     public static void WriteIoPort(uint port, byte value) {
   292       if (driver == null)
   293         return;
   294 
   295       WriteIoPortInput input = new WriteIoPortInput();
   296       input.PortNumber = port;
   297       input.Value = value;
   298 
   299       driver.DeviceIOControl(IOCTL_OLS_WRITE_IO_PORT_BYTE, input);
   300     }
   301 
   302     public const uint InvalidPciAddress = 0xFFFFFFFF;
   303 
   304     public static uint GetPciAddress(byte bus, byte device, byte function) {
   305       return
   306         (uint)(((bus & 0xFF) << 8) | ((device & 0x1F) << 3) | (function & 7));
   307     }
   308 
   309     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   310     private struct ReadPciConfigInput {
   311       public uint PciAddress;
   312       public uint RegAddress;
   313     }
   314 
   315     public static bool ReadPciConfig(uint pciAddress, uint regAddress, 
   316       out uint value) 
   317     {
   318       if (driver == null || (regAddress & 3) != 0) {
   319         value = 0;
   320         return false;
   321       }
   322 
   323       ReadPciConfigInput input = new ReadPciConfigInput();
   324       input.PciAddress = pciAddress;
   325       input.RegAddress = regAddress;
   326 
   327       value = 0;
   328       return driver.DeviceIOControl(IOCTL_OLS_READ_PCI_CONFIG, input, 
   329         ref value);
   330     }
   331 
   332     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   333     private struct WritePciConfigInput {
   334       public uint PciAddress;
   335       public uint RegAddress;
   336       public uint Value;
   337     }
   338 
   339     public static bool WritePciConfig(uint pciAddress, uint regAddress, 
   340       uint value) 
   341     {
   342       if (driver == null || (regAddress & 3) != 0)
   343         return false;
   344 
   345       WritePciConfigInput input = new WritePciConfigInput();
   346       input.PciAddress = pciAddress;
   347       input.RegAddress = regAddress;
   348       input.Value = value;
   349 
   350       return driver.DeviceIOControl(IOCTL_OLS_WRITE_PCI_CONFIG, input);
   351     }
   352 
   353     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   354     private struct ReadMemoryInput {
   355       public ulong address;
   356       public uint unitSize;
   357       public uint count;
   358     }
   359 
   360     public static bool ReadMemory<T>(ulong address, ref T buffer) {
   361       if (driver == null) {
   362         return false;
   363       }
   364 
   365       ReadMemoryInput input = new ReadMemoryInput();
   366       input.address = address;
   367       input.unitSize = 1;
   368       input.count = (uint)Marshal.SizeOf(buffer);
   369 
   370       return driver.DeviceIOControl(IOCTL_OLS_READ_MEMORY, input,
   371         ref buffer);
   372     }
   373   }
   374 }