Hardware/Opcode.cs
author moel.mich
Sun, 24 Jul 2011 16:18:56 +0000
changeset 313 596df85bb4e1
parent 238 bddc6e01840a
child 344 3145aadca3d2
permissions -rw-r--r--
Improved the CPU load sensors. The values displayed for the load per core and the total load should now be more accurate.
     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 using System.Reflection;
    41 
    42 namespace OpenHardwareMonitor.Hardware {
    43   internal static class Opcode {
    44     
    45     private static IntPtr codeBuffer;
    46     private static ulong size;
    47 
    48     public static void Open() {  
    49       int p = (int)Environment.OSVersion.Platform;
    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         
    59         if ((p == 4) || (p == 128)) { // Unix
    60           cpuidCode = CPUID_64_LINUX;
    61         } else { // Windows
    62           cpuidCode = CPUID_64_WINDOWS;
    63         }
    64       }
    65       
    66       size = (ulong)(rdtscCode.Length + cpuidCode.Length);
    67 
    68       if ((p == 4) || (p == 128)) { // Unix   
    69         Assembly assembly = 
    70           Assembly.Load("Mono.Posix, Version=2.0.0.0, Culture=neutral, " +
    71           "PublicKeyToken=0738eb9f132ed756");
    72 
    73         Type syscall = assembly.GetType("Mono.Unix.Native.Syscall");
    74         MethodInfo mmap = syscall.GetMethod("mmap");
    75 
    76         Type mmapProts = assembly.GetType("Mono.Unix.Native.MmapProts");
    77         object mmapProtsParam = Enum.ToObject(mmapProts,
    78           (int)mmapProts.GetField("PROT_READ").GetValue(null) |
    79           (int)mmapProts.GetField("PROT_WRITE").GetValue(null) |
    80           (int)mmapProts.GetField("PROT_EXEC").GetValue(null));
    81 
    82         Type mmapFlags = assembly.GetType("Mono.Unix.Native.MmapFlags");
    83         object mmapFlagsParam = Enum.ToObject(mmapFlags,
    84           (int)mmapFlags.GetField("MAP_ANONYMOUS").GetValue(null) |
    85           (int)mmapFlags.GetField("MAP_PRIVATE").GetValue(null));
    86         
    87         codeBuffer = (IntPtr)mmap.Invoke(null, new object[] { IntPtr.Zero, 
    88           size, mmapProtsParam, mmapFlagsParam, -1, 0 });        
    89       } else { // Windows
    90         codeBuffer = NativeMethods.VirtualAlloc(IntPtr.Zero,
    91           (UIntPtr)size, AllocationType.COMMIT | AllocationType.RESERVE, 
    92           MemoryProtection.EXECUTE_READWRITE);
    93       }
    94 
    95       Marshal.Copy(rdtscCode, 0, codeBuffer, rdtscCode.Length);
    96 
    97       Rdtsc = Marshal.GetDelegateForFunctionPointer(
    98         codeBuffer, typeof(RdtscDelegate)) as RdtscDelegate;
    99 
   100       IntPtr cpuidAddress = (IntPtr)((long)codeBuffer + rdtscCode.Length);
   101       Marshal.Copy(cpuidCode, 0, cpuidAddress, cpuidCode.Length);
   102 
   103       Cpuid = Marshal.GetDelegateForFunctionPointer(
   104         cpuidAddress, typeof(CpuidDelegate)) as CpuidDelegate;         
   105     }
   106 
   107     public static void Close() {
   108       Rdtsc = null;
   109       Cpuid = null;
   110       
   111       int p = (int)Environment.OSVersion.Platform;
   112       if ((p == 4) || (p == 128)) { // Unix
   113         Assembly assembly =
   114           Assembly.Load("Mono.Posix, Version=2.0.0.0, Culture=neutral, " +
   115           "PublicKeyToken=0738eb9f132ed756");
   116 
   117         Type syscall = assembly.GetType("Mono.Unix.Native.Syscall");
   118         MethodInfo munmap = syscall.GetMethod("munmap");
   119         munmap.Invoke(null, new object[] { codeBuffer, size });
   120 
   121       } else { // Windows
   122         NativeMethods.VirtualFree(codeBuffer, UIntPtr.Zero, 
   123           FreeType.RELEASE);        
   124       }
   125     }
   126 
   127     [UnmanagedFunctionPointer(CallingConvention.StdCall)]
   128     public delegate ulong RdtscDelegate();
   129 
   130     public static RdtscDelegate Rdtsc;
   131 
   132     // unsigned __int64 __stdcall rdtsc() {
   133     //   return __rdtsc();
   134     // }
   135 
   136     private static readonly byte[] RDTSC_32 = new byte[] {
   137       0x0F, 0x31,                     // rdtsc   
   138       0xC3                            // ret  
   139     };
   140 
   141     private static readonly byte[] RDTSC_64 = new byte[] {
   142       0x0F, 0x31,                     // rdtsc  
   143       0x48, 0xC1, 0xE2, 0x20,         // shl rdx, 20h  
   144       0x48, 0x0B, 0xC2,               // or rax, rdx  
   145       0xC3                            // ret  
   146     };
   147     
   148     [UnmanagedFunctionPointer(CallingConvention.StdCall)]
   149     public delegate bool CpuidDelegate(uint index, uint ecxValue,
   150       out uint eax, out uint ebx, out uint ecx, out uint edx);
   151 
   152     public static CpuidDelegate Cpuid;
   153 
   154 
   155     // void __stdcall cpuidex(unsigned int index, unsigned int ecxValue, 
   156     //   unsigned int* eax, unsigned int* ebx, unsigned int* ecx, 
   157     //   unsigned int* edx)
   158     // {
   159     //   int info[4];	
   160     //   __cpuidex(info, index, ecxValue);
   161     //   *eax = info[0];
   162     //   *ebx = info[1];
   163     //   *ecx = info[2];
   164     //   *edx = info[3];
   165     // }
   166 
   167     private static readonly byte[] CPUID_32 = new byte[] {
   168       0x55,                           // push ebp  
   169       0x8B, 0xEC,                     // mov ebp, esp  
   170       0x83, 0xEC, 0x10,               // sub esp, 10h  
   171       0x8B, 0x45, 0x08,               // mov eax, dword ptr [ebp+8]  
   172       0x8B, 0x4D, 0x0C,               // mov ecx, dword ptr [ebp+0Ch]  
   173       0x53,                           // push ebx  
   174       0x0F, 0xA2,                     // cpuid  
   175       0x56,                           // push esi  
   176       0x8D, 0x75, 0xF0,               // lea esi, [info]  
   177       0x89, 0x06,                     // mov dword ptr [esi],eax  
   178       0x8B, 0x45, 0x10,               // mov eax, dword ptr [eax]  
   179       0x89, 0x5E, 0x04,               // mov dword ptr [esi+4], ebx  
   180       0x89, 0x4E, 0x08,               // mov dword ptr [esi+8], ecx  
   181       0x89, 0x56, 0x0C,               // mov dword ptr [esi+0Ch], edx  
   182       0x8B, 0x4D, 0xF0,               // mov ecx, dword ptr [info]  
   183       0x89, 0x08,                     // mov dword ptr [eax], ecx  
   184       0x8B, 0x45, 0x14,               // mov eax, dword ptr [ebx]  
   185       0x8B, 0x4D, 0xF4,               // mov ecx, dword ptr [ebp-0Ch]  
   186       0x89, 0x08,                     // mov dword ptr [eax], ecx  
   187       0x8B, 0x45, 0x18,               // mov eax, dword ptr [ecx]  
   188       0x8B, 0x4D, 0xF8,               // mov ecx, dword ptr [ebp-8]  
   189       0x89, 0x08,                     // mov dword ptr [eax], ecx  
   190       0x8B, 0x45, 0x1C,               // mov eax, dword ptr [edx]  
   191       0x8B, 0x4D, 0xFC,               // mov ecx, dword ptr [ebp-4]  
   192       0x5E,                           // pop esi  
   193       0x89, 0x08,                     // mov dword ptr [eax], ecx  
   194       0x5B,                           // pop ebx  
   195       0xC9,                           // leave  
   196       0xC2, 0x18, 0x00                // ret 18h  
   197     };
   198              
   199     private static readonly byte[] CPUID_64_WINDOWS = new byte[] {
   200       0x48, 0x89, 0x5C, 0x24, 0x08,   // mov qword ptr [rsp+8], rbx  
   201       0x8B, 0xC1,                     // mov eax, ecx  
   202       0x8B, 0xCA,                     // mov ecx, edx        
   203       0x0F, 0xA2,                     // cpuid        
   204       0x41, 0x89, 0x00,               // mov dword ptr [r8], eax        
   205       0x48, 0x8B, 0x44, 0x24, 0x28,   // mov rax, qword ptr [rsp+28h]       
   206       0x41, 0x89, 0x19,               // mov dword ptr [r9], ebx        
   207       0x48, 0x8B, 0x5C, 0x24, 0x08,   // mov rbx, qword ptr [rsp+8]      
   208       0x89, 0x08,                     // mov dword ptr [rax], ecx        
   209       0x48, 0x8B, 0x44, 0x24, 0x30,   // mov rax, qword ptr [rsp+30h]  
   210       0x89, 0x10,                     // mov dword ptr [rax], edx  
   211       0xC3                            // ret  
   212     };
   213     
   214     private static readonly byte[] CPUID_64_LINUX = new byte[] {
   215       0x49, 0x89, 0xD2,               // mov r10, rdx
   216       0x49, 0x89, 0xCB,               // mov r11, rcx
   217       0x53,                           // push rbx
   218       0x89, 0xF8,                     // mov eax, edi
   219       0x89, 0xF1,                     // mov ecx, esi
   220       0x0F, 0xA2,                     // cpuid
   221       0x41, 0x89, 0x02,               // mov dword ptr [r10], eax
   222       0x41, 0x89, 0x1B,               // mov dword ptr [r11], ebx
   223       0x41, 0x89, 0x08,               // mov dword ptr [r8], ecx
   224       0x41, 0x89, 0x11,               // mov dword ptr [r9], edx
   225       0x5B,                           // pop rbx
   226       0xC3,                           // ret
   227     };
   228 
   229     public static bool CpuidTx(uint index, uint ecxValue, 
   230       out uint eax, out uint ebx, out uint ecx, out uint edx, 
   231       ulong threadAffinityMask) {
   232       
   233       ulong mask = ThreadAffinity.Set(threadAffinityMask);
   234 
   235       if (mask == 0) {
   236         eax = ebx = ecx = edx = 0;
   237         return false;
   238       } 
   239 
   240       Cpuid(index, ecxValue, out eax, out ebx, out ecx, out edx);
   241 
   242       ThreadAffinity.Set(mask);      
   243       return true;
   244     }
   245     
   246     [Flags()]
   247     public enum AllocationType : uint {
   248       COMMIT = 0x1000,
   249       RESERVE = 0x2000,
   250       RESET = 0x80000,
   251       LARGE_PAGES = 0x20000000,
   252       PHYSICAL = 0x400000,
   253       TOP_DOWN = 0x100000,
   254       WRITE_WATCH = 0x200000
   255     }
   256 
   257     [Flags()]
   258     public enum MemoryProtection : uint {
   259       EXECUTE = 0x10,
   260       EXECUTE_READ = 0x20,
   261       EXECUTE_READWRITE = 0x40,
   262       EXECUTE_WRITECOPY = 0x80,
   263       NOACCESS = 0x01,
   264       READONLY = 0x02,
   265       READWRITE = 0x04,
   266       WRITECOPY = 0x08,
   267       GUARD = 0x100,
   268       NOCACHE = 0x200,
   269       WRITECOMBINE = 0x400
   270     }
   271 
   272     [Flags]
   273     public enum FreeType {
   274       DECOMMIT = 0x4000,
   275       RELEASE = 0x8000
   276     }
   277 
   278     private static class NativeMethods {      
   279       private const string KERNEL = "kernel32.dll";
   280 
   281       [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   282       public static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize,
   283         AllocationType flAllocationType, MemoryProtection flProtect);
   284 
   285       [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   286       public static extern bool VirtualFree(IntPtr lpAddress, UIntPtr dwSize,
   287         FreeType dwFreeType);                 
   288     }
   289   }
   290 }