WattsKernelDriver: Motivation & Implementation

July 18, 2025

1. Motivation & Research

First, I researched how to get CPU information like temperature, voltage, and wattage. I studied Model Specific Registers (MSRs) and read Intel and AMD manuals to understand the exact register layouts for power and energy counters. Along the way, I learned that:

So I decided to build my own KMDF driver reliable, low‑latency CPU telemetry as other solutions would have required sign testing and secure boot disabled anyway.

This is just a super summarized, high level view of the basic layout of my driver. This was developed specifically with Intel and AMD CPU wattage monitoring in mind.

While I have added extra features such as SMU mailing and EC access, most of them were unable to be utilized due to this being only deployed on mobile CPUs


   +------------+        +------------+        +-----------------+
   | User-mode  | <----> | Kernel     | <----> | MSR Registers   |
   | Application|  IOCTL | Driver     |  __readmsr()      | (Intel/AMD)
   +------------+        +------------+        +-----------------+
      

2. Basic Driver Layout

At a high level, WattsKernelDriver implements the standard KMDF entry points and a dispatch table for IOCTLs:

3. Technical Details & Edge Cases

Under the hood, each IOCTL handler deals with its own quirks:

I paid special attention to error paths (e.g. zero MSR base, insufficient resources) and added DbgPrint traces to make testing easier.

4. User‑Mode Interaction

From user space, applications simply open the device and issue IOCTLs. For example, to read package energy:


HANDLE h = CreateFile(
    L"\\\\.\\WattsKernelDriver",
    GENERIC_READ, 0, NULL,
    OPEN_EXISTING, 0, NULL);

UINT64 energy = 0;
DWORD bytes = 0;
DeviceIoControl(
    h,
    IOCTL_RAPL_READ_PKG,
    NULL, 0,
    &energy, sizeof(energy),
    &bytes, NULL);
      

Handle STATUS_BUFFER_TOO_SMALL and STATUS_INVALID_PARAMETER to ensure robust clients. Now any C/C++, .NET, or scripting tool can pull CPU wattage with a simple IOCTL call.

← Back to blog overview