From: AkiraZheng <1428384878(a)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(a)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