:p
atchew
Login
The idea here is to expose the DTS sensors through XENPF_resource_op and introduce a new dedicated tool to expose it for the user. Teddy Astie (2): x86/platform: Expose DTS sensors MSR tools: Introduce xen-inteltemp tool tools/misc/.gitignore | 1 + tools/misc/Makefile | 4 ++ tools/misc/xen-inteltemp.c | 98 ++++++++++++++++++++++++++++ xen/arch/x86/include/asm/msr-index.h | 2 + xen/arch/x86/platform_hypercall.c | 6 ++ 5 files changed, 111 insertions(+) create mode 100644 tools/misc/xen-inteltemp.c -- 2.51.1 -- Teddy Astie | Vates XCP-ng Developer XCP-ng & Xen Orchestra - Vates solutions web: https://vates.tech
Intel provide CPU sensors through "DTS" MSRs. As there MSR are core-specific (or package-specific), we can't reliably fetch them from Dom0 directly. Expose these MSR (if supported) through XENPF_resource_op so that it is accessible through hypercall. Suggested-by: Jan Beulich <jbeulich@suse.com> Signed-off-by: Teddy Astie <teddy.astie@vates.tech> --- I'm not a fan of doing a inline cpuid check here, but I don't have a better approach in mind. xen/arch/x86/include/asm/msr-index.h | 2 ++ xen/arch/x86/platform_hypercall.c | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/xen/arch/x86/include/asm/msr-index.h b/xen/arch/x86/include/asm/msr-index.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/msr-index.h +++ b/xen/arch/x86/include/asm/msr-index.h @@ -XXX,XX +XXX,XX @@ #define MSR_IA32_THERM_INTERRUPT 0x0000019b #define MSR_IA32_THERM_STATUS 0x0000019c #define MSR_IA32_MISC_ENABLE 0x000001a0 +#define MSR_IA32_TEMPERATURE_TARGET 0x000001a2 +#define MSR_IA32_PACKAGE_THERM_STATUS 0x000001b1 #define MSR_IA32_MISC_ENABLE_FAST_STRING (1<<0) #define MSR_IA32_MISC_ENABLE_PERF_AVAIL (1<<7) #define MSR_IA32_MISC_ENABLE_BTS_UNAVAIL (1<<11) diff --git a/xen/arch/x86/platform_hypercall.c b/xen/arch/x86/platform_hypercall.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/platform_hypercall.c +++ b/xen/arch/x86/platform_hypercall.c @@ -XXX,XX +XXX,XX @@ static bool msr_read_allowed(unsigned int msr) case MSR_MCU_OPT_CTRL: return cpu_has_srbds_ctrl; + + case MSR_IA32_TEMPERATURE_TARGET: + case MSR_IA32_THERM_STATUS: + case MSR_IA32_PACKAGE_THERM_STATUS: + return boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && + (cpuid_eax(0x6) & 0x1); /* Digital temperature sensor */ } if ( ppin_msr && msr == ppin_msr ) -- 2.51.1 -- Teddy Astie | Vates XCP-ng Developer XCP-ng & Xen Orchestra - Vates solutions web: https://vates.tech
Introduce a new tool to fetch Intel CPU temperatures through the Intel DTS interface using XENPF_resource_op hypercall. Signed-off-by: Teddy Astie <teddy.astie@vates.tech> --- 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 XXXXXXX..XXXXXXX 100644 --- a/tools/misc/.gitignore +++ b/tools/misc/.gitignore @@ -XXX,XX +XXX,XX @@ 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 XXXXXXX..XXXXXXX 100644 --- a/tools/misc/Makefile +++ b/tools/misc/Makefile @@ -XXX,XX +XXX,XX @@ 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 @@ -XXX,XX +XXX,XX @@ 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 XXXXXXX..XXXXXXX --- /dev/null +++ b/tools/misc/xen-inteltemp.c @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * xen-inteltemp.c + * + * Get the CPU temperature of Intel processors. + * + * Copyright 2025 Teddy Astie <teddy.astie@vates.tech> + */ + +#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
The idea here is to expose the DTS sensors through XENPF_resource_op and expose it for the user through xenpm. v4: - reuse original cpu-policy patch - remove xenpm building on non-x86 - add changelog notes - reviewed xc_resource_op return code handling - only print missing MSR_TEMPERATURE_TARGET message once - formatting changes v3: - use msr-index.h instead of adding defines to MSRs in xenpm v2: - moved userland part to xenpm - use cpu policy infrastructure instead of inline cpuid_* Jan Beulich (1): x86/cpu-policy: define bits of leaf 6 Teddy Astie (3): xenpm: Don't build outside of x86 x86/platform: Expose DTS sensors MSR xenpm: Add get-intel-temp subcommand CHANGELOG.md | 6 ++ tools/misc/Makefile | 2 +- tools/misc/xenpm.c | 113 ++++++++++++++++++++++++++- xen/arch/x86/include/asm/msr-index.h | 3 + xen/arch/x86/platform_hypercall.c | 6 ++ xen/include/xen/lib/x86/cpu-policy.h | 27 ++++++- 6 files changed, 154 insertions(+), 3 deletions(-) -- 2.51.2 -- Teddy Astie | Vates XCP-ng Developer XCP-ng & Xen Orchestra - Vates solutions web: https://vates.tech
From: Jan Beulich <jbeulich@suse.com> ... as far as we presently use them in the codebase. Signed-off-by: Jan Beulich <jbeulich@suse.com> Signed-off-by: Teddy Astie <teddy.astie@vates.tech> --- I don't know to which extend Reviewed-by applies as I only applied Andrew's proposal. xen/include/xen/lib/x86/cpu-policy.h | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/xen/include/xen/lib/x86/cpu-policy.h b/xen/include/xen/lib/x86/cpu-policy.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/lib/x86/cpu-policy.h +++ b/xen/include/xen/lib/x86/cpu-policy.h @@ -XXX,XX +XXX,XX @@ struct cpu_policy uint64_t :64, :64; /* Leaf 0x3 - PSN. */ uint64_t :64, :64; /* Leaf 0x4 - Structured Cache. */ uint64_t :64, :64; /* Leaf 0x5 - MONITOR. */ - uint64_t :64, :64; /* Leaf 0x6 - Therm/Perf. */ + + /* Leaf 0x6 - Therm/Perf. */ + bool :1, + turbo:1, + arat:1, + :1, + :1, + :1, + :1, + hwp:1, + hwp_notification:1, + hwp_activity_window:1, + hwp_epp:1, + hwp_plr:1, + :1, + hdc:1, + :1, + :1, + hwp_peci:1, + :1, + :1, + hw_feedback:1; + uint32_t :32; /* b */ + bool aperfmperf:1; + uint32_t :32; /* d */ + uint64_t :64, :64; /* Leaf 0x7 - Structured Features. */ uint64_t :64, :64; /* Leaf 0x8 - rsvd */ uint64_t :64, :64; /* Leaf 0x9 - DCA */ -- 2.51.2 -- Teddy Astie | Vates XCP-ng Developer XCP-ng & Xen Orchestra - Vates solutions web: https://vates.tech
xenpm doesn't provide any interesting usable features outside of x86, skip building it if we are not x86. Suggested-by: Jan Beulich <jbeulich@suse.com> Signed-off-by: Teddy Astie <teddy.astie@vates.tech> --- CHANGELOG.md | 3 +++ tools/misc/Makefile | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index XXXXXXX..XXXXXXX 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -XXX,XX +XXX,XX @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) deprecated in Xen 4.7 and noted not to work correctly with AMD CPUs from 2011 onwards. + - Removed xenpm on non-x86 platforms as it doesn't actually provide anything + useful outside of x86. + ## [4.21.0](https://xenbits.xenproject.org/gitweb/?p=xen.git;a=shortlog;h=RELEASE-4.21.0) - 2025-11-19 ### Changed diff --git a/tools/misc/Makefile b/tools/misc/Makefile index XXXXXXX..XXXXXXX 100644 --- a/tools/misc/Makefile +++ b/tools/misc/Makefile @@ -XXX,XX +XXX,XX @@ INSTALL_SBIN-$(CONFIG_X86) += xen-lowmemd INSTALL_SBIN-$(CONFIG_X86) += xen-mceinj INSTALL_SBIN-$(CONFIG_X86) += xen-memshare INSTALL_SBIN-$(CONFIG_X86) += xen-mfndump +INSTALL_SBIN-$(CONFIG_X86) += xenpm INSTALL_SBIN-$(CONFIG_X86) += xen-ucode INSTALL_SBIN-$(CONFIG_X86) += xen-vmtrace INSTALL_SBIN += xencov INSTALL_SBIN += xenhypfs INSTALL_SBIN += xenlockprof INSTALL_SBIN += xenperf -INSTALL_SBIN += xenpm INSTALL_SBIN += xenwatchdogd INSTALL_SBIN += xen-access INSTALL_SBIN += xen-livepatch -- 2.51.2 -- Teddy Astie | Vates XCP-ng Developer XCP-ng & Xen Orchestra - Vates solutions web: https://vates.tech
Intel provide CPU sensors through "DTS" MSRs. As these MSR are core-specific (or package-specific), we can't reliably fetch them from Dom0 directly. Expose these MSR (if supported) through XENPF_resource_op so that it is accessible through hypercall. Suggested-by: Jan Beulich <jbeulich@suse.com> Signed-off-by: Teddy Astie <teddy.astie@vates.tech> --- xen/arch/x86/include/asm/msr-index.h | 3 +++ xen/arch/x86/platform_hypercall.c | 6 ++++++ xen/include/xen/lib/x86/cpu-policy.h | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/xen/arch/x86/include/asm/msr-index.h b/xen/arch/x86/include/asm/msr-index.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/msr-index.h +++ b/xen/arch/x86/include/asm/msr-index.h @@ -XXX,XX +XXX,XX @@ #define MCU_OPT_CTRL_GDS_MIT_DIS (_AC(1, ULL) << 4) #define MCU_OPT_CTRL_GDS_MIT_LOCK (_AC(1, ULL) << 5) +#define MSR_TEMPERATURE_TARGET 0x000001a2 +#define MSR_PACKAGE_THERM_STATUS 0x000001b1 + #define MSR_FRED_RSP_SL0 0x000001cc #define MSR_FRED_RSP_SL1 0x000001cd #define MSR_FRED_RSP_SL2 0x000001ce diff --git a/xen/arch/x86/platform_hypercall.c b/xen/arch/x86/platform_hypercall.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/platform_hypercall.c +++ b/xen/arch/x86/platform_hypercall.c @@ -XXX,XX +XXX,XX @@ #include <asm/current.h> #include <public/platform.h> #include <acpi/cpufreq/processor_perf.h> +#include <asm/cpu-policy.h> #include <asm/edd.h> #include <asm/microcode.h> #include <asm/mtrr.h> @@ -XXX,XX +XXX,XX @@ static bool msr_read_allowed(unsigned int msr) case MSR_MCU_OPT_CTRL: return cpu_has_srbds_ctrl; + + case MSR_IA32_THERM_STATUS: + case MSR_TEMPERATURE_TARGET: + case MSR_PACKAGE_THERM_STATUS: + return host_cpu_policy.basic.dts; } if ( ppin_msr && msr == ppin_msr ) diff --git a/xen/include/xen/lib/x86/cpu-policy.h b/xen/include/xen/lib/x86/cpu-policy.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/lib/x86/cpu-policy.h +++ b/xen/include/xen/lib/x86/cpu-policy.h @@ -XXX,XX +XXX,XX @@ struct cpu_policy uint64_t :64, :64; /* Leaf 0x5 - MONITOR. */ /* Leaf 0x6 - Therm/Perf. */ - bool :1, + bool dts:1, turbo:1, arat:1, :1, -- 2.51.2 -- Teddy Astie | Vates XCP-ng Developer XCP-ng & Xen Orchestra - Vates solutions web: https://vates.tech
get-intel-temp allows querying the per-core CPU temperature and per-package one on Intel processors (as usual Dom0 drivers cannot work due to misalignment between Dom0 vCPU and pCPUs). Signed-off-by: Teddy Astie <teddy.astie@vates.tech> --- CHANGELOG.md | 3 ++ tools/misc/xenpm.c | 113 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 115 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index XXXXXXX..XXXXXXX 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -XXX,XX +XXX,XX @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ### Changed ### Added + - On x86: + - Introduce get-intel-temp to xenpm to query CPU temperatures on Intel + platforms. ### Removed - On x86: diff --git a/tools/misc/xenpm.c b/tools/misc/xenpm.c index XXXXXXX..XXXXXXX 100644 --- a/tools/misc/xenpm.c +++ b/tools/misc/xenpm.c @@ -XXX,XX +XXX,XX @@ #include <xen-tools/common-macros.h> +#include <xen/asm/msr-index.h> + #define MAX_PKG_RESIDENCIES 12 #define MAX_CORE_RESIDENCIES 8 static xc_interface *xc_handle; static unsigned int max_cpu_nr; +static xc_physinfo_t physinfo; /* help message */ void show_help(void) @@ -XXX,XX +XXX,XX @@ void show_help(void) " units default to \"us\" if unspecified.\n" " truncates un-representable values.\n" " 0 lets the hardware decide.\n" + " get-intel-temp [cpuid] get Intel CPU temperature of <cpuid> or all\n" " start [seconds] start collect Cx/Px statistics,\n" " output after CTRL-C or SIGINT or several seconds.\n" " enable-turbo-mode [cpuid] enable Turbo Mode for processors that support it.\n" @@ -XXX,XX +XXX,XX @@ void enable_turbo_mode(int argc, char *argv[]) errno, strerror(errno)); } +static int fetch_dts_temp(xc_interface *xch, uint32_t cpu, bool package, int *temp) +{ + xc_resource_entry_t entries[] = { + { .idx = package ? MSR_PACKAGE_THERM_STATUS : MSR_IA32_THERM_STATUS }, + { .idx = MSR_TEMPERATURE_TARGET }, + }; + struct xc_resource_op ops = { + .cpu = cpu, + .entries = entries, + .nr_entries = ARRAY_SIZE(entries), + }; + int tjmax; + + int ret = xc_resource_op(xch, 1, &ops); + + switch ( ret ) + { + case -1: + /* xc_resource_op returns -1 in out of memory scenarios */ + return -ENOMEM; + case 0: + /* This CPU isn't online or can't query this MSR */ + return -ENODATA; + case 1: + { + /* + * The CPU doesn't support MSR_TEMPERATURE_TARGET, we assume it's 100 + * which is correct aside a few selected Atom CPUs. Check Linux + * kernel's coretemp.c for more information. + */ + static bool has_reported_once = false; + + if ( !has_reported_once ) + { + fprintf(stderr, "MSR_TEMPERATURE_TARGET is not supported, assume " + "tjmax = 100, readings may be incorrect.\n"); + has_reported_once = true; + } + + tjmax = 100; + break; + } + case 2: + { + tjmax = (entries[1].val >> 16) & 0xff; + break; + } + default: + if ( ret > 0 ) + { + fprintf(stderr, "Got unexpected xc_resource_op return value: %d", + ret); + return -EINVAL; + } + return ret; + } + + *temp = tjmax - ((entries[0].val >> 16) & 0xff); + return 0; +} + +static void get_intel_temp(int argc, char *argv[]) +{ + int temp = -1, cpu = -1; + unsigned int socket; + bool has_data = false; + + if ( argc > 0 ) + parse_cpuid(argv[0], &cpu); + + if ( cpu != -1 ) + { + if ( !fetch_dts_temp(xc_handle, cpu, false, &temp) ) + printf("CPU%d: %d°C\n", cpu, temp); + else + printf("No data\n"); + return; + } + + /* Per socket measurement */ + for ( socket = 0, cpu = 0; cpu < max_cpu_nr; + socket++, cpu += physinfo.cores_per_socket * physinfo.threads_per_core ) + { + if ( !fetch_dts_temp(xc_handle, cpu, true, &temp) ) + { + has_data = true; + printf("Package%u: %d°C\n", socket, temp); + } + } + + if ( has_data ) + /* Avoid inserting a trailing line if we have nothing */ + printf("\n"); + + for ( cpu = 0; cpu < max_cpu_nr; cpu += physinfo.threads_per_core ) + { + if ( fetch_dts_temp(xc_handle, cpu, false, &temp) ) + continue; + + has_data = true; + printf("CPU%d: %d°C\n", cpu, temp); + } + + if ( !has_data ) + printf("No data\n"); +} + void disable_turbo_mode(int argc, char *argv[]) { int cpuid = -1; @@ -XXX,XX +XXX,XX @@ struct { { "set-max-cstate", set_max_cstate_func}, { "enable-turbo-mode", enable_turbo_mode }, { "disable-turbo-mode", disable_turbo_mode }, + { "get-intel-temp", get_intel_temp }, }; int main(int argc, char *argv[]) { int i, ret = 0; - xc_physinfo_t physinfo; int nr_matches = 0; int matches_main_options[ARRAY_SIZE(main_options)]; -- 2.51.2 -- Teddy Astie | Vates XCP-ng Developer XCP-ng & Xen Orchestra - Vates solutions web: https://vates.tech