moel@236: /* moel@236: moel@344: This Source Code Form is subject to the terms of the Mozilla Public moel@344: License, v. 2.0. If a copy of the MPL was not distributed with this moel@344: file, You can obtain one at http://mozilla.org/MPL/2.0/. moel@236: moel@344: Copyright (C) 2010 Michael Möller moel@344: moel@236: */ moel@236: moel@236: using System; moel@236: using System.Runtime.InteropServices; moel@239: using System.Reflection; moel@236: moel@236: namespace OpenHardwareMonitor.Hardware { moel@236: internal static class Opcode { moel@238: moel@236: private static IntPtr codeBuffer; moel@238: private static ulong size; moel@236: moel@238: public static void Open() { moel@236: int p = (int)Environment.OSVersion.Platform; moel@238: 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@238: moel@238: if ((p == 4) || (p == 128)) { // Unix moel@238: cpuidCode = CPUID_64_LINUX; moel@238: } else { // Windows moel@238: cpuidCode = CPUID_64_WINDOWS; moel@238: } moel@236: } moel@238: moel@238: size = (ulong)(rdtscCode.Length + cpuidCode.Length); moel@239: moel@239: if ((p == 4) || (p == 128)) { // Unix moel@239: Assembly assembly = moel@239: Assembly.Load("Mono.Posix, Version=2.0.0.0, Culture=neutral, " + moel@239: "PublicKeyToken=0738eb9f132ed756"); moel@239: moel@239: Type syscall = assembly.GetType("Mono.Unix.Native.Syscall"); moel@239: MethodInfo mmap = syscall.GetMethod("mmap"); moel@239: moel@239: Type mmapProts = assembly.GetType("Mono.Unix.Native.MmapProts"); moel@239: object mmapProtsParam = Enum.ToObject(mmapProts, moel@239: (int)mmapProts.GetField("PROT_READ").GetValue(null) | moel@239: (int)mmapProts.GetField("PROT_WRITE").GetValue(null) | moel@239: (int)mmapProts.GetField("PROT_EXEC").GetValue(null)); moel@239: moel@239: Type mmapFlags = assembly.GetType("Mono.Unix.Native.MmapFlags"); moel@239: object mmapFlagsParam = Enum.ToObject(mmapFlags, moel@239: (int)mmapFlags.GetField("MAP_ANONYMOUS").GetValue(null) | moel@239: (int)mmapFlags.GetField("MAP_PRIVATE").GetValue(null)); moel@239: moel@239: codeBuffer = (IntPtr)mmap.Invoke(null, new object[] { IntPtr.Zero, moel@239: size, mmapProtsParam, mmapFlagsParam, -1, 0 }); moel@238: } else { // Windows moel@238: codeBuffer = NativeMethods.VirtualAlloc(IntPtr.Zero, moel@238: (UIntPtr)size, AllocationType.COMMIT | AllocationType.RESERVE, moel@238: MemoryProtection.EXECUTE_READWRITE); moel@238: } 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@238: cpuidAddress, typeof(CpuidDelegate)) as CpuidDelegate; moel@236: } moel@236: moel@236: public static void Close() { moel@236: Rdtsc = null; moel@236: Cpuid = null; moel@238: moel@238: int p = (int)Environment.OSVersion.Platform; moel@238: if ((p == 4) || (p == 128)) { // Unix moel@239: Assembly assembly = moel@239: Assembly.Load("Mono.Posix, Version=2.0.0.0, Culture=neutral, " + moel@239: "PublicKeyToken=0738eb9f132ed756"); moel@239: moel@239: Type syscall = assembly.GetType("Mono.Unix.Native.Syscall"); moel@239: MethodInfo munmap = syscall.GetMethod("munmap"); moel@239: munmap.Invoke(null, new object[] { codeBuffer, size }); moel@239: moel@238: } else { // Windows moel@238: NativeMethods.VirtualFree(codeBuffer, UIntPtr.Zero, moel@238: FreeType.RELEASE); moel@238: } 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@238: 0x48, 0xC1, 0xE2, 0x20, // shl rdx, 20h moel@238: 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@238: 0x8B, 0xEC, // mov ebp, esp moel@238: 0x83, 0xEC, 0x10, // sub esp, 10h moel@238: 0x8B, 0x45, 0x08, // mov eax, dword ptr [ebp+8] moel@238: 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@238: 0x8D, 0x75, 0xF0, // lea esi, [info] moel@238: 0x89, 0x06, // mov dword ptr [esi],eax moel@238: 0x8B, 0x45, 0x10, // mov eax, dword ptr [eax] moel@238: 0x89, 0x5E, 0x04, // mov dword ptr [esi+4], ebx moel@238: 0x89, 0x4E, 0x08, // mov dword ptr [esi+8], ecx moel@238: 0x89, 0x56, 0x0C, // mov dword ptr [esi+0Ch], edx moel@238: 0x8B, 0x4D, 0xF0, // mov ecx, dword ptr [info] moel@238: 0x89, 0x08, // mov dword ptr [eax], ecx moel@238: 0x8B, 0x45, 0x14, // mov eax, dword ptr [ebx] moel@238: 0x8B, 0x4D, 0xF4, // mov ecx, dword ptr [ebp-0Ch] moel@238: 0x89, 0x08, // mov dword ptr [eax], ecx moel@238: 0x8B, 0x45, 0x18, // mov eax, dword ptr [ecx] moel@238: 0x8B, 0x4D, 0xF8, // mov ecx, dword ptr [ebp-8] moel@238: 0x89, 0x08, // mov dword ptr [eax], ecx moel@238: 0x8B, 0x45, 0x1C, // mov eax, dword ptr [edx] moel@238: 0x8B, 0x4D, 0xFC, // mov ecx, dword ptr [ebp-4] moel@236: 0x5E, // pop esi moel@238: 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@238: private static readonly byte[] CPUID_64_WINDOWS = new byte[] { moel@238: 0x48, 0x89, 0x5C, 0x24, 0x08, // mov qword ptr [rsp+8], rbx moel@238: 0x8B, 0xC1, // mov eax, ecx moel@238: 0x8B, 0xCA, // mov ecx, edx moel@238: 0x0F, 0xA2, // cpuid moel@238: 0x41, 0x89, 0x00, // mov dword ptr [r8], eax moel@238: 0x48, 0x8B, 0x44, 0x24, 0x28, // mov rax, qword ptr [rsp+28h] moel@238: 0x41, 0x89, 0x19, // mov dword ptr [r9], ebx moel@238: 0x48, 0x8B, 0x5C, 0x24, 0x08, // mov rbx, qword ptr [rsp+8] moel@238: 0x89, 0x08, // mov dword ptr [rax], ecx moel@238: 0x48, 0x8B, 0x44, 0x24, 0x30, // mov rax, qword ptr [rsp+30h] moel@238: 0x89, 0x10, // mov dword ptr [rax], edx moel@236: 0xC3 // ret moel@236: }; moel@238: moel@238: private static readonly byte[] CPUID_64_LINUX = new byte[] { moel@238: 0x49, 0x89, 0xD2, // mov r10, rdx moel@238: 0x49, 0x89, 0xCB, // mov r11, rcx moel@238: 0x53, // push rbx moel@238: 0x89, 0xF8, // mov eax, edi moel@238: 0x89, 0xF1, // mov ecx, esi moel@238: 0x0F, 0xA2, // cpuid moel@238: 0x41, 0x89, 0x02, // mov dword ptr [r10], eax moel@238: 0x41, 0x89, 0x1B, // mov dword ptr [r11], ebx moel@238: 0x41, 0x89, 0x08, // mov dword ptr [r8], ecx moel@238: 0x41, 0x89, 0x11, // mov dword ptr [r9], edx moel@238: 0x5B, // pop rbx moel@238: 0xC3, // ret moel@238: }; 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@238: ulong threadAffinityMask) { moel@238: moel@238: ulong mask = ThreadAffinity.Set(threadAffinityMask); moel@236: moel@238: if (mask == 0) { moel@236: eax = ebx = ecx = edx = 0; moel@236: return false; moel@238: } moel@236: moel@236: Cpuid(index, ecxValue, out eax, out ebx, out ecx, out edx); moel@236: moel@238: ThreadAffinity.Set(mask); moel@236: return true; moel@236: } moel@238: 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@239: public enum FreeType { moel@236: DECOMMIT = 0x4000, moel@236: RELEASE = 0x8000 moel@236: } moel@236: moel@238: 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@238: FreeType dwFreeType); moel@236: } moel@236: } moel@236: }