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