A minimal Windows kernel driver that exposes x86 Model-Specific Register (MSR) read/write to userspace via IOCTLs, paired with a header-only userspace library for C99 and C++20.
CPUs with >64 cores are handled properly, and the device \\.\msr is accessible to SYSTEM and Administrators only, keeping the driver secure.
Inspired by the Linux msr kernel module arch/x86/kernel/msr.c.
Download msr.sys from the latest release and place it at C:\msr.sys.
Note: Test-signed drivers require test signing mode to be enabled. This is a one-time step that requires a reboot.
bcdedit /set testsigning onMake sure to reboot, then create and start the driver service:
sc create msr type= kernel binPath= C:\msr.sys
sc start msrStop and delete the driver service:
sc stop msr
sc delete msrDelete the msr.sys driver binary itself:
del C:\msr.sysDisable test signing mode:
bcdedit /set testsigning offand reboot.
Drop msr.hpp into your project's include path and include it:
#include <msr.hpp>try {
msr::device dev; // opens \\.\msr; throws std::system_error on failure
// Read MSR 0x1A2 (MSR_TEMPERATURE_TARGET) on logical CPU 0
msr::value value = dev.read(0, 0x1A2);
// Write a 64 bit value to an MSR on logical CPU 0
dev.write(0, 0x1A2, 0x3640000);
// or write a split value to an MSR on logical CPU 0
dev.write(0, 0x1A2, { .lo = 0x0640000, .hi = 0x3 });
} catch (std::exception const& error) {
std::cerr << "Error: " << error.what();
}HANDLE dev = msr_open(); // opens \\.\msr; returns INVALID_HANDLE_VALUE on failure
// Read MSR 0x1A2 (MSR_TEMPERATURE_TARGET) on logical CPU 0
MSR_VALUE value;
msr_read(dev, 0, 0x1A2, &value);
// Write a value to an MSR on logical CPU 0
msr_write(dev, 0, 0x1A2, (MSR_VALUE) { .q = 0x3640000 });
// or write a split value to an MSR on logical CPU 0
msr_write(dev, 0, 0x1A2, (MSR_VALUE) { .lo = 0x0640000, .hi = 0x3 });
msr_close(dev);msr_read and msr_write return BOOL. On failure, call GetLastError() for the error code.
The driver exposes two IOCTLs over the \\.\msr device using buffered I/O.
| IOCTL | Code | Direction |
|---|---|---|
IOCTL_READ_MSR |
CTL_CODE(40000, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS) |
In/Out |
IOCTL_WRITE_MSR |
CTL_CODE(40000, 0x801, METHOD_BUFFERED, FILE_WRITE_ACCESS) |
In |
Both IOCTLs use MSR_REQUEST as the input (and output for reads) buffer:
typedef struct _MSR_REQUEST {
MSR_NO msr_no; // MSR register number (32-bit)
MSR_CPU cpu; // Flat system-wide processor index (32-bit)
MSR_VALUE val; // Value: input for write, output for read (64-bit)
} MSR_REQUEST;Use the provided build script (Release x64 by default):
scripts\build <configuration, optional> <platform, optional>Or, build directly with MSBuild:
msbuild driver\msr.vcxproj /p:Configuration=Release /p:Platform=x64The driver is output at driver\<platform>\<configuration>\msr.sys
- Windows 10 x64 (or later)
- Visual Studio with the C++ desktop & WDK workload
- Windows SDK matching the installed VS version
- Windows Driver Kit (WDK) matching the installed SDK version