Hardware/Opcode.cs
author Stephane Lenclud
Sat, 30 Jan 2016 23:01:51 +0100
branchMiniDisplay
changeset 454 f84878f52cd9
parent 239 91800d0f54de
permissions -rw-r--r--
Disabling Nuvoton NCT6791D because of fan full speed bug on Asus Z97 WS.
     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 }