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);