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