How to access CPU's heat sensors?
Asked Answered
S

3

22

I am working on software in which I need to access the temperature sensors in the CPU and get control over them.

I don't know much hardware interfacing; I just know how to interface with the mouse. I have googled a lot about it but failed to find any relevant information or piece of code.

I really need to add this in my software. Please guide me how to have the control over the sensors using C or C++ or ASM.

Sophia answered 16/3, 2011 at 15:3 Comment(0)
G
20

Without a specific kernel driver, it's difficult to query the temperature, other than through WMI. Here is a piece of C code that does it, based on WMI's MSAcpi_ThermalZoneTemperature class:

HRESULT GetCpuTemperature(LPLONG pTemperature)
{
    if (pTemperature == NULL)
        return E_INVALIDARG;

    *pTemperature = -1;
    HRESULT ci = CoInitialize(NULL); // needs comdef.h
    HRESULT hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
    if (SUCCEEDED(hr))
    {
        IWbemLocator *pLocator; // needs Wbemidl.h & Wbemuuid.lib
        hr = CoCreateInstance(CLSID_WbemAdministrativeLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&pLocator);
        if (SUCCEEDED(hr))
        {
            IWbemServices *pServices;
            BSTR ns = SysAllocString(L"root\\WMI");
            hr = pLocator->ConnectServer(ns, NULL, NULL, NULL, 0, NULL, NULL, &pServices);
            pLocator->Release();
            SysFreeString(ns);
            if (SUCCEEDED(hr))
            {
                BSTR query = SysAllocString(L"SELECT * FROM MSAcpi_ThermalZoneTemperature");
                BSTR wql = SysAllocString(L"WQL");
                IEnumWbemClassObject *pEnum;
                hr = pServices->ExecQuery(wql, query, WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, &pEnum);
                SysFreeString(wql);
                SysFreeString(query);
                pServices->Release();
                if (SUCCEEDED(hr))
                {
                    IWbemClassObject *pObject;
                    ULONG returned;
                    hr = pEnum->Next(WBEM_INFINITE, 1, &pObject, &returned);
                    pEnum->Release();
                    if (SUCCEEDED(hr))
                    {
                        BSTR temp = SysAllocString(L"CurrentTemperature");
                        VARIANT v;
                        VariantInit(&v);
                        hr = pObject->Get(temp, 0, &v, NULL, NULL);
                        pObject->Release();
                        SysFreeString(temp);
                        if (SUCCEEDED(hr))
                        {
                            *pTemperature = V_I4(&v);
                        }
                        VariantClear(&v);
                    }
                }
            }
            if (ci == S_OK)
            {
                CoUninitialize();
            }
        }
    }
    return hr;
}

and some test code:

HRESULT GetCpuTemperature(LPLONG pTemperature);

int _tmain(int argc, _TCHAR* argv[])
{
    LONG temp;
    HRESULT hr = GetCpuTemperature(&temp);
    printf("hr=0x%08x temp=%i\n", hr, temp);
}
Geisler answered 26/10, 2011 at 21:4 Comment(10)
It's really quite a shame that almost no system drivers implement this WMI class, because it means you have to write your own kernel-mode driver for this most of the time.Justle
Two issues: (1) For some reason when I call this WMI method (from a non-elevated process) IEnumWbemClassObject::Next() always returns 80041003. And (2) even if I call this process elevated the WMI call succeeds but the value returned never changes, assuming one outputs it as such: ((double)temp / 10 - 273.15). I'm getting 27.85 which is wrong. Any idea why?Towpath
@Towpath - 0x80041003 is clearly WBEM_E_ACCESS_DENIED. For 2) MSAcpi_ThermalZoneTemperature strictly reads the "thermal zone" temperature, not the CPU, so it may be kind of incorrect. It very depends on the hardware/vendor/drivers... For an accurate reading you need a kernel driver as other point out. There is a superb open source project here: github.com/openhardwaremonitor/openhardwaremonitor that has everything you need (no magic, it's a lot of work to get it right in every situation)Geisler
@SimonMourier: Thanks. Wow. Speaking of an unnecessary privilege escalation -- do I "really" need to run my code as a kernel driver just to get CPU temp. Anyway. I'm curious, in that library you posted they install the driver using CreateService and dwServiceType set to SERVICE_KERNEL_DRIVER. To distribute such code, do I need to sign that service with Extended Validation digital certificate as well?Towpath
@Towpath - If you want to distribute a kernel driver publicly, yes, you'll have to go thru a specific process msdn.microsoft.com/en-us/windows/hardware/drivers/dashboard/… , alas, not only EV signature. Microsoft has put that in place to make sure when Windows blue-screens, we known whose fault it is.Geisler
@SimonMourier: No, I don't want to write a driver. All I want to do is to get current CPU temp :) But it seems like Microsoft makes me write one. And yes, of course it will be distributed. I'm not gonna just use it myself :) I was thinking though, there must be a way to do it without Microsoft certification & EV certs. Apps like Core Temp can do it with just one exe file that does not even have an EV cert. Will user mode driver work for that?Towpath
@Towpath - It's not because it's "just one exe file" that it doesn't use a kernel driver. Core Temp also uses a kernel driver called ALSysIO(64).sys with the exact same technique as in openhardwaremonitor (CreateService, needs to be admin, etc.). This driver is signed. You can see it in the %temp% where it was extracted. I don't know if it's an EV or not, but it doesn't look so. You may succeed with a non EV signature. Signing does not mean you won't have any problems, for example: sevenforums.com/bsod-help-support/…Geisler
@SimonMourier: No. I don't have ALSysIO(64).sys in the %temp% folder. I ran Core Temp.exe thru ProcMon and it doesn't create that file.Towpath
@Towpath - It's AlSysIO64.sys or AlSysIO.sys. End of transmissionGeisler
@SimonMourier: OK, you're correct. Although what you should've mentioned is the %temp% folder for the admin account. (I was looking it up in my logged in standard user account's %temp% folder.) And off the record, I don't think it's a good thing to place your kernel driver into a temp folder. But that is beside the point here. Unfortunately with much harsher kernel driver signing restrictions under Win10 the MSR registers approach is off the table for most developers.Towpath
M
18

I assume you are interested in a IA-32 (Intel Architecture, 32-bit) CPU and Microsoft Windows.

The Model Specific Register (MSR) IA32_THERM_STATUS has 7 bits encoding the "Digital Readout (bits 22:16, RO) — Digital temperature reading in 1 degree Celsius relative to the TCC activation temperature." (see "14.5.5.2 Reading the Digital Sensor" in "Intel® 64 and IA-32 Architectures - Software Developer’s Manual - Volume 3 (3A & 3B): System Programming Guide" http://www.intel.com/Assets/PDF/manual/325384.pdf).

So IA32_THERM_STATUS will not give you the "CPU temperature" but some proxy for it.

In order to read the IA32_THERM_STATUS register you use the asm instruction rdmsr, now rdmsr cannot be called from user space code and so you need some kernel space code (maybe a device driver?).

You can also use the intrinsic __readmsr (see http://msdn.microsoft.com/en-us/library/y55zyfdx(v=VS.100).aspx) which has anyway the same limitation: "This function is only available in kernel mode".

Every CPU cores has its own Digital Thermal Sensors (DTS) and so some more code is needed to get all the temperatures (maybe with the affinity mask? see Win32 API SetThreadAffinityMask).

I did some tests and actually found a correlation between the IA32_THERM_STATUS DTS readouts and the Prime95 "In-place large FFTs (maximum heat, power consumption, some RAM tested)" test. Prime95 is ftp://mersenne.org/gimps/p95v266.zip

I did not find a formula to get the "CPU temperature" (whatever that may mean) from the DTS readout.

Edit:

Quoting from an interesting post TJunction Max? #THERMTRIP? #PROCHOT? by "fgw" (December 2007):

there is no way to find tjmax of a certain processor in any register. thus no software can read this value. what various software developers are doing, is they simply assume a certain tjunction for a certain processor and hold this information in a table within the program. besides that, tjmax is not even the correct value they are after. in fact they are looking for TCC activacion temperature threshold. this temperature threshold is used to calculate current absolute coretemperatures from. theoretical you can say: absolute coretemperature = TCC activacion temperature threshold - DTS i had to say theoretically because, as stated above, this TCC activacion temperature threshold cant be read by software and has to be assumed by the programmer. in most situations (coretemp, everest, ...) they assume a value of 85C or 100C depending on processor family and revision. as this TCC activacion temperature threshold is calibrated during manufacturing individually per processor, it could be 83C for one processor but may be 87C for the other. taking into account the way those programms are calculating coretemperatures, you can figure out at your own, how accurate absolute coretemperatures are! neither tjmax nor the "most wanted" TCC activacion temperature threshold can be found in any public intel documents. following some discussions over on the intel developer forum, intel shows no sign to make this information available.

Mccray answered 24/7, 2011 at 9:2 Comment(5)
Can I somehow change the values of it?Sophia
@Akito Do you mean writing to the register IA32_THERM_STATUS? What is the purpose?Mccray
I am trying to do research on hardware security vulnerabilities so I was thinking to find out if you could somehow change to value temperature measured so the computer may get turned off.Sophia
@Akito You may check the manual from Intel. It seems to me you can write to some bits of the registry.Mccray
Sorry to revive and old thread. The TJ MAX can be found at the MSR IA32_TEMPERATURE_TARGET. For details see: intel.com/content/www/us/en/embedded/testing-and-validation/… However I do not know if that MSR is supported across different Intel processors families.Vito
R
11

You can read it from the MSAcpi_ThermalZoneTemperature in WMI

Using WMI from C++ is a bit involved, see MSDN explanantion and examples

note: changed original unhelpful answer

Refine answered 16/3, 2011 at 15:10 Comment(1)
Sorry - yes it's just a wrapper around some proprietry dll.Refine

© 2022 - 2024 — McMap. All rights reserved.