Hardware/Opcode.cs
author moel.mich
Sun, 31 Oct 2010 22:08:47 +0000
changeset 236 763675f19ff4
child 238 bddc6e01840a
permissions -rw-r--r--
Replaced the non-kernel code of WinRing0 with a managed implementation. The new implementation should fix Issue 32 and simplify further work on Issue 46.
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@236
    39
using System.Runtime.InteropServices;
moel@236
    40
moel@236
    41
namespace OpenHardwareMonitor.Hardware {
moel@236
    42
  internal static class Opcode {
moel@236
    43
    private static IntPtr codeBuffer;
moel@236
    44
moel@236
    45
    public static void Open() {
moel@236
    46
      // No implementation for Unix systems
moel@236
    47
      int p = (int)Environment.OSVersion.Platform;
moel@236
    48
      if ((p == 4) || (p == 128))
moel@236
    49
        return;  
moel@236
    50
moel@236
    51
      byte[] rdtscCode;
moel@236
    52
      byte[] cpuidCode;
moel@236
    53
      if (IntPtr.Size == 4) {
moel@236
    54
        rdtscCode = RDTSC_32;
moel@236
    55
        cpuidCode = CPUID_32;
moel@236
    56
      } else {
moel@236
    57
        rdtscCode = RDTSC_64;
moel@236
    58
        cpuidCode = CPUID_64;
moel@236
    59
      }
moel@236
    60
moel@236
    61
      codeBuffer = NativeMethods.VirtualAlloc(IntPtr.Zero,
moel@236
    62
        (UIntPtr)(rdtscCode.Length + cpuidCode.Length),
moel@236
    63
      AllocationType.COMMIT | AllocationType.RESERVE, 
moel@236
    64
      MemoryProtection.EXECUTE_READWRITE);
moel@236
    65
moel@236
    66
      Marshal.Copy(rdtscCode, 0, codeBuffer, rdtscCode.Length);
moel@236
    67
moel@236
    68
      Rdtsc = Marshal.GetDelegateForFunctionPointer(
moel@236
    69
        codeBuffer, typeof(RdtscDelegate)) as RdtscDelegate;
moel@236
    70
moel@236
    71
      IntPtr cpuidAddress = (IntPtr)((long)codeBuffer + rdtscCode.Length);
moel@236
    72
      Marshal.Copy(cpuidCode, 0, cpuidAddress, cpuidCode.Length);
moel@236
    73
moel@236
    74
      Cpuid = Marshal.GetDelegateForFunctionPointer(
moel@236
    75
        cpuidAddress, typeof(CpuidDelegate)) as CpuidDelegate;
moel@236
    76
    }
moel@236
    77
moel@236
    78
    public static void Close() {
moel@236
    79
      Rdtsc = null;
moel@236
    80
      Cpuid = null;
moel@236
    81
moel@236
    82
      NativeMethods.VirtualFree(codeBuffer, UIntPtr.Zero, 
moel@236
    83
        FreeType.RELEASE);
moel@236
    84
    }
moel@236
    85
moel@236
    86
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
moel@236
    87
    public delegate ulong RdtscDelegate();
moel@236
    88
moel@236
    89
    public static RdtscDelegate Rdtsc;
moel@236
    90
moel@236
    91
    // unsigned __int64 __stdcall rdtsc() {
moel@236
    92
    //   return __rdtsc();
moel@236
    93
    // }
moel@236
    94
moel@236
    95
    private static readonly byte[] RDTSC_32 = new byte[] {
moel@236
    96
      0x0F, 0x31,                     // rdtsc   
moel@236
    97
      0xC3                            // ret  
moel@236
    98
    };
moel@236
    99
moel@236
   100
    private static readonly byte[] RDTSC_64 = new byte[] {
moel@236
   101
      0x0F, 0x31,                     // rdtsc  
moel@236
   102
      0x48, 0xC1, 0xE2, 0x20,         // shl rdx,20h  
moel@236
   103
      0x48, 0x0B, 0xC2,               // or rax,rdx  
moel@236
   104
      0xC3                            // ret  
moel@236
   105
    };
moel@236
   106
    
moel@236
   107
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
moel@236
   108
    public delegate bool CpuidDelegate(uint index, uint ecxValue,
moel@236
   109
      out uint eax, out uint ebx, out uint ecx, out uint edx);
moel@236
   110
moel@236
   111
    public static CpuidDelegate Cpuid;
moel@236
   112
moel@236
   113
moel@236
   114
    // void __stdcall cpuidex(unsigned int index, unsigned int ecxValue, 
moel@236
   115
    //   unsigned int* eax, unsigned int* ebx, unsigned int* ecx, 
moel@236
   116
    //   unsigned int* edx)
moel@236
   117
    // {
moel@236
   118
    //   int info[4];	
moel@236
   119
    //   __cpuidex(info, index, ecxValue);
moel@236
   120
    //   *eax = info[0];
moel@236
   121
    //   *ebx = info[1];
moel@236
   122
    //   *ecx = info[2];
moel@236
   123
    //   *edx = info[3];
moel@236
   124
    // }
moel@236
   125
moel@236
   126
    private static readonly byte[] CPUID_32 = new byte[] {
moel@236
   127
      0x55,                           // push ebp  
moel@236
   128
      0x8B, 0xEC,                      // mov ebp,esp  
moel@236
   129
      0x83, 0xEC, 0x10,               // sub esp,10h  
moel@236
   130
      0x8B, 0x45, 0x08,               // mov eax,dword ptr [ebp+8]  
moel@236
   131
      0x8B, 0x4D, 0x0C,               // mov ecx,dword ptr [ebp+0Ch]  
moel@236
   132
      0x53,                           // push ebx  
moel@236
   133
      0x0F, 0xA2,                     // cpuid  
moel@236
   134
      0x56,                           // push esi  
moel@236
   135
      0x8D, 0x75, 0xF0,               // lea esi,[info]  
moel@236
   136
      0x89, 0x06,                      // mov dword ptr [esi],eax  
moel@236
   137
      0x8B, 0x45, 0x10,               // mov eax,dword ptr [eax]  
moel@236
   138
      0x89, 0x5E, 0x04,               // mov dword ptr [esi+4],ebx  
moel@236
   139
      0x89, 0x4E, 0x08,               // mov dword ptr [esi+8],ecx  
moel@236
   140
      0x89, 0x56, 0x0C,               // mov dword ptr [esi+0Ch],edx  
moel@236
   141
      0x8B, 0x4D, 0xF0,               // mov ecx,dword ptr [info]  
moel@236
   142
      0x89, 0x08,                      // mov dword ptr [eax],ecx  
moel@236
   143
      0x8B, 0x45, 0x14,               // mov eax,dword ptr [ebx]  
moel@236
   144
      0x8B, 0x4D, 0xF4,               // mov ecx,dword ptr [ebp-0Ch]  
moel@236
   145
      0x89, 0x08,                      // mov dword ptr [eax],ecx  
moel@236
   146
      0x8B, 0x45, 0x18,               // mov eax,dword ptr [ecx]  
moel@236
   147
      0x8B, 0x4D, 0xF8,               // mov ecx,dword ptr [ebp-8]  
moel@236
   148
      0x89, 0x08,                      // mov dword ptr [eax],ecx  
moel@236
   149
      0x8B, 0x45, 0x1C,               // mov eax,dword ptr [edx]  
moel@236
   150
      0x8B, 0x4D, 0xFC,               // mov ecx,dword ptr [ebp-4]  
moel@236
   151
      0x5E,                           // pop esi  
moel@236
   152
      0x89, 0x08,                     // mov dword ptr [eax],ecx  
moel@236
   153
      0x5B,                           // pop ebx  
moel@236
   154
      0xC9,                           // leave  
moel@236
   155
      0xC2, 0x18, 0x00                // ret 18h  
moel@236
   156
    };
moel@236
   157
             
moel@236
   158
    private static readonly byte[] CPUID_64 = new byte[] {
moel@236
   159
      0x48, 0x89, 0x5C, 0x24, 0x08,   // mov qword ptr [rsp+8],rbx  
moel@236
   160
      0x8B, 0xC1,                     // mov eax,ecx  
moel@236
   161
      0x8B, 0xCA,                     // mov ecx,edx  
moel@236
   162
      0x0F, 0xA2,                     // cpuid  
moel@236
   163
      0x41, 0x89, 0x00,               // mov dword ptr [r8],eax  
moel@236
   164
      0x48, 0x8B, 0x44, 0x24, 0x28,   // mov rax,qword ptr [ecx]  
moel@236
   165
      0x41, 0x89, 0x19,               // mov dword ptr [r9],ebx  
moel@236
   166
      0x48, 0x8B, 0x5C, 0x24, 0x08,   // mov rbx,qword ptr [rsp+8]  
moel@236
   167
      0x89, 0x08,                     // mov dword ptr [rax],ecx  
moel@236
   168
      0x48, 0x8B, 0x44, 0x24, 0x30,   // mov rax,qword ptr [rsp+30h]  
moel@236
   169
      0x89, 0x10,                     // mov dword ptr [rax],edx  
moel@236
   170
      0xC3                            // ret  
moel@236
   171
    };
moel@236
   172
moel@236
   173
    public static bool CpuidTx(uint index, uint ecxValue, 
moel@236
   174
      out uint eax, out uint ebx, out uint ecx, out uint edx, 
moel@236
   175
      UIntPtr threadAffinityMask) {
moel@236
   176
moel@236
   177
      IntPtr thread = NativeMethods.GetCurrentThread();
moel@236
   178
      UIntPtr mask = NativeMethods.SetThreadAffinityMask(thread, 
moel@236
   179
        threadAffinityMask);
moel@236
   180
moel@236
   181
      if (mask == UIntPtr.Zero) {
moel@236
   182
        eax = ebx = ecx = edx = 0;
moel@236
   183
        return false;
moel@236
   184
      }
moel@236
   185
moel@236
   186
      Cpuid(index, ecxValue, out eax, out ebx, out ecx, out edx);
moel@236
   187
moel@236
   188
      NativeMethods.SetThreadAffinityMask(thread, mask);
moel@236
   189
      
moel@236
   190
      return true;
moel@236
   191
    }
moel@236
   192
moel@236
   193
    [Flags()]
moel@236
   194
    public enum AllocationType : uint {
moel@236
   195
      COMMIT = 0x1000,
moel@236
   196
      RESERVE = 0x2000,
moel@236
   197
      RESET = 0x80000,
moel@236
   198
      LARGE_PAGES = 0x20000000,
moel@236
   199
      PHYSICAL = 0x400000,
moel@236
   200
      TOP_DOWN = 0x100000,
moel@236
   201
      WRITE_WATCH = 0x200000
moel@236
   202
    }
moel@236
   203
moel@236
   204
    [Flags()]
moel@236
   205
    public enum MemoryProtection : uint {
moel@236
   206
      EXECUTE = 0x10,
moel@236
   207
      EXECUTE_READ = 0x20,
moel@236
   208
      EXECUTE_READWRITE = 0x40,
moel@236
   209
      EXECUTE_WRITECOPY = 0x80,
moel@236
   210
      NOACCESS = 0x01,
moel@236
   211
      READONLY = 0x02,
moel@236
   212
      READWRITE = 0x04,
moel@236
   213
      WRITECOPY = 0x08,
moel@236
   214
      GUARD = 0x100,
moel@236
   215
      NOCACHE = 0x200,
moel@236
   216
      WRITECOMBINE = 0x400
moel@236
   217
    }
moel@236
   218
moel@236
   219
    [Flags]
moel@236
   220
    enum FreeType {
moel@236
   221
      DECOMMIT = 0x4000,
moel@236
   222
      RELEASE = 0x8000
moel@236
   223
    }
moel@236
   224
moel@236
   225
    private static class NativeMethods {
moel@236
   226
      private const string KERNEL = "kernel32.dll";
moel@236
   227
moel@236
   228
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@236
   229
      public static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize,
moel@236
   230
        AllocationType flAllocationType, MemoryProtection flProtect);
moel@236
   231
moel@236
   232
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@236
   233
      public static extern bool VirtualFree(IntPtr lpAddress, UIntPtr dwSize,
moel@236
   234
        FreeType dwFreeType);
moel@236
   235
moel@236
   236
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@236
   237
      public static extern UIntPtr
moel@236
   238
        SetThreadAffinityMask(IntPtr handle, UIntPtr mask);
moel@236
   239
moel@236
   240
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@236
   241
      public static extern IntPtr GetCurrentThread();
moel@236
   242
    }
moel@236
   243
  }
moel@236
   244
}