Hardware/KernelDriver.cs
author moel.mich
Sun, 08 May 2011 22:10:13 +0000
changeset 279 6bce967ba1b5
parent 236 763675f19ff4
child 344 3145aadca3d2
permissions -rw-r--r--
Fixed the bus and core clock reading on AMD family 10h model Ah CPUs. The new "Core Performance Boost" feature of these CPUs resulted in very low accuracy of the bus speed (and as a consequence also an inaccurate TSC multiplier). This fixed Issue 205.
     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.Runtime.InteropServices;
    41 using System.Security.AccessControl;
    42 using Microsoft.Win32.SafeHandles;
    43 
    44 namespace OpenHardwareMonitor.Hardware {
    45   internal class KernelDriver {
    46 
    47     private string id;
    48 
    49     private SafeFileHandle device; 
    50     
    51     public KernelDriver(string id) {
    52       this.id = id;
    53     }
    54    
    55     public bool Install(string path) {
    56       IntPtr manager = NativeMethods.OpenSCManager(null, null,
    57         ServiceControlManagerAccessRights.SC_MANAGER_ALL_ACCESS);
    58 
    59       if (manager == IntPtr.Zero)
    60         return false;
    61 
    62       IntPtr service = NativeMethods.CreateService(manager, id, id,
    63         ServiceAccessRights.SERVICE_ALL_ACCESS,
    64         ServiceType.SERVICE_KERNEL_DRIVER, StartType.SERVICE_DEMAND_START,
    65         ErrorControl.SERVICE_ERROR_NORMAL, path, null, null, null, null,
    66         null);
    67 
    68       if (service == IntPtr.Zero) {
    69         if (Marshal.GetHRForLastWin32Error() == ERROR_SERVICE_EXISTS)
    70           service = NativeMethods.OpenService(manager, id,
    71             ServiceAccessRights.SERVICE_ALL_ACCESS);
    72         else
    73           return false;
    74       }
    75 
    76       if (!NativeMethods.StartService(service, 0, null)) {
    77         if (Marshal.GetHRForLastWin32Error() != ERROR_SERVICE_ALREADY_RUNNING)
    78           return false;
    79       }
    80 
    81       NativeMethods.CloseServiceHandle(service);
    82       NativeMethods.CloseServiceHandle(manager);
    83       
    84       try {
    85         // restrict the driver access to system (SY) and builtin admins (BA)
    86         // TODO: replace with a call to IoCreateDeviceSecure in the driver
    87         FileSecurity fileSecurity = File.GetAccessControl(@"\\.\" + id);
    88         fileSecurity.SetSecurityDescriptorSddlForm(
    89           "O:BAG:SYD:(A;;FA;;;SY)(A;;FA;;;BA)");
    90         File.SetAccessControl(@"\\.\" + id, fileSecurity);
    91       } catch { }
    92       
    93       return true;
    94     }
    95 
    96     public bool Open() {
    97       device = new SafeFileHandle(NativeMethods.CreateFile(@"\\.\" + id,
    98         FileAccess.GENERIC_READ | FileAccess.GENERIC_WRITE, 0, IntPtr.Zero,
    99         CreationDisposition.OPEN_EXISTING, FileAttributes.FILE_ATTRIBUTE_NORMAL,
   100         IntPtr.Zero), true);
   101 
   102       if (device.IsInvalid) {
   103         device.Close();
   104         device.Dispose();
   105         device = null;
   106       }
   107 
   108       return device != null;
   109     }
   110 
   111     public bool IsOpen {
   112       get { return device != null; }
   113     }
   114 
   115     public bool DeviceIOControl(IOControlCode ioControlCode, object inBuffer) {
   116       if (device == null)
   117         return false;
   118 
   119       uint bytesReturned;
   120       bool b = NativeMethods.DeviceIoControl(device, ioControlCode,
   121         inBuffer, inBuffer == null ? 0 : (uint)Marshal.SizeOf(inBuffer),
   122         null, 0, out bytesReturned, IntPtr.Zero);
   123       return b;
   124     }
   125 
   126     public bool DeviceIOControl<T>(IOControlCode ioControlCode, object inBuffer, 
   127       ref T outBuffer) 
   128     {
   129       if (device == null)
   130         return false;
   131 
   132       object boxedOutBuffer = outBuffer;
   133       uint bytesReturned;
   134       bool b = NativeMethods.DeviceIoControl(device, ioControlCode,
   135         inBuffer, inBuffer == null ? 0 : (uint)Marshal.SizeOf(inBuffer),
   136         boxedOutBuffer, (uint)Marshal.SizeOf(boxedOutBuffer),
   137         out bytesReturned, IntPtr.Zero);
   138       outBuffer = (T)boxedOutBuffer;
   139       return b;
   140     }
   141 
   142     public void Close() {
   143       if (device != null) {
   144         device.Close();
   145         device.Dispose();
   146         device = null;
   147       }
   148     }
   149 
   150     public bool Delete() {
   151       IntPtr manager = NativeMethods.OpenSCManager(null, null,
   152       ServiceControlManagerAccessRights.SC_MANAGER_ALL_ACCESS);
   153 
   154       if (manager == IntPtr.Zero)
   155         return false;      
   156 
   157       IntPtr service = NativeMethods.OpenService(manager, id,
   158         ServiceAccessRights.SERVICE_ALL_ACCESS);
   159 
   160       if (service == IntPtr.Zero)
   161         return true;
   162 
   163       ServiceStatus status = new ServiceStatus();
   164       NativeMethods.ControlService(service, ServiceControl.SERVICE_CONTROL_STOP, 
   165         ref status);
   166 
   167       NativeMethods.DeleteService(service);
   168 
   169       NativeMethods.CloseServiceHandle(service);
   170       NativeMethods.CloseServiceHandle(manager);
   171       
   172       return true;
   173     }
   174 
   175     private enum ServiceAccessRights : uint {
   176       SERVICE_ALL_ACCESS = 0xF01FF
   177     }
   178 
   179     private enum ServiceControlManagerAccessRights : uint {
   180       SC_MANAGER_ALL_ACCESS = 0xF003F
   181     }
   182 
   183     private enum ServiceType : uint {
   184       SERVICE_KERNEL_DRIVER = 1,
   185       SERVICE_FILE_SYSTEM_DRIVER = 2
   186     }
   187 
   188     private enum StartType : uint {
   189       SERVICE_BOOT_START = 0,
   190       SERVICE_SYSTEM_START = 1,
   191       SERVICE_AUTO_START = 2,
   192       SERVICE_DEMAND_START = 3,
   193       SERVICE_DISABLED = 4
   194     }
   195 
   196     private enum ErrorControl : uint {
   197       SERVICE_ERROR_IGNORE = 0,
   198       SERVICE_ERROR_NORMAL = 1,
   199       SERVICE_ERROR_SEVERE = 2,
   200       SERVICE_ERROR_CRITICAL = 3
   201     }
   202 
   203     private enum ServiceControl : uint {
   204       SERVICE_CONTROL_STOP = 1,
   205       SERVICE_CONTROL_PAUSE = 2,
   206       SERVICE_CONTROL_CONTINUE = 3,
   207       SERVICE_CONTROL_INTERROGATE = 4,
   208       SERVICE_CONTROL_SHUTDOWN = 5,
   209       SERVICE_CONTROL_PARAMCHANGE = 6,
   210       SERVICE_CONTROL_NETBINDADD = 7,
   211       SERVICE_CONTROL_NETBINDREMOVE = 8,
   212       SERVICE_CONTROL_NETBINDENABLE = 9,
   213       SERVICE_CONTROL_NETBINDDISABLE = 10,
   214       SERVICE_CONTROL_DEVICEEVENT = 11,
   215       SERVICE_CONTROL_HARDWAREPROFILECHANGE = 12,
   216       SERVICE_CONTROL_POWEREVENT = 13,
   217       SERVICE_CONTROL_SESSIONCHANGE = 14
   218     }
   219 
   220     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   221     private struct ServiceStatus {
   222       public uint dwServiceType;
   223       public uint dwCurrentState;
   224       public uint dwControlsAccepted;
   225       public uint dwWin32ExitCode;
   226       public uint dwServiceSpecificExitCode;
   227       public uint dwCheckPoint;
   228       public uint dwWaitHint;
   229     }
   230 
   231     private enum FileAccess : uint {
   232       GENERIC_READ = 0x80000000,
   233       GENERIC_WRITE = 0x40000000
   234     }
   235 
   236     private enum CreationDisposition : uint {
   237       CREATE_NEW = 1,
   238       CREATE_ALWAYS = 2,
   239       OPEN_EXISTING = 3,
   240       OPEN_ALWAYS = 4,
   241       TRUNCATE_EXISTING = 5
   242     }
   243 
   244     private enum FileAttributes : uint {
   245       FILE_ATTRIBUTE_NORMAL = 0x80
   246     }
   247 
   248     private const int
   249       ERROR_SERVICE_EXISTS = unchecked((int)0x80070431),
   250       ERROR_SERVICE_ALREADY_RUNNING = unchecked((int)0x80070420);
   251 
   252     private static class NativeMethods {
   253       private const string ADVAPI = "advapi32.dll";
   254       private const string KERNEL = "kernel32.dll";
   255 
   256       [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi)]
   257       public static extern IntPtr OpenSCManager(string machineName,
   258         string databaseName, ServiceControlManagerAccessRights dwAccess);
   259 
   260       [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi)]
   261       [return: MarshalAs(UnmanagedType.Bool)]
   262       public static extern bool CloseServiceHandle(IntPtr hSCObject);
   263 
   264       [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
   265         SetLastError = true)]
   266       public static extern IntPtr CreateService(IntPtr hSCManager,
   267         string lpServiceName, string lpDisplayName, 
   268         ServiceAccessRights dwDesiredAccess, ServiceType dwServiceType,
   269         StartType dwStartType, ErrorControl dwErrorControl,
   270         string lpBinaryPathName, string lpLoadOrderGroup, string lpdwTagId,
   271         string lpDependencies, string lpServiceStartName, string lpPassword);
   272 
   273       [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
   274         SetLastError = true)]
   275       public static extern IntPtr OpenService(IntPtr hSCManager,
   276         string lpServiceName, ServiceAccessRights dwDesiredAccess);
   277 
   278       [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
   279         SetLastError = true)]
   280       [return: MarshalAs(UnmanagedType.Bool)]
   281       public static extern bool DeleteService(IntPtr hService);
   282 
   283       [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
   284         SetLastError = true)]
   285       [return: MarshalAs(UnmanagedType.Bool)]
   286       public static extern bool StartService(IntPtr hService, 
   287         uint dwNumServiceArgs, string[] lpServiceArgVectors);
   288 
   289       [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
   290         SetLastError = true)]
   291       [return: MarshalAs(UnmanagedType.Bool)]
   292       public static extern bool ControlService(IntPtr hService,
   293         ServiceControl dwControl, ref ServiceStatus lpServiceStatus);
   294 
   295       [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   296       public static extern bool DeviceIoControl(SafeFileHandle device,
   297         IOControlCode ioControlCode, 
   298         [MarshalAs(UnmanagedType.AsAny)] [In] object inBuffer, 
   299         uint inBufferSize,
   300         [MarshalAs(UnmanagedType.AsAny)] [Out] object outBuffer,
   301         uint nOutBufferSize, out uint bytesReturned, IntPtr overlapped);
   302 
   303       [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi, 
   304         SetLastError = true)]
   305       public static extern IntPtr CreateFile(string lpFileName,
   306         FileAccess dwDesiredAccess, uint dwShareMode, 
   307         IntPtr lpSecurityAttributes, CreationDisposition dwCreationDisposition, 
   308         FileAttributes dwFlagsAndAttributes, IntPtr hTemplateFile);
   309     }
   310   }
   311 }