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