first commit
This commit is contained in:
@@ -0,0 +1,301 @@
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
// Copyright (C) LibreHardwareMonitor and Contributors.
|
||||
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
|
||||
// All Rights Reserved.
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace LibreHardwareMonitor.Hardware;
|
||||
|
||||
internal static class OpCode
|
||||
{
|
||||
public static CpuidDelegate CpuId;
|
||||
public static RdtscDelegate Rdtsc;
|
||||
|
||||
private static IntPtr _codeBuffer;
|
||||
private static ulong _size;
|
||||
|
||||
// void __stdcall cpuidex(unsigned int index, unsigned int ecxValue,
|
||||
// unsigned int* eax, unsigned int* ebx, unsigned int* ecx,
|
||||
// unsigned int* edx)
|
||||
// {
|
||||
// int info[4];
|
||||
// __cpuidex(info, index, ecxValue);
|
||||
// *eax = info[0];
|
||||
// *ebx = info[1];
|
||||
// *ecx = info[2];
|
||||
// *edx = info[3];
|
||||
// }
|
||||
|
||||
private static readonly byte[] CpuId32 =
|
||||
{
|
||||
0x55, // push ebp
|
||||
0x8B,
|
||||
0xEC, // mov ebp, esp
|
||||
0x83,
|
||||
0xEC,
|
||||
0x10, // sub esp, 10h
|
||||
0x8B,
|
||||
0x45,
|
||||
0x08, // mov eax, dword ptr [ebp+8]
|
||||
0x8B,
|
||||
0x4D,
|
||||
0x0C, // mov ecx, dword ptr [ebp+0Ch]
|
||||
0x53, // push ebx
|
||||
0x0F,
|
||||
0xA2, // cpuid
|
||||
0x56, // push esi
|
||||
0x8D,
|
||||
0x75,
|
||||
0xF0, // lea esi, [info]
|
||||
0x89,
|
||||
0x06, // mov dword ptr [esi],eax
|
||||
0x8B,
|
||||
0x45,
|
||||
0x10, // mov eax, dword ptr [eax]
|
||||
0x89,
|
||||
0x5E,
|
||||
0x04, // mov dword ptr [esi+4], ebx
|
||||
0x89,
|
||||
0x4E,
|
||||
0x08, // mov dword ptr [esi+8], ecx
|
||||
0x89,
|
||||
0x56,
|
||||
0x0C, // mov dword ptr [esi+0Ch], edx
|
||||
0x8B,
|
||||
0x4D,
|
||||
0xF0, // mov ecx, dword ptr [info]
|
||||
0x89,
|
||||
0x08, // mov dword ptr [eax], ecx
|
||||
0x8B,
|
||||
0x45,
|
||||
0x14, // mov eax, dword ptr [ebx]
|
||||
0x8B,
|
||||
0x4D,
|
||||
0xF4, // mov ecx, dword ptr [ebp-0Ch]
|
||||
0x89,
|
||||
0x08, // mov dword ptr [eax], ecx
|
||||
0x8B,
|
||||
0x45,
|
||||
0x18, // mov eax, dword ptr [ecx]
|
||||
0x8B,
|
||||
0x4D,
|
||||
0xF8, // mov ecx, dword ptr [ebp-8]
|
||||
0x89,
|
||||
0x08, // mov dword ptr [eax], ecx
|
||||
0x8B,
|
||||
0x45,
|
||||
0x1C, // mov eax, dword ptr [edx]
|
||||
0x8B,
|
||||
0x4D,
|
||||
0xFC, // mov ecx, dword ptr [ebp-4]
|
||||
0x5E, // pop esi
|
||||
0x89,
|
||||
0x08, // mov dword ptr [eax], ecx
|
||||
0x5B, // pop ebx
|
||||
0xC9, // leave
|
||||
0xC2,
|
||||
0x18,
|
||||
0x00 // ret 18h
|
||||
};
|
||||
|
||||
private static readonly byte[] CpuId64Linux =
|
||||
{
|
||||
0x49,
|
||||
0x89,
|
||||
0xD2, // mov r10, rdx
|
||||
0x49,
|
||||
0x89,
|
||||
0xCB, // mov r11, rcx
|
||||
0x53, // push rbx
|
||||
0x89,
|
||||
0xF8, // mov eax, edi
|
||||
0x89,
|
||||
0xF1, // mov ecx, esi
|
||||
0x0F,
|
||||
0xA2, // cpuid
|
||||
0x41,
|
||||
0x89,
|
||||
0x02, // mov dword ptr [r10], eax
|
||||
0x41,
|
||||
0x89,
|
||||
0x1B, // mov dword ptr [r11], ebx
|
||||
0x41,
|
||||
0x89,
|
||||
0x08, // mov dword ptr [r8], ecx
|
||||
0x41,
|
||||
0x89,
|
||||
0x11, // mov dword ptr [r9], edx
|
||||
0x5B, // pop rbx
|
||||
0xC3 // ret
|
||||
};
|
||||
|
||||
private static readonly byte[] CpuId64Windows =
|
||||
{
|
||||
0x48,
|
||||
0x89,
|
||||
0x5C,
|
||||
0x24,
|
||||
0x08, // mov qword ptr [rsp+8], rbx
|
||||
0x8B,
|
||||
0xC1, // mov eax, ecx
|
||||
0x8B,
|
||||
0xCA, // mov ecx, edx
|
||||
0x0F,
|
||||
0xA2, // cpuid
|
||||
0x41,
|
||||
0x89,
|
||||
0x00, // mov dword ptr [r8], eax
|
||||
0x48,
|
||||
0x8B,
|
||||
0x44,
|
||||
0x24,
|
||||
0x28, // mov rax, qword ptr [rsp+28h]
|
||||
0x41,
|
||||
0x89,
|
||||
0x19, // mov dword ptr [r9], ebx
|
||||
0x48,
|
||||
0x8B,
|
||||
0x5C,
|
||||
0x24,
|
||||
0x08, // mov rbx, qword ptr [rsp+8]
|
||||
0x89,
|
||||
0x08, // mov dword ptr [rax], ecx
|
||||
0x48,
|
||||
0x8B,
|
||||
0x44,
|
||||
0x24,
|
||||
0x30, // mov rax, qword ptr [rsp+30h]
|
||||
0x89,
|
||||
0x10, // mov dword ptr [rax], edx
|
||||
0xC3 // ret
|
||||
};
|
||||
|
||||
// unsigned __int64 __stdcall rdtsc() {
|
||||
// return __rdtsc();
|
||||
// }
|
||||
|
||||
private static readonly byte[] Rdtsc32 =
|
||||
{
|
||||
0x0F,
|
||||
0x31, // rdtsc
|
||||
0xC3 // ret
|
||||
};
|
||||
|
||||
private static readonly byte[] Rdtsc64 =
|
||||
{
|
||||
0x0F,
|
||||
0x31, // rdtsc
|
||||
0x48,
|
||||
0xC1,
|
||||
0xE2,
|
||||
0x20, // shl rdx, 20h
|
||||
0x48,
|
||||
0x0B,
|
||||
0xC2, // or rax, rdx
|
||||
0xC3 // ret
|
||||
};
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate bool CpuidDelegate(uint index, uint ecxValue, out uint eax, out uint ebx, out uint ecx, out uint edx);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate ulong RdtscDelegate();
|
||||
|
||||
public static void Open()
|
||||
{
|
||||
byte[] rdTscCode;
|
||||
byte[] cpuidCode;
|
||||
if (IntPtr.Size == 4)
|
||||
{
|
||||
rdTscCode = Rdtsc32;
|
||||
cpuidCode = CpuId32;
|
||||
}
|
||||
else
|
||||
{
|
||||
rdTscCode = Rdtsc64;
|
||||
cpuidCode = Software.OperatingSystem.IsUnix ? CpuId64Linux : CpuId64Windows;
|
||||
}
|
||||
|
||||
_size = (ulong)(rdTscCode.Length + cpuidCode.Length);
|
||||
|
||||
if (Software.OperatingSystem.IsUnix)
|
||||
{
|
||||
#if NETFRAMEWORK
|
||||
Assembly assembly = Assembly.Load("Mono.Posix, Version=2.0.0.0, Culture=neutral, " + "PublicKeyToken=0738eb9f132ed756");
|
||||
#else
|
||||
Assembly assembly = Assembly.Load("Mono.Posix.NETStandard, Version=1.0.0.0, Culture=neutral");
|
||||
#endif
|
||||
|
||||
Type sysCall = assembly.GetType("Mono.Unix.Native.Syscall");
|
||||
MethodInfo mmap = sysCall.GetMethod("mmap");
|
||||
|
||||
Type mmapProts = assembly.GetType("Mono.Unix.Native.MmapProts");
|
||||
object mmapProtsParam = Enum.ToObject(mmapProts,
|
||||
(int)mmapProts.GetField("PROT_READ").GetValue(null) |
|
||||
(int)mmapProts.GetField("PROT_WRITE").GetValue(null) |
|
||||
(int)mmapProts.GetField("PROT_EXEC").GetValue(null));
|
||||
|
||||
Type mmapFlags = assembly.GetType("Mono.Unix.Native.MmapFlags");
|
||||
object mmapFlagsParam = Enum.ToObject(mmapFlags,
|
||||
(int)mmapFlags.GetField("MAP_ANONYMOUS").GetValue(null) |
|
||||
(int)mmapFlags.GetField("MAP_PRIVATE").GetValue(null));
|
||||
|
||||
if (mmap != null)
|
||||
_codeBuffer = (IntPtr)mmap.Invoke(null, new[] { IntPtr.Zero, _size, mmapProtsParam, mmapFlagsParam, -1, 0 });
|
||||
}
|
||||
else
|
||||
{
|
||||
_codeBuffer = Interop.Kernel32.VirtualAlloc(IntPtr.Zero,
|
||||
(UIntPtr)_size,
|
||||
Interop.Kernel32.MEM.MEM_COMMIT | Interop.Kernel32.MEM.MEM_RESERVE,
|
||||
Interop.Kernel32.PAGE.PAGE_EXECUTE_READWRITE);
|
||||
}
|
||||
|
||||
Marshal.Copy(rdTscCode, 0, _codeBuffer, rdTscCode.Length);
|
||||
Rdtsc = Marshal.GetDelegateForFunctionPointer(_codeBuffer, typeof(RdtscDelegate)) as RdtscDelegate;
|
||||
IntPtr cpuidAddress = (IntPtr)((long)_codeBuffer + rdTscCode.Length);
|
||||
Marshal.Copy(cpuidCode, 0, cpuidAddress, cpuidCode.Length);
|
||||
CpuId = Marshal.GetDelegateForFunctionPointer(cpuidAddress, typeof(CpuidDelegate)) as CpuidDelegate;
|
||||
}
|
||||
|
||||
public static void Close()
|
||||
{
|
||||
Rdtsc = null;
|
||||
CpuId = null;
|
||||
|
||||
if (Software.OperatingSystem.IsUnix)
|
||||
{
|
||||
#if NETFRAMEWORK
|
||||
Assembly assembly = Assembly.Load("Mono.Posix, Version=2.0.0.0, Culture=neutral, " + "PublicKeyToken=0738eb9f132ed756");
|
||||
#else
|
||||
Assembly assembly = Assembly.Load("Mono.Posix.NETStandard, Version=1.0.0.0, Culture=neutral");
|
||||
#endif
|
||||
|
||||
Type sysCall = assembly.GetType("Mono.Unix.Native.Syscall");
|
||||
MethodInfo method = sysCall.GetMethod("munmap");
|
||||
method?.Invoke(null, new object[] { _codeBuffer, _size });
|
||||
}
|
||||
else
|
||||
{
|
||||
Interop.Kernel32.VirtualFree(_codeBuffer, UIntPtr.Zero, Interop.Kernel32.MEM.MEM_RELEASE);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool CpuIdTx(uint index, uint ecxValue, out uint eax, out uint ebx, out uint ecx, out uint edx, GroupAffinity affinity)
|
||||
{
|
||||
GroupAffinity previousAffinity = ThreadAffinity.Set(affinity);
|
||||
if (previousAffinity == GroupAffinity.Undefined)
|
||||
{
|
||||
eax = ebx = ecx = edx = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
CpuId(index, ecxValue, out eax, out ebx, out ecx, out edx);
|
||||
ThreadAffinity.Set(previousAffinity);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user