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