On 7/10/2024 12:51 PM, Zhao Liu wrote: > The select&umask is the common way for x86 to identify the PMU event, > so support this way as the "x86-default" format in kvm-pmu-filter > object. > > Signed-off-by: Zhao Liu <zhao1.liu@xxxxxxxxx> > --- > accel/kvm/kvm-pmu.c | 62 ++++++++++++++++++++++++++++++++++++++++ > include/sysemu/kvm-pmu.h | 13 +++++++++ > qapi/kvm.json | 46 +++++++++++++++++++++++++++-- > target/i386/kvm/kvm.c | 5 ++++ > 4 files changed, 123 insertions(+), 3 deletions(-) > > diff --git a/accel/kvm/kvm-pmu.c b/accel/kvm/kvm-pmu.c > index 483d1bdf4807..51d3fba5a72a 100644 > --- a/accel/kvm/kvm-pmu.c > +++ b/accel/kvm/kvm-pmu.c > @@ -17,6 +17,8 @@ > #include "qom/object_interfaces.h" > #include "sysemu/kvm-pmu.h" > > +#define UINT12_MAX (4095) > + > static void kvm_pmu_filter_get_event(Object *obj, Visitor *v, const char *name, > void *opaque, Error **errp) > { > @@ -38,6 +40,12 @@ static void kvm_pmu_filter_get_event(Object *obj, Visitor *v, const char *name, > str_event->u.raw.code = g_strdup_printf("0x%lx", > event->u.raw.code); > break; > + case KVM_PMU_EVENT_FMT_X86_DEFAULT: > + str_event->u.x86_default.select = > + g_strdup_printf("0x%x", event->u.x86_default.select); > + str_event->u.x86_default.umask = > + g_strdup_printf("0x%x", event->u.x86_default.umask); > + break; > default: > g_assert_not_reached(); > } > @@ -83,6 +91,60 @@ static void kvm_pmu_filter_set_event(Object *obj, Visitor *v, const char *name, > goto fail; > } > break; > + case KVM_PMU_EVENT_FMT_X86_DEFAULT: { > + uint64_t select, umask; > + > + ret = qemu_strtou64(str_event->u.x86_default.select, NULL, > + 0, &select); > + if (ret < 0) { > + error_setg(errp, > + "Invalid %s PMU event (select: %s): %s. " > + "The select must be a " > + "12-bit unsigned number string.", > + KVMPMUEventEncodeFmt_str(str_event->format), > + str_event->u.x86_default.select, > + strerror(-ret)); > + g_free(event); > + goto fail; > + } > + if (select > UINT12_MAX) { > + error_setg(errp, > + "Invalid %s PMU event (select: %s): " > + "Numerical result out of range. " > + "The select must be a " > + "12-bit unsigned number string.", > + KVMPMUEventEncodeFmt_str(str_event->format), > + str_event->u.x86_default.select); > + g_free(event); > + goto fail; > + } > + event->u.x86_default.select = select; > + > + ret = qemu_strtou64(str_event->u.x86_default.umask, NULL, > + 0, &umask); > + if (ret < 0) { > + error_setg(errp, > + "Invalid %s PMU event (umask: %s): %s. " > + "The umask must be a uint8 string.", > + KVMPMUEventEncodeFmt_str(str_event->format), > + str_event->u.x86_default.umask, > + strerror(-ret)); > + g_free(event); > + goto fail; > + } > + if (umask > UINT8_MAX) { umask is extended to 16 bits from Perfmon v6+. Please notice we need to upgrade this to 16 bits in the future. More details can be found here. [PATCH V3 00/13] Support Lunar Lake and Arrow Lake core PMU - kan.liang (kernel.org) <https://lore.kernel.org/all/20240626143545.480761-1-kan.liang@xxxxxxxxxxxxxxx/> > + error_setg(errp, > + "Invalid %s PMU event (umask: %s): " > + "Numerical result out of range. " > + "The umask must be a uint8 string.", > + KVMPMUEventEncodeFmt_str(str_event->format), > + str_event->u.x86_default.umask); > + g_free(event); > + goto fail; > + } > + event->u.x86_default.umask = umask; > + break; > + } > default: > g_assert_not_reached(); > } > diff --git a/include/sysemu/kvm-pmu.h b/include/sysemu/kvm-pmu.h > index 4707759761f1..707f33d604fd 100644 > --- a/include/sysemu/kvm-pmu.h > +++ b/include/sysemu/kvm-pmu.h > @@ -26,4 +26,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 */ > diff --git a/qapi/kvm.json b/qapi/kvm.json > index 0619da83c123..0d759884c229 100644 > --- a/qapi/kvm.json > +++ b/qapi/kvm.json > @@ -27,11 +27,13 @@ > # > # @raw: the encoded event code that KVM can directly consume. > # > +# @x86-default: standard x86 encoding format with select and umask. > +# > # Since 9.1 > ## > { 'enum': 'KVMPMUEventEncodeFmt', > 'prefix': 'KVM_PMU_EVENT_FMT', > - 'data': ['raw'] } > + 'data': ['raw', 'x86-default'] } > > ## > # @KVMPMURawEvent: > @@ -46,6 +48,25 @@ > { 'struct': 'KVMPMURawEvent', > 'data': { 'code': 'uint64' } } > > +## > +# @KVMPMUX86DefalutEvent: > +# > +# x86 PMU event encoding with select and umask. > +# raw_event = ((select & 0xf00UL) << 24) | \ > +# (select) & 0xff) | \ > +# ((umask) & 0xff) << 8) > +# > +# @select: x86 PMU event select field, which is a 12-bit unsigned > +# number. > +# > +# @umask: x86 PMU event umask field. > +# > +# Since 9.1 > +## > +{ 'struct': 'KVMPMUX86DefalutEvent', > + 'data': { 'select': 'uint16', > + 'umask': 'uint8' } } > + > ## > # @KVMPMUFilterEvent: > # > @@ -61,7 +82,8 @@ > 'base': { 'action': 'KVMPMUFilterAction', > 'format': 'KVMPMUEventEncodeFmt' }, > 'discriminator': 'format', > - 'data': { 'raw': 'KVMPMURawEvent' } } > + 'data': { 'raw': 'KVMPMURawEvent', > + 'x86-default': 'KVMPMUX86DefalutEvent' } } > > ## > # @KVMPMUFilterProperty: > @@ -89,6 +111,23 @@ > { 'struct': 'KVMPMURawEventVariant', > 'data': { 'code': 'str' } } > > +## > +# @KVMPMUX86DefalutEventVariant: > +# > +# The variant of KVMPMUX86DefalutEvent with the string, rather than > +# the numeric value. > +# > +# @select: x86 PMU event select field. This field is a 12-bit > +# unsigned number string. > +# > +# @umask: x86 PMU event umask field. This field is a uint8 string. > +# > +# Since 9.1 > +## > +{ 'struct': 'KVMPMUX86DefalutEventVariant', > + 'data': { 'select': 'str', > + 'umask': 'str' } } > + > ## > # @KVMPMUFilterEventVariant: > # > @@ -104,7 +143,8 @@ > 'base': { 'action': 'KVMPMUFilterAction', > 'format': 'KVMPMUEventEncodeFmt' }, > 'discriminator': 'format', > - 'data': { 'raw': 'KVMPMURawEventVariant' } } > + 'data': { 'raw': 'KVMPMURawEventVariant', > + 'x86-default': 'KVMPMUX86DefalutEventVariant' } } > > ## > # @KVMPMUFilterPropertyVariant: > diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c > index e9bf79782316..391531c036a6 100644 > --- a/target/i386/kvm/kvm.c > +++ b/target/i386/kvm/kvm.c > @@ -5393,6 +5393,10 @@ kvm_config_pmu_event(KVMPMUFilter *filter, > case KVM_PMU_EVENT_FMT_RAW: > code = event->u.raw.code; > break; > + case KVM_PMU_EVENT_FMT_X86_DEFAULT: > + code = X86_PMU_RAW_EVENT(event->u.x86_default.select, > + event->u.x86_default.umask); > + break; > default: > g_assert_not_reached(); > } > @@ -6073,6 +6077,7 @@ static void kvm_arch_check_pmu_filter(const Object *obj, const char *name, > > switch (event->format) { > case KVM_PMU_EVENT_FMT_RAW: > + case KVM_PMU_EVENT_FMT_X86_DEFAULT: > break; > default: > error_setg(errp,