KVM_SET_PMU_EVENT_FILTER of x86 KVM allows user to configure x86 fixed
function counters by a bitmap.
Add the support of x86-fixed-counter in kvm-pmu-filter object and handle
this in i386 kvm codes.
Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
Tested-by: Yi Lai <yi1.lai@intel.com>
---
Changes since RFC v2:
* Drop KVMPMUX86FixedCounter structure and use uint32_t to represent
bitmap in QAPI directly.
* Add Tested-by from Yi.
* Add documentation in qemu-options.hx.
* Bump up the supported QAPI version to v10.1.
Changes since RFC v1:
* Make "action" as a global (per filter object) item, not a per-counter
parameter. (Dapeng)
* Bump up the supported QAPI version to v10.0.
---
accel/kvm/kvm-pmu.c | 31 +++++++++++++++++++++++++++++++
include/system/kvm-pmu.h | 5 ++++-
qapi/kvm.json | 6 +++++-
qemu-options.hx | 6 +++++-
target/i386/kvm/kvm.c | 39 ++++++++++++++++++++++++---------------
5 files changed, 69 insertions(+), 18 deletions(-)
diff --git a/accel/kvm/kvm-pmu.c b/accel/kvm/kvm-pmu.c
index 9205907d1779..509d69d9c515 100644
--- a/accel/kvm/kvm-pmu.c
+++ b/accel/kvm/kvm-pmu.c
@@ -101,6 +101,29 @@ fail:
qapi_free_KvmPmuFilterEventList(head);
}
+static void kvm_pmu_filter_get_fixed_counter(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ KVMPMUFilter *filter = KVM_PMU_FILTER(obj);
+
+ visit_type_uint32(v, name, &filter->x86_fixed_counter, errp);
+}
+
+static void kvm_pmu_filter_set_fixed_counter(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ KVMPMUFilter *filter = KVM_PMU_FILTER(obj);
+ uint32_t counter;
+
+ if (!visit_type_uint32(v, name, &counter, errp)) {
+ return;
+ }
+
+ filter->x86_fixed_counter = counter;
+}
+
static void kvm_pmu_filter_class_init(ObjectClass *oc, void *data)
{
object_class_property_add_enum(oc, "action", "KvmPmuFilterAction",
@@ -116,6 +139,14 @@ static void kvm_pmu_filter_class_init(ObjectClass *oc, void *data)
NULL, NULL);
object_class_property_set_description(oc, "events",
"KVM PMU event list");
+
+ object_class_property_add(oc, "x86-fixed-counter", "uint32_t",
+ kvm_pmu_filter_get_fixed_counter,
+ kvm_pmu_filter_set_fixed_counter,
+ NULL, NULL);
+ object_class_property_set_description(oc, "x86-fixed-counter",
+ "Enablement bitmap of "
+ "x86 PMU fixed counter");
}
static void kvm_pmu_filter_instance_init(Object *obj)
diff --git a/include/system/kvm-pmu.h b/include/system/kvm-pmu.h
index 6abc0d037aee..5238b2b4dcc7 100644
--- a/include/system/kvm-pmu.h
+++ b/include/system/kvm-pmu.h
@@ -19,10 +19,12 @@ OBJECT_DECLARE_SIMPLE_TYPE(KVMPMUFilter, KVM_PMU_FILTER)
/**
* KVMPMUFilter:
- * @action: action that KVM PMU filter will take for selected PMU events.
+ * @action: action that KVM PMU filter will take for selected PMU events
+ * and counters.
* @nevents: number of PMU event entries listed in @events
* @events: list of PMU event entries. A PMU event entry may represent one
* event or multiple events due to its format.
+ * @x86_fixed_counter: bitmap of x86 fixed counter.
*/
struct KVMPMUFilter {
Object parent_obj;
@@ -30,6 +32,7 @@ struct KVMPMUFilter {
KvmPmuFilterAction action;
uint32_t nevents;
KvmPmuFilterEventList *events;
+ uint32_t x86_fixed_counter;
};
/*
diff --git a/qapi/kvm.json b/qapi/kvm.json
index 1b523e058731..5374c8340e5a 100644
--- a/qapi/kvm.json
+++ b/qapi/kvm.json
@@ -115,7 +115,10 @@
#
# Properties of KVM PMU Filter.
#
-# @action: action that KVM PMU filter will take for selected PMU events.
+# @action: action that KVM PMU filter will take for selected PMU events
+# and counters.
+#
+# @x86-fixed-counter: enablement bitmap of x86 fixed counters.
#
# @events: list of selected PMU events.
#
@@ -123,4 +126,5 @@
##
{ 'struct': 'KvmPmuFilterProperties',
'data': { 'action': 'KvmPmuFilterAction',
+ '*x86-fixed-counter': 'uint32',
'*events': ['KvmPmuFilterEvent'] } }
diff --git a/qemu-options.hx b/qemu-options.hx
index bb89198971e0..eadfb69c8876 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -6150,7 +6150,7 @@ SRST
(qemu) qom-set /objects/iothread1 poll-max-ns 100000
- ``-object '{"qom-type":"kvm-pmu-filter","id":id,"action":action,"events":[entry_list]}'``
+ ``-object '{"qom-type":"kvm-pmu-filter","id":id,"x86-fixed-counter":bitmap,"action":action,"events":[entry_list]}'``
Create a kvm-pmu-filter object that configures KVM to filter
selected PMU events for Guest.
@@ -6165,6 +6165,10 @@ SRST
will be denied, while all other events can be accessed normally
in the Guest.
+ The ``x86-fixed-counter`` parameter sets a bitmap of x86 fixed
+ counters, and ``action`` will also take effect on the selected
+ fixed counters.
+
The ``events`` parameter accepts a list of PMU event entries in
JSON format. Event entries, based on different encoding formats,
have the following types:
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 8786501e9c7e..8b916dbb5d6f 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -6016,19 +6016,25 @@ static int kvm_install_pmu_event_filter(KVMState *s)
g_assert_not_reached();
}
- kvm_filter->flags = filter->events->value->format ==
- KVM_PMU_EVENT_FORMAT_X86_MASKED_ENTRY ?
- KVM_PMU_EVENT_FLAG_MASKED_EVENTS : 0;
-
- if (kvm_filter->flags == KVM_PMU_EVENT_FLAG_MASKED_EVENTS &&
- !kvm_vm_check_extension(s, KVM_CAP_PMU_EVENT_MASKED_EVENTS)) {
- error_report("Masked entry format of PMU event "
- "is not supported by Host.");
- goto fail;
+ if (filter->x86_fixed_counter) {
+ kvm_filter->fixed_counter_bitmap = filter->x86_fixed_counter;
}
- if (!kvm_config_pmu_event(filter, kvm_filter)) {
- goto fail;
+ if (filter->nevents) {
+ kvm_filter->flags = filter->events->value->format ==
+ KVM_PMU_EVENT_FORMAT_X86_MASKED_ENTRY ?
+ KVM_PMU_EVENT_FLAG_MASKED_EVENTS : 0;
+
+ if (kvm_filter->flags == KVM_PMU_EVENT_FLAG_MASKED_EVENTS &&
+ !kvm_vm_check_extension(s, KVM_CAP_PMU_EVENT_MASKED_EVENTS)) {
+ error_report("Masked entry format of PMU event "
+ "is not supported by Host.");
+ goto fail;
+ }
+
+ if (!kvm_config_pmu_event(filter, kvm_filter)) {
+ goto fail;
+ }
}
ret = kvm_vm_ioctl(s, KVM_SET_PMU_EVENT_FILTER, kvm_filter);
@@ -6656,16 +6662,19 @@ static void kvm_arch_check_pmu_filter(const Object *obj, const char *name,
KvmPmuFilterEventList *events = filter->events;
uint32_t base_flag;
- if (!filter->nevents) {
+ if (!filter->x86_fixed_counter && !filter->nevents) {
error_setg(errp,
"Empty KVM PMU filter.");
return;
}
/* Pick the first event's flag as the base one. */
- base_flag = events->value->format ==
- KVM_PMU_EVENT_FORMAT_X86_MASKED_ENTRY ?
- KVM_PMU_EVENT_FLAG_MASKED_EVENTS : 0;
+ base_flag = 0;
+ if (filter->nevents &&
+ events->value->format == KVM_PMU_EVENT_FORMAT_X86_MASKED_ENTRY) {
+ base_flag = KVM_PMU_EVENT_FLAG_MASKED_EVENTS;
+ }
+
while (events) {
KvmPmuFilterEvent *event = events->value;
uint32_t flag;
--
2.34.1
On 9/4/25 10:26, Zhao Liu wrote:
> KVM_SET_PMU_EVENT_FILTER of x86 KVM allows user to configure x86 fixed
> function counters by a bitmap.
>
> Add the support of x86-fixed-counter in kvm-pmu-filter object and handle
> this in i386 kvm codes.
>
> Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
> Tested-by: Yi Lai <yi1.lai@intel.com>
> ---
> Changes since RFC v2:
> * Drop KVMPMUX86FixedCounter structure and use uint32_t to represent
> bitmap in QAPI directly.
> * Add Tested-by from Yi.
> * Add documentation in qemu-options.hx.
> * Bump up the supported QAPI version to v10.1.
>
> Changes since RFC v1:
> * Make "action" as a global (per filter object) item, not a per-counter
> parameter. (Dapeng)
> * Bump up the supported QAPI version to v10.0.
> ---
> accel/kvm/kvm-pmu.c | 31 +++++++++++++++++++++++++++++++
> include/system/kvm-pmu.h | 5 ++++-
> qapi/kvm.json | 6 +++++-
> qemu-options.hx | 6 +++++-
> target/i386/kvm/kvm.c | 39 ++++++++++++++++++++++++---------------
> 5 files changed, 69 insertions(+), 18 deletions(-)
>
> diff --git a/accel/kvm/kvm-pmu.c b/accel/kvm/kvm-pmu.c
> index 9205907d1779..509d69d9c515 100644
> --- a/accel/kvm/kvm-pmu.c
> +++ b/accel/kvm/kvm-pmu.c
> @@ -101,6 +101,29 @@ fail:
> qapi_free_KvmPmuFilterEventList(head);
> }
>
> +static void kvm_pmu_filter_get_fixed_counter(Object *obj, Visitor *v,
> + const char *name, void *opaque,
> + Error **errp)
> +{
> + KVMPMUFilter *filter = KVM_PMU_FILTER(obj);
> +
> + visit_type_uint32(v, name, &filter->x86_fixed_counter, errp);
> +}
> +
> +static void kvm_pmu_filter_set_fixed_counter(Object *obj, Visitor *v,
> + const char *name, void *opaque,
> + Error **errp)
> +{
> + KVMPMUFilter *filter = KVM_PMU_FILTER(obj);
> + uint32_t counter;
> +
> + if (!visit_type_uint32(v, name, &counter, errp)) {
> + return;
> + }
> +
> + filter->x86_fixed_counter = counter;
> +}
> +
> static void kvm_pmu_filter_class_init(ObjectClass *oc, void *data)
> {
> object_class_property_add_enum(oc, "action", "KvmPmuFilterAction",
> @@ -116,6 +139,14 @@ static void kvm_pmu_filter_class_init(ObjectClass *oc, void *data)
> NULL, NULL);
> object_class_property_set_description(oc, "events",
> "KVM PMU event list");
> +
> + object_class_property_add(oc, "x86-fixed-counter", "uint32_t",
> + kvm_pmu_filter_get_fixed_counter,
> + kvm_pmu_filter_set_fixed_counter,
> + NULL, NULL);
> + object_class_property_set_description(oc, "x86-fixed-counter",
> + "Enablement bitmap of "
> + "x86 PMU fixed counter");
Adding that x86-specific field to all architectures is a bit dubious.
> }
>
> static void kvm_pmu_filter_instance_init(Object *obj)
> diff --git a/include/system/kvm-pmu.h b/include/system/kvm-pmu.h
> index 6abc0d037aee..5238b2b4dcc7 100644
> --- a/include/system/kvm-pmu.h
> +++ b/include/system/kvm-pmu.h
> @@ -19,10 +19,12 @@ OBJECT_DECLARE_SIMPLE_TYPE(KVMPMUFilter, KVM_PMU_FILTER)
>
> /**
> * KVMPMUFilter:
> - * @action: action that KVM PMU filter will take for selected PMU events.
> + * @action: action that KVM PMU filter will take for selected PMU events
> + * and counters.
> * @nevents: number of PMU event entries listed in @events
> * @events: list of PMU event entries. A PMU event entry may represent one
> * event or multiple events due to its format.
> + * @x86_fixed_counter: bitmap of x86 fixed counter.
> */
> struct KVMPMUFilter {
> Object parent_obj;
> @@ -30,6 +32,7 @@ struct KVMPMUFilter {
> KvmPmuFilterAction action;
> uint32_t nevents;
> KvmPmuFilterEventList *events;
> + uint32_t x86_fixed_counter;
> };
> > static void kvm_pmu_filter_class_init(ObjectClass *oc, void *data)
> > {
> > object_class_property_add_enum(oc, "action", "KvmPmuFilterAction",
> > @@ -116,6 +139,14 @@ static void kvm_pmu_filter_class_init(ObjectClass *oc, void *data)
> > NULL, NULL);
> > object_class_property_set_description(oc, "events",
> > "KVM PMU event list");
> > +
> > + object_class_property_add(oc, "x86-fixed-counter", "uint32_t",
> > + kvm_pmu_filter_get_fixed_counter,
> > + kvm_pmu_filter_set_fixed_counter,
> > + NULL, NULL);
> > + object_class_property_set_description(oc, "x86-fixed-counter",
> > + "Enablement bitmap of "
> > + "x86 PMU fixed counter");
>
> Adding that x86-specific field to all architectures is a bit dubious.
Similarly, do you think that it would be a good idea to wrap x86 related
codes in "#if defined(TARGET_I386)"? Like I said in this reply:
https://lore.kernel.org/qemu-devel/aA3TeaYG9mNMdEiW@intel.com/
On 4/9/2025 4:26 PM, Zhao Liu wrote:
> KVM_SET_PMU_EVENT_FILTER of x86 KVM allows user to configure x86 fixed
> function counters by a bitmap.
>
> Add the support of x86-fixed-counter in kvm-pmu-filter object and handle
> this in i386 kvm codes.
>
> Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
> Tested-by: Yi Lai <yi1.lai@intel.com>
> ---
> Changes since RFC v2:
> * Drop KVMPMUX86FixedCounter structure and use uint32_t to represent
> bitmap in QAPI directly.
> * Add Tested-by from Yi.
> * Add documentation in qemu-options.hx.
> * Bump up the supported QAPI version to v10.1.
>
> Changes since RFC v1:
> * Make "action" as a global (per filter object) item, not a per-counter
> parameter. (Dapeng)
> * Bump up the supported QAPI version to v10.0.
> ---
> accel/kvm/kvm-pmu.c | 31 +++++++++++++++++++++++++++++++
> include/system/kvm-pmu.h | 5 ++++-
> qapi/kvm.json | 6 +++++-
> qemu-options.hx | 6 +++++-
> target/i386/kvm/kvm.c | 39 ++++++++++++++++++++++++---------------
> 5 files changed, 69 insertions(+), 18 deletions(-)
>
> diff --git a/accel/kvm/kvm-pmu.c b/accel/kvm/kvm-pmu.c
> index 9205907d1779..509d69d9c515 100644
> --- a/accel/kvm/kvm-pmu.c
> +++ b/accel/kvm/kvm-pmu.c
> @@ -101,6 +101,29 @@ fail:
> qapi_free_KvmPmuFilterEventList(head);
> }
>
> +static void kvm_pmu_filter_get_fixed_counter(Object *obj, Visitor *v,
> + const char *name, void *opaque,
> + Error **errp)
> +{
> + KVMPMUFilter *filter = KVM_PMU_FILTER(obj);
> +
> + visit_type_uint32(v, name, &filter->x86_fixed_counter, errp);
> +}
> +
> +static void kvm_pmu_filter_set_fixed_counter(Object *obj, Visitor *v,
> + const char *name, void *opaque,
> + Error **errp)
> +{
> + KVMPMUFilter *filter = KVM_PMU_FILTER(obj);
> + uint32_t counter;
> +
> + if (!visit_type_uint32(v, name, &counter, errp)) {
> + return;
> + }
> +
> + filter->x86_fixed_counter = counter;
> +}
> +
> static void kvm_pmu_filter_class_init(ObjectClass *oc, void *data)
> {
> object_class_property_add_enum(oc, "action", "KvmPmuFilterAction",
> @@ -116,6 +139,14 @@ static void kvm_pmu_filter_class_init(ObjectClass *oc, void *data)
> NULL, NULL);
> object_class_property_set_description(oc, "events",
> "KVM PMU event list");
> +
> + object_class_property_add(oc, "x86-fixed-counter", "uint32_t",
> + kvm_pmu_filter_get_fixed_counter,
> + kvm_pmu_filter_set_fixed_counter,
> + NULL, NULL);
> + object_class_property_set_description(oc, "x86-fixed-counter",
> + "Enablement bitmap of "
> + "x86 PMU fixed counter");
> }
>
> static void kvm_pmu_filter_instance_init(Object *obj)
> diff --git a/include/system/kvm-pmu.h b/include/system/kvm-pmu.h
> index 6abc0d037aee..5238b2b4dcc7 100644
> --- a/include/system/kvm-pmu.h
> +++ b/include/system/kvm-pmu.h
> @@ -19,10 +19,12 @@ OBJECT_DECLARE_SIMPLE_TYPE(KVMPMUFilter, KVM_PMU_FILTER)
>
> /**
> * KVMPMUFilter:
> - * @action: action that KVM PMU filter will take for selected PMU events.
> + * @action: action that KVM PMU filter will take for selected PMU events
> + * and counters.
Maybe more accurate "fixed counters".
> * @nevents: number of PMU event entries listed in @events
> * @events: list of PMU event entries. A PMU event entry may represent one
> * event or multiple events due to its format.
> + * @x86_fixed_counter: bitmap of x86 fixed counter.
> */
> struct KVMPMUFilter {
> Object parent_obj;
> @@ -30,6 +32,7 @@ struct KVMPMUFilter {
> KvmPmuFilterAction action;
> uint32_t nevents;
> KvmPmuFilterEventList *events;
> + uint32_t x86_fixed_counter;
> };
>
> /*
> diff --git a/qapi/kvm.json b/qapi/kvm.json
> index 1b523e058731..5374c8340e5a 100644
> --- a/qapi/kvm.json
> +++ b/qapi/kvm.json
> @@ -115,7 +115,10 @@
> #
> # Properties of KVM PMU Filter.
> #
> -# @action: action that KVM PMU filter will take for selected PMU events.
> +# @action: action that KVM PMU filter will take for selected PMU events
> +# and counters.
> +#
> +# @x86-fixed-counter: enablement bitmap of x86 fixed counters.
> #
> # @events: list of selected PMU events.
> #
> @@ -123,4 +126,5 @@
> ##
> { 'struct': 'KvmPmuFilterProperties',
> 'data': { 'action': 'KvmPmuFilterAction',
> + '*x86-fixed-counter': 'uint32',
> '*events': ['KvmPmuFilterEvent'] } }
> diff --git a/qemu-options.hx b/qemu-options.hx
> index bb89198971e0..eadfb69c8876 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -6150,7 +6150,7 @@ SRST
>
> (qemu) qom-set /objects/iothread1 poll-max-ns 100000
>
> - ``-object '{"qom-type":"kvm-pmu-filter","id":id,"action":action,"events":[entry_list]}'``
> + ``-object '{"qom-type":"kvm-pmu-filter","id":id,"x86-fixed-counter":bitmap,"action":action,"events":[entry_list]}'``
> Create a kvm-pmu-filter object that configures KVM to filter
> selected PMU events for Guest.
>
> @@ -6165,6 +6165,10 @@ SRST
> will be denied, while all other events can be accessed normally
> in the Guest.
>
> + The ``x86-fixed-counter`` parameter sets a bitmap of x86 fixed
> + counters, and ``action`` will also take effect on the selected
> + fixed counters.
> +
> The ``events`` parameter accepts a list of PMU event entries in
> JSON format. Event entries, based on different encoding formats,
> have the following types:
> diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
> index 8786501e9c7e..8b916dbb5d6f 100644
> --- a/target/i386/kvm/kvm.c
> +++ b/target/i386/kvm/kvm.c
> @@ -6016,19 +6016,25 @@ static int kvm_install_pmu_event_filter(KVMState *s)
> g_assert_not_reached();
> }
>
> - kvm_filter->flags = filter->events->value->format ==
> - KVM_PMU_EVENT_FORMAT_X86_MASKED_ENTRY ?
> - KVM_PMU_EVENT_FLAG_MASKED_EVENTS : 0;
> -
> - if (kvm_filter->flags == KVM_PMU_EVENT_FLAG_MASKED_EVENTS &&
> - !kvm_vm_check_extension(s, KVM_CAP_PMU_EVENT_MASKED_EVENTS)) {
> - error_report("Masked entry format of PMU event "
> - "is not supported by Host.");
> - goto fail;
> + if (filter->x86_fixed_counter) {
> + kvm_filter->fixed_counter_bitmap = filter->x86_fixed_counter;
> }
>
> - if (!kvm_config_pmu_event(filter, kvm_filter)) {
> - goto fail;
> + if (filter->nevents) {
> + kvm_filter->flags = filter->events->value->format ==
> + KVM_PMU_EVENT_FORMAT_X86_MASKED_ENTRY ?
> + KVM_PMU_EVENT_FLAG_MASKED_EVENTS : 0;
> +
> + if (kvm_filter->flags == KVM_PMU_EVENT_FLAG_MASKED_EVENTS &&
> + !kvm_vm_check_extension(s, KVM_CAP_PMU_EVENT_MASKED_EVENTS)) {
> + error_report("Masked entry format of PMU event "
> + "is not supported by Host.");
> + goto fail;
> + }
> +
> + if (!kvm_config_pmu_event(filter, kvm_filter)) {
> + goto fail;
> + }
> }
>
> ret = kvm_vm_ioctl(s, KVM_SET_PMU_EVENT_FILTER, kvm_filter);
> @@ -6656,16 +6662,19 @@ static void kvm_arch_check_pmu_filter(const Object *obj, const char *name,
> KvmPmuFilterEventList *events = filter->events;
> uint32_t base_flag;
>
> - if (!filter->nevents) {
> + if (!filter->x86_fixed_counter && !filter->nevents) {
> error_setg(errp,
> "Empty KVM PMU filter.");
> return;
> }
>
> /* Pick the first event's flag as the base one. */
> - base_flag = events->value->format ==
> - KVM_PMU_EVENT_FORMAT_X86_MASKED_ENTRY ?
> - KVM_PMU_EVENT_FLAG_MASKED_EVENTS : 0;
> + base_flag = 0;
> + if (filter->nevents &&
> + events->value->format == KVM_PMU_EVENT_FORMAT_X86_MASKED_ENTRY) {
> + base_flag = KVM_PMU_EVENT_FLAG_MASKED_EVENTS;
> + }
> +
> while (events) {
> KvmPmuFilterEvent *event = events->value;
> uint32_t flag;
> > /** > > * KVMPMUFilter: > > - * @action: action that KVM PMU filter will take for selected PMU events. > > + * @action: action that KVM PMU filter will take for selected PMU events > > + * and counters. > > Maybe more accurate "fixed counters". Yes, will fix. Thanks, Zhao
© 2016 - 2025 Red Hat, Inc.