Hardware/Ring0.cs
author moel.mich
Wed, 03 Nov 2010 22:07:46 +0000
changeset 238 bddc6e01840a
parent 236 763675f19ff4
child 254 d8079800a888
permissions -rw-r--r--
Added CPUID support for Linux.
     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
    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 
    44 namespace OpenHardwareMonitor.Hardware {
    45   internal static class Ring0 {
    46 
    47     private static KernelDriver driver;
    48     private static Mutex isaBusMutex;
    49 
    50     private const uint OLS_TYPE = 40000;
    51     private static IOControlCode
    52       IOCTL_OLS_GET_REFCOUNT = new IOControlCode(OLS_TYPE, 0x801,
    53         IOControlCode.Access.Any),
    54       IOCTL_OLS_GET_DRIVER_VERSION = new IOControlCode(OLS_TYPE, 0x800,
    55         IOControlCode.Access.Any),
    56       IOCTL_OLS_READ_MSR = new IOControlCode(OLS_TYPE, 0x821,
    57         IOControlCode.Access.Any),
    58       IOCTL_OLS_WRITE_MSR = new IOControlCode(OLS_TYPE, 0x822, 
    59         IOControlCode.Access.Any),
    60       IOCTL_OLS_READ_IO_PORT_BYTE = new IOControlCode(OLS_TYPE, 0x833,
    61         IOControlCode.Access.Read),
    62       IOCTL_OLS_WRITE_IO_PORT_BYTE = new IOControlCode(OLS_TYPE, 0x836, 
    63         IOControlCode.Access.Write),
    64       IOCTL_OLS_READ_PCI_CONFIG = new IOControlCode(OLS_TYPE, 0x851, 
    65         IOControlCode.Access.Read),
    66       IOCTL_OLS_WRITE_PCI_CONFIG = new IOControlCode(OLS_TYPE, 0x852,
    67         IOControlCode.Access.Write);
    68 
    69     private static bool ExtractDriver(string fileName) {
    70       string resourceName = "OpenHardwareMonitor.Hardware." +
    71         (IntPtr.Size == 4 ? "WinRing0.sys" : "WinRing0x64.sys");
    72 
    73       string[] names =
    74         Assembly.GetExecutingAssembly().GetManifestResourceNames();
    75       byte[] buffer = null;
    76       for (int i = 0; i < names.Length; i++) {
    77         if (names[i].Replace('\\', '.') == resourceName) {
    78           using (Stream stream = Assembly.GetExecutingAssembly().
    79             GetManifestResourceStream(names[i])) 
    80           {
    81               buffer = new byte[stream.Length];
    82               stream.Read(buffer, 0, buffer.Length);
    83           }
    84         }
    85       }
    86 
    87       if (buffer == null)
    88         return false;
    89 
    90       using (FileStream target = new FileStream(fileName, FileMode.Create)) {
    91         target.Write(buffer, 0, buffer.Length);
    92       }
    93 
    94       return true;
    95     }
    96 
    97     public static void Open() {
    98       // No implementation for Unix systems
    99       int p = (int)Environment.OSVersion.Platform;
   100       if ((p == 4) || (p == 128))
   101         return;  
   102       
   103       if (driver != null)
   104         return;
   105      
   106       driver = new KernelDriver("WinRing0_1_2_0");
   107       driver.Open();
   108 
   109       if (!driver.IsOpen) {
   110         string fileName = Path.GetTempFileName();
   111         if (ExtractDriver(fileName)) {
   112 
   113           driver.Install(fileName);
   114           File.Delete(fileName);
   115 
   116           driver.Open();
   117 
   118           if (!driver.IsOpen)
   119             driver.Delete();
   120         }
   121       }
   122 
   123       if (!driver.IsOpen) 
   124         driver = null;
   125 
   126       isaBusMutex = new Mutex(false, "Access_ISABUS.HTP.Method");
   127     }
   128 
   129     public static bool IsOpen {
   130       get { return driver != null; }
   131     }
   132 
   133     public static void Close() {
   134       if (driver == null)
   135         return;
   136 
   137       uint refCount = 0;
   138       driver.DeviceIOControl(IOCTL_OLS_GET_REFCOUNT, null, ref refCount);
   139 
   140       driver.Close();
   141 
   142       if (refCount <= 1)
   143         driver.Delete();
   144 
   145       driver = null;
   146 
   147       isaBusMutex.Close(); 
   148     }
   149 
   150     public static bool WaitIsaBusMutex(int millisecondsTimeout) {
   151       try {
   152         return isaBusMutex.WaitOne(millisecondsTimeout, false);
   153       } catch (AbandonedMutexException) { return false; } 
   154         catch (InvalidOperationException) { return false; }
   155     }
   156 
   157     public static void ReleaseIsaBusMutex() {
   158       isaBusMutex.ReleaseMutex();
   159     }
   160 
   161     public static bool Rdmsr(uint index, out uint eax, out uint edx) {
   162       if (driver == null) {
   163         eax = 0;
   164         edx = 0;
   165         return false;
   166       }
   167 
   168       ulong buffer = 0;
   169       bool result = driver.DeviceIOControl(IOCTL_OLS_READ_MSR, index,
   170         ref buffer);
   171 
   172       edx = (uint)((buffer >> 32) & 0xFFFFFFFF);
   173       eax = (uint)(buffer & 0xFFFFFFFF);
   174       return result;
   175     }
   176 
   177     public static bool RdmsrTx(uint index, out uint eax, out uint edx,
   178       ulong threadAffinityMask) 
   179     {
   180       ulong mask = ThreadAffinity.Set(threadAffinityMask);
   181 
   182       bool result = Rdmsr(index, out eax, out edx);
   183 
   184       ThreadAffinity.Set(mask);
   185       return result;
   186     }
   187 
   188     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   189     private struct WrmsrInput {
   190       public uint Register;
   191       public ulong Value;
   192     }
   193 
   194     public static bool Wrmsr(uint index, uint eax, uint edx) {
   195       if (driver == null)
   196         return false;
   197 
   198       WrmsrInput input = new WrmsrInput();
   199       input.Register = index;
   200       input.Value = ((ulong)edx << 32) | eax;
   201 
   202       return driver.DeviceIOControl(IOCTL_OLS_WRITE_MSR, input);
   203     }
   204 
   205     public static byte ReadIoPort(uint port) {
   206       if (driver == null)
   207         return 0;
   208 
   209       uint value = 0;
   210       driver.DeviceIOControl(IOCTL_OLS_READ_IO_PORT_BYTE, port, ref value);
   211 
   212       return (byte)(value & 0xFF);
   213     }
   214 
   215     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   216     private struct WriteIoPortInput {
   217       public uint PortNumber;
   218       public byte Value;
   219     }
   220 
   221     public static void WriteIoPort(uint port, byte value) {
   222       if (driver == null)
   223         return;
   224 
   225       WriteIoPortInput input = new WriteIoPortInput();
   226       input.PortNumber = port;
   227       input.Value = value;
   228 
   229       driver.DeviceIOControl(IOCTL_OLS_WRITE_IO_PORT_BYTE, input);
   230     }
   231 
   232     public const uint InvalidPciAddress = 0xFFFFFFFF;
   233 
   234     public static uint GetPciAddress(byte bus, byte device, byte function) {
   235       return
   236         (uint)(((bus & 0xFF) << 8) | ((device & 0x1F) << 3) | (function & 7));
   237     }
   238 
   239     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   240     private struct ReadPciConfigInput {
   241       public uint PciAddress;
   242       public uint RegAddress;
   243     }
   244 
   245     public static bool ReadPciConfig(uint pciAddress, uint regAddress, 
   246       out uint value) 
   247     {
   248       if (driver == null || (regAddress & 3) != 0) {
   249         value = 0;
   250         return false;
   251       }
   252 
   253       ReadPciConfigInput input = new ReadPciConfigInput();
   254       input.PciAddress = pciAddress;
   255       input.RegAddress = regAddress;
   256 
   257       value = 0;
   258       return driver.DeviceIOControl(IOCTL_OLS_READ_PCI_CONFIG, input, 
   259         ref value);
   260     }
   261 
   262     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   263     private struct WritePciConfigInput {
   264       public uint PciAddress;
   265       public uint RegAddress;
   266       public uint Value;
   267     }
   268 
   269     public static bool WritePciConfig(uint pciAddress, uint regAddress, 
   270       uint value) 
   271     {
   272       if (driver == null || (regAddress & 3) != 0)
   273         return false;
   274 
   275       WritePciConfigInput input = new WritePciConfigInput();
   276       input.PciAddress = pciAddress;
   277       input.RegAddress = regAddress;
   278       input.Value = value;
   279 
   280       return driver.DeviceIOControl(IOCTL_OLS_WRITE_PCI_CONFIG, input);
   281     }
   282   }
   283 }