| 1 |
/** |
|---|
| 2 |
* Device driver for access to Model-specific registers and control registers |
|---|
| 3 |
* in Windows 2000 and later (32 and 64 bit x86 platform). |
|---|
| 4 |
* Author: Agner Fog. Translation to D by Don Clugston. |
|---|
| 5 |
* License: GNU General Public License (GPL) |
|---|
| 6 |
* Copyright: (c) 2007-06-09 Agner Fog. |
|---|
| 7 |
* (c) 2005-2007 GNU General Public License www.gnu.org/copyleft/gpl.html |
|---|
| 8 |
*/ |
|---|
| 9 |
module Blade.Performance.MSRDriver; |
|---|
| 10 |
import win32.core; //std.c.windows.windows; |
|---|
| 11 |
import win32.winnt; |
|---|
| 12 |
import win32.winsvc; |
|---|
| 13 |
import win32.windef; |
|---|
| 14 |
import std.string; |
|---|
| 15 |
/* |
|---|
| 16 |
alias HANDLE SC_HANDLE; |
|---|
| 17 |
struct SERVICE_STATUS { |
|---|
| 18 |
DWORD dwServiceType; |
|---|
| 19 |
DWORD dwCurrentState; |
|---|
| 20 |
DWORD dwControlsAccepted; |
|---|
| 21 |
DWORD dwWin32ExitCode; |
|---|
| 22 |
DWORD dwServiceSpecificExitCode; |
|---|
| 23 |
DWORD dwCheckPoint; |
|---|
| 24 |
DWORD dwWaitHint; |
|---|
| 25 |
} |
|---|
| 26 |
|
|---|
| 27 |
extern(Windows) { |
|---|
| 28 |
SC_HANDLE OpenServiceA(SC_HANDLE, LPCWSTR, DWORD); |
|---|
| 29 |
BOOL DeleteService(SC_HANDLE); |
|---|
| 30 |
|
|---|
| 31 |
} |
|---|
| 32 |
alias OpenServiceA OpenService; |
|---|
| 33 |
*/ |
|---|
| 34 |
|
|---|
| 35 |
// commands for MSR driver |
|---|
| 36 |
enum EMSR_COMMAND { |
|---|
| 37 |
MSR_IGNORE = 0, // do nothing |
|---|
| 38 |
MSR_STOP = 1, // skip rest of list |
|---|
| 39 |
MSR_READ = 2, // read model specific register |
|---|
| 40 |
MSR_WRITE = 3, // write model specific register |
|---|
| 41 |
CR_READ = 4, // read control register |
|---|
| 42 |
CR_WRITE = 5, // write control register |
|---|
| 43 |
UNUSED1 = 0x7fffffff // make sure this enum takes 32 bits |
|---|
| 44 |
}; |
|---|
| 45 |
|
|---|
| 46 |
|
|---|
| 47 |
// input/output data structure for MSR driver |
|---|
| 48 |
struct SMSRInOut { |
|---|
| 49 |
EMSR_COMMAND msr_command; // command for read or write register |
|---|
| 50 |
uint register_number; // register number |
|---|
| 51 |
union { |
|---|
| 52 |
long value; // 64 bit value to read or write |
|---|
| 53 |
uint val[2]; // lower and upper 32 bits |
|---|
| 54 |
}; |
|---|
| 55 |
}; |
|---|
| 56 |
|
|---|
| 57 |
|
|---|
| 58 |
// functions defined in MSRDriver2.asm |
|---|
| 59 |
// replaced by intrinsics in MSRDriver.cpp |
|---|
| 60 |
//extern "C" __int64 ReadMSR (int r); // read model specific register |
|---|
| 61 |
//extern "C" void WriteMSR (int r, __int64 value); // write model specific register |
|---|
| 62 |
//extern (C) size_t ReadCR(int r); // read control register |
|---|
| 63 |
//extern (C) void WriteCR(int r, size_t value); // write control register |
|---|
| 64 |
|
|---|
| 65 |
|
|---|
| 66 |
void lockToSingleCPU() |
|---|
| 67 |
{ |
|---|
| 68 |
// We must lock the process to a single CPU core in case the system has |
|---|
| 69 |
// multiple CPUs or a CPU with multiple cores. Otherwise, we can get |
|---|
| 70 |
// errors if the MSRDriver happens to set up the counters on one core |
|---|
| 71 |
// and the test code runs on another core. |
|---|
| 72 |
uint ProcessAffMask = 0, SystemAffMask = 0; |
|---|
| 73 |
|
|---|
| 74 |
// Get mask of possible CPU cores |
|---|
| 75 |
GetProcessAffinityMask(GetCurrentProcess(), &ProcessAffMask, &SystemAffMask); |
|---|
| 76 |
//printf("\nProcess mask %X, system mask %X\n\n", ProcessAffMask, SystemAffMask); |
|---|
| 77 |
if (ProcessAffMask > 1) { |
|---|
| 78 |
// more than one CPU core available. Fix to only one: |
|---|
| 79 |
if (ProcessAffMask & 2) { |
|---|
| 80 |
ProcessAffMask = 2; |
|---|
| 81 |
} else { |
|---|
| 82 |
ProcessAffMask = 1; |
|---|
| 83 |
} |
|---|
| 84 |
// Lock process to a single CPU core |
|---|
| 85 |
SetProcessAffinityMask(GetCurrentProcess(), ProcessAffMask); |
|---|
| 86 |
} |
|---|
| 87 |
} |
|---|
| 88 |
|
|---|
| 89 |
|
|---|
| 90 |
// class CMSRDriver encapsulates the interface to the driver MSRDriver32.sys |
|---|
| 91 |
// which is needed for privileged access to set up the MSRs. This class |
|---|
| 92 |
// loads, unloads and sends commands to MSRDriver |
|---|
| 93 |
class CMSRDriver { |
|---|
| 94 |
public: |
|---|
| 95 |
const char[] DriverFileName = "MSRDriver32"; |
|---|
| 96 |
const char[] DriverSymbolicName = "\\\\.\\slMSRDriver"; |
|---|
| 97 |
|
|---|
| 98 |
this() { |
|---|
| 99 |
/* |
|---|
| 100 |
// Define Driver filename |
|---|
| 101 |
if (Need64BitDriver()) { |
|---|
| 102 |
DriverFileName = "MSRDriver64"; |
|---|
| 103 |
} |
|---|
| 104 |
else { |
|---|
| 105 |
DriverFileName = "MSRDriver32"; |
|---|
| 106 |
} |
|---|
| 107 |
|
|---|
| 108 |
// Define driver symbolic link name |
|---|
| 109 |
DriverSymbolicName = "\\\\.\\slMSRDriver"; |
|---|
| 110 |
*/ |
|---|
| 111 |
// Initialize |
|---|
| 112 |
scm = null; |
|---|
| 113 |
service = null; |
|---|
| 114 |
hDriver = null; |
|---|
| 115 |
} |
|---|
| 116 |
~this() { |
|---|
| 117 |
// Unload driver if not already unloaded |
|---|
| 118 |
if (scm) UnloadDriver(); |
|---|
| 119 |
} |
|---|
| 120 |
int AccessRegisters(SMSRInOut [] data) |
|---|
| 121 |
{ |
|---|
| 122 |
if (data.length==0) return 0; |
|---|
| 123 |
|
|---|
| 124 |
const int DeviceType = 0x22; // FILE_DEVICE_UNKNOWN; |
|---|
| 125 |
const int Function = 0x800; |
|---|
| 126 |
const int Method = 0; // METHOD_BUFFERED; |
|---|
| 127 |
const int Access = 1 | 2; // FILE_READ_ACCESS | FILE_WRITE_ACCESS; |
|---|
| 128 |
const int IOCTL_MSR_DRIVER = DeviceType << 16 | Access << 14 | Function << 2 | Method; |
|---|
| 129 |
|
|---|
| 130 |
DWORD len = 0; |
|---|
| 131 |
|
|---|
| 132 |
// This call results in a call to the driver rutine DispatchControl() |
|---|
| 133 |
int res = DeviceIoControl(hDriver, IOCTL_MSR_DRIVER, &data[0], data.length*SMSRInOut.sizeof, |
|---|
| 134 |
&data[0], data.length*SMSRInOut.sizeof, &len, null); |
|---|
| 135 |
if (!res) return GetLastError(); |
|---|
| 136 |
return 0; |
|---|
| 137 |
} |
|---|
| 138 |
// send commands to driver to read or write MSR registers |
|---|
| 139 |
int AccessRegisters(void * pnIn, int nInLen, void * pnOut, int nOutLen) |
|---|
| 140 |
{ |
|---|
| 141 |
if (nInLen <= 0) return 0; |
|---|
| 142 |
|
|---|
| 143 |
const int DeviceType = 0x22; // FILE_DEVICE_UNKNOWN; |
|---|
| 144 |
const int Function = 0x800; |
|---|
| 145 |
const int Method = 0; // METHOD_BUFFERED; |
|---|
| 146 |
const int Access = 1 | 2; // FILE_READ_ACCESS | FILE_WRITE_ACCESS; |
|---|
| 147 |
const int IOCTL_MSR_DRIVER = DeviceType << 16 | Access << 14 | Function << 2 | Method; |
|---|
| 148 |
|
|---|
| 149 |
DWORD len = 0; |
|---|
| 150 |
|
|---|
| 151 |
// This call results in a call to the driver rutine DispatchControl() |
|---|
| 152 |
int res = DeviceIoControl(hDriver, IOCTL_MSR_DRIVER, pnIn, nInLen, |
|---|
| 153 |
pnOut, nOutLen, &len, null); |
|---|
| 154 |
if (!res) { |
|---|
| 155 |
// Error |
|---|
| 156 |
return GetLastError();} |
|---|
| 157 |
return 0; |
|---|
| 158 |
} |
|---|
| 159 |
/+ |
|---|
| 160 |
// Read a control register cr0 or cr4 |
|---|
| 161 |
size_t CRRead(int r) { |
|---|
| 162 |
if (r != 0 && r != 4) return -11; |
|---|
| 163 |
SMSRInOut a; |
|---|
| 164 |
a.msr_command = CR_READ; |
|---|
| 165 |
a.register_number = r; |
|---|
| 166 |
a.value = 0; |
|---|
| 167 |
AccessRegisters(&a,sizeof(a),&a,sizeof(a)); |
|---|
| 168 |
return size_t(a.value); |
|---|
| 169 |
} |
|---|
| 170 |
// send command to driver to write one control register |
|---|
| 171 |
int CRWrite(int r, size_t val) { |
|---|
| 172 |
if (r != 0 && r != 4) return -12; |
|---|
| 173 |
SMSRInOut a; |
|---|
| 174 |
a.msr_command = CR_WRITE; |
|---|
| 175 |
a.register_number = r; |
|---|
| 176 |
a.value = val; |
|---|
| 177 |
return AccessRegisters(&a,sizeof(a),&a,sizeof(a)); |
|---|
| 178 |
} |
|---|
| 179 |
+/ |
|---|
| 180 |
int LoadDriver() { |
|---|
| 181 |
|
|---|
| 182 |
// char[MAX_PATH] DriverFileNameE, DriverFilePath; |
|---|
| 183 |
// char *p; |
|---|
| 184 |
|
|---|
| 185 |
// Open connection to Windows Service Control Manager (SCM) |
|---|
| 186 |
scm = OpenSCManager(null, null, SC_MANAGER_ALL_ACCESS); |
|---|
| 187 |
if(scm != null) { |
|---|
| 188 |
/* |
|---|
| 189 |
// Get the full path of the driver file name |
|---|
| 190 |
strcpy(DriverFileNameE, DriverFileName); |
|---|
| 191 |
strcat(DriverFileNameE, ".sys"); // append .sys to DriverName |
|---|
| 192 |
GetFullPathName(DriverFileNameE, MAX_PATH, DriverFilePath, &p); |
|---|
| 193 |
*/ |
|---|
| 194 |
char* DriverFilePath = toStringz("C:\\Sandbox\\blade\\performance\\MSRDriver32.sys"); |
|---|
| 195 |
char* DriverFileNameE = toStringz("MSRDriver32.sys"); |
|---|
| 196 |
// char [MAX_PATH] DriverFilePathBuff; |
|---|
| 197 |
// char *p; |
|---|
| 198 |
// GetFullPathName(DriverFileNameE, MAX_PATH, &DriverFilePathBuff[0], &p); |
|---|
| 199 |
// char * DriverFilePath = toString(DriverFilePathBuff); |
|---|
| 200 |
|
|---|
| 201 |
// Load the driver into memory and call its entry rutine |
|---|
| 202 |
service = CreateService(scm, DriverFileNameE, toStringz("MSR driver"), |
|---|
| 203 |
SERVICE_START + SERVICE_STOP + DELETE, SERVICE_KERNEL_DRIVER, |
|---|
| 204 |
SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE, DriverFilePath, |
|---|
| 205 |
null, null, null, null, null); |
|---|
| 206 |
|
|---|
| 207 |
if(service == null) { |
|---|
| 208 |
// Cannot load driver. |
|---|
| 209 |
// Unload it in case it was not unloaded last time |
|---|
| 210 |
service = OpenService(scm, DriverFileNameE, SERVICE_ALL_ACCESS); |
|---|
| 211 |
SERVICE_STATUS ss; |
|---|
| 212 |
ControlService(service, SERVICE_CONTROL_STOP, &ss); |
|---|
| 213 |
DeleteService(service); |
|---|
| 214 |
CloseServiceHandle(service); |
|---|
| 215 |
|
|---|
| 216 |
// Try again to load driver |
|---|
| 217 |
service = CreateService(scm, DriverFileNameE, toStringz("MSR driver"), |
|---|
| 218 |
SERVICE_START + SERVICE_STOP + DELETE, SERVICE_KERNEL_DRIVER, |
|---|
| 219 |
SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE, DriverFilePath, |
|---|
| 220 |
null, null, null, null, null); |
|---|
| 221 |
|
|---|
| 222 |
if(service is null) { |
|---|
| 223 |
// Still cannot load driver |
|---|
| 224 |
CloseServiceHandle(scm); scm = null; |
|---|
| 225 |
return -3; |
|---|
| 226 |
} |
|---|
| 227 |
} |
|---|
| 228 |
|
|---|
| 229 |
// Start the service |
|---|
| 230 |
if(!StartService(service, 0, null)) { |
|---|
| 231 |
// Error |
|---|
| 232 |
int ErrNo = GetLastError(); |
|---|
| 233 |
// Stop service and cleanup |
|---|
| 234 |
service = OpenService(scm, toStringz(DriverFileName), SERVICE_ALL_ACCESS); |
|---|
| 235 |
SERVICE_STATUS ss; |
|---|
| 236 |
ControlService(service, SERVICE_CONTROL_STOP, &ss); |
|---|
| 237 |
DeleteService(service); |
|---|
| 238 |
CloseServiceHandle(service); |
|---|
| 239 |
CloseServiceHandle(scm); scm = null; |
|---|
| 240 |
return ErrNo; |
|---|
| 241 |
} |
|---|
| 242 |
|
|---|
| 243 |
if(service) { |
|---|
| 244 |
// Get handle to driver |
|---|
| 245 |
hDriver = CreateFile(toStringz(DriverSymbolicName), GENERIC_READ + GENERIC_WRITE, |
|---|
| 246 |
0, null, OPEN_EXISTING, 0, null); |
|---|
| 247 |
|
|---|
| 248 |
if(hDriver == null || hDriver == INVALID_HANDLE_VALUE) return -5; |
|---|
| 249 |
} |
|---|
| 250 |
else return -2; |
|---|
| 251 |
} |
|---|
| 252 |
else return GetLastError(); |
|---|
| 253 |
|
|---|
| 254 |
return 0; |
|---|
| 255 |
} |
|---|
| 256 |
|
|---|
| 257 |
int UnloadDriver() { |
|---|
| 258 |
if(scm == null || service == null || hDriver == null) { |
|---|
| 259 |
return -6;} |
|---|
| 260 |
|
|---|
| 261 |
CloseHandle(hDriver); hDriver = null; |
|---|
| 262 |
|
|---|
| 263 |
SERVICE_STATUS ss; |
|---|
| 264 |
ControlService(service, SERVICE_CONTROL_STOP, &ss); |
|---|
| 265 |
|
|---|
| 266 |
DeleteService(service); |
|---|
| 267 |
CloseServiceHandle(service); service = null; |
|---|
| 268 |
CloseServiceHandle(scm); scm = null; |
|---|
| 269 |
|
|---|
| 270 |
return 0; |
|---|
| 271 |
} |
|---|
| 272 |
protected: |
|---|
| 273 |
bool Need64BitDriver() { return 0; } // tell whether we need 32 bit or 64 bit driver |
|---|
| 274 |
SC_HANDLE scm; |
|---|
| 275 |
SC_HANDLE service; |
|---|
| 276 |
HANDLE hDriver; |
|---|
| 277 |
// LPCTSTR DriverFileName; |
|---|
| 278 |
// LPCTSTR DriverSymbolicName; |
|---|
| 279 |
}; |
|---|