Hardware/Opcode.cs
author moel.mich
Sun, 27 May 2012 14:23:31 +0000
changeset 344 3145aadca3d2
parent 239 91800d0f54de
permissions -rw-r--r--
Changed the license to the Mozilla Public License 2.0 and update the licensing information.
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
}