Hardware/Opcode.cs
author moel.mich
Sun, 23 Sep 2012 18:37:43 +0000
changeset 380 573f1fff48b2
parent 239 91800d0f54de
permissions -rw-r--r--
Fixed Issue 387. The new implementation does not try to start a ring 0 driver that already exists, but could not be opened. It tries to delete the driver and install it new. The driver is now stored temporarily in the application folder. The driver is not correctly removed on system shutdown.
moel@236
     1
/*
moel@236
     2
 
moel@344
     3
  This Source Code Form is subject to the terms of the Mozilla Public
moel@344
     4
  License, v. 2.0. If a copy of the MPL was not distributed with this
moel@344
     5
  file, You can obtain one at http://mozilla.org/MPL/2.0/.
moel@236
     6
 
moel@344
     7
  Copyright (C) 2010 Michael Möller <mmoeller@openhardwaremonitor.org>
moel@344
     8
	
moel@236
     9
*/
moel@236
    10
moel@236
    11
using System;
moel@236
    12
using System.Runtime.InteropServices;
moel@239
    13
using System.Reflection;
moel@236
    14
moel@236
    15
namespace OpenHardwareMonitor.Hardware {
moel@236
    16
  internal static class Opcode {
moel@238
    17
    
moel@236
    18
    private static IntPtr codeBuffer;
moel@238
    19
    private static ulong size;
moel@236
    20
moel@238
    21
    public static void Open() {  
moel@236
    22
      int p = (int)Environment.OSVersion.Platform;
moel@238
    23
            
moel@236
    24
      byte[] rdtscCode;
moel@236
    25
      byte[] cpuidCode;
moel@236
    26
      if (IntPtr.Size == 4) {
moel@236
    27
        rdtscCode = RDTSC_32;
moel@236
    28
        cpuidCode = CPUID_32;
moel@236
    29
      } else {
moel@236
    30
        rdtscCode = RDTSC_64;
moel@238
    31
        
moel@238
    32
        if ((p == 4) || (p == 128)) { // Unix
moel@238
    33
          cpuidCode = CPUID_64_LINUX;
moel@238
    34
        } else { // Windows
moel@238
    35
          cpuidCode = CPUID_64_WINDOWS;
moel@238
    36
        }
moel@236
    37
      }
moel@238
    38
      
moel@238
    39
      size = (ulong)(rdtscCode.Length + cpuidCode.Length);
moel@239
    40
moel@239
    41
      if ((p == 4) || (p == 128)) { // Unix   
moel@239
    42
        Assembly assembly = 
moel@239
    43
          Assembly.Load("Mono.Posix, Version=2.0.0.0, Culture=neutral, " +
moel@239
    44
          "PublicKeyToken=0738eb9f132ed756");
moel@239
    45
moel@239
    46
        Type syscall = assembly.GetType("Mono.Unix.Native.Syscall");
moel@239
    47
        MethodInfo mmap = syscall.GetMethod("mmap");
moel@239
    48
moel@239
    49
        Type mmapProts = assembly.GetType("Mono.Unix.Native.MmapProts");
moel@239
    50
        object mmapProtsParam = Enum.ToObject(mmapProts,
moel@239
    51
          (int)mmapProts.GetField("PROT_READ").GetValue(null) |
moel@239
    52
          (int)mmapProts.GetField("PROT_WRITE").GetValue(null) |
moel@239
    53
          (int)mmapProts.GetField("PROT_EXEC").GetValue(null));
moel@239
    54
moel@239
    55
        Type mmapFlags = assembly.GetType("Mono.Unix.Native.MmapFlags");
moel@239
    56
        object mmapFlagsParam = Enum.ToObject(mmapFlags,
moel@239
    57
          (int)mmapFlags.GetField("MAP_ANONYMOUS").GetValue(null) |
moel@239
    58
          (int)mmapFlags.GetField("MAP_PRIVATE").GetValue(null));
moel@239
    59
        
moel@239
    60
        codeBuffer = (IntPtr)mmap.Invoke(null, new object[] { IntPtr.Zero, 
moel@239
    61
          size, mmapProtsParam, mmapFlagsParam, -1, 0 });        
moel@238
    62
      } else { // Windows
moel@238
    63
        codeBuffer = NativeMethods.VirtualAlloc(IntPtr.Zero,
moel@238
    64
          (UIntPtr)size, AllocationType.COMMIT | AllocationType.RESERVE, 
moel@238
    65
          MemoryProtection.EXECUTE_READWRITE);
moel@238
    66
      }
moel@236
    67
moel@236
    68
      Marshal.Copy(rdtscCode, 0, codeBuffer, rdtscCode.Length);
moel@236
    69
moel@236
    70
      Rdtsc = Marshal.GetDelegateForFunctionPointer(
moel@236
    71
        codeBuffer, typeof(RdtscDelegate)) as RdtscDelegate;
moel@236
    72
moel@236
    73
      IntPtr cpuidAddress = (IntPtr)((long)codeBuffer + rdtscCode.Length);
moel@236
    74
      Marshal.Copy(cpuidCode, 0, cpuidAddress, cpuidCode.Length);
moel@236
    75
moel@236
    76
      Cpuid = Marshal.GetDelegateForFunctionPointer(
moel@238
    77
        cpuidAddress, typeof(CpuidDelegate)) as CpuidDelegate;         
moel@236
    78
    }
moel@236
    79
moel@236
    80
    public static void Close() {
moel@236
    81
      Rdtsc = null;
moel@236
    82
      Cpuid = null;
moel@238
    83
      
moel@238
    84
      int p = (int)Environment.OSVersion.Platform;
moel@238
    85
      if ((p == 4) || (p == 128)) { // Unix
moel@239
    86
        Assembly assembly =
moel@239
    87
          Assembly.Load("Mono.Posix, Version=2.0.0.0, Culture=neutral, " +
moel@239
    88
          "PublicKeyToken=0738eb9f132ed756");
moel@239
    89
moel@239
    90
        Type syscall = assembly.GetType("Mono.Unix.Native.Syscall");
moel@239
    91
        MethodInfo munmap = syscall.GetMethod("munmap");
moel@239
    92
        munmap.Invoke(null, new object[] { codeBuffer, size });
moel@239
    93
moel@238
    94
      } else { // Windows
moel@238
    95
        NativeMethods.VirtualFree(codeBuffer, UIntPtr.Zero, 
moel@238
    96
          FreeType.RELEASE);        
moel@238
    97
      }
moel@236
    98
    }
moel@236
    99
moel@236
   100
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
moel@236
   101
    public delegate ulong RdtscDelegate();
moel@236
   102
moel@236
   103
    public static RdtscDelegate Rdtsc;
moel@236
   104
moel@236
   105
    // unsigned __int64 __stdcall rdtsc() {
moel@236
   106
    //   return __rdtsc();
moel@236
   107
    // }
moel@236
   108
moel@236
   109
    private static readonly byte[] RDTSC_32 = new byte[] {
moel@236
   110
      0x0F, 0x31,                     // rdtsc   
moel@236
   111
      0xC3                            // ret  
moel@236
   112
    };
moel@236
   113
moel@236
   114
    private static readonly byte[] RDTSC_64 = new byte[] {
moel@236
   115
      0x0F, 0x31,                     // rdtsc  
moel@238
   116
      0x48, 0xC1, 0xE2, 0x20,         // shl rdx, 20h  
moel@238
   117
      0x48, 0x0B, 0xC2,               // or rax, rdx  
moel@236
   118
      0xC3                            // ret  
moel@236
   119
    };
moel@236
   120
    
moel@236
   121
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
moel@236
   122
    public delegate bool CpuidDelegate(uint index, uint ecxValue,
moel@236
   123
      out uint eax, out uint ebx, out uint ecx, out uint edx);
moel@236
   124
moel@236
   125
    public static CpuidDelegate Cpuid;
moel@236
   126
moel@236
   127
moel@236
   128
    // void __stdcall cpuidex(unsigned int index, unsigned int ecxValue, 
moel@236
   129
    //   unsigned int* eax, unsigned int* ebx, unsigned int* ecx, 
moel@236
   130
    //   unsigned int* edx)
moel@236
   131
    // {
moel@236
   132
    //   int info[4];	
moel@236
   133
    //   __cpuidex(info, index, ecxValue);
moel@236
   134
    //   *eax = info[0];
moel@236
   135
    //   *ebx = info[1];
moel@236
   136
    //   *ecx = info[2];
moel@236
   137
    //   *edx = info[3];
moel@236
   138
    // }
moel@236
   139
moel@236
   140
    private static readonly byte[] CPUID_32 = new byte[] {
moel@236
   141
      0x55,                           // push ebp  
moel@238
   142
      0x8B, 0xEC,                     // mov ebp, esp  
moel@238
   143
      0x83, 0xEC, 0x10,               // sub esp, 10h  
moel@238
   144
      0x8B, 0x45, 0x08,               // mov eax, dword ptr [ebp+8]  
moel@238
   145
      0x8B, 0x4D, 0x0C,               // mov ecx, dword ptr [ebp+0Ch]  
moel@236
   146
      0x53,                           // push ebx  
moel@236
   147
      0x0F, 0xA2,                     // cpuid  
moel@236
   148
      0x56,                           // push esi  
moel@238
   149
      0x8D, 0x75, 0xF0,               // lea esi, [info]  
moel@238
   150
      0x89, 0x06,                     // mov dword ptr [esi],eax  
moel@238
   151
      0x8B, 0x45, 0x10,               // mov eax, dword ptr [eax]  
moel@238
   152
      0x89, 0x5E, 0x04,               // mov dword ptr [esi+4], ebx  
moel@238
   153
      0x89, 0x4E, 0x08,               // mov dword ptr [esi+8], ecx  
moel@238
   154
      0x89, 0x56, 0x0C,               // mov dword ptr [esi+0Ch], edx  
moel@238
   155
      0x8B, 0x4D, 0xF0,               // mov ecx, dword ptr [info]  
moel@238
   156
      0x89, 0x08,                     // mov dword ptr [eax], ecx  
moel@238
   157
      0x8B, 0x45, 0x14,               // mov eax, dword ptr [ebx]  
moel@238
   158
      0x8B, 0x4D, 0xF4,               // mov ecx, dword ptr [ebp-0Ch]  
moel@238
   159
      0x89, 0x08,                     // mov dword ptr [eax], ecx  
moel@238
   160
      0x8B, 0x45, 0x18,               // mov eax, dword ptr [ecx]  
moel@238
   161
      0x8B, 0x4D, 0xF8,               // mov ecx, dword ptr [ebp-8]  
moel@238
   162
      0x89, 0x08,                     // mov dword ptr [eax], ecx  
moel@238
   163
      0x8B, 0x45, 0x1C,               // mov eax, dword ptr [edx]  
moel@238
   164
      0x8B, 0x4D, 0xFC,               // mov ecx, dword ptr [ebp-4]  
moel@236
   165
      0x5E,                           // pop esi  
moel@238
   166
      0x89, 0x08,                     // mov dword ptr [eax], ecx  
moel@236
   167
      0x5B,                           // pop ebx  
moel@236
   168
      0xC9,                           // leave  
moel@236
   169
      0xC2, 0x18, 0x00                // ret 18h  
moel@236
   170
    };
moel@236
   171
             
moel@238
   172
    private static readonly byte[] CPUID_64_WINDOWS = new byte[] {
moel@238
   173
      0x48, 0x89, 0x5C, 0x24, 0x08,   // mov qword ptr [rsp+8], rbx  
moel@238
   174
      0x8B, 0xC1,                     // mov eax, ecx  
moel@238
   175
      0x8B, 0xCA,                     // mov ecx, edx        
moel@238
   176
      0x0F, 0xA2,                     // cpuid        
moel@238
   177
      0x41, 0x89, 0x00,               // mov dword ptr [r8], eax        
moel@238
   178
      0x48, 0x8B, 0x44, 0x24, 0x28,   // mov rax, qword ptr [rsp+28h]       
moel@238
   179
      0x41, 0x89, 0x19,               // mov dword ptr [r9], ebx        
moel@238
   180
      0x48, 0x8B, 0x5C, 0x24, 0x08,   // mov rbx, qword ptr [rsp+8]      
moel@238
   181
      0x89, 0x08,                     // mov dword ptr [rax], ecx        
moel@238
   182
      0x48, 0x8B, 0x44, 0x24, 0x30,   // mov rax, qword ptr [rsp+30h]  
moel@238
   183
      0x89, 0x10,                     // mov dword ptr [rax], edx  
moel@236
   184
      0xC3                            // ret  
moel@236
   185
    };
moel@238
   186
    
moel@238
   187
    private static readonly byte[] CPUID_64_LINUX = new byte[] {
moel@238
   188
      0x49, 0x89, 0xD2,               // mov r10, rdx
moel@238
   189
      0x49, 0x89, 0xCB,               // mov r11, rcx
moel@238
   190
      0x53,                           // push rbx
moel@238
   191
      0x89, 0xF8,                     // mov eax, edi
moel@238
   192
      0x89, 0xF1,                     // mov ecx, esi
moel@238
   193
      0x0F, 0xA2,                     // cpuid
moel@238
   194
      0x41, 0x89, 0x02,               // mov dword ptr [r10], eax
moel@238
   195
      0x41, 0x89, 0x1B,               // mov dword ptr [r11], ebx
moel@238
   196
      0x41, 0x89, 0x08,               // mov dword ptr [r8], ecx
moel@238
   197
      0x41, 0x89, 0x11,               // mov dword ptr [r9], edx
moel@238
   198
      0x5B,                           // pop rbx
moel@238
   199
      0xC3,                           // ret
moel@238
   200
    };
moel@236
   201
moel@236
   202
    public static bool CpuidTx(uint index, uint ecxValue, 
moel@236
   203
      out uint eax, out uint ebx, out uint ecx, out uint edx, 
moel@238
   204
      ulong threadAffinityMask) {
moel@238
   205
      
moel@238
   206
      ulong mask = ThreadAffinity.Set(threadAffinityMask);
moel@236
   207
moel@238
   208
      if (mask == 0) {
moel@236
   209
        eax = ebx = ecx = edx = 0;
moel@236
   210
        return false;
moel@238
   211
      } 
moel@236
   212
moel@236
   213
      Cpuid(index, ecxValue, out eax, out ebx, out ecx, out edx);
moel@236
   214
moel@238
   215
      ThreadAffinity.Set(mask);      
moel@236
   216
      return true;
moel@236
   217
    }
moel@238
   218
    
moel@236
   219
    [Flags()]
moel@236
   220
    public enum AllocationType : uint {
moel@236
   221
      COMMIT = 0x1000,
moel@236
   222
      RESERVE = 0x2000,
moel@236
   223
      RESET = 0x80000,
moel@236
   224
      LARGE_PAGES = 0x20000000,
moel@236
   225
      PHYSICAL = 0x400000,
moel@236
   226
      TOP_DOWN = 0x100000,
moel@236
   227
      WRITE_WATCH = 0x200000
moel@236
   228
    }
moel@236
   229
moel@236
   230
    [Flags()]
moel@236
   231
    public enum MemoryProtection : uint {
moel@236
   232
      EXECUTE = 0x10,
moel@236
   233
      EXECUTE_READ = 0x20,
moel@236
   234
      EXECUTE_READWRITE = 0x40,
moel@236
   235
      EXECUTE_WRITECOPY = 0x80,
moel@236
   236
      NOACCESS = 0x01,
moel@236
   237
      READONLY = 0x02,
moel@236
   238
      READWRITE = 0x04,
moel@236
   239
      WRITECOPY = 0x08,
moel@236
   240
      GUARD = 0x100,
moel@236
   241
      NOCACHE = 0x200,
moel@236
   242
      WRITECOMBINE = 0x400
moel@236
   243
    }
moel@236
   244
moel@236
   245
    [Flags]
moel@239
   246
    public enum FreeType {
moel@236
   247
      DECOMMIT = 0x4000,
moel@236
   248
      RELEASE = 0x8000
moel@236
   249
    }
moel@236
   250
moel@238
   251
    private static class NativeMethods {      
moel@236
   252
      private const string KERNEL = "kernel32.dll";
moel@236
   253
moel@236
   254
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@236
   255
      public static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize,
moel@236
   256
        AllocationType flAllocationType, MemoryProtection flProtect);
moel@236
   257
moel@236
   258
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@236
   259
      public static extern bool VirtualFree(IntPtr lpAddress, UIntPtr dwSize,
moel@238
   260
        FreeType dwFreeType);                 
moel@236
   261
    }
moel@236
   262
  }
moel@236
   263
}