如何访问CPU的温度传感器?

22

我正在开发一款软件,需要访问CPU中的温度传感器并控制它们。

我对硬件接口不太了解,只知道如何与鼠标进行接口交互。我已经搜索了很多相关信息,但没有找到任何有用的信息或代码片段。

我真的需要在我的软件中添加这个功能。请指导我如何使用C、C++或ASM控制传感器。

3个回答

20

如果没有特定的内核驱动程序,查询温度除了通过WMI之外非常困难。以下是一段基于WMI的MSAcpi_ThermalZoneTemperature类的C代码来实现此功能:

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;
}

还有一些测试代码:

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);
}

1
真的很遗憾,几乎没有系统驱动程序实现这个 WMI 类,因为这意味着你大部分时间都必须编写自己的内核模式驱动程序。 - Andon M. Coleman
@SimonMourier:谢谢。哇。说到不必要的特权升级——我“真的”需要将我的代码作为内核驱动程序运行才能获得CPU温度吗?无论如何,我很好奇,在你发布的那个库中,他们使用CreateServicedwServiceType来安装驱动程序,设置为SERVICE_KERNEL_DRIVER。要分发这样的代码,我是否还需要使用“扩展验证”数字证书对该服务进行签名? - c00000fd
如果您想公开分发内核驱动程序,是的,您必须通过特定的过程进行认证签名 https://msdn.microsoft.com/zh-cn/windows/hardware/drivers/dashboard/attestation-signing-a-kernel-driver-for-public-release ,不仅需要EV签名。 微软已经采取这种措施,以确保当Windows蓝屏时,我们知道是谁的责任。 - Simon Mourier
@SimonMourier:没有ALSysIO(64).sys文件在%temp%文件夹中。我通过ProcMon运行了Core Temp.exe,它并没有创建该文件。 - c00000fd
@SimonMourier:好的,你是正确的。虽然你应该提到admin账户的%temp%文件夹。(我在查看我的已登录的standard user账户的%temp%文件夹。)顺便说一句,我认为将内核驱动程序放入临时文件夹并不是一件好事。但这不是重点。不幸的是,在Win10下,由于更严格的内核驱动程序签名限制,对于大多数开发人员来说,MSR寄存器方法已经行不通了。 - c00000fd
显示剩余5条评论

18

假设您对IA-32(Intel Architecture, 32-bit)CPU和Microsoft Windows感兴趣。模型特定寄存器(MSR)IA32_THERM_STATUS有7位编码的“数字读数(位22:16,只读)——1度摄氏度相对于TCC激活温度。”(见“Intel® 64 and IA-32 Architectures - Software Developer’s Manual - Volume 3 (3A & 3B): System Programming Guide”的“14.5.5.2 Reading the Digital Sensor”http://www.intel.com/Assets/PDF/manual/325384.pdf)。 因此,IA32_THERM_STATUS将不会给出“CPU温度”,但是会给出某些代理。要读取IA32_THERM_STATUS寄存器,您可以使用汇编指令rdmsr,现在rdmsr不能从用户空间代码调用,因此您需要一些内核空间代码(可能是设备驱动程序?)。您还可以使用相同限制的内在函数__readmsr(请参见http://msdn.microsoft.com/en-us/library/y55zyfdx(v=VS.100).aspx)。 每个CPU核心都有自己的数字热传感器(DTS),因此需要一些更多代码来获取所有温度(可以使用亲和力掩码吗?请参见Win32 APISetThreadAffinityMask)。我进行了一些测试,实际上发现了IA32_THERM_STATUS DTS读数与Prime95“置于大型FFT(最大热量、功率消耗、一些RAM测试)”测试之间的相关性。 Prime95是ftp://mersenne.org/gimps/p95v266.zip。 我没有找到从DTS读数得出“CPU温度”的公式(无论这意味着什么)。 编辑:引用TJunction Max? #THERMTRIP? #PROCHOT?帖子中的有趣帖子由“fgw”(2007年12月)。

无法在任何寄存器中找到某个处理器的Tjmax。因此,没有软件可以读取此值。各种软件开发人员所做的是,他们简单地假定某个处理器的某个Tjunction并将此信息保存在程序中的表中。除此之外,Tjmax甚至不是他们正在寻找的正确值。事实上,他们正在寻找的是TCC激活温度阈值。这个温度阈值用于计算当前绝对核心温度。理论上你可以说:绝对核心温度= TCC激活温度阈值 - DTS。我必须说理论上面,因为如上所述,这个TCC激活温度阈值无法被软件读取,必须由程序员假定。 在大多数情况下(coretemp、everest等),它们假定一个85C或100C的值,这取决于处理器家族和版本。由于这个TCC激活温度阈值在制造过程中会针对每个处理器进行校准,因此对于一个处理器来说可能是83C,但对于另一个处理器来说可能是87C。考虑到这些程序计算核心温度的方式,您可以自己推断出绝对核心温度有多精确!Tjmax和“最想要的”TCC激活温度阈值都不会出现在任何公共英特尔文档中。根据英特尔开发者论坛上的一些讨论,英特尔并没有表现出提供此信息的迹象。

我能以某种方式更改它的值吗? - user379888
@Akito 你的意思是写入寄存器“IA32_THERM_STATUS”吗?目的是什么? - Alessandro Jacopson
我正在研究硬件安全漏洞,所以我想找出是否可以通过改变测量的温度值来关闭计算机。 - user379888
@Akito 你可以查看英特尔的手册。在我看来,你可以写入一些注册表位。 - Alessandro Jacopson
抱歉重新激活旧线程。TJ MAX 可在 MSR IA32_TEMPERATURE_TARGET 中找到。详情请参见:http://www.intel.com/content/www/us/en/embedded/testing-and-validation/cpu-monitoring-dts-peci-paper.html但是我不知道该 MSR 是否支持不同的英特尔处理器系列。 - Bernardo Martinez

11

您可以从WMI中的MSAcpi_ThermalZoneTemperature读取它。

使用C++从WMI读取需要一些步骤,详见MSDN解释和示例

注意:已更改原始无用答案。


抱歉 - 是的,它只是一些专有dll的包装器。 - Martin Beckett

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接