Fixed Issue 216.
     3   Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
     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
 
     9   http://www.mozilla.org/MPL/
 
    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.
 
    15   The Original Code is the Open Hardware Monitor code.
 
    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.
 
    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.
 
    40 using System.Reflection;
 
    41 using System.Runtime.InteropServices;
 
    42 using System.Threading;
 
    45 namespace OpenHardwareMonitor.Hardware {
 
    46   internal static class Ring0 {
 
    48     private static KernelDriver driver;
 
    49     private static string fileName;
 
    50     private static Mutex isaBusMutex;
 
    51     private static readonly StringBuilder report = new StringBuilder();
 
    53     private const uint OLS_TYPE = 40000;
 
    54     private static IOControlCode
 
    55       IOCTL_OLS_GET_REFCOUNT = new IOControlCode(OLS_TYPE, 0x801,
 
    56         IOControlCode.Access.Any),
 
    57       IOCTL_OLS_GET_DRIVER_VERSION = new IOControlCode(OLS_TYPE, 0x800,
 
    58         IOControlCode.Access.Any),
 
    59       IOCTL_OLS_READ_MSR = new IOControlCode(OLS_TYPE, 0x821,
 
    60         IOControlCode.Access.Any),
 
    61       IOCTL_OLS_WRITE_MSR = new IOControlCode(OLS_TYPE, 0x822, 
 
    62         IOControlCode.Access.Any),
 
    63       IOCTL_OLS_READ_IO_PORT_BYTE = new IOControlCode(OLS_TYPE, 0x833,
 
    64         IOControlCode.Access.Read),
 
    65       IOCTL_OLS_WRITE_IO_PORT_BYTE = new IOControlCode(OLS_TYPE, 0x836, 
 
    66         IOControlCode.Access.Write),
 
    67       IOCTL_OLS_READ_PCI_CONFIG = new IOControlCode(OLS_TYPE, 0x851, 
 
    68         IOControlCode.Access.Read),
 
    69       IOCTL_OLS_WRITE_PCI_CONFIG = new IOControlCode(OLS_TYPE, 0x852,
 
    70         IOControlCode.Access.Write),
 
    71       IOCTL_OLS_READ_MEMORY = new IOControlCode(OLS_TYPE, 0x841,
 
    72         IOControlCode.Access.Read);
 
    74     private static bool ExtractDriver(string fileName) {
 
    75       string resourceName = "OpenHardwareMonitor.Hardware." +
 
    76         (IntPtr.Size == 4 ? "WinRing0.sys" : "WinRing0x64.sys");
 
    79         Assembly.GetExecutingAssembly().GetManifestResourceNames();
 
    81       for (int i = 0; i < names.Length; i++) {
 
    82         if (names[i].Replace('\\', '.') == resourceName) {
 
    83           using (Stream stream = Assembly.GetExecutingAssembly().
 
    84             GetManifestResourceStream(names[i])) 
 
    86               buffer = new byte[stream.Length];
 
    87               stream.Read(buffer, 0, buffer.Length);
 
    95       using (FileStream target = new FileStream(fileName, FileMode.Create)) {
 
    96         target.Write(buffer, 0, buffer.Length);
 
   102     public static void Open() {
 
   103       // no implementation for unix systems
 
   104       int p = (int)Environment.OSVersion.Platform;
 
   105       if ((p == 4) || (p == 128))
 
   111       // clear the current report
 
   114       driver = new KernelDriver("WinRing0_1_2_0");
 
   117       if (!driver.IsOpen) {
 
   118         // driver is not loaded, try to reinstall and open
 
   121         fileName = Path.GetTempFileName();
 
   122         if (ExtractDriver(fileName)) {
 
   123           if (driver.Install(fileName)) {
 
   126             if (!driver.IsOpen) {
 
   128               report.AppendLine("Status: Opening driver failed");
 
   131             report.AppendLine("Status: Installing driver \"" + 
 
   132               fileName + "\" failed" + 
 
   133               (File.Exists(fileName) ? " and file exists" : ""));
 
   135             report.Append("Exception: " + Marshal.GetExceptionForHR(
 
   136               Marshal.GetHRForLastWin32Error()).Message);
 
   141             "Status: Extracting driver to \"" + fileName + "\" failed");
 
   145           // try to delte the driver file
 
   146           if (File.Exists(fileName))
 
   147             File.Delete(fileName);
 
   149         } catch (IOException) { } 
 
   150           catch (UnauthorizedAccessException) { }
 
   156       isaBusMutex = new Mutex(false, "Global\\Access_ISABUS.HTP.Method");
 
   159     public static bool IsOpen {
 
   160       get { return driver != null; }
 
   163     public static void Close() {
 
   168       driver.DeviceIOControl(IOCTL_OLS_GET_REFCOUNT, null, ref refCount);
 
   179       // try to delete temporary driver file again if failed during open
 
   180       if (fileName != null && File.Exists(fileName)) {
 
   182           File.Delete(fileName);
 
   184         } catch (IOException) { } 
 
   185           catch (UnauthorizedAccessException) { }
 
   189     public static string GetReport() {
 
   190       if (report.Length > 0) {
 
   191         StringBuilder r = new StringBuilder();
 
   192         r.AppendLine("Ring0");
 
   201     public static bool WaitIsaBusMutex(int millisecondsTimeout) {
 
   203         return isaBusMutex.WaitOne(millisecondsTimeout, false);
 
   204       } catch (AbandonedMutexException) { return false; } 
 
   205         catch (InvalidOperationException) { return false; }
 
   208     public static void ReleaseIsaBusMutex() {
 
   209       isaBusMutex.ReleaseMutex();
 
   212     public static bool Rdmsr(uint index, out uint eax, out uint edx) {
 
   213       if (driver == null) {
 
   220       bool result = driver.DeviceIOControl(IOCTL_OLS_READ_MSR, index,
 
   223       edx = (uint)((buffer >> 32) & 0xFFFFFFFF);
 
   224       eax = (uint)(buffer & 0xFFFFFFFF);
 
   228     public static bool RdmsrTx(uint index, out uint eax, out uint edx,
 
   229       ulong threadAffinityMask) 
 
   231       ulong mask = ThreadAffinity.Set(threadAffinityMask);
 
   233       bool result = Rdmsr(index, out eax, out edx);
 
   235       ThreadAffinity.Set(mask);
 
   239     [StructLayout(LayoutKind.Sequential, Pack = 1)]
 
   240     private struct WrmsrInput {
 
   241       public uint Register;
 
   245     public static bool Wrmsr(uint index, uint eax, uint edx) {
 
   249       WrmsrInput input = new WrmsrInput();
 
   250       input.Register = index;
 
   251       input.Value = ((ulong)edx << 32) | eax;
 
   253       return driver.DeviceIOControl(IOCTL_OLS_WRITE_MSR, input);
 
   256     public static byte ReadIoPort(uint port) {
 
   261       driver.DeviceIOControl(IOCTL_OLS_READ_IO_PORT_BYTE, port, ref value);
 
   263       return (byte)(value & 0xFF);
 
   266     [StructLayout(LayoutKind.Sequential, Pack = 1)]
 
   267     private struct WriteIoPortInput {
 
   268       public uint PortNumber;
 
   272     public static void WriteIoPort(uint port, byte value) {
 
   276       WriteIoPortInput input = new WriteIoPortInput();
 
   277       input.PortNumber = port;
 
   280       driver.DeviceIOControl(IOCTL_OLS_WRITE_IO_PORT_BYTE, input);
 
   283     public const uint InvalidPciAddress = 0xFFFFFFFF;
 
   285     public static uint GetPciAddress(byte bus, byte device, byte function) {
 
   287         (uint)(((bus & 0xFF) << 8) | ((device & 0x1F) << 3) | (function & 7));
 
   290     [StructLayout(LayoutKind.Sequential, Pack = 1)]
 
   291     private struct ReadPciConfigInput {
 
   292       public uint PciAddress;
 
   293       public uint RegAddress;
 
   296     public static bool ReadPciConfig(uint pciAddress, uint regAddress, 
 
   299       if (driver == null || (regAddress & 3) != 0) {
 
   304       ReadPciConfigInput input = new ReadPciConfigInput();
 
   305       input.PciAddress = pciAddress;
 
   306       input.RegAddress = regAddress;
 
   309       return driver.DeviceIOControl(IOCTL_OLS_READ_PCI_CONFIG, input, 
 
   313     [StructLayout(LayoutKind.Sequential, Pack = 1)]
 
   314     private struct WritePciConfigInput {
 
   315       public uint PciAddress;
 
   316       public uint RegAddress;
 
   320     public static bool WritePciConfig(uint pciAddress, uint regAddress, 
 
   323       if (driver == null || (regAddress & 3) != 0)
 
   326       WritePciConfigInput input = new WritePciConfigInput();
 
   327       input.PciAddress = pciAddress;
 
   328       input.RegAddress = regAddress;
 
   331       return driver.DeviceIOControl(IOCTL_OLS_WRITE_PCI_CONFIG, input);
 
   334     [StructLayout(LayoutKind.Sequential, Pack = 1)]
 
   335     private struct ReadMemoryInput {
 
   336       public ulong address;
 
   337       public uint unitSize;
 
   341     public static bool ReadMemory<T>(ulong address, ref T buffer) {
 
   342       if (driver == null) {
 
   346       ReadMemoryInput input = new ReadMemoryInput();
 
   347       input.address = address;
 
   349       input.count = (uint)Marshal.SizeOf(buffer);
 
   351       return driver.DeviceIOControl(IOCTL_OLS_READ_MEMORY, input,