Introduce a new tool to fetch Intel CPU temperatures through the Intel DTS interface using XENPF_resource_op hypercall.
Signed-off-by: Teddy Astie <[email protected]> --- tools/misc/.gitignore | 1 + tools/misc/Makefile | 4 ++ tools/misc/xen-inteltemp.c | 98 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 tools/misc/xen-inteltemp.c diff --git a/tools/misc/.gitignore b/tools/misc/.gitignore index 28af46280f..65048eb901 100644 --- a/tools/misc/.gitignore +++ b/tools/misc/.gitignore @@ -5,6 +5,7 @@ xen-diag xen-hptool xen-hvmcrash xen-hvmctx +xen-inteltemp xen-livepatch xen-lowmemd xen-mceinj diff --git a/tools/misc/Makefile b/tools/misc/Makefile index c26e544e83..6498b47ec0 100644 --- a/tools/misc/Makefile +++ b/tools/misc/Makefile @@ -25,6 +25,7 @@ INSTALL_SBIN-$(CONFIG_X86) += xen-memshare INSTALL_SBIN-$(CONFIG_X86) += xen-mfndump INSTALL_SBIN-$(CONFIG_X86) += xen-ucode INSTALL_SBIN-$(CONFIG_X86) += xen-vmtrace +INSTALL_SBIN-$(CONFIG_X86) += xen-inteltemp INSTALL_SBIN += xencov INSTALL_SBIN += xenhypfs INSTALL_SBIN += xenlockprof @@ -89,6 +90,9 @@ xen-memshare: xen-memshare.o xen-vmtrace: xen-vmtrace.o $(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenctrl) $(LDLIBS_libxenforeignmemory) $(APPEND_LDFLAGS) +xen-inteltemp: xen-inteltemp.o + $(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenctrl) $(APPEND_LDFLAGS) + xen-mceinj: xen-mceinj.o $(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenctrl) $(LDLIBS_libxenguest) $(LDLIBS_libxenstore) $(APPEND_LDFLAGS) diff --git a/tools/misc/xen-inteltemp.c b/tools/misc/xen-inteltemp.c new file mode 100644 index 0000000000..624c74ca7f --- /dev/null +++ b/tools/misc/xen-inteltemp.c @@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * xen-inteltemp.c + * + * Get the CPU temperature of Intel processors. + * + * Copyright 2025 Teddy Astie <[email protected]> + */ + +#include <stdio.h> +#include <errno.h> +#include <xenctrl.h> + +#define MSR_IA32_THERM_STATUS 0x0000019c +#define MSR_IA32_TEMPERATURE_TARGET 0x000001a2 +#define MSR_IA32_PACKAGE_THERM_STATUS 0x000001b1 + +int fetch_dts_temp(xc_interface *xch, uint32_t cpu, bool package, int *temp) +{ + xc_resource_entry_t entries[2] = { + (xc_resource_entry_t){ + .idx = package ? MSR_IA32_PACKAGE_THERM_STATUS : MSR_IA32_THERM_STATUS + }, + (xc_resource_entry_t){ .idx = MSR_IA32_TEMPERATURE_TARGET }, + }; + struct xc_resource_op ops = { + .cpu = cpu, + .entries = entries, + .nr_entries = 2, + }; + int tjmax; + + int ret = xc_resource_op(xch, 1, &ops); + + if ( ret <= 0 ) + /* This CPU isn't online or can't query this MSR */ + return ret ?: -EOPNOTSUPP; + + if ( ret == 2 ) + tjmax = (entries[1].val >> 16) & 0xff; + else + { + /* + * The CPU doesn't support MSR_IA32_TEMPERATURE_TARGET, we assume it's 100 which + * is correct aside a few selected Atom CPUs. Check coretemp source code for more + * information. + */ + fprintf(stderr, "CPU%d doesn't support MSR_IA32_TEMPERATURE_TARGET, assume " + "tjmax=100°C, readings may be incorrect\n", cpu); + tjmax = 100; + } + + *temp = tjmax - ((entries[0].val >> 16) & 0xff); + return 0; +} + +int main(void) +{ + int rc = 0, temp, cpu, socket; + bool has_data = false; + xc_interface *xch = xc_interface_open(0, 0, 0); + xc_physinfo_t info; + + if ( (rc = xc_physinfo(xch, &info)) < 0 ) + { + perror("Getting physinfo failed"); + return rc; + } + + /* Per socket measurement */ + for ( socket = 0, cpu = 0; + cpu < (info.max_cpu_id + 1); + socket++, cpu += info.cores_per_socket * info.threads_per_core ) + { + if ( !fetch_dts_temp(xch, cpu, true, &temp) ) + { + has_data = true; + printf("Package%d: %d°C\n", socket, temp); + } + } + + printf("\n"); + + for ( cpu = 0; cpu < (info.max_cpu_id + 1); cpu += info.threads_per_core ) + { + if ( fetch_dts_temp(xch, cpu, false, &temp) ) + continue; + + has_data = true; + printf("CPU%d: %d°C\n", cpu, temp); + } + + if ( !has_data ) + printf("No data\n"); + + xc_interface_close(xch); + return 0; +} \ No newline at end of file -- 2.51.1 -- Teddy Astie | Vates XCP-ng Developer XCP-ng & Xen Orchestra - Vates solutions web: https://vates.tech
