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.
     1 /*
     2   
     3   Version: MPL 1.1/GPL 2.0/LGPL 2.1
     4 
     5   The contents of this file are subject to the Mozilla Public License Version
     6   1.1 (the "License"); you may not use this file except in compliance with
     7   the License. You may obtain a copy of the License at
     8  
     9   http://www.mozilla.org/MPL/
    10 
    11   Software distributed under the License is distributed on an "AS IS" basis,
    12   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
    13   for the specific language governing rights and limitations under the License.
    14 
    15   The Original Code is the Open Hardware Monitor code.
    16 
    17   The Initial Developer of the Original Code is 
    18   Michael Möller <m.moeller@gmx.ch>.
    19   Portions created by the Initial Developer are Copyright (C) 2010
    20   the Initial Developer. All Rights Reserved.
    21 
    22   Contributor(s):
    23 
    24   Alternatively, the contents of this file may be used under the terms of
    25   either the GNU General Public License Version 2 or later (the "GPL"), or
    26   the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
    27   in which case the provisions of the GPL or the LGPL are applicable instead
    28   of those above. If you wish to allow use of your version of this file only
    29   under the terms of either the GPL or the LGPL, and not to allow others to
    30   use your version of this file under the terms of the MPL, indicate your
    31   decision by deleting the provisions above and replace them with the notice
    32   and other provisions required by the GPL or the LGPL. If you do not delete
    33   the provisions above, a recipient may use your version of this file under
    34   the terms of any one of the MPL, the GPL or the LGPL.
    35  
    36 */
    37 
    38 using System;
    39 using System.Runtime.InteropServices;
    40 
    41 namespace OpenHardwareMonitor.Hardware {
    42   internal static class Opcode {
    43     private static IntPtr codeBuffer;
    44 
    45     public static void Open() {
    46       // No implementation for Unix systems
    47       int p = (int)Environment.OSVersion.Platform;
    48       if ((p == 4) || (p == 128))
    49         return;  
    50 
    51       byte[] rdtscCode;
    52       byte[] cpuidCode;
    53       if (IntPtr.Size == 4) {
    54         rdtscCode = RDTSC_32;
    55         cpuidCode = CPUID_32;
    56       } else {
    57         rdtscCode = RDTSC_64;
    58         cpuidCode = CPUID_64;
    59       }
    60 
    61       codeBuffer = NativeMethods.VirtualAlloc(IntPtr.Zero,
    62         (UIntPtr)(rdtscCode.Length + cpuidCode.Length),
    63       AllocationType.COMMIT | AllocationType.RESERVE, 
    64       MemoryProtection.EXECUTE_READWRITE);
    65 
    66       Marshal.Copy(rdtscCode, 0, codeBuffer, rdtscCode.Length);
    67 
    68       Rdtsc = Marshal.GetDelegateForFunctionPointer(
    69         codeBuffer, typeof(RdtscDelegate)) as RdtscDelegate;
    70 
    71       IntPtr cpuidAddress = (IntPtr)((long)codeBuffer + rdtscCode.Length);
    72       Marshal.Copy(cpuidCode, 0, cpuidAddress, cpuidCode.Length);
    73 
    74       Cpuid = Marshal.GetDelegateForFunctionPointer(
    75         cpuidAddress, typeof(CpuidDelegate)) as CpuidDelegate;
    76     }
    77 
    78     public static void Close() {
    79       Rdtsc = null;
    80       Cpuid = null;
    81 
    82       NativeMethods.VirtualFree(codeBuffer, UIntPtr.Zero, 
    83         FreeType.RELEASE);
    84     }
    85 
    86     [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    87     public delegate ulong RdtscDelegate();
    88 
    89     public static RdtscDelegate Rdtsc;
    90 
    91     // unsigned __int64 __stdcall rdtsc() {
    92     //   return __rdtsc();
    93     // }
    94 
    95     private static readonly byte[] RDTSC_32 = new byte[] {
    96       0x0F, 0x31,                     // rdtsc   
    97       0xC3                            // ret  
    98     };
    99 
   100     private static readonly byte[] RDTSC_64 = new byte[] {
   101       0x0F, 0x31,                     // rdtsc  
   102       0x48, 0xC1, 0xE2, 0x20,         // shl rdx,20h  
   103       0x48, 0x0B, 0xC2,               // or rax,rdx  
   104       0xC3                            // ret  
   105     };
   106     
   107     [UnmanagedFunctionPointer(CallingConvention.StdCall)]
   108     public delegate bool CpuidDelegate(uint index, uint ecxValue,
   109       out uint eax, out uint ebx, out uint ecx, out uint edx);
   110 
   111     public static CpuidDelegate Cpuid;
   112 
   113 
   114     // void __stdcall cpuidex(unsigned int index, unsigned int ecxValue, 
   115     //   unsigned int* eax, unsigned int* ebx, unsigned int* ecx, 
   116     //   unsigned int* edx)
   117     // {
   118     //   int info[4];	
   119     //   __cpuidex(info, index, ecxValue);
   120     //   *eax = info[0];
   121     //   *ebx = info[1];
   122     //   *ecx = info[2];
   123     //   *edx = info[3];
   124     // }
   125 
   126     private static readonly byte[] CPUID_32 = new byte[] {
   127       0x55,                           // push ebp  
   128       0x8B, 0xEC,                      // mov ebp,esp  
   129       0x83, 0xEC, 0x10,               // sub esp,10h  
   130       0x8B, 0x45, 0x08,               // mov eax,dword ptr [ebp+8]  
   131       0x8B, 0x4D, 0x0C,               // mov ecx,dword ptr [ebp+0Ch]  
   132       0x53,                           // push ebx  
   133       0x0F, 0xA2,                     // cpuid  
   134       0x56,                           // push esi  
   135       0x8D, 0x75, 0xF0,               // lea esi,[info]  
   136       0x89, 0x06,                      // mov dword ptr [esi],eax  
   137       0x8B, 0x45, 0x10,               // mov eax,dword ptr [eax]  
   138       0x89, 0x5E, 0x04,               // mov dword ptr [esi+4],ebx  
   139       0x89, 0x4E, 0x08,               // mov dword ptr [esi+8],ecx  
   140       0x89, 0x56, 0x0C,               // mov dword ptr [esi+0Ch],edx  
   141       0x8B, 0x4D, 0xF0,               // mov ecx,dword ptr [info]  
   142       0x89, 0x08,                      // mov dword ptr [eax],ecx  
   143       0x8B, 0x45, 0x14,               // mov eax,dword ptr [ebx]  
   144       0x8B, 0x4D, 0xF4,               // mov ecx,dword ptr [ebp-0Ch]  
   145       0x89, 0x08,                      // mov dword ptr [eax],ecx  
   146       0x8B, 0x45, 0x18,               // mov eax,dword ptr [ecx]  
   147       0x8B, 0x4D, 0xF8,               // mov ecx,dword ptr [ebp-8]  
   148       0x89, 0x08,                      // mov dword ptr [eax],ecx  
   149       0x8B, 0x45, 0x1C,               // mov eax,dword ptr [edx]  
   150       0x8B, 0x4D, 0xFC,               // mov ecx,dword ptr [ebp-4]  
   151       0x5E,                           // pop esi  
   152       0x89, 0x08,                     // mov dword ptr [eax],ecx  
   153       0x5B,                           // pop ebx  
   154       0xC9,                           // leave  
   155       0xC2, 0x18, 0x00                // ret 18h  
   156     };
   157              
   158     private static readonly byte[] CPUID_64 = new byte[] {
   159       0x48, 0x89, 0x5C, 0x24, 0x08,   // mov qword ptr [rsp+8],rbx  
   160       0x8B, 0xC1,                     // mov eax,ecx  
   161       0x8B, 0xCA,                     // mov ecx,edx  
   162       0x0F, 0xA2,                     // cpuid  
   163       0x41, 0x89, 0x00,               // mov dword ptr [r8],eax  
   164       0x48, 0x8B, 0x44, 0x24, 0x28,   // mov rax,qword ptr [ecx]  
   165       0x41, 0x89, 0x19,               // mov dword ptr [r9],ebx  
   166       0x48, 0x8B, 0x5C, 0x24, 0x08,   // mov rbx,qword ptr [rsp+8]  
   167       0x89, 0x08,                     // mov dword ptr [rax],ecx  
   168       0x48, 0x8B, 0x44, 0x24, 0x30,   // mov rax,qword ptr [rsp+30h]  
   169       0x89, 0x10,                     // mov dword ptr [rax],edx  
   170       0xC3                            // ret  
   171     };
   172 
   173     public static bool CpuidTx(uint index, uint ecxValue, 
   174       out uint eax, out uint ebx, out uint ecx, out uint edx, 
   175       UIntPtr threadAffinityMask) {
   176 
   177       IntPtr thread = NativeMethods.GetCurrentThread();
   178       UIntPtr mask = NativeMethods.SetThreadAffinityMask(thread, 
   179         threadAffinityMask);
   180 
   181       if (mask == UIntPtr.Zero) {
   182         eax = ebx = ecx = edx = 0;
   183         return false;
   184       }
   185 
   186       Cpuid(index, ecxValue, out eax, out ebx, out ecx, out edx);
   187 
   188       NativeMethods.SetThreadAffinityMask(thread, mask);
   189       
   190       return true;
   191     }
   192 
   193     [Flags()]
   194     public enum AllocationType : uint {
   195       COMMIT = 0x1000,
   196       RESERVE = 0x2000,
   197       RESET = 0x80000,
   198       LARGE_PAGES = 0x20000000,
   199       PHYSICAL = 0x400000,
   200       TOP_DOWN = 0x100000,
   201       WRITE_WATCH = 0x200000
   202     }
   203 
   204     [Flags()]
   205     public enum MemoryProtection : uint {
   206       EXECUTE = 0x10,
   207       EXECUTE_READ = 0x20,
   208       EXECUTE_READWRITE = 0x40,
   209       EXECUTE_WRITECOPY = 0x80,
   210       NOACCESS = 0x01,
   211       READONLY = 0x02,
   212       READWRITE = 0x04,
   213       WRITECOPY = 0x08,
   214       GUARD = 0x100,
   215       NOCACHE = 0x200,
   216       WRITECOMBINE = 0x400
   217     }
   218 
   219     [Flags]
   220     enum FreeType {
   221       DECOMMIT = 0x4000,
   222       RELEASE = 0x8000
   223     }
   224 
   225     private static class NativeMethods {
   226       private const string KERNEL = "kernel32.dll";
   227 
   228       [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   229       public static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize,
   230         AllocationType flAllocationType, MemoryProtection flProtect);
   231 
   232       [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   233       public static extern bool VirtualFree(IntPtr lpAddress, UIntPtr dwSize,
   234         FreeType dwFreeType);
   235 
   236       [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   237       public static extern UIntPtr
   238         SetThreadAffinityMask(IntPtr handle, UIntPtr mask);
   239 
   240       [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   241       public static extern IntPtr GetCurrentThread();
   242     }
   243   }
   244 }