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