* [PATCH 0/2] Add AMD CPU for RAPL MSR support
@ 2025-03-13 10:19 Anthony Harivel
2025-03-13 10:19 ` [PATCH 1/2] target/i386/kvm: add AMD support for RAPL MSR Anthony Harivel
2025-03-13 10:19 ` [PATCH 2/2] target/i386/kvm: Change error_report() to tracepoint in vmsr_read_thread_stat() Anthony Harivel
0 siblings, 2 replies; 3+ messages in thread
From: Anthony Harivel @ 2025-03-13 10:19 UTC (permalink / raw)
To: pbonzini, berrange; +Cc: qemu-devel, Anthony Harivel
Hi,
The following patch add the support for AMD CPU for RAPL MSR. This was
one of the two current limitation of the introduction patch.
This has been tested on AMD Ryzen 5850U. I was able to mount the RAPL
driver in a VM with '-cpu host'. The counter value are increasing
properly.
I added a second patch to silence an error that is not really an error.
I change it to a tracepoint following Daniel advice. Thanks Daniel !
Thanks
Anthony
Anthony Harivel (2):
target/i386/kvm: add AMD support for RAPL MSR
target/i386/kvm: Change error_report() to tracepoint in
vmsr_read_thread_stat()
docs/specs/rapl-msr.rst | 21 ++++---
include/system/kvm_int.h | 4 ++
target/i386/cpu.h | 2 +
target/i386/kvm/kvm.c | 111 ++++++++++++++++++++++------------
target/i386/kvm/trace-events | 3 +
target/i386/kvm/vmsr_energy.c | 13 +++-
target/i386/kvm/vmsr_energy.h | 1 +
tools/i386/qemu-vmsr-helper.c | 47 ++++++++------
tools/i386/rapl-msr-index.h | 4 ++
9 files changed, 139 insertions(+), 67 deletions(-)
--
2.48.1
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 1/2] target/i386/kvm: add AMD support for RAPL MSR
2025-03-13 10:19 [PATCH 0/2] Add AMD CPU for RAPL MSR support Anthony Harivel
@ 2025-03-13 10:19 ` Anthony Harivel
2025-03-13 10:19 ` [PATCH 2/2] target/i386/kvm: Change error_report() to tracepoint in vmsr_read_thread_stat() Anthony Harivel
1 sibling, 0 replies; 3+ messages in thread
From: Anthony Harivel @ 2025-03-13 10:19 UTC (permalink / raw)
To: pbonzini, berrange; +Cc: qemu-devel, Anthony Harivel
Rework the RAPL MSR support to function with AMD specific RAPL MSR.
Implement support for AMD-specific RAPL MSRs. AMD CPUs support three
MSRs: MSR_AMD_RAPL_POWER_UNIT, MSR_AMD_PKG_ENERGY_STATUS, and
MSR_AMD_CORE_ENERGY_STATUS. These MSRs have different addresses compared
to their Intel counterparts. Integrate the first two MSRs to align with
the current RAPL MSR implementation. Automatically detect the host CPU
at runtime and select the appropriate MSRs.
Signed-off-by: Anthony Harivel <aharivel@redhat.com>
---
docs/specs/rapl-msr.rst | 21 ++++---
include/system/kvm_int.h | 4 ++
target/i386/cpu.h | 2 +
target/i386/kvm/kvm.c | 111 ++++++++++++++++++++++------------
target/i386/kvm/vmsr_energy.c | 10 +++
target/i386/kvm/vmsr_energy.h | 1 +
tools/i386/qemu-vmsr-helper.c | 47 ++++++++------
tools/i386/rapl-msr-index.h | 4 ++
8 files changed, 134 insertions(+), 66 deletions(-)
diff --git a/docs/specs/rapl-msr.rst b/docs/specs/rapl-msr.rst
index aaf0db9f91b9..37fb9677c9a4 100644
--- a/docs/specs/rapl-msr.rst
+++ b/docs/specs/rapl-msr.rst
@@ -20,10 +20,14 @@ At the moment the following MSRs are involved:
.. code:: C
+ // Intel CPU
#define MSR_RAPL_POWER_UNIT 0x00000606
#define MSR_PKG_POWER_LIMIT 0x00000610
#define MSR_PKG_ENERGY_STATUS 0x00000611
#define MSR_PKG_POWER_INFO 0x00000614
+ // AMD CPU
+ #define MSR_AMD_RAPL_POWER_UNIT 0xc0010299
+ #define MSR_AMD_PKG_ENERGY_STATUS 0xc001029b
The ``*_POWER_UNIT``, ``*_POWER_LIMIT``, ``*_POWER INFO`` are part of the RAPL
spec and specify the power limit of the package, provide range of parameter(min
@@ -32,18 +36,18 @@ counter to calculate the power. Those MSRs are populated once at the beginning
by reading the host CPU MSRs and are given back to the guest 1:1 when
requested.
-The MSR_PKG_ENERGY_STATUS is a counter; it represents the total amount of
+The ``*_PKG_ENERGY_STATUS`` is a counter; it represents the total amount of
energy consumed since the last time the register was cleared. If you multiply
it with the UNIT provided above you'll get the power in micro-joules. This
counter is always increasing and it increases more or less faster depending on
the consumption of the package. This counter is supposed to overflow at some
point.
-Each core belonging to the same Package reading the MSR_PKG_ENERGY_STATUS (i.e
-"rdmsr 0x611") will retrieve the same value. The value represents the energy
-for the whole package. Whatever Core reading it will get the same value and a
-core that belongs to PKG-0 will not be able to get the value of PKG-1 and
-vice-versa.
+Each core belonging to the same Package reading the ``*_PKG_ENERGY_STATUS`` (i.e
+"rdmsr 0x611" for Intel CPU) will retrieve the same value. The value represents
+the energy for the whole package. Whatever Core reading it will get the same
+value and a core that belongs to PKG-0 will not be able to get the value of
+PKG-1 and vice-versa.
High level implementation
-------------------------
@@ -146,9 +150,6 @@ See the qemu-pr-helper documentation or manpage for further details.
Current Limitations
-------------------
-- Works only on Intel host CPUs because AMD CPUs are using different MSR
- addresses.
-
-- Only the Package Power-Plane (MSR_PKG_ENERGY_STATUS) is reported at the
+- Only the Package Power-Plane (``*_PKG_ENERGY_STATUS``) is reported at the
moment.
diff --git a/include/system/kvm_int.h b/include/system/kvm_int.h
index 4de6106869b0..3c91aa35d1a5 100644
--- a/include/system/kvm_int.h
+++ b/include/system/kvm_int.h
@@ -76,6 +76,10 @@ struct KVMMsrEnergy {
X86CPUTopoInfo guest_topo_info;
KVMHostTopoInfo host_topo;
const CPUArchIdList *guest_cpu_list;
+ uint64_t msr_value_addr;
+ uint64_t msr_unit_addr;
+ uint64_t msr_limit_addr;
+ uint64_t msr_info_addr;
uint64_t *msr_value;
uint64_t msr_unit;
uint64_t msr_limit;
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 76f24446a55d..89a0202e3f40 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -420,6 +420,8 @@ typedef enum X86Seg {
#define MSR_ARCH_LBR_FROM_0 0x00001500
#define MSR_ARCH_LBR_TO_0 0x00001600
#define MSR_ARCH_LBR_INFO_0 0x00001200
+#define MSR_AMD_RAPL_POWER_UNIT 0xc0010299
+#define MSR_AMD_PKG_ENERGY_STATUS 0xc001029b
#define FEATURE_CONTROL_LOCKED (1<<0)
#define FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX (1ULL << 1)
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 6c749d4ee812..4bd40d4060a4 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -2772,7 +2772,7 @@ static void *kvm_msr_energy_thread(void *data)
*/
if (thd_stat[j].pkg_id == i) {
pkg_stat[i].e_start =
- vmsr_read_msr(MSR_PKG_ENERGY_STATUS,
+ vmsr_read_msr(s->msr_energy.msr_value_addr,
thd_stat[j].cpu_id,
thd_stat[j].thread_id,
s->msr_energy.sioc);
@@ -2796,7 +2796,7 @@ static void *kvm_msr_energy_thread(void *data)
*/
if (thd_stat[j].pkg_id == i) {
pkg_stat[i].e_end =
- vmsr_read_msr(MSR_PKG_ENERGY_STATUS,
+ vmsr_read_msr(s->msr_energy.msr_value_addr,
thd_stat[j].cpu_id,
thd_stat[j].thread_id,
s->msr_energy.sioc);
@@ -2936,12 +2936,23 @@ static int kvm_msr_energy_thread_init(KVMState *s, MachineState *ms)
/*
* Sanity check
- * 1. Host cpu must be Intel cpu
+ * 1. Host cpu must be Intel or AMD cpu
* 2. RAPL must be enabled on the Host
*/
- if (!is_host_cpu_intel()) {
+ if (is_host_cpu_intel()) {
+ r->msr_value_addr = MSR_PKG_ENERGY_STATUS;
+ r->msr_unit_addr = MSR_RAPL_POWER_UNIT;
+ r->msr_limit_addr = MSR_PKG_POWER_LIMIT;
+ r->msr_info_addr = MSR_PKG_POWER_INFO;
+ } else if (is_host_cpu_amd()) {
+ r->msr_value_addr = MSR_AMD_PKG_ENERGY_STATUS;
+ r->msr_unit_addr = MSR_AMD_RAPL_POWER_UNIT;
+ /* The following MSR are not available on AMD CPU */
+ r->msr_limit_addr = 0;
+ r->msr_info_addr = 0;
+ } else {
error_report("The RAPL feature can only be enabled on hosts "
- "with Intel CPU models");
+ "with Intel or AMD CPU models");
return -1;
}
@@ -3008,17 +3019,22 @@ static int kvm_msr_energy_thread_init(KVMState *s, MachineState *ms)
}
/* Those MSR values should not change */
- r->msr_unit = vmsr_read_msr(MSR_RAPL_POWER_UNIT, 0, r->pid,
+ r->msr_unit = vmsr_read_msr(r->msr_unit_addr, 0, r->pid,
s->msr_energy.sioc);
- r->msr_limit = vmsr_read_msr(MSR_PKG_POWER_LIMIT, 0, r->pid,
- s->msr_energy.sioc);
- r->msr_info = vmsr_read_msr(MSR_PKG_POWER_INFO, 0, r->pid,
- s->msr_energy.sioc);
- if (r->msr_unit == 0 || r->msr_limit == 0 || r->msr_info == 0) {
- error_report("can't read any virtual msr");
+
+ if (r->msr_unit == 0) {
+ error_report("Can't read Unit info virtual msr");
return -1;
}
+ /* Only Intel CPU expose those MSR */
+ if (!r->msr_limit_addr == 0 || !r->msr_info_addr == 0) {
+ r->msr_limit = vmsr_read_msr(r->msr_limit_addr, 0, r->pid,
+ s->msr_energy.sioc);
+ r->msr_info = vmsr_read_msr(r->msr_info_addr, 0, r->pid,
+ s->msr_energy.sioc);
+ }
+
qemu_thread_create(&r->msr_thr, "kvm-msr",
kvm_msr_energy_thread,
s, QEMU_THREAD_JOINABLE);
@@ -3164,35 +3180,52 @@ static int kvm_vm_enable_energy_msrs(KVMState *s)
int ret;
if (s->msr_energy.enable == true) {
- ret = kvm_filter_msr(s, MSR_RAPL_POWER_UNIT,
- kvm_rdmsr_rapl_power_unit, NULL);
- if (ret < 0) {
- error_report("Could not install MSR_RAPL_POWER_UNIT handler: %s",
- strerror(-ret));
- return ret;
- }
+ if (is_host_cpu_intel()) {
+ ret = kvm_filter_msr(s, MSR_RAPL_POWER_UNIT,
+ kvm_rdmsr_rapl_power_unit, NULL);
+ if (ret < 0) {
+ error_report("Could not install RAPL POWER UNIT handler: %s",
+ strerror(-ret));
+ return ret;
+ }
- ret = kvm_filter_msr(s, MSR_PKG_POWER_LIMIT,
- kvm_rdmsr_pkg_power_limit, NULL);
- if (ret < 0) {
- error_report("Could not install MSR_PKG_POWER_LIMIT handler: %s",
- strerror(-ret));
- return ret;
- }
+ ret = kvm_filter_msr(s, MSR_PKG_POWER_LIMIT,
+ kvm_rdmsr_pkg_power_limit, NULL);
+ if (ret < 0) {
+ error_report("Could not install RAPL POWER LIMIT handler: %s",
+ strerror(-ret));
+ return ret;
+ }
- ret = kvm_filter_msr(s, MSR_PKG_POWER_INFO,
- kvm_rdmsr_pkg_power_info, NULL);
- if (ret < 0) {
- error_report("Could not install MSR_PKG_POWER_INFO handler: %s",
- strerror(-ret));
- return ret;
- }
- ret = kvm_filter_msr(s, MSR_PKG_ENERGY_STATUS,
- kvm_rdmsr_pkg_energy_status, NULL);
- if (ret < 0) {
- error_report("Could not install MSR_PKG_ENERGY_STATUS handler: %s",
- strerror(-ret));
- return ret;
+ ret = kvm_filter_msr(s, MSR_PKG_POWER_INFO,
+ kvm_rdmsr_pkg_power_info, NULL);
+ if (ret < 0) {
+ error_report("Could not install RAPL POWER INFO handler: %s",
+ strerror(-ret));
+ return ret;
+ }
+ ret = kvm_filter_msr(s, MSR_PKG_ENERGY_STATUS,
+ kvm_rdmsr_pkg_energy_status, NULL);
+ if (ret < 0) {
+ error_report("Could not install RAPL ENERGY STATUS handler: %s",
+ strerror(-ret));
+ return ret;
+ }
+ } else if (is_host_cpu_amd()) {
+ ret = kvm_filter_msr(s, MSR_AMD_RAPL_POWER_UNIT,
+ kvm_rdmsr_rapl_power_unit, NULL);
+ if (ret < 0) {
+ error_report("Could not install RAPL POWER UNIT handler: %s",
+ strerror(-ret));
+ return ret;
+ }
+ ret = kvm_filter_msr(s, MSR_AMD_PKG_ENERGY_STATUS,
+ kvm_rdmsr_pkg_energy_status, NULL);
+ if (ret < 0) {
+ error_report("Could not install RAPL ENERGY STATUS handler: %s",
+ strerror(-ret));
+ return ret;
+ }
}
}
return 0;
diff --git a/target/i386/kvm/vmsr_energy.c b/target/i386/kvm/vmsr_energy.c
index 31508d4e77a2..f3861d0607bb 100644
--- a/target/i386/kvm/vmsr_energy.c
+++ b/target/i386/kvm/vmsr_energy.c
@@ -37,6 +37,16 @@ bool is_host_cpu_intel(void)
return g_str_equal(vendor, CPUID_VENDOR_INTEL);
}
+bool is_host_cpu_amd(void)
+{
+ int family, model, stepping;
+ char vendor[CPUID_VENDOR_SZ + 1];
+
+ host_cpu_vendor_fms(vendor, &family, &model, &stepping);
+
+ return g_str_equal(vendor, CPUID_VENDOR_AMD);
+}
+
int is_rapl_enabled(void)
{
const char *path = "/sys/class/powercap/intel-rapl/enabled";
diff --git a/target/i386/kvm/vmsr_energy.h b/target/i386/kvm/vmsr_energy.h
index 16cc1f4814f6..8aeed09c33b7 100644
--- a/target/i386/kvm/vmsr_energy.h
+++ b/target/i386/kvm/vmsr_energy.h
@@ -95,5 +95,6 @@ double vmsr_get_ratio(uint64_t e_delta,
unsigned int maxticks);
void vmsr_init_topo_info(X86CPUTopoInfo *topo_info, const MachineState *ms);
bool is_host_cpu_intel(void);
+bool is_host_cpu_amd(void);
int is_rapl_enabled(void);
#endif /* VMSR_ENERGY_H */
diff --git a/tools/i386/qemu-vmsr-helper.c b/tools/i386/qemu-vmsr-helper.c
index a35dcb88a3fd..35831423cd53 100644
--- a/tools/i386/qemu-vmsr-helper.c
+++ b/tools/i386/qemu-vmsr-helper.c
@@ -48,6 +48,15 @@
#define MSR_PATH_TEMPLATE "/dev/cpu/%u/msr"
+/* Constants for Intel and AMD vendor IDs */
+#define INTEL_VENDOR_ID_EBX 0x756e6547
+#define INTEL_VENDOR_ID_ECX 0x6c65746e
+#define INTEL_VENDOR_ID_EDX 0x49656e69
+
+#define AMD_VENDOR_ID_EBX 0x68747541
+#define AMD_VENDOR_ID_ECX 0x444d4163
+#define AMD_VENDOR_ID_EDX 0x69746e65
+
static char *socket_path;
static char *pidfile;
static enum { RUNNING, TERMINATE, TERMINATING } state;
@@ -69,27 +78,29 @@ static void compute_default_paths(void)
pidfile = g_build_filename(state, "run", "qemu-vmsr-helper.pid", NULL);
}
-static int is_intel_processor(void)
+static void get_cpu_vendor_ids(uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
{
- int result;
- int ebx, ecx, edx;
-
- /* Execute CPUID instruction with eax=0 (basic identification) */
asm volatile (
"cpuid"
- : "=b" (ebx), "=c" (ecx), "=d" (edx)
+ : "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
: "a" (0)
);
+}
- /*
- * Check if processor is "GenuineIntel"
- * 0x756e6547 = "Genu"
- * 0x49656e69 = "ineI"
- * 0x6c65746e = "ntel"
- */
- result = (ebx == 0x756e6547) && (edx == 0x49656e69) && (ecx == 0x6c65746e);
+static int is_intel_processor(void)
+{
+ uint32_t ebx, ecx, edx;
+ get_cpu_vendor_ids(&ebx, &ecx, &edx);
+ return (ebx == INTEL_VENDOR_ID_EBX) && (ecx == INTEL_VENDOR_ID_ECX)
+ && (edx == INTEL_VENDOR_ID_EDX);
+}
- return result;
+static int is_amd_processor(void)
+{
+ uint32_t ebx, ecx, edx;
+ get_cpu_vendor_ids(&ebx, &ecx, &edx);
+ return (ebx == AMD_VENDOR_ID_EBX) && (ecx == AMD_VENDOR_ID_ECX)
+ && (edx == AMD_VENDOR_ID_EDX);
}
static int is_rapl_enabled(void)
@@ -137,6 +148,8 @@ static bool is_msr_allowed(uint32_t reg)
case MSR_PKG_POWER_LIMIT:
case MSR_PKG_ENERGY_STATUS:
case MSR_PKG_POWER_INFO:
+ case MSR_AMD_RAPL_POWER_UNIT:
+ case MSR_AMD_PKG_ENERGY_STATUS:
return true;
default:
return false;
@@ -369,11 +382,11 @@ int main(int argc, char **argv)
/*
* Sanity check
- * 1. cpu must be Intel cpu
+ * 1. cpu must be Intel or AMD cpu
* 2. RAPL must be enabled
*/
- if (!is_intel_processor()) {
- error_report("error: CPU is not INTEL cpu");
+ if (!is_intel_processor() && !is_amd_processor()) {
+ error_report("error: CPU is neither INTEL nor AMD cpu");
exit(EXIT_FAILURE);
}
diff --git a/tools/i386/rapl-msr-index.h b/tools/i386/rapl-msr-index.h
index 9a7118639ae3..45e89823a647 100644
--- a/tools/i386/rapl-msr-index.h
+++ b/tools/i386/rapl-msr-index.h
@@ -26,3 +26,7 @@
#define MSR_PKG_POWER_LIMIT 0x00000610
#define MSR_PKG_ENERGY_STATUS 0x00000611
#define MSR_PKG_POWER_INFO 0x00000614
+
+/* AMD Specific RAPL MSR */
+#define MSR_AMD_RAPL_POWER_UNIT 0xc0010299
+#define MSR_AMD_PKG_ENERGY_STATUS 0xc001029b
--
2.48.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 2/2] target/i386/kvm: Change error_report() to tracepoint in vmsr_read_thread_stat()
2025-03-13 10:19 [PATCH 0/2] Add AMD CPU for RAPL MSR support Anthony Harivel
2025-03-13 10:19 ` [PATCH 1/2] target/i386/kvm: add AMD support for RAPL MSR Anthony Harivel
@ 2025-03-13 10:19 ` Anthony Harivel
1 sibling, 0 replies; 3+ messages in thread
From: Anthony Harivel @ 2025-03-13 10:19 UTC (permalink / raw)
To: pbonzini, berrange; +Cc: qemu-devel, Anthony Harivel
Threads in QEMU are frequently created and destroyed, leading to
non-critical errors. Replace `error_report()` with a tracepoint to
prevent flooding the serial terminal with non-essential error messages.
Signed-off-by: Anthony Harivel <aharivel@redhat.com>
---
target/i386/kvm/trace-events | 3 +++
target/i386/kvm/vmsr_energy.c | 3 ++-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/target/i386/kvm/trace-events b/target/i386/kvm/trace-events
index 74a6234ff7f5..527750e3b23d 100644
--- a/target/i386/kvm/trace-events
+++ b/target/i386/kvm/trace-events
@@ -13,3 +13,6 @@ kvm_xen_soft_reset(void) ""
kvm_xen_set_shared_info(uint64_t gfn) "shared info at gfn 0x%" PRIx64
kvm_xen_set_vcpu_attr(int cpu, int type, uint64_t gpa) "vcpu attr cpu %d type %d gpa 0x%" PRIx64
kvm_xen_set_vcpu_callback(int cpu, int vector) "callback vcpu %d vector %d"
+
+# vmsr_energy.c
+vmsr_read_thread_stat(const char *path) "Error opening path %s"
diff --git a/target/i386/kvm/vmsr_energy.c b/target/i386/kvm/vmsr_energy.c
index f3861d0607bb..f99aa9cfeb94 100644
--- a/target/i386/kvm/vmsr_energy.c
+++ b/target/i386/kvm/vmsr_energy.c
@@ -19,6 +19,7 @@
#include "hw/boards.h"
#include "cpu.h"
#include "host-cpu.h"
+#include "trace.h"
char *vmsr_compute_default_paths(void)
{
@@ -280,7 +281,7 @@ void vmsr_read_thread_stat(pid_t pid,
FILE *file = fopen(path, "r");
if (file == NULL) {
- error_report("Error opening %s", path_name);
+ trace_vmsr_read_thread_stat(path_name);
return;
}
--
2.48.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2025-03-13 10:21 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-03-13 10:19 [PATCH 0/2] Add AMD CPU for RAPL MSR support Anthony Harivel
2025-03-13 10:19 ` [PATCH 1/2] target/i386/kvm: add AMD support for RAPL MSR Anthony Harivel
2025-03-13 10:19 ` [PATCH 2/2] target/i386/kvm: Change error_report() to tracepoint in vmsr_read_thread_stat() Anthony Harivel
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).