Added CPUID support for Linux.
     3   Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
     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
 
     9   http://www.mozilla.org/MPL/
 
    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.
 
    15   The Original Code is the Open Hardware Monitor code.
 
    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.
 
    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.
 
    39 using System.Runtime.InteropServices;
 
    40 using Mono.Unix.Native;
 
    42 namespace OpenHardwareMonitor.Hardware {
 
    43   internal static class Opcode {
 
    45     private static IntPtr codeBuffer;
 
    46     private static ulong size;
 
    48     public static void Open() {  
 
    49       int p = (int)Environment.OSVersion.Platform;
 
    53       if (IntPtr.Size == 4) {
 
    59         if ((p == 4) || (p == 128)) { // Unix
 
    60           cpuidCode = CPUID_64_LINUX;
 
    62           cpuidCode = CPUID_64_WINDOWS;
 
    66       size = (ulong)(rdtscCode.Length + cpuidCode.Length);
 
    68       if ((p == 4) || (p == 128)) { // Unix
 
    69         codeBuffer = Syscall.mmap(IntPtr.Zero, size, 
 
    70           MmapProts.PROT_READ | MmapProts.PROT_WRITE | MmapProts.PROT_EXEC, 
 
    71           MmapFlags.MAP_ANONYMOUS | MmapFlags.MAP_PRIVATE, -1, 0);
 
    73         codeBuffer = NativeMethods.VirtualAlloc(IntPtr.Zero,
 
    74           (UIntPtr)size, AllocationType.COMMIT | AllocationType.RESERVE, 
 
    75           MemoryProtection.EXECUTE_READWRITE);
 
    78       Marshal.Copy(rdtscCode, 0, codeBuffer, rdtscCode.Length);
 
    80       Rdtsc = Marshal.GetDelegateForFunctionPointer(
 
    81         codeBuffer, typeof(RdtscDelegate)) as RdtscDelegate;
 
    83       IntPtr cpuidAddress = (IntPtr)((long)codeBuffer + rdtscCode.Length);
 
    84       Marshal.Copy(cpuidCode, 0, cpuidAddress, cpuidCode.Length);
 
    86       Cpuid = Marshal.GetDelegateForFunctionPointer(
 
    87         cpuidAddress, typeof(CpuidDelegate)) as CpuidDelegate;         
 
    90     public static void Close() {
 
    94       int p = (int)Environment.OSVersion.Platform;
 
    95       if ((p == 4) || (p == 128)) { // Unix
 
    96         Syscall.munmap(codeBuffer, size);
 
    98         NativeMethods.VirtualFree(codeBuffer, UIntPtr.Zero, 
 
   103     [UnmanagedFunctionPointer(CallingConvention.StdCall)]
 
   104     public delegate ulong RdtscDelegate();
 
   106     public static RdtscDelegate Rdtsc;
 
   108     // unsigned __int64 __stdcall rdtsc() {
 
   112     private static readonly byte[] RDTSC_32 = new byte[] {
 
   117     private static readonly byte[] RDTSC_64 = new byte[] {
 
   119       0x48, 0xC1, 0xE2, 0x20,         // shl rdx, 20h  
 
   120       0x48, 0x0B, 0xC2,               // or rax, rdx  
 
   124     [UnmanagedFunctionPointer(CallingConvention.StdCall)]
 
   125     public delegate bool CpuidDelegate(uint index, uint ecxValue,
 
   126       out uint eax, out uint ebx, out uint ecx, out uint edx);
 
   128     public static CpuidDelegate Cpuid;
 
   131     // void __stdcall cpuidex(unsigned int index, unsigned int ecxValue, 
 
   132     //   unsigned int* eax, unsigned int* ebx, unsigned int* ecx, 
 
   133     //   unsigned int* edx)
 
   136     //   __cpuidex(info, index, ecxValue);
 
   143     private static readonly byte[] CPUID_32 = new byte[] {
 
   145       0x8B, 0xEC,                     // mov ebp, esp  
 
   146       0x83, 0xEC, 0x10,               // sub esp, 10h  
 
   147       0x8B, 0x45, 0x08,               // mov eax, dword ptr [ebp+8]  
 
   148       0x8B, 0x4D, 0x0C,               // mov ecx, dword ptr [ebp+0Ch]  
 
   152       0x8D, 0x75, 0xF0,               // lea esi, [info]  
 
   153       0x89, 0x06,                     // mov dword ptr [esi],eax  
 
   154       0x8B, 0x45, 0x10,               // mov eax, dword ptr [eax]  
 
   155       0x89, 0x5E, 0x04,               // mov dword ptr [esi+4], ebx  
 
   156       0x89, 0x4E, 0x08,               // mov dword ptr [esi+8], ecx  
 
   157       0x89, 0x56, 0x0C,               // mov dword ptr [esi+0Ch], edx  
 
   158       0x8B, 0x4D, 0xF0,               // mov ecx, dword ptr [info]  
 
   159       0x89, 0x08,                     // mov dword ptr [eax], ecx  
 
   160       0x8B, 0x45, 0x14,               // mov eax, dword ptr [ebx]  
 
   161       0x8B, 0x4D, 0xF4,               // mov ecx, dword ptr [ebp-0Ch]  
 
   162       0x89, 0x08,                     // mov dword ptr [eax], ecx  
 
   163       0x8B, 0x45, 0x18,               // mov eax, dword ptr [ecx]  
 
   164       0x8B, 0x4D, 0xF8,               // mov ecx, dword ptr [ebp-8]  
 
   165       0x89, 0x08,                     // mov dword ptr [eax], ecx  
 
   166       0x8B, 0x45, 0x1C,               // mov eax, dword ptr [edx]  
 
   167       0x8B, 0x4D, 0xFC,               // mov ecx, dword ptr [ebp-4]  
 
   169       0x89, 0x08,                     // mov dword ptr [eax], ecx  
 
   172       0xC2, 0x18, 0x00                // ret 18h  
 
   175     private static readonly byte[] CPUID_64_WINDOWS = new byte[] {
 
   176       0x48, 0x89, 0x5C, 0x24, 0x08,   // mov qword ptr [rsp+8], rbx  
 
   177       0x8B, 0xC1,                     // mov eax, ecx  
 
   178       0x8B, 0xCA,                     // mov ecx, edx        
 
   180       0x41, 0x89, 0x00,               // mov dword ptr [r8], eax        
 
   181       0x48, 0x8B, 0x44, 0x24, 0x28,   // mov rax, qword ptr [rsp+28h]       
 
   182       0x41, 0x89, 0x19,               // mov dword ptr [r9], ebx        
 
   183       0x48, 0x8B, 0x5C, 0x24, 0x08,   // mov rbx, qword ptr [rsp+8]      
 
   184       0x89, 0x08,                     // mov dword ptr [rax], ecx        
 
   185       0x48, 0x8B, 0x44, 0x24, 0x30,   // mov rax, qword ptr [rsp+30h]  
 
   186       0x89, 0x10,                     // mov dword ptr [rax], edx  
 
   190     private static readonly byte[] CPUID_64_LINUX = new byte[] {
 
   191       0x49, 0x89, 0xD2,               // mov r10, rdx
 
   192       0x49, 0x89, 0xCB,               // mov r11, rcx
 
   194       0x89, 0xF8,                     // mov eax, edi
 
   195       0x89, 0xF1,                     // mov ecx, esi
 
   197       0x41, 0x89, 0x02,               // mov dword ptr [r10], eax
 
   198       0x41, 0x89, 0x1B,               // mov dword ptr [r11], ebx
 
   199       0x41, 0x89, 0x08,               // mov dword ptr [r8], ecx
 
   200       0x41, 0x89, 0x11,               // mov dword ptr [r9], edx
 
   205     public static bool CpuidTx(uint index, uint ecxValue, 
 
   206       out uint eax, out uint ebx, out uint ecx, out uint edx, 
 
   207       ulong threadAffinityMask) {
 
   209       ulong mask = ThreadAffinity.Set(threadAffinityMask);
 
   212         eax = ebx = ecx = edx = 0;
 
   216       Cpuid(index, ecxValue, out eax, out ebx, out ecx, out edx);
 
   218       ThreadAffinity.Set(mask);      
 
   223     public enum AllocationType : uint {
 
   227       LARGE_PAGES = 0x20000000,
 
   230       WRITE_WATCH = 0x200000
 
   234     public enum MemoryProtection : uint {
 
   237       EXECUTE_READWRITE = 0x40,
 
   238       EXECUTE_WRITECOPY = 0x80,
 
   254     private static class NativeMethods {      
 
   255       private const string KERNEL = "kernel32.dll";
 
   257       [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
 
   258       public static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize,
 
   259         AllocationType flAllocationType, MemoryProtection flProtect);
 
   261       [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
 
   262       public static extern bool VirtualFree(IntPtr lpAddress, UIntPtr dwSize,
 
   263         FreeType dwFreeType);