moel@236: /* moel@236: moel@236: Version: MPL 1.1/GPL 2.0/LGPL 2.1 moel@236: moel@236: The contents of this file are subject to the Mozilla Public License Version moel@236: 1.1 (the "License"); you may not use this file except in compliance with moel@236: the License. You may obtain a copy of the License at moel@236: moel@236: http://www.mozilla.org/MPL/ moel@236: moel@236: Software distributed under the License is distributed on an "AS IS" basis, moel@236: WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License moel@236: for the specific language governing rights and limitations under the License. moel@236: moel@236: The Original Code is the Open Hardware Monitor code. moel@236: moel@236: The Initial Developer of the Original Code is moel@236: Michael Möller . moel@236: Portions created by the Initial Developer are Copyright (C) 2010 moel@236: the Initial Developer. All Rights Reserved. moel@236: moel@236: Contributor(s): moel@236: moel@236: Alternatively, the contents of this file may be used under the terms of moel@236: either the GNU General Public License Version 2 or later (the "GPL"), or moel@236: the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), moel@236: in which case the provisions of the GPL or the LGPL are applicable instead moel@236: of those above. If you wish to allow use of your version of this file only moel@236: under the terms of either the GPL or the LGPL, and not to allow others to moel@236: use your version of this file under the terms of the MPL, indicate your moel@236: decision by deleting the provisions above and replace them with the notice moel@236: and other provisions required by the GPL or the LGPL. If you do not delete moel@236: the provisions above, a recipient may use your version of this file under moel@236: the terms of any one of the MPL, the GPL or the LGPL. moel@236: moel@236: */ moel@236: moel@236: using System; moel@236: using System.Runtime.InteropServices; moel@236: moel@236: namespace OpenHardwareMonitor.Hardware { moel@236: internal static class Opcode { moel@236: private static IntPtr codeBuffer; moel@236: moel@236: public static void Open() { moel@236: // No implementation for Unix systems moel@236: int p = (int)Environment.OSVersion.Platform; moel@236: if ((p == 4) || (p == 128)) moel@236: return; moel@236: moel@236: byte[] rdtscCode; moel@236: byte[] cpuidCode; moel@236: if (IntPtr.Size == 4) { moel@236: rdtscCode = RDTSC_32; moel@236: cpuidCode = CPUID_32; moel@236: } else { moel@236: rdtscCode = RDTSC_64; moel@236: cpuidCode = CPUID_64; moel@236: } moel@236: moel@236: codeBuffer = NativeMethods.VirtualAlloc(IntPtr.Zero, moel@236: (UIntPtr)(rdtscCode.Length + cpuidCode.Length), moel@236: AllocationType.COMMIT | AllocationType.RESERVE, moel@236: MemoryProtection.EXECUTE_READWRITE); moel@236: moel@236: Marshal.Copy(rdtscCode, 0, codeBuffer, rdtscCode.Length); moel@236: moel@236: Rdtsc = Marshal.GetDelegateForFunctionPointer( moel@236: codeBuffer, typeof(RdtscDelegate)) as RdtscDelegate; moel@236: moel@236: IntPtr cpuidAddress = (IntPtr)((long)codeBuffer + rdtscCode.Length); moel@236: Marshal.Copy(cpuidCode, 0, cpuidAddress, cpuidCode.Length); moel@236: moel@236: Cpuid = Marshal.GetDelegateForFunctionPointer( moel@236: cpuidAddress, typeof(CpuidDelegate)) as CpuidDelegate; moel@236: } moel@236: moel@236: public static void Close() { moel@236: Rdtsc = null; moel@236: Cpuid = null; moel@236: moel@236: NativeMethods.VirtualFree(codeBuffer, UIntPtr.Zero, moel@236: FreeType.RELEASE); moel@236: } moel@236: moel@236: [UnmanagedFunctionPointer(CallingConvention.StdCall)] moel@236: public delegate ulong RdtscDelegate(); moel@236: moel@236: public static RdtscDelegate Rdtsc; moel@236: moel@236: // unsigned __int64 __stdcall rdtsc() { moel@236: // return __rdtsc(); moel@236: // } moel@236: moel@236: private static readonly byte[] RDTSC_32 = new byte[] { moel@236: 0x0F, 0x31, // rdtsc moel@236: 0xC3 // ret moel@236: }; moel@236: moel@236: private static readonly byte[] RDTSC_64 = new byte[] { moel@236: 0x0F, 0x31, // rdtsc moel@236: 0x48, 0xC1, 0xE2, 0x20, // shl rdx,20h moel@236: 0x48, 0x0B, 0xC2, // or rax,rdx moel@236: 0xC3 // ret moel@236: }; moel@236: moel@236: [UnmanagedFunctionPointer(CallingConvention.StdCall)] moel@236: public delegate bool CpuidDelegate(uint index, uint ecxValue, moel@236: out uint eax, out uint ebx, out uint ecx, out uint edx); moel@236: moel@236: public static CpuidDelegate Cpuid; moel@236: moel@236: moel@236: // void __stdcall cpuidex(unsigned int index, unsigned int ecxValue, moel@236: // unsigned int* eax, unsigned int* ebx, unsigned int* ecx, moel@236: // unsigned int* edx) moel@236: // { moel@236: // int info[4]; moel@236: // __cpuidex(info, index, ecxValue); moel@236: // *eax = info[0]; moel@236: // *ebx = info[1]; moel@236: // *ecx = info[2]; moel@236: // *edx = info[3]; moel@236: // } moel@236: moel@236: private static readonly byte[] CPUID_32 = new byte[] { moel@236: 0x55, // push ebp moel@236: 0x8B, 0xEC, // mov ebp,esp moel@236: 0x83, 0xEC, 0x10, // sub esp,10h moel@236: 0x8B, 0x45, 0x08, // mov eax,dword ptr [ebp+8] moel@236: 0x8B, 0x4D, 0x0C, // mov ecx,dword ptr [ebp+0Ch] moel@236: 0x53, // push ebx moel@236: 0x0F, 0xA2, // cpuid moel@236: 0x56, // push esi moel@236: 0x8D, 0x75, 0xF0, // lea esi,[info] moel@236: 0x89, 0x06, // mov dword ptr [esi],eax moel@236: 0x8B, 0x45, 0x10, // mov eax,dword ptr [eax] moel@236: 0x89, 0x5E, 0x04, // mov dword ptr [esi+4],ebx moel@236: 0x89, 0x4E, 0x08, // mov dword ptr [esi+8],ecx moel@236: 0x89, 0x56, 0x0C, // mov dword ptr [esi+0Ch],edx moel@236: 0x8B, 0x4D, 0xF0, // mov ecx,dword ptr [info] moel@236: 0x89, 0x08, // mov dword ptr [eax],ecx moel@236: 0x8B, 0x45, 0x14, // mov eax,dword ptr [ebx] moel@236: 0x8B, 0x4D, 0xF4, // mov ecx,dword ptr [ebp-0Ch] moel@236: 0x89, 0x08, // mov dword ptr [eax],ecx moel@236: 0x8B, 0x45, 0x18, // mov eax,dword ptr [ecx] moel@236: 0x8B, 0x4D, 0xF8, // mov ecx,dword ptr [ebp-8] moel@236: 0x89, 0x08, // mov dword ptr [eax],ecx moel@236: 0x8B, 0x45, 0x1C, // mov eax,dword ptr [edx] moel@236: 0x8B, 0x4D, 0xFC, // mov ecx,dword ptr [ebp-4] moel@236: 0x5E, // pop esi moel@236: 0x89, 0x08, // mov dword ptr [eax],ecx moel@236: 0x5B, // pop ebx moel@236: 0xC9, // leave moel@236: 0xC2, 0x18, 0x00 // ret 18h moel@236: }; moel@236: moel@236: private static readonly byte[] CPUID_64 = new byte[] { moel@236: 0x48, 0x89, 0x5C, 0x24, 0x08, // mov qword ptr [rsp+8],rbx moel@236: 0x8B, 0xC1, // mov eax,ecx moel@236: 0x8B, 0xCA, // mov ecx,edx moel@236: 0x0F, 0xA2, // cpuid moel@236: 0x41, 0x89, 0x00, // mov dword ptr [r8],eax moel@236: 0x48, 0x8B, 0x44, 0x24, 0x28, // mov rax,qword ptr [ecx] moel@236: 0x41, 0x89, 0x19, // mov dword ptr [r9],ebx moel@236: 0x48, 0x8B, 0x5C, 0x24, 0x08, // mov rbx,qword ptr [rsp+8] moel@236: 0x89, 0x08, // mov dword ptr [rax],ecx moel@236: 0x48, 0x8B, 0x44, 0x24, 0x30, // mov rax,qword ptr [rsp+30h] moel@236: 0x89, 0x10, // mov dword ptr [rax],edx moel@236: 0xC3 // ret moel@236: }; moel@236: moel@236: public static bool CpuidTx(uint index, uint ecxValue, moel@236: out uint eax, out uint ebx, out uint ecx, out uint edx, moel@236: UIntPtr threadAffinityMask) { moel@236: moel@236: IntPtr thread = NativeMethods.GetCurrentThread(); moel@236: UIntPtr mask = NativeMethods.SetThreadAffinityMask(thread, moel@236: threadAffinityMask); moel@236: moel@236: if (mask == UIntPtr.Zero) { moel@236: eax = ebx = ecx = edx = 0; moel@236: return false; moel@236: } moel@236: moel@236: Cpuid(index, ecxValue, out eax, out ebx, out ecx, out edx); moel@236: moel@236: NativeMethods.SetThreadAffinityMask(thread, mask); moel@236: moel@236: return true; moel@236: } moel@236: moel@236: [Flags()] moel@236: public enum AllocationType : uint { moel@236: COMMIT = 0x1000, moel@236: RESERVE = 0x2000, moel@236: RESET = 0x80000, moel@236: LARGE_PAGES = 0x20000000, moel@236: PHYSICAL = 0x400000, moel@236: TOP_DOWN = 0x100000, moel@236: WRITE_WATCH = 0x200000 moel@236: } moel@236: moel@236: [Flags()] moel@236: public enum MemoryProtection : uint { moel@236: EXECUTE = 0x10, moel@236: EXECUTE_READ = 0x20, moel@236: EXECUTE_READWRITE = 0x40, moel@236: EXECUTE_WRITECOPY = 0x80, moel@236: NOACCESS = 0x01, moel@236: READONLY = 0x02, moel@236: READWRITE = 0x04, moel@236: WRITECOPY = 0x08, moel@236: GUARD = 0x100, moel@236: NOCACHE = 0x200, moel@236: WRITECOMBINE = 0x400 moel@236: } moel@236: moel@236: [Flags] moel@236: enum FreeType { moel@236: DECOMMIT = 0x4000, moel@236: RELEASE = 0x8000 moel@236: } moel@236: moel@236: private static class NativeMethods { moel@236: private const string KERNEL = "kernel32.dll"; moel@236: moel@236: [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)] moel@236: public static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize, moel@236: AllocationType flAllocationType, MemoryProtection flProtect); moel@236: moel@236: [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)] moel@236: public static extern bool VirtualFree(IntPtr lpAddress, UIntPtr dwSize, moel@236: FreeType dwFreeType); moel@236: moel@236: [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)] moel@236: public static extern UIntPtr moel@236: SetThreadAffinityMask(IntPtr handle, UIntPtr mask); moel@236: moel@236: [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)] moel@236: public static extern IntPtr GetCurrentThread(); moel@236: } moel@236: } moel@236: }