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