[PATCH 1/3] kvm: Add hdbss-buffer-size accelerator property for HDBSS buffer configuration
From: AkiraZheng <1428384878@qq.com> Add a new KVM accelerator property 'hdbss-buffer-size' that allows userspace to configure the HDBSS (Hardware Dirty Bit State Structure) buffer size per-VM before vCPUs are created. The property accepts a size in entries (number of u64 slots), matching the convention of dirty-ring-size which also uses entries as the user-facing unit. QEMU converts entries to bytes (entries * sizeof(u64)) before passing to the KVM_ENABLE_CAP ioctl, consistent with how dirty-ring-size converts entries to bytes (entries * sizeof(kvm_dirty_gfn)). hdbss-buffer-size and dirty-ring-size are mutually exclusive: setting one while the other is already set returns an error. In dirty-ring mode, the kernel auto-configures the HDBSS buffer size based on the dirty ring size (see kvm_arch_dirty_ring_size_updated). Usage: -accel kvm,hdbss-buffer-size=512 When set to 0 (default), the kernel uses its default buffer size (PAGE_SIZE / sizeof(u64) entries per vCPU). Signed-off-by: AkiraZheng <1428384878@qq.com> --- accel/kvm/kvm-all.c | 5 ++++ include/sysemu/kvm_int.h | 1 + linux-headers/linux/kvm.h | 1 + qemu-options.hx | 1 + target/arm/kvm.c | 57 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 65 insertions(+) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 4f2a84c94c..c5cb768c9c 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -3831,6 +3831,10 @@ static void kvm_set_dirty_ring_size(Object *obj, Visitor *v, error_setg(errp, "dirty-ring-size must be a power of two."); return; } + if (value && s->kvm_hdbss_buffer_size) { + error_setg(errp, "dirty-ring-size and hdbss-buffer-size are mutually exclusive"); + return; + } s->kvm_dirty_ring_size = value; } @@ -3849,6 +3853,7 @@ static void kvm_accel_instance_init(Object *obj) s->kvm_dirty_ring_with_bitmap = false; s->kvm_smccc_filter_enabled = false; s->kvm_eager_split_size = 0; + s->kvm_hdbss_buffer_size = 0; s->notify_vmexit = NOTIFY_VMEXIT_OPTION_RUN; s->notify_window = 0; s->xen_version = 0; diff --git a/include/sysemu/kvm_int.h b/include/sysemu/kvm_int.h index 7b90117a86..68e9d21652 100644 --- a/include/sysemu/kvm_int.h +++ b/include/sysemu/kvm_int.h @@ -115,6 +115,7 @@ struct KVMState bool kvm_dirty_ring_with_bitmap; bool kvm_smccc_filter_enabled; uint64_t kvm_eager_split_size; /* Eager Page Splitting chunk size */ + uint32_t kvm_hdbss_buffer_size; /* HDBSS buffer size in entries per vCPU */ struct KVMDirtyRingReaper reaper; NotifyVmexitOption notify_vmexit; uint32_t notify_window; diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 15c55c7f82..0ef9a8a6b5 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -1243,6 +1243,7 @@ struct kvm_ppc_resize_hpt { /* support userspace to request management of CSV3 shared pages */ #define KVM_CAP_HYGON_COCO_EXT_CSV3_SP_MGR (1 << 4) +#define KVM_CAP_ARM_HDBSS_BUFFER_SIZE 251 #define KVM_CAP_ARM_HW_DIRTY_STATE_TRACK 502 #define KVM_CAP_ARM_TLBIDOMAIN 503 diff --git a/qemu-options.hx b/qemu-options.hx index 9c50a41c2a..3e4a58477a 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -187,6 +187,7 @@ DEF("accel", HAS_ARG, QEMU_OPTION_accel, " tb-size=n (TCG translation block cache size)\n" " dirty-ring-size=n (KVM dirty ring GFN count, default 0)\n" " eager-split-size=n (KVM Eager Page Split chunk size, default 0, disabled. ARM only)\n" + " hdbss-buffer-size=n (KVM HDBSS buffer entry count, default 0, kernel default. ARM only)\n" " notify-vmexit=run|internal-error|disable,notify-window=n (enable notify VM exit and set notify window, x86 only)\n" " thread=single|multi (enable multi-threaded TCG)\n", QEMU_ARCH_ALL) SRST diff --git a/target/arm/kvm.c b/target/arm/kvm.c index 435459632c..4d9ecbd0c2 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -417,6 +417,18 @@ int kvm_arch_init(MachineState *ms, KVMState *s) } } + if (s->kvm_hdbss_buffer_size) { + uint64_t buffer_bytes = (uint64_t)s->kvm_hdbss_buffer_size * sizeof(uint64_t); + + ret = kvm_vm_enable_cap(s, KVM_CAP_ARM_HDBSS_BUFFER_SIZE, 0, + buffer_bytes); + if (ret < 0) { + error_report("Enabling of HDBSS buffer size failed: %s", + strerror(-ret)); + return ret; + } + } + /* * To be able to handle PSCI CPU ON calls in QEMU, we need to install SMCCC * filter in the Host KVM. This is required to support features like @@ -1586,6 +1598,43 @@ static void kvm_arch_set_eager_split_size(Object *obj, Visitor *v, s->kvm_eager_split_size = value; } +static void kvm_arch_get_hdbss_buffer_size(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + KVMState *s = KVM_STATE(obj); + uint32_t value = s->kvm_hdbss_buffer_size; + + visit_type_uint32(v, name, &value, errp); +} + +static void kvm_arch_set_hdbss_buffer_size(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + KVMState *s = KVM_STATE(obj); + uint32_t value; + + if (s->fd != -1) { + error_setg(errp, "Cannot set hdbss-buffer-size after the accelerator has been initialized"); + return; + } + + if (!visit_type_uint32(v, name, &value, errp)) { + return; + } + if (value && (value & (value - 1))) { + error_setg(errp, "hdbss-buffer-size must be a power of two"); + return; + } + if (value && s->kvm_dirty_ring_size) { + error_setg(errp, "hdbss-buffer-size and dirty-ring-size are mutually exclusive"); + return; + } + + s->kvm_hdbss_buffer_size = value; +} + static bool virt_get_ipiv(Object *obj, Error **errp) { KVMState *s = KVM_STATE(obj); @@ -1609,6 +1658,14 @@ void kvm_arch_accel_class_init(ObjectClass *oc) object_class_property_set_description(oc, "eager-split-size", "Eager Page Split chunk size for hugepages. (default: 0, disabled)"); + object_class_property_add(oc, "hdbss-buffer-size", "uint32", + kvm_arch_get_hdbss_buffer_size, + kvm_arch_set_hdbss_buffer_size, NULL, NULL); + + object_class_property_set_description(oc, "hdbss-buffer-size", + "HDBSS buffer size in entries for hardware dirty page tracking. " + "(default: 0, use kernel default. ARM only)"); + object_class_property_add_bool(oc, "ipiv", virt_get_ipiv, virt_set_ipiv); -- 2.33.0
Add a boolean 'hdbss' accelerator property (default: on) to allow enabling or disabling HDBSS hardware dirty tracking per VM via KVM_CAP_ARM_HDBSS (cap 252). Usage: -accel kvm,hdbss=on (default, enables HDBSS) -accel kvm,hdbss=off (disables HDBSS for comparison testing) A fallback define is provided for KVM_CAP_ARM_HDBSS in case the installed kernel headers do not yet have the definition. --- accel/kvm/kvm-all.c | 48 ++++++++++++++++++++++++++++++++++++++++ include/sysemu/kvm_int.h | 1 + 2 files changed, 49 insertions(+) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index c5cb768c9c..495f1c9d44 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -19,6 +19,10 @@ #include <linux/kvm.h> +#ifndef KVM_CAP_ARM_HDBSS +#define KVM_CAP_ARM_HDBSS 252 +#endif + #include "qemu/atomic.h" #include "qemu/option.h" #include "qemu/config-file.h" @@ -2648,6 +2652,14 @@ static int kvm_init(MachineState *ms) goto err; } + ret = kvm_vm_check_extension(s, KVM_CAP_ARM_HDBSS); + if (ret > 0) { + ret = kvm_vm_enable_cap(s, KVM_CAP_ARM_HDBSS, 0, s->kvm_hdbss ? 1 : 0); + if (ret < 0) { + goto err; + } + } + /* * KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 is not needed when dirty ring is * enabled. More importantly, KVM_DIRTY_LOG_INITIALLY_SET will assume no @@ -3812,6 +3824,35 @@ static void kvm_get_dirty_ring_size(Object *obj, Visitor *v, visit_type_uint32(v, name, &value, errp); } +static void kvm_get_hdbss(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + KVMState *s = KVM_STATE(obj); + bool value = s->kvm_hdbss; + + visit_type_bool(v, name, &value, errp); +} + +static void kvm_set_hdbss(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + KVMState *s = KVM_STATE(obj); + bool value; + + if (s->fd != -1) { + error_setg(errp, "Cannot set properties after the accelerator has been initialized"); + return; + } + + if (!visit_type_bool(v, name, &value, errp)) { + return; + } + + s->kvm_hdbss = value; +} + static void kvm_set_dirty_ring_size(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) @@ -3854,6 +3895,7 @@ static void kvm_accel_instance_init(Object *obj) s->kvm_smccc_filter_enabled = false; s->kvm_eager_split_size = 0; s->kvm_hdbss_buffer_size = 0; + s->kvm_hdbss = true; s->notify_vmexit = NOTIFY_VMEXIT_OPTION_RUN; s->notify_window = 0; s->xen_version = 0; @@ -3899,6 +3941,12 @@ static void kvm_accel_class_init(ObjectClass *oc, void *data) object_class_property_set_description(oc, "dirty-ring-size", "Size of KVM dirty page ring buffer (default: 0, i.e. use bitmap)"); + object_class_property_add(oc, "hdbss", "bool", + kvm_get_hdbss, kvm_set_hdbss, + NULL, NULL); + object_class_property_set_description(oc, "hdbss", + "Enable/disable HDBSS hardware dirty tracking (on/off, default: on)"); + kvm_arch_accel_class_init(oc); } diff --git a/include/sysemu/kvm_int.h b/include/sysemu/kvm_int.h index 68e9d21652..9268f7b18b 100644 --- a/include/sysemu/kvm_int.h +++ b/include/sysemu/kvm_int.h @@ -114,6 +114,7 @@ struct KVMState uint32_t kvm_dirty_ring_size; /* Number of dirty GFNs per ring */ bool kvm_dirty_ring_with_bitmap; bool kvm_smccc_filter_enabled; + bool kvm_hdbss; /* Enable/disable HDBSS hardware dirty tracking */ uint64_t kvm_eager_split_size; /* Eager Page Splitting chunk size */ uint32_t kvm_hdbss_buffer_size; /* HDBSS buffer size in entries per vCPU */ struct KVMDirtyRingReaper reaper; -- 2.33.0
--- accel/kvm/kvm-all.c | 2 +- linux-headers/linux/kvm.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 495f1c9d44..a8d63eb9fb 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -20,7 +20,7 @@ #include <linux/kvm.h> #ifndef KVM_CAP_ARM_HDBSS -#define KVM_CAP_ARM_HDBSS 252 +#define KVM_CAP_ARM_HDBSS 253 #endif #include "qemu/atomic.h" diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 0ef9a8a6b5..22e63ab687 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -1243,7 +1243,8 @@ struct kvm_ppc_resize_hpt { /* support userspace to request management of CSV3 shared pages */ #define KVM_CAP_HYGON_COCO_EXT_CSV3_SP_MGR (1 << 4) -#define KVM_CAP_ARM_HDBSS_BUFFER_SIZE 251 +#define KVM_CAP_ARM_HDBSS_BUFFER_SIZE 252 +#define KVM_CAP_ARM_HDBSS 253 #define KVM_CAP_ARM_HW_DIRTY_STATE_TRACK 502 #define KVM_CAP_ARM_TLBIDOMAIN 503 -- 2.33.0
participants (1)
-
Tian Zheng