Hardware/Ring0.cs
author moel.mich
Sun, 24 Jul 2011 16:18:56 +0000
changeset 313 596df85bb4e1
parent 293 9c1b242b1c63
child 344 3145aadca3d2
permissions -rw-r--r--
Improved the CPU load sensors. The values displayed for the load per core and the total load should now be more accurate.
     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       try {
   125         using (FileStream target = new FileStream(fileName, FileMode.Create)) {
   126           target.Write(buffer, 0, buffer.Length);
   127         }
   128       } catch (IOException) { 
   129         // for example there is not enough space on the disk
   130         return false; 
   131       }
   132 
   133       return true;
   134     }
   135 
   136     public static void Open() {
   137       // no implementation for unix systems
   138       int p = (int)Environment.OSVersion.Platform;
   139       if ((p == 4) || (p == 128))
   140         return;  
   141       
   142       if (driver != null)
   143         return;
   144 
   145       // clear the current report
   146       report.Length = 0;
   147      
   148       driver = new KernelDriver("WinRing0_1_2_0");
   149       driver.Open();
   150 
   151       if (!driver.IsOpen) {
   152         // driver is not loaded, try to reinstall and open
   153 
   154         driver.Delete();
   155         fileName = GetTempFileName();
   156         if (fileName != null && ExtractDriver(fileName)) {
   157           if (driver.Install(fileName)) {
   158             driver.Open();
   159 
   160             if (!driver.IsOpen) {
   161               driver.Delete();
   162               report.AppendLine("Status: Opening driver failed");
   163             }
   164           } else {
   165             report.AppendLine("Status: Installing driver \"" +
   166               fileName + "\" failed" +
   167               (File.Exists(fileName) ? " and file exists" : ""));
   168             report.AppendLine();
   169             report.Append("Exception: " + Marshal.GetExceptionForHR(
   170               Marshal.GetHRForLastWin32Error()).Message);
   171           }
   172         } else {
   173           report.AppendLine("Status: Extracting driver failed");
   174         }
   175 
   176         try {
   177           // try to delte the driver file
   178           if (File.Exists(fileName))
   179             File.Delete(fileName);
   180           fileName = null;
   181         } catch (IOException) { } 
   182           catch (UnauthorizedAccessException) { }
   183       }
   184 
   185       if (!driver.IsOpen) 
   186         driver = null;
   187 
   188       string mutexName = "Global\\Access_ISABUS.HTP.Method";
   189       try {
   190         isaBusMutex = new Mutex(false, mutexName);
   191       } catch (UnauthorizedAccessException) {
   192         try {
   193           isaBusMutex = Mutex.OpenExisting(mutexName, MutexRights.Synchronize);
   194         } catch { }
   195       }
   196     }
   197 
   198     public static bool IsOpen {
   199       get { return driver != null; }
   200     }
   201 
   202     public static void Close() {
   203       if (driver == null)
   204         return;
   205 
   206       uint refCount = 0;
   207       driver.DeviceIOControl(IOCTL_OLS_GET_REFCOUNT, null, ref refCount);
   208 
   209       driver.Close();
   210 
   211       if (refCount <= 1)
   212         driver.Delete();
   213 
   214       driver = null;
   215 
   216       if (isaBusMutex != null) {
   217         isaBusMutex.Close();
   218         isaBusMutex = null;
   219       }
   220 
   221       // try to delete temporary driver file again if failed during open
   222       if (fileName != null && File.Exists(fileName)) {
   223         try {
   224           File.Delete(fileName);
   225           fileName = null;
   226         } catch (IOException) { } 
   227           catch (UnauthorizedAccessException) { }
   228       }
   229     }
   230 
   231     public static string GetReport() {
   232       if (report.Length > 0) {
   233         StringBuilder r = new StringBuilder();
   234         r.AppendLine("Ring0");
   235         r.AppendLine();
   236         r.Append(report);
   237         r.AppendLine();
   238         return r.ToString();
   239       } else
   240         return null;
   241     }
   242 
   243     public static bool WaitIsaBusMutex(int millisecondsTimeout) {
   244       if (isaBusMutex == null)
   245         return true;
   246       try {
   247         return isaBusMutex.WaitOne(millisecondsTimeout, false);
   248       } catch (AbandonedMutexException) { return false; } 
   249         catch (InvalidOperationException) { return false; }
   250     }
   251 
   252     public static void ReleaseIsaBusMutex() {
   253       if (isaBusMutex == null)
   254         return;
   255       isaBusMutex.ReleaseMutex();
   256     }
   257 
   258     public static bool Rdmsr(uint index, out uint eax, out uint edx) {
   259       if (driver == null) {
   260         eax = 0;
   261         edx = 0;
   262         return false;
   263       }
   264 
   265       ulong buffer = 0;
   266       bool result = driver.DeviceIOControl(IOCTL_OLS_READ_MSR, index,
   267         ref buffer);
   268 
   269       edx = (uint)((buffer >> 32) & 0xFFFFFFFF);
   270       eax = (uint)(buffer & 0xFFFFFFFF);
   271       return result;
   272     }
   273 
   274     public static bool RdmsrTx(uint index, out uint eax, out uint edx,
   275       ulong threadAffinityMask) 
   276     {
   277       ulong mask = ThreadAffinity.Set(threadAffinityMask);
   278 
   279       bool result = Rdmsr(index, out eax, out edx);
   280 
   281       ThreadAffinity.Set(mask);
   282       return result;
   283     }
   284 
   285     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   286     private struct WrmsrInput {
   287       public uint Register;
   288       public ulong Value;
   289     }
   290 
   291     public static bool Wrmsr(uint index, uint eax, uint edx) {
   292       if (driver == null)
   293         return false;
   294 
   295       WrmsrInput input = new WrmsrInput();
   296       input.Register = index;
   297       input.Value = ((ulong)edx << 32) | eax;
   298 
   299       return driver.DeviceIOControl(IOCTL_OLS_WRITE_MSR, input);
   300     }
   301 
   302     public static byte ReadIoPort(uint port) {
   303       if (driver == null)
   304         return 0;
   305 
   306       uint value = 0;
   307       driver.DeviceIOControl(IOCTL_OLS_READ_IO_PORT_BYTE, port, ref value);
   308 
   309       return (byte)(value & 0xFF);
   310     }
   311 
   312     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   313     private struct WriteIoPortInput {
   314       public uint PortNumber;
   315       public byte Value;
   316     }
   317 
   318     public static void WriteIoPort(uint port, byte value) {
   319       if (driver == null)
   320         return;
   321 
   322       WriteIoPortInput input = new WriteIoPortInput();
   323       input.PortNumber = port;
   324       input.Value = value;
   325 
   326       driver.DeviceIOControl(IOCTL_OLS_WRITE_IO_PORT_BYTE, input);
   327     }
   328 
   329     public const uint InvalidPciAddress = 0xFFFFFFFF;
   330 
   331     public static uint GetPciAddress(byte bus, byte device, byte function) {
   332       return
   333         (uint)(((bus & 0xFF) << 8) | ((device & 0x1F) << 3) | (function & 7));
   334     }
   335 
   336     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   337     private struct ReadPciConfigInput {
   338       public uint PciAddress;
   339       public uint RegAddress;
   340     }
   341 
   342     public static bool ReadPciConfig(uint pciAddress, uint regAddress, 
   343       out uint value) 
   344     {
   345       if (driver == null || (regAddress & 3) != 0) {
   346         value = 0;
   347         return false;
   348       }
   349 
   350       ReadPciConfigInput input = new ReadPciConfigInput();
   351       input.PciAddress = pciAddress;
   352       input.RegAddress = regAddress;
   353 
   354       value = 0;
   355       return driver.DeviceIOControl(IOCTL_OLS_READ_PCI_CONFIG, input, 
   356         ref value);
   357     }
   358 
   359     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   360     private struct WritePciConfigInput {
   361       public uint PciAddress;
   362       public uint RegAddress;
   363       public uint Value;
   364     }
   365 
   366     public static bool WritePciConfig(uint pciAddress, uint regAddress, 
   367       uint value) 
   368     {
   369       if (driver == null || (regAddress & 3) != 0)
   370         return false;
   371 
   372       WritePciConfigInput input = new WritePciConfigInput();
   373       input.PciAddress = pciAddress;
   374       input.RegAddress = regAddress;
   375       input.Value = value;
   376 
   377       return driver.DeviceIOControl(IOCTL_OLS_WRITE_PCI_CONFIG, input);
   378     }
   379 
   380     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   381     private struct ReadMemoryInput {
   382       public ulong address;
   383       public uint unitSize;
   384       public uint count;
   385     }
   386 
   387     public static bool ReadMemory<T>(ulong address, ref T buffer) {
   388       if (driver == null) {
   389         return false;
   390       }
   391 
   392       ReadMemoryInput input = new ReadMemoryInput();
   393       input.address = address;
   394       input.unitSize = 1;
   395       input.count = (uint)Marshal.SizeOf(buffer);
   396 
   397       return driver.DeviceIOControl(IOCTL_OLS_READ_MEMORY, input,
   398         ref buffer);
   399     }
   400   }
   401 }