moel@236
|
1 |
/*
|
moel@236
|
2 |
|
moel@236
|
3 |
Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
moel@236
|
4 |
|
moel@236
|
5 |
The contents of this file are subject to the Mozilla Public License Version
|
moel@236
|
6 |
1.1 (the "License"); you may not use this file except in compliance with
|
moel@236
|
7 |
the License. You may obtain a copy of the License at
|
moel@236
|
8 |
|
moel@236
|
9 |
http://www.mozilla.org/MPL/
|
moel@236
|
10 |
|
moel@236
|
11 |
Software distributed under the License is distributed on an "AS IS" basis,
|
moel@236
|
12 |
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
moel@236
|
13 |
for the specific language governing rights and limitations under the License.
|
moel@236
|
14 |
|
moel@236
|
15 |
The Original Code is the Open Hardware Monitor code.
|
moel@236
|
16 |
|
moel@236
|
17 |
The Initial Developer of the Original Code is
|
moel@236
|
18 |
Michael Möller <m.moeller@gmx.ch>.
|
moel@236
|
19 |
Portions created by the Initial Developer are Copyright (C) 2010
|
moel@236
|
20 |
the Initial Developer. All Rights Reserved.
|
moel@236
|
21 |
|
moel@236
|
22 |
Contributor(s):
|
moel@236
|
23 |
|
moel@236
|
24 |
Alternatively, the contents of this file may be used under the terms of
|
moel@236
|
25 |
either the GNU General Public License Version 2 or later (the "GPL"), or
|
moel@236
|
26 |
the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
moel@236
|
27 |
in which case the provisions of the GPL or the LGPL are applicable instead
|
moel@236
|
28 |
of those above. If you wish to allow use of your version of this file only
|
moel@236
|
29 |
under the terms of either the GPL or the LGPL, and not to allow others to
|
moel@236
|
30 |
use your version of this file under the terms of the MPL, indicate your
|
moel@236
|
31 |
decision by deleting the provisions above and replace them with the notice
|
moel@236
|
32 |
and other provisions required by the GPL or the LGPL. If you do not delete
|
moel@236
|
33 |
the provisions above, a recipient may use your version of this file under
|
moel@236
|
34 |
the terms of any one of the MPL, the GPL or the LGPL.
|
moel@236
|
35 |
|
moel@236
|
36 |
*/
|
moel@236
|
37 |
|
moel@236
|
38 |
using System;
|
moel@236
|
39 |
using System.Runtime.InteropServices;
|
moel@239
|
40 |
using System.Reflection;
|
moel@236
|
41 |
|
moel@236
|
42 |
namespace OpenHardwareMonitor.Hardware {
|
moel@236
|
43 |
internal static class Opcode {
|
moel@238
|
44 |
|
moel@236
|
45 |
private static IntPtr codeBuffer;
|
moel@238
|
46 |
private static ulong size;
|
moel@236
|
47 |
|
moel@238
|
48 |
public static void Open() {
|
moel@236
|
49 |
int p = (int)Environment.OSVersion.Platform;
|
moel@238
|
50 |
|
moel@236
|
51 |
byte[] rdtscCode;
|
moel@236
|
52 |
byte[] cpuidCode;
|
moel@236
|
53 |
if (IntPtr.Size == 4) {
|
moel@236
|
54 |
rdtscCode = RDTSC_32;
|
moel@236
|
55 |
cpuidCode = CPUID_32;
|
moel@236
|
56 |
} else {
|
moel@236
|
57 |
rdtscCode = RDTSC_64;
|
moel@238
|
58 |
|
moel@238
|
59 |
if ((p == 4) || (p == 128)) { // Unix
|
moel@238
|
60 |
cpuidCode = CPUID_64_LINUX;
|
moel@238
|
61 |
} else { // Windows
|
moel@238
|
62 |
cpuidCode = CPUID_64_WINDOWS;
|
moel@238
|
63 |
}
|
moel@236
|
64 |
}
|
moel@238
|
65 |
|
moel@238
|
66 |
size = (ulong)(rdtscCode.Length + cpuidCode.Length);
|
moel@239
|
67 |
|
moel@239
|
68 |
if ((p == 4) || (p == 128)) { // Unix
|
moel@239
|
69 |
Assembly assembly =
|
moel@239
|
70 |
Assembly.Load("Mono.Posix, Version=2.0.0.0, Culture=neutral, " +
|
moel@239
|
71 |
"PublicKeyToken=0738eb9f132ed756");
|
moel@239
|
72 |
|
moel@239
|
73 |
Type syscall = assembly.GetType("Mono.Unix.Native.Syscall");
|
moel@239
|
74 |
MethodInfo mmap = syscall.GetMethod("mmap");
|
moel@239
|
75 |
|
moel@239
|
76 |
Type mmapProts = assembly.GetType("Mono.Unix.Native.MmapProts");
|
moel@239
|
77 |
object mmapProtsParam = Enum.ToObject(mmapProts,
|
moel@239
|
78 |
(int)mmapProts.GetField("PROT_READ").GetValue(null) |
|
moel@239
|
79 |
(int)mmapProts.GetField("PROT_WRITE").GetValue(null) |
|
moel@239
|
80 |
(int)mmapProts.GetField("PROT_EXEC").GetValue(null));
|
moel@239
|
81 |
|
moel@239
|
82 |
Type mmapFlags = assembly.GetType("Mono.Unix.Native.MmapFlags");
|
moel@239
|
83 |
object mmapFlagsParam = Enum.ToObject(mmapFlags,
|
moel@239
|
84 |
(int)mmapFlags.GetField("MAP_ANONYMOUS").GetValue(null) |
|
moel@239
|
85 |
(int)mmapFlags.GetField("MAP_PRIVATE").GetValue(null));
|
moel@239
|
86 |
|
moel@239
|
87 |
codeBuffer = (IntPtr)mmap.Invoke(null, new object[] { IntPtr.Zero,
|
moel@239
|
88 |
size, mmapProtsParam, mmapFlagsParam, -1, 0 });
|
moel@238
|
89 |
} else { // Windows
|
moel@238
|
90 |
codeBuffer = NativeMethods.VirtualAlloc(IntPtr.Zero,
|
moel@238
|
91 |
(UIntPtr)size, AllocationType.COMMIT | AllocationType.RESERVE,
|
moel@238
|
92 |
MemoryProtection.EXECUTE_READWRITE);
|
moel@238
|
93 |
}
|
moel@236
|
94 |
|
moel@236
|
95 |
Marshal.Copy(rdtscCode, 0, codeBuffer, rdtscCode.Length);
|
moel@236
|
96 |
|
moel@236
|
97 |
Rdtsc = Marshal.GetDelegateForFunctionPointer(
|
moel@236
|
98 |
codeBuffer, typeof(RdtscDelegate)) as RdtscDelegate;
|
moel@236
|
99 |
|
moel@236
|
100 |
IntPtr cpuidAddress = (IntPtr)((long)codeBuffer + rdtscCode.Length);
|
moel@236
|
101 |
Marshal.Copy(cpuidCode, 0, cpuidAddress, cpuidCode.Length);
|
moel@236
|
102 |
|
moel@236
|
103 |
Cpuid = Marshal.GetDelegateForFunctionPointer(
|
moel@238
|
104 |
cpuidAddress, typeof(CpuidDelegate)) as CpuidDelegate;
|
moel@236
|
105 |
}
|
moel@236
|
106 |
|
moel@236
|
107 |
public static void Close() {
|
moel@236
|
108 |
Rdtsc = null;
|
moel@236
|
109 |
Cpuid = null;
|
moel@238
|
110 |
|
moel@238
|
111 |
int p = (int)Environment.OSVersion.Platform;
|
moel@238
|
112 |
if ((p == 4) || (p == 128)) { // Unix
|
moel@239
|
113 |
Assembly assembly =
|
moel@239
|
114 |
Assembly.Load("Mono.Posix, Version=2.0.0.0, Culture=neutral, " +
|
moel@239
|
115 |
"PublicKeyToken=0738eb9f132ed756");
|
moel@239
|
116 |
|
moel@239
|
117 |
Type syscall = assembly.GetType("Mono.Unix.Native.Syscall");
|
moel@239
|
118 |
MethodInfo munmap = syscall.GetMethod("munmap");
|
moel@239
|
119 |
munmap.Invoke(null, new object[] { codeBuffer, size });
|
moel@239
|
120 |
|
moel@238
|
121 |
} else { // Windows
|
moel@238
|
122 |
NativeMethods.VirtualFree(codeBuffer, UIntPtr.Zero,
|
moel@238
|
123 |
FreeType.RELEASE);
|
moel@238
|
124 |
}
|
moel@236
|
125 |
}
|
moel@236
|
126 |
|
moel@236
|
127 |
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
moel@236
|
128 |
public delegate ulong RdtscDelegate();
|
moel@236
|
129 |
|
moel@236
|
130 |
public static RdtscDelegate Rdtsc;
|
moel@236
|
131 |
|
moel@236
|
132 |
// unsigned __int64 __stdcall rdtsc() {
|
moel@236
|
133 |
// return __rdtsc();
|
moel@236
|
134 |
// }
|
moel@236
|
135 |
|
moel@236
|
136 |
private static readonly byte[] RDTSC_32 = new byte[] {
|
moel@236
|
137 |
0x0F, 0x31, // rdtsc
|
moel@236
|
138 |
0xC3 // ret
|
moel@236
|
139 |
};
|
moel@236
|
140 |
|
moel@236
|
141 |
private static readonly byte[] RDTSC_64 = new byte[] {
|
moel@236
|
142 |
0x0F, 0x31, // rdtsc
|
moel@238
|
143 |
0x48, 0xC1, 0xE2, 0x20, // shl rdx, 20h
|
moel@238
|
144 |
0x48, 0x0B, 0xC2, // or rax, rdx
|
moel@236
|
145 |
0xC3 // ret
|
moel@236
|
146 |
};
|
moel@236
|
147 |
|
moel@236
|
148 |
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
moel@236
|
149 |
public delegate bool CpuidDelegate(uint index, uint ecxValue,
|
moel@236
|
150 |
out uint eax, out uint ebx, out uint ecx, out uint edx);
|
moel@236
|
151 |
|
moel@236
|
152 |
public static CpuidDelegate Cpuid;
|
moel@236
|
153 |
|
moel@236
|
154 |
|
moel@236
|
155 |
// void __stdcall cpuidex(unsigned int index, unsigned int ecxValue,
|
moel@236
|
156 |
// unsigned int* eax, unsigned int* ebx, unsigned int* ecx,
|
moel@236
|
157 |
// unsigned int* edx)
|
moel@236
|
158 |
// {
|
moel@236
|
159 |
// int info[4];
|
moel@236
|
160 |
// __cpuidex(info, index, ecxValue);
|
moel@236
|
161 |
// *eax = info[0];
|
moel@236
|
162 |
// *ebx = info[1];
|
moel@236
|
163 |
// *ecx = info[2];
|
moel@236
|
164 |
// *edx = info[3];
|
moel@236
|
165 |
// }
|
moel@236
|
166 |
|
moel@236
|
167 |
private static readonly byte[] CPUID_32 = new byte[] {
|
moel@236
|
168 |
0x55, // push ebp
|
moel@238
|
169 |
0x8B, 0xEC, // mov ebp, esp
|
moel@238
|
170 |
0x83, 0xEC, 0x10, // sub esp, 10h
|
moel@238
|
171 |
0x8B, 0x45, 0x08, // mov eax, dword ptr [ebp+8]
|
moel@238
|
172 |
0x8B, 0x4D, 0x0C, // mov ecx, dword ptr [ebp+0Ch]
|
moel@236
|
173 |
0x53, // push ebx
|
moel@236
|
174 |
0x0F, 0xA2, // cpuid
|
moel@236
|
175 |
0x56, // push esi
|
moel@238
|
176 |
0x8D, 0x75, 0xF0, // lea esi, [info]
|
moel@238
|
177 |
0x89, 0x06, // mov dword ptr [esi],eax
|
moel@238
|
178 |
0x8B, 0x45, 0x10, // mov eax, dword ptr [eax]
|
moel@238
|
179 |
0x89, 0x5E, 0x04, // mov dword ptr [esi+4], ebx
|
moel@238
|
180 |
0x89, 0x4E, 0x08, // mov dword ptr [esi+8], ecx
|
moel@238
|
181 |
0x89, 0x56, 0x0C, // mov dword ptr [esi+0Ch], edx
|
moel@238
|
182 |
0x8B, 0x4D, 0xF0, // mov ecx, dword ptr [info]
|
moel@238
|
183 |
0x89, 0x08, // mov dword ptr [eax], ecx
|
moel@238
|
184 |
0x8B, 0x45, 0x14, // mov eax, dword ptr [ebx]
|
moel@238
|
185 |
0x8B, 0x4D, 0xF4, // mov ecx, dword ptr [ebp-0Ch]
|
moel@238
|
186 |
0x89, 0x08, // mov dword ptr [eax], ecx
|
moel@238
|
187 |
0x8B, 0x45, 0x18, // mov eax, dword ptr [ecx]
|
moel@238
|
188 |
0x8B, 0x4D, 0xF8, // mov ecx, dword ptr [ebp-8]
|
moel@238
|
189 |
0x89, 0x08, // mov dword ptr [eax], ecx
|
moel@238
|
190 |
0x8B, 0x45, 0x1C, // mov eax, dword ptr [edx]
|
moel@238
|
191 |
0x8B, 0x4D, 0xFC, // mov ecx, dword ptr [ebp-4]
|
moel@236
|
192 |
0x5E, // pop esi
|
moel@238
|
193 |
0x89, 0x08, // mov dword ptr [eax], ecx
|
moel@236
|
194 |
0x5B, // pop ebx
|
moel@236
|
195 |
0xC9, // leave
|
moel@236
|
196 |
0xC2, 0x18, 0x00 // ret 18h
|
moel@236
|
197 |
};
|
moel@236
|
198 |
|
moel@238
|
199 |
private static readonly byte[] CPUID_64_WINDOWS = new byte[] {
|
moel@238
|
200 |
0x48, 0x89, 0x5C, 0x24, 0x08, // mov qword ptr [rsp+8], rbx
|
moel@238
|
201 |
0x8B, 0xC1, // mov eax, ecx
|
moel@238
|
202 |
0x8B, 0xCA, // mov ecx, edx
|
moel@238
|
203 |
0x0F, 0xA2, // cpuid
|
moel@238
|
204 |
0x41, 0x89, 0x00, // mov dword ptr [r8], eax
|
moel@238
|
205 |
0x48, 0x8B, 0x44, 0x24, 0x28, // mov rax, qword ptr [rsp+28h]
|
moel@238
|
206 |
0x41, 0x89, 0x19, // mov dword ptr [r9], ebx
|
moel@238
|
207 |
0x48, 0x8B, 0x5C, 0x24, 0x08, // mov rbx, qword ptr [rsp+8]
|
moel@238
|
208 |
0x89, 0x08, // mov dword ptr [rax], ecx
|
moel@238
|
209 |
0x48, 0x8B, 0x44, 0x24, 0x30, // mov rax, qword ptr [rsp+30h]
|
moel@238
|
210 |
0x89, 0x10, // mov dword ptr [rax], edx
|
moel@236
|
211 |
0xC3 // ret
|
moel@236
|
212 |
};
|
moel@238
|
213 |
|
moel@238
|
214 |
private static readonly byte[] CPUID_64_LINUX = new byte[] {
|
moel@238
|
215 |
0x49, 0x89, 0xD2, // mov r10, rdx
|
moel@238
|
216 |
0x49, 0x89, 0xCB, // mov r11, rcx
|
moel@238
|
217 |
0x53, // push rbx
|
moel@238
|
218 |
0x89, 0xF8, // mov eax, edi
|
moel@238
|
219 |
0x89, 0xF1, // mov ecx, esi
|
moel@238
|
220 |
0x0F, 0xA2, // cpuid
|
moel@238
|
221 |
0x41, 0x89, 0x02, // mov dword ptr [r10], eax
|
moel@238
|
222 |
0x41, 0x89, 0x1B, // mov dword ptr [r11], ebx
|
moel@238
|
223 |
0x41, 0x89, 0x08, // mov dword ptr [r8], ecx
|
moel@238
|
224 |
0x41, 0x89, 0x11, // mov dword ptr [r9], edx
|
moel@238
|
225 |
0x5B, // pop rbx
|
moel@238
|
226 |
0xC3, // ret
|
moel@238
|
227 |
};
|
moel@236
|
228 |
|
moel@236
|
229 |
public static bool CpuidTx(uint index, uint ecxValue,
|
moel@236
|
230 |
out uint eax, out uint ebx, out uint ecx, out uint edx,
|
moel@238
|
231 |
ulong threadAffinityMask) {
|
moel@238
|
232 |
|
moel@238
|
233 |
ulong mask = ThreadAffinity.Set(threadAffinityMask);
|
moel@236
|
234 |
|
moel@238
|
235 |
if (mask == 0) {
|
moel@236
|
236 |
eax = ebx = ecx = edx = 0;
|
moel@236
|
237 |
return false;
|
moel@238
|
238 |
}
|
moel@236
|
239 |
|
moel@236
|
240 |
Cpuid(index, ecxValue, out eax, out ebx, out ecx, out edx);
|
moel@236
|
241 |
|
moel@238
|
242 |
ThreadAffinity.Set(mask);
|
moel@236
|
243 |
return true;
|
moel@236
|
244 |
}
|
moel@238
|
245 |
|
moel@236
|
246 |
[Flags()]
|
moel@236
|
247 |
public enum AllocationType : uint {
|
moel@236
|
248 |
COMMIT = 0x1000,
|
moel@236
|
249 |
RESERVE = 0x2000,
|
moel@236
|
250 |
RESET = 0x80000,
|
moel@236
|
251 |
LARGE_PAGES = 0x20000000,
|
moel@236
|
252 |
PHYSICAL = 0x400000,
|
moel@236
|
253 |
TOP_DOWN = 0x100000,
|
moel@236
|
254 |
WRITE_WATCH = 0x200000
|
moel@236
|
255 |
}
|
moel@236
|
256 |
|
moel@236
|
257 |
[Flags()]
|
moel@236
|
258 |
public enum MemoryProtection : uint {
|
moel@236
|
259 |
EXECUTE = 0x10,
|
moel@236
|
260 |
EXECUTE_READ = 0x20,
|
moel@236
|
261 |
EXECUTE_READWRITE = 0x40,
|
moel@236
|
262 |
EXECUTE_WRITECOPY = 0x80,
|
moel@236
|
263 |
NOACCESS = 0x01,
|
moel@236
|
264 |
READONLY = 0x02,
|
moel@236
|
265 |
READWRITE = 0x04,
|
moel@236
|
266 |
WRITECOPY = 0x08,
|
moel@236
|
267 |
GUARD = 0x100,
|
moel@236
|
268 |
NOCACHE = 0x200,
|
moel@236
|
269 |
WRITECOMBINE = 0x400
|
moel@236
|
270 |
}
|
moel@236
|
271 |
|
moel@236
|
272 |
[Flags]
|
moel@239
|
273 |
public enum FreeType {
|
moel@236
|
274 |
DECOMMIT = 0x4000,
|
moel@236
|
275 |
RELEASE = 0x8000
|
moel@236
|
276 |
}
|
moel@236
|
277 |
|
moel@238
|
278 |
private static class NativeMethods {
|
moel@236
|
279 |
private const string KERNEL = "kernel32.dll";
|
moel@236
|
280 |
|
moel@236
|
281 |
[DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
|
moel@236
|
282 |
public static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize,
|
moel@236
|
283 |
AllocationType flAllocationType, MemoryProtection flProtect);
|
moel@236
|
284 |
|
moel@236
|
285 |
[DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
|
moel@236
|
286 |
public static extern bool VirtualFree(IntPtr lpAddress, UIntPtr dwSize,
|
moel@238
|
287 |
FreeType dwFreeType);
|
moel@236
|
288 |
}
|
moel@236
|
289 |
}
|
moel@236
|
290 |
}
|