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.
moel@236
     1
/*
moel@236
     2
  
moel@236
     3
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@236
     4
moel@236
     5
  The contents of this file are subject to the Mozilla Public License Version
moel@236
     6
  1.1 (the "License"); you may not use this file except in compliance with
moel@236
     7
  the License. You may obtain a copy of the License at
moel@236
     8
 
moel@236
     9
  http://www.mozilla.org/MPL/
moel@236
    10
moel@236
    11
  Software distributed under the License is distributed on an "AS IS" basis,
moel@236
    12
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@236
    13
  for the specific language governing rights and limitations under the License.
moel@236
    14
moel@236
    15
  The Original Code is the Open Hardware Monitor code.
moel@236
    16
moel@236
    17
  The Initial Developer of the Original Code is 
moel@236
    18
  Michael Möller <m.moeller@gmx.ch>.
moel@236
    19
  Portions created by the Initial Developer are Copyright (C) 2010
moel@236
    20
  the Initial Developer. All Rights Reserved.
moel@236
    21
moel@236
    22
  Contributor(s):
moel@236
    23
moel@236
    24
  Alternatively, the contents of this file may be used under the terms of
moel@236
    25
  either the GNU General Public License Version 2 or later (the "GPL"), or
moel@236
    26
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@236
    27
  in which case the provisions of the GPL or the LGPL are applicable instead
moel@236
    28
  of those above. If you wish to allow use of your version of this file only
moel@236
    29
  under the terms of either the GPL or the LGPL, and not to allow others to
moel@236
    30
  use your version of this file under the terms of the MPL, indicate your
moel@236
    31
  decision by deleting the provisions above and replace them with the notice
moel@236
    32
  and other provisions required by the GPL or the LGPL. If you do not delete
moel@236
    33
  the provisions above, a recipient may use your version of this file under
moel@236
    34
  the terms of any one of the MPL, the GPL or the LGPL.
moel@236
    35
 
moel@236
    36
*/
moel@236
    37
moel@236
    38
using System;
moel@237
    39
using System.IO;
moel@236
    40
using System.Runtime.InteropServices;
moel@237
    41
using System.Security.AccessControl;
moel@236
    42
using Microsoft.Win32.SafeHandles;
moel@236
    43
moel@236
    44
namespace OpenHardwareMonitor.Hardware {
moel@236
    45
  internal class KernelDriver {
moel@236
    46
moel@236
    47
    private string id;
moel@236
    48
moel@236
    49
    private SafeFileHandle device; 
moel@236
    50
    
moel@236
    51
    public KernelDriver(string id) {
moel@236
    52
      this.id = id;
moel@236
    53
    }
moel@236
    54
   
moel@236
    55
    public bool Install(string path) {
moel@236
    56
      IntPtr manager = NativeMethods.OpenSCManager(null, null,
moel@236
    57
        ServiceControlManagerAccessRights.SC_MANAGER_ALL_ACCESS);
moel@236
    58
moel@236
    59
      if (manager == IntPtr.Zero)
moel@236
    60
        return false;
moel@236
    61
moel@236
    62
      IntPtr service = NativeMethods.CreateService(manager, id, id,
moel@236
    63
        ServiceAccessRights.SERVICE_ALL_ACCESS,
moel@236
    64
        ServiceType.SERVICE_KERNEL_DRIVER, StartType.SERVICE_DEMAND_START,
moel@236
    65
        ErrorControl.SERVICE_ERROR_NORMAL, path, null, null, null, null,
moel@236
    66
        null);
moel@236
    67
moel@236
    68
      if (service == IntPtr.Zero) {
moel@236
    69
        if (Marshal.GetHRForLastWin32Error() == ERROR_SERVICE_EXISTS)
moel@236
    70
          service = NativeMethods.OpenService(manager, id,
moel@236
    71
            ServiceAccessRights.SERVICE_ALL_ACCESS);
moel@236
    72
        else
moel@236
    73
          return false;
moel@236
    74
      }
moel@236
    75
moel@236
    76
      if (!NativeMethods.StartService(service, 0, null)) {
moel@236
    77
        if (Marshal.GetHRForLastWin32Error() != ERROR_SERVICE_ALREADY_RUNNING)
moel@236
    78
          return false;
moel@236
    79
      }
moel@236
    80
moel@236
    81
      NativeMethods.CloseServiceHandle(service);
moel@236
    82
      NativeMethods.CloseServiceHandle(manager);
moel@237
    83
      
moel@237
    84
      try {
moel@237
    85
        // restrict the driver access to system (SY) and builtin admins (BA)
moel@237
    86
        // TODO: replace with a call to IoCreateDeviceSecure in the driver
moel@237
    87
        FileSecurity fileSecurity = File.GetAccessControl(@"\\.\" + id);
moel@237
    88
        fileSecurity.SetSecurityDescriptorSddlForm(
moel@237
    89
          "O:BAG:SYD:(A;;FA;;;SY)(A;;FA;;;BA)");
moel@237
    90
        File.SetAccessControl(@"\\.\" + id, fileSecurity);
moel@237
    91
      } catch { }
moel@237
    92
      
moel@236
    93
      return true;
moel@236
    94
    }
moel@236
    95
moel@236
    96
    public bool Open() {
moel@236
    97
      device = new SafeFileHandle(NativeMethods.CreateFile(@"\\.\" + id,
moel@236
    98
        FileAccess.GENERIC_READ | FileAccess.GENERIC_WRITE, 0, IntPtr.Zero,
moel@236
    99
        CreationDisposition.OPEN_EXISTING, FileAttributes.FILE_ATTRIBUTE_NORMAL,
moel@236
   100
        IntPtr.Zero), true);
moel@236
   101
moel@236
   102
      if (device.IsInvalid) {
moel@236
   103
        device.Close();
moel@236
   104
        device.Dispose();
moel@236
   105
        device = null;
moel@236
   106
      }
moel@236
   107
moel@236
   108
      return device != null;
moel@236
   109
    }
moel@236
   110
moel@236
   111
    public bool IsOpen {
moel@236
   112
      get { return device != null; }
moel@236
   113
    }
moel@236
   114
moel@236
   115
    public bool DeviceIOControl(IOControlCode ioControlCode, object inBuffer) {
moel@236
   116
      if (device == null)
moel@236
   117
        return false;
moel@236
   118
moel@236
   119
      uint bytesReturned;
moel@236
   120
      bool b = NativeMethods.DeviceIoControl(device, ioControlCode,
moel@236
   121
        inBuffer, inBuffer == null ? 0 : (uint)Marshal.SizeOf(inBuffer),
moel@236
   122
        null, 0, out bytesReturned, IntPtr.Zero);
moel@236
   123
      return b;
moel@236
   124
    }
moel@236
   125
moel@236
   126
    public bool DeviceIOControl<T>(IOControlCode ioControlCode, object inBuffer, 
moel@236
   127
      ref T outBuffer) 
moel@236
   128
    {
moel@236
   129
      if (device == null)
moel@236
   130
        return false;
moel@236
   131
moel@236
   132
      object boxedOutBuffer = outBuffer;
moel@236
   133
      uint bytesReturned;
moel@236
   134
      bool b = NativeMethods.DeviceIoControl(device, ioControlCode,
moel@236
   135
        inBuffer, inBuffer == null ? 0 : (uint)Marshal.SizeOf(inBuffer),
moel@236
   136
        boxedOutBuffer, (uint)Marshal.SizeOf(boxedOutBuffer),
moel@236
   137
        out bytesReturned, IntPtr.Zero);
moel@236
   138
      outBuffer = (T)boxedOutBuffer;
moel@236
   139
      return b;
moel@236
   140
    }
moel@236
   141
moel@236
   142
    public void Close() {
moel@236
   143
      if (device != null) {
moel@236
   144
        device.Close();
moel@236
   145
        device.Dispose();
moel@236
   146
        device = null;
moel@236
   147
      }
moel@236
   148
    }
moel@236
   149
moel@236
   150
    public bool Delete() {
moel@236
   151
      IntPtr manager = NativeMethods.OpenSCManager(null, null,
moel@236
   152
      ServiceControlManagerAccessRights.SC_MANAGER_ALL_ACCESS);
moel@236
   153
moel@236
   154
      if (manager == IntPtr.Zero)
moel@236
   155
        return false;      
moel@236
   156
moel@236
   157
      IntPtr service = NativeMethods.OpenService(manager, id,
moel@236
   158
        ServiceAccessRights.SERVICE_ALL_ACCESS);
moel@236
   159
moel@236
   160
      if (service == IntPtr.Zero)
moel@236
   161
        return true;
moel@236
   162
moel@236
   163
      ServiceStatus status = new ServiceStatus();
moel@236
   164
      NativeMethods.ControlService(service, ServiceControl.SERVICE_CONTROL_STOP, 
moel@236
   165
        ref status);
moel@236
   166
moel@236
   167
      NativeMethods.DeleteService(service);
moel@236
   168
moel@236
   169
      NativeMethods.CloseServiceHandle(service);
moel@236
   170
      NativeMethods.CloseServiceHandle(manager);
moel@236
   171
      
moel@236
   172
      return true;
moel@236
   173
    }
moel@236
   174
moel@236
   175
    private enum ServiceAccessRights : uint {
moel@236
   176
      SERVICE_ALL_ACCESS = 0xF01FF
moel@236
   177
    }
moel@236
   178
moel@236
   179
    private enum ServiceControlManagerAccessRights : uint {
moel@236
   180
      SC_MANAGER_ALL_ACCESS = 0xF003F
moel@236
   181
    }
moel@236
   182
moel@236
   183
    private enum ServiceType : uint {
moel@236
   184
      SERVICE_KERNEL_DRIVER = 1,
moel@236
   185
      SERVICE_FILE_SYSTEM_DRIVER = 2
moel@236
   186
    }
moel@236
   187
moel@236
   188
    private enum StartType : uint {
moel@236
   189
      SERVICE_BOOT_START = 0,
moel@236
   190
      SERVICE_SYSTEM_START = 1,
moel@236
   191
      SERVICE_AUTO_START = 2,
moel@236
   192
      SERVICE_DEMAND_START = 3,
moel@236
   193
      SERVICE_DISABLED = 4
moel@236
   194
    }
moel@236
   195
moel@236
   196
    private enum ErrorControl : uint {
moel@236
   197
      SERVICE_ERROR_IGNORE = 0,
moel@236
   198
      SERVICE_ERROR_NORMAL = 1,
moel@236
   199
      SERVICE_ERROR_SEVERE = 2,
moel@236
   200
      SERVICE_ERROR_CRITICAL = 3
moel@236
   201
    }
moel@236
   202
moel@236
   203
    private enum ServiceControl : uint {
moel@236
   204
      SERVICE_CONTROL_STOP = 1,
moel@236
   205
      SERVICE_CONTROL_PAUSE = 2,
moel@236
   206
      SERVICE_CONTROL_CONTINUE = 3,
moel@236
   207
      SERVICE_CONTROL_INTERROGATE = 4,
moel@236
   208
      SERVICE_CONTROL_SHUTDOWN = 5,
moel@236
   209
      SERVICE_CONTROL_PARAMCHANGE = 6,
moel@236
   210
      SERVICE_CONTROL_NETBINDADD = 7,
moel@236
   211
      SERVICE_CONTROL_NETBINDREMOVE = 8,
moel@236
   212
      SERVICE_CONTROL_NETBINDENABLE = 9,
moel@236
   213
      SERVICE_CONTROL_NETBINDDISABLE = 10,
moel@236
   214
      SERVICE_CONTROL_DEVICEEVENT = 11,
moel@236
   215
      SERVICE_CONTROL_HARDWAREPROFILECHANGE = 12,
moel@236
   216
      SERVICE_CONTROL_POWEREVENT = 13,
moel@236
   217
      SERVICE_CONTROL_SESSIONCHANGE = 14
moel@236
   218
    }
moel@236
   219
moel@236
   220
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@236
   221
    private struct ServiceStatus {
moel@236
   222
      public uint dwServiceType;
moel@236
   223
      public uint dwCurrentState;
moel@236
   224
      public uint dwControlsAccepted;
moel@236
   225
      public uint dwWin32ExitCode;
moel@236
   226
      public uint dwServiceSpecificExitCode;
moel@236
   227
      public uint dwCheckPoint;
moel@236
   228
      public uint dwWaitHint;
moel@236
   229
    }
moel@236
   230
moel@236
   231
    private enum FileAccess : uint {
moel@236
   232
      GENERIC_READ = 0x80000000,
moel@236
   233
      GENERIC_WRITE = 0x40000000
moel@236
   234
    }
moel@236
   235
moel@236
   236
    private enum CreationDisposition : uint {
moel@236
   237
      CREATE_NEW = 1,
moel@236
   238
      CREATE_ALWAYS = 2,
moel@236
   239
      OPEN_EXISTING = 3,
moel@236
   240
      OPEN_ALWAYS = 4,
moel@236
   241
      TRUNCATE_EXISTING = 5
moel@236
   242
    }
moel@236
   243
moel@236
   244
    private enum FileAttributes : uint {
moel@236
   245
      FILE_ATTRIBUTE_NORMAL = 0x80
moel@236
   246
    }
moel@236
   247
moel@236
   248
    private const int
moel@236
   249
      ERROR_SERVICE_EXISTS = unchecked((int)0x80070431),
moel@236
   250
      ERROR_SERVICE_ALREADY_RUNNING = unchecked((int)0x80070420);
moel@236
   251
moel@236
   252
    private static class NativeMethods {
moel@236
   253
      private const string ADVAPI = "advapi32.dll";
moel@236
   254
      private const string KERNEL = "kernel32.dll";
moel@236
   255
moel@236
   256
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi)]
moel@236
   257
      public static extern IntPtr OpenSCManager(string machineName,
moel@236
   258
        string databaseName, ServiceControlManagerAccessRights dwAccess);
moel@236
   259
moel@236
   260
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi)]
moel@236
   261
      [return: MarshalAs(UnmanagedType.Bool)]
moel@236
   262
      public static extern bool CloseServiceHandle(IntPtr hSCObject);
moel@236
   263
moel@236
   264
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
moel@236
   265
        SetLastError = true)]
moel@236
   266
      public static extern IntPtr CreateService(IntPtr hSCManager,
moel@236
   267
        string lpServiceName, string lpDisplayName, 
moel@236
   268
        ServiceAccessRights dwDesiredAccess, ServiceType dwServiceType,
moel@236
   269
        StartType dwStartType, ErrorControl dwErrorControl,
moel@236
   270
        string lpBinaryPathName, string lpLoadOrderGroup, string lpdwTagId,
moel@236
   271
        string lpDependencies, string lpServiceStartName, string lpPassword);
moel@236
   272
moel@236
   273
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
moel@236
   274
        SetLastError = true)]
moel@236
   275
      public static extern IntPtr OpenService(IntPtr hSCManager,
moel@236
   276
        string lpServiceName, ServiceAccessRights dwDesiredAccess);
moel@236
   277
moel@236
   278
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
moel@236
   279
        SetLastError = true)]
moel@236
   280
      [return: MarshalAs(UnmanagedType.Bool)]
moel@236
   281
      public static extern bool DeleteService(IntPtr hService);
moel@236
   282
moel@236
   283
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
moel@236
   284
        SetLastError = true)]
moel@236
   285
      [return: MarshalAs(UnmanagedType.Bool)]
moel@236
   286
      public static extern bool StartService(IntPtr hService, 
moel@236
   287
        uint dwNumServiceArgs, string[] lpServiceArgVectors);
moel@236
   288
moel@236
   289
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
moel@236
   290
        SetLastError = true)]
moel@236
   291
      [return: MarshalAs(UnmanagedType.Bool)]
moel@236
   292
      public static extern bool ControlService(IntPtr hService,
moel@236
   293
        ServiceControl dwControl, ref ServiceStatus lpServiceStatus);
moel@236
   294
moel@236
   295
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@236
   296
      public static extern bool DeviceIoControl(SafeFileHandle device,
moel@236
   297
        IOControlCode ioControlCode, 
moel@236
   298
        [MarshalAs(UnmanagedType.AsAny)] [In] object inBuffer, 
moel@236
   299
        uint inBufferSize,
moel@236
   300
        [MarshalAs(UnmanagedType.AsAny)] [Out] object outBuffer,
moel@236
   301
        uint nOutBufferSize, out uint bytesReturned, IntPtr overlapped);
moel@236
   302
moel@236
   303
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi, 
moel@236
   304
        SetLastError = true)]
moel@236
   305
      public static extern IntPtr CreateFile(string lpFileName,
moel@236
   306
        FileAccess dwDesiredAccess, uint dwShareMode, 
moel@236
   307
        IntPtr lpSecurityAttributes, CreationDisposition dwCreationDisposition, 
moel@236
   308
        FileAttributes dwFlagsAndAttributes, IntPtr hTemplateFile);
moel@236
   309
    }
moel@236
   310
  }
moel@236
   311
}