]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
qemu_process: Populate hyperv features for host-model
authorMichal Privoznik <mprivozn@redhat.com>
Mon, 29 Sep 2025 12:54:23 +0000 (14:54 +0200)
committerMichal Privoznik <mprivozn@redhat.com>
Wed, 15 Oct 2025 08:04:12 +0000 (10:04 +0200)
Pretty straightforward. The only "weird" thing here is that
'hv-time' enlightenment is exposed as a <timer/> under <clock/>
element. Since it's required by 'hv-stimer' and
'hv-stimer-direct' it needs to be enabled too.

Resolves: https://issues.redhat.com/browse/RHEL-114003
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
src/qemu/qemu_command.c
src/qemu/qemu_process.c
tests/qemuxmlconfdata/hyperv-host-model.x86_64-latest.args

index 609d0677df7c8d9288d1faddf9832f16703057e5..fcf5fc19350f54d36a60e65b60053213fcc57264 100644 (file)
@@ -6461,13 +6461,13 @@ qemuBuildCpuHypervCommandLine(virBuffer *buf,
 
     switch ((virDomainHyperVMode) def->features[VIR_DOMAIN_FEATURE_HYPERV]) {
     case VIR_DOMAIN_HYPERV_MODE_CUSTOM:
-    case VIR_DOMAIN_HYPERV_MODE_HOST_MODEL:
         break;
 
     case VIR_DOMAIN_HYPERV_MODE_PASSTHROUGH:
         virBufferAddLit(buf, ",hv-passthrough=on");
         break;
 
+    case VIR_DOMAIN_HYPERV_MODE_HOST_MODEL:
     case VIR_DOMAIN_HYPERV_MODE_NONE:
     case VIR_DOMAIN_HYPERV_MODE_LAST:
     default:
index d42e3f612bbee9e927d795c0dcbcd33bc522e2ec..9926998f8522bb9ce2853419d811fad8131f7d46 100644 (file)
@@ -6835,6 +6835,75 @@ qemuProcessPrepareChardevSource(virDomainDef *def,
 }
 
 
+static void
+qemuProcessMaybeAddHypervTimer(virDomainDef *def)
+{
+    g_autofree virDomainTimerDef *timer = NULL;
+
+    if (virDomainDefHasTimer(def, VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK))
+        return;
+
+    timer = g_new0(virDomainTimerDef, 1);
+    timer->name = VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK;
+    timer->present = VIR_TRISTATE_BOOL_YES;
+
+    VIR_APPEND_ELEMENT(def->clock.timers, def->clock.ntimers, timer);
+}
+
+
+static int
+qemuProcessEnableDomainFeatures(virDomainObj *vm)
+{
+    virDomainCapsFeatureHyperv *hv = NULL;
+    qemuDomainObjPrivate *priv = vm->privateData;
+    size_t i;
+
+    if (vm->def->features[VIR_DOMAIN_FEATURE_HYPERV] != VIR_DOMAIN_HYPERV_MODE_HOST_MODEL)
+        return 0;
+
+    hv = virQEMUCapsGetHypervCapabilities(priv->qemuCaps);
+    if (!hv || hv->supported != VIR_TRISTATE_BOOL_YES) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("host-model hyperv mode unsupported, no hyperv capabilities found"));
+        return -1;
+    }
+
+    for (i = 0; i < VIR_DOMAIN_HYPERV_LAST; i++) {
+        if (!VIR_DOMAIN_CAPS_ENUM_IS_SET(hv->features, i))
+            continue;
+
+        vm->def->hyperv.features[i] = VIR_TRISTATE_SWITCH_ON;
+
+        if (i == VIR_DOMAIN_HYPERV_SPINLOCKS) {
+            if (hv->spinlocks != 0) {
+                vm->def->hyperv.spinlocks = hv->spinlocks;
+            } else {
+                vm->def->hyperv.features[i] = VIR_TRISTATE_SWITCH_ABSENT;
+            }
+        } else if (i == VIR_DOMAIN_HYPERV_STIMER) {
+            vm->def->hyperv.stimer_direct = hv->stimer_direct;
+            /* Both hv-stimer and hv-stimer-direct require hv-time which is
+             * expose as a timer. Enable it. */
+            qemuProcessMaybeAddHypervTimer(vm->def);
+        } else if (i == VIR_DOMAIN_HYPERV_TLBFLUSH) {
+            vm->def->hyperv.tlbflush_direct = hv->tlbflush_direct;
+            vm->def->hyperv.tlbflush_extended = hv->tlbflush_extended;
+        } else if (i == VIR_DOMAIN_HYPERV_VENDOR_ID) {
+            if (hv->vendor_id) {
+                vm->def->hyperv.vendor_id = g_strdup(hv->vendor_id);
+            } else {
+                vm->def->hyperv.features[i] = VIR_TRISTATE_SWITCH_ABSENT;
+            }
+        }
+    }
+
+    vm->def->features[VIR_DOMAIN_FEATURE_HYPERV] = VIR_DOMAIN_HYPERV_MODE_CUSTOM;
+
+    return 0;
+}
+
+
+
 /**
  * qemuProcessPrepareDomain:
  * @driver: qemu driver
@@ -6948,6 +7017,9 @@ qemuProcessPrepareDomain(virQEMUDriver *driver,
         VIR_DEBUG("Aligning guest memory");
         if (qemuDomainAlignMemorySizes(vm->def) < 0)
             return -1;
+
+        if (qemuProcessEnableDomainFeatures(vm) < 0)
+            return -1;
     }
 
     for (i = 0; i < vm->def->nchannels; i++) {
index 2ed72fcd1b1b4918e5ab3fb49a40c9b561f9f7fb..58502ff51ef1caa0a4de1d989382db98a7ae59e8 100644 (file)
@@ -12,7 +12,7 @@ XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.config \
 -object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/var/lib/libvirt/qemu/domain--1-QEMUGuest1/master-key.aes"}' \
 -machine pc,usb=off,dump-guest-core=off,memory-backend=pc.ram,acpi=on \
 -accel tcg \
--cpu qemu64 \
+-cpu 'qemu64,hv-time=on,hv-relaxed=on,hv-vapic=on,hv-spinlocks=0xfff,hv-vpindex=on,hv-runtime=on,hv-synic=on,hv-stimer=on,hv-stimer-direct=on,hv-reset=on,hv-vendor-id=Linux KVM Hv,hv-frequencies=on,hv-reenlightenment=on,hv-tlbflush=on,hv-tlbflush-direct=on,hv-tlbflush-ext=on,hv-ipi=on,hv-avic=on,hv-emsr-bitmap=on,hv-xmm-input=on' \
 -m size=219136k \
 -object '{"qom-type":"memory-backend-ram","id":"pc.ram","size":224395264}' \
 -overcommit mem-lock=off \