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