@@ -16,6 +16,8 @@
#include "qom/object_interfaces.h"
#include "system/kvm-pmu.h"
+#define UINT12_MAX (4095)
+
static void kvm_pmu_filter_set_action(Object *obj, int value,
Error **errp G_GNUC_UNUSED)
{
@@ -53,9 +55,22 @@ static void kvm_pmu_filter_set_event(Object *obj, Visitor *v, const char *name,
}
for (node = head; node; node = node->next) {
- switch (node->value->format) {
+ KvmPmuFilterEvent *event = node->value;
+
+ switch (event->format) {
case KVM_PMU_EVENT_FORMAT_RAW:
break;
+ case KVM_PMU_EVENT_FORMAT_X86_SELECT_UMASK: {
+ if (event->u.x86_select_umask.select > UINT12_MAX) {
+ error_setg(errp,
+ "Parameter 'select' out of range (%d).",
+ UINT12_MAX);
+ goto fail;
+ }
+
+ /* No need to check the range of umask since it's uint8_t. */
+ break;
+ }
default:
g_assert_not_reached();
}
@@ -67,6 +82,9 @@ static void kvm_pmu_filter_set_event(Object *obj, Visitor *v, const char *name,
filter->events = head;
qapi_free_KvmPmuFilterEventList(old_head);
return;
+
+fail:
+ qapi_free_KvmPmuFilterEventList(head);
}
static void kvm_pmu_filter_class_init(ObjectClass *oc, void *data)
@@ -32,4 +32,17 @@ struct KVMPMUFilter {
KvmPmuFilterEventList *events;
};
+/*
+ * Stolen from Linux kernel (RAW_EVENT at tools/testing/selftests/kvm/include/
+ * x86_64/pmu.h).
+ *
+ * Encode an eventsel+umask pair into event-select MSR format. Note, this is
+ * technically AMD's format, as Intel's format only supports 8 bits for the
+ * event selector, i.e. doesn't use bits 24:16 for the selector. But, OR-ing
+ * in '0' is a nop and won't clobber the CMASK.
+ */
+#define X86_PMU_RAW_EVENT(eventsel, umask) (((eventsel & 0xf00UL) << 24) | \
+ ((eventsel) & 0xff) | \
+ ((umask) & 0xff) << 8)
+
#endif /* KVM_PMU_H */
@@ -36,10 +36,12 @@
#
# @raw: the encoded event code that KVM can directly consume.
#
+# @x86-select-umask: standard x86 encoding format with select and umask.
+#
# Since 10.1
##
{ 'enum': 'KvmPmuEventFormat',
- 'data': ['raw'] }
+ 'data': ['raw', 'x86-select-umask'] }
##
# @KvmPmuRawEvent:
@@ -54,6 +56,20 @@
{ 'struct': 'KvmPmuRawEvent',
'data': { 'code': 'uint64' } }
+##
+# @KvmPmuX86SelectUmaskEvent:
+#
+# @select: x86 PMU event select field, which is a 12-bit unsigned
+# number.
+#
+# @umask: x86 PMU event umask field.
+#
+# Since 10.1
+##
+{ 'struct': 'KvmPmuX86SelectUmaskEvent',
+ 'data': { 'select': 'uint16',
+ 'umask': 'uint8' } }
+
##
# @KvmPmuFilterEvent:
#
@@ -66,7 +82,8 @@
{ 'union': 'KvmPmuFilterEvent',
'base': { 'format': 'KvmPmuEventFormat' },
'discriminator': 'format',
- 'data': { 'raw': 'KvmPmuRawEvent' } }
+ 'data': { 'raw': 'KvmPmuRawEvent',
+ 'x86-select-umask': 'KvmPmuX86SelectUmaskEvent' } }
##
# @KvmPmuFilterProperties:
@@ -6180,6 +6180,9 @@ SRST
((select) & 0xff) | \
((umask) & 0xff) << 8)
+ ``{"format":"x86-select-umask","select":event_select,"umask":event_umask}``
+ Specify the single x86 PMU event with select and umask fields.
+
An example KVM PMU filter object would look like:
.. parsed-literal::
@@ -5974,6 +5974,10 @@ static bool kvm_config_pmu_event(KVMPMUFilter *filter,
case KVM_PMU_EVENT_FORMAT_RAW:
code = event->u.raw.code;
break;
+ case KVM_PMU_EVENT_FORMAT_X86_SELECT_UMASK:
+ code = X86_PMU_RAW_EVENT(event->u.x86_select_umask.select,
+ event->u.x86_select_umask.umask);
+ break;
default:
g_assert_not_reached();
}
@@ -6644,6 +6648,7 @@ static void kvm_arch_check_pmu_filter(const Object *obj, const char *name,
switch (event->format) {
case KVM_PMU_EVENT_FORMAT_RAW:
+ case KVM_PMU_EVENT_FORMAT_X86_SELECT_UMASK:
break;
default:
error_setg(errp,