Added fan control for Nvidia GPUs based on a patch by Christian Valli?res.
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 System.Reflection;
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
70 Assembly.Load("Mono.Posix, Version=2.0.0.0, Culture=neutral, " +
71 "PublicKeyToken=0738eb9f132ed756");
73 Type syscall = assembly.GetType("Mono.Unix.Native.Syscall");
74 MethodInfo mmap = syscall.GetMethod("mmap");
76 Type mmapProts = assembly.GetType("Mono.Unix.Native.MmapProts");
77 object mmapProtsParam = Enum.ToObject(mmapProts,
78 (int)mmapProts.GetField("PROT_READ").GetValue(null) |
79 (int)mmapProts.GetField("PROT_WRITE").GetValue(null) |
80 (int)mmapProts.GetField("PROT_EXEC").GetValue(null));
82 Type mmapFlags = assembly.GetType("Mono.Unix.Native.MmapFlags");
83 object mmapFlagsParam = Enum.ToObject(mmapFlags,
84 (int)mmapFlags.GetField("MAP_ANONYMOUS").GetValue(null) |
85 (int)mmapFlags.GetField("MAP_PRIVATE").GetValue(null));
87 codeBuffer = (IntPtr)mmap.Invoke(null, new object[] { IntPtr.Zero,
88 size, mmapProtsParam, mmapFlagsParam, -1, 0 });
90 codeBuffer = NativeMethods.VirtualAlloc(IntPtr.Zero,
91 (UIntPtr)size, AllocationType.COMMIT | AllocationType.RESERVE,
92 MemoryProtection.EXECUTE_READWRITE);
95 Marshal.Copy(rdtscCode, 0, codeBuffer, rdtscCode.Length);
97 Rdtsc = Marshal.GetDelegateForFunctionPointer(
98 codeBuffer, typeof(RdtscDelegate)) as RdtscDelegate;
100 IntPtr cpuidAddress = (IntPtr)((long)codeBuffer + rdtscCode.Length);
101 Marshal.Copy(cpuidCode, 0, cpuidAddress, cpuidCode.Length);
103 Cpuid = Marshal.GetDelegateForFunctionPointer(
104 cpuidAddress, typeof(CpuidDelegate)) as CpuidDelegate;
107 public static void Close() {
111 int p = (int)Environment.OSVersion.Platform;
112 if ((p == 4) || (p == 128)) { // Unix
114 Assembly.Load("Mono.Posix, Version=2.0.0.0, Culture=neutral, " +
115 "PublicKeyToken=0738eb9f132ed756");
117 Type syscall = assembly.GetType("Mono.Unix.Native.Syscall");
118 MethodInfo munmap = syscall.GetMethod("munmap");
119 munmap.Invoke(null, new object[] { codeBuffer, size });
122 NativeMethods.VirtualFree(codeBuffer, UIntPtr.Zero,
127 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
128 public delegate ulong RdtscDelegate();
130 public static RdtscDelegate Rdtsc;
132 // unsigned __int64 __stdcall rdtsc() {
136 private static readonly byte[] RDTSC_32 = new byte[] {
141 private static readonly byte[] RDTSC_64 = new byte[] {
143 0x48, 0xC1, 0xE2, 0x20, // shl rdx, 20h
144 0x48, 0x0B, 0xC2, // or rax, rdx
148 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
149 public delegate bool CpuidDelegate(uint index, uint ecxValue,
150 out uint eax, out uint ebx, out uint ecx, out uint edx);
152 public static CpuidDelegate Cpuid;
155 // void __stdcall cpuidex(unsigned int index, unsigned int ecxValue,
156 // unsigned int* eax, unsigned int* ebx, unsigned int* ecx,
157 // unsigned int* edx)
160 // __cpuidex(info, index, ecxValue);
167 private static readonly byte[] CPUID_32 = new byte[] {
169 0x8B, 0xEC, // mov ebp, esp
170 0x83, 0xEC, 0x10, // sub esp, 10h
171 0x8B, 0x45, 0x08, // mov eax, dword ptr [ebp+8]
172 0x8B, 0x4D, 0x0C, // mov ecx, dword ptr [ebp+0Ch]
176 0x8D, 0x75, 0xF0, // lea esi, [info]
177 0x89, 0x06, // mov dword ptr [esi],eax
178 0x8B, 0x45, 0x10, // mov eax, dword ptr [eax]
179 0x89, 0x5E, 0x04, // mov dword ptr [esi+4], ebx
180 0x89, 0x4E, 0x08, // mov dword ptr [esi+8], ecx
181 0x89, 0x56, 0x0C, // mov dword ptr [esi+0Ch], edx
182 0x8B, 0x4D, 0xF0, // mov ecx, dword ptr [info]
183 0x89, 0x08, // mov dword ptr [eax], ecx
184 0x8B, 0x45, 0x14, // mov eax, dword ptr [ebx]
185 0x8B, 0x4D, 0xF4, // mov ecx, dword ptr [ebp-0Ch]
186 0x89, 0x08, // mov dword ptr [eax], ecx
187 0x8B, 0x45, 0x18, // mov eax, dword ptr [ecx]
188 0x8B, 0x4D, 0xF8, // mov ecx, dword ptr [ebp-8]
189 0x89, 0x08, // mov dword ptr [eax], ecx
190 0x8B, 0x45, 0x1C, // mov eax, dword ptr [edx]
191 0x8B, 0x4D, 0xFC, // mov ecx, dword ptr [ebp-4]
193 0x89, 0x08, // mov dword ptr [eax], ecx
196 0xC2, 0x18, 0x00 // ret 18h
199 private static readonly byte[] CPUID_64_WINDOWS = new byte[] {
200 0x48, 0x89, 0x5C, 0x24, 0x08, // mov qword ptr [rsp+8], rbx
201 0x8B, 0xC1, // mov eax, ecx
202 0x8B, 0xCA, // mov ecx, edx
204 0x41, 0x89, 0x00, // mov dword ptr [r8], eax
205 0x48, 0x8B, 0x44, 0x24, 0x28, // mov rax, qword ptr [rsp+28h]
206 0x41, 0x89, 0x19, // mov dword ptr [r9], ebx
207 0x48, 0x8B, 0x5C, 0x24, 0x08, // mov rbx, qword ptr [rsp+8]
208 0x89, 0x08, // mov dword ptr [rax], ecx
209 0x48, 0x8B, 0x44, 0x24, 0x30, // mov rax, qword ptr [rsp+30h]
210 0x89, 0x10, // mov dword ptr [rax], edx
214 private static readonly byte[] CPUID_64_LINUX = new byte[] {
215 0x49, 0x89, 0xD2, // mov r10, rdx
216 0x49, 0x89, 0xCB, // mov r11, rcx
218 0x89, 0xF8, // mov eax, edi
219 0x89, 0xF1, // mov ecx, esi
221 0x41, 0x89, 0x02, // mov dword ptr [r10], eax
222 0x41, 0x89, 0x1B, // mov dword ptr [r11], ebx
223 0x41, 0x89, 0x08, // mov dword ptr [r8], ecx
224 0x41, 0x89, 0x11, // mov dword ptr [r9], edx
229 public static bool CpuidTx(uint index, uint ecxValue,
230 out uint eax, out uint ebx, out uint ecx, out uint edx,
231 ulong threadAffinityMask) {
233 ulong mask = ThreadAffinity.Set(threadAffinityMask);
236 eax = ebx = ecx = edx = 0;
240 Cpuid(index, ecxValue, out eax, out ebx, out ecx, out edx);
242 ThreadAffinity.Set(mask);
247 public enum AllocationType : uint {
251 LARGE_PAGES = 0x20000000,
254 WRITE_WATCH = 0x200000
258 public enum MemoryProtection : uint {
261 EXECUTE_READWRITE = 0x40,
262 EXECUTE_WRITECOPY = 0x80,
273 public enum FreeType {
278 private static class NativeMethods {
279 private const string KERNEL = "kernel32.dll";
281 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
282 public static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize,
283 AllocationType flAllocationType, MemoryProtection flProtect);
285 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
286 public static extern bool VirtualFree(IntPtr lpAddress, UIntPtr dwSize,
287 FreeType dwFreeType);