[RFC PATCH v1 02/17] hw/riscv/virt: add the cove-vm machine property

Baolong Duan <[email protected]> Fri, 31 Jul 2026 11:49:56 +0800
Newsgroups org.nongnu.qemu-riscv,org.nongnu.qemu-devel
Message-ID <[email protected]>
A RISC-V CoVE guest is a TEE VM (TVM) whose memory and vCPU state are
owned by the TEE Security Manager (TSM) rather than by the host.  Add a
'cove-vm' property to the virt machine to ask for one.

Subsystems outside of hw/riscv/, such as the KVM accelerator and the
virtio code, have to know whether the guest is a TVM.  The state is
therefore mirrored into target independent code and queried through
riscv_cove_vm_active(); keeping the implementation in hw/core/machine.c
avoids a link time dependency on target/riscv.

Nothing looks at the property yet.  Add a MAINTAINERS entry for the new
header.

Signed-off-by: Baolong Duan <[email protected]>
---
 MAINTAINERS             |  6 ++++++
 hw/core/machine.c       | 18 ++++++++++++++++++
 hw/riscv/virt.c         | 26 ++++++++++++++++++++++++++
 include/hw/riscv/cove.h | 24 ++++++++++++++++++++++++
 include/hw/riscv/virt.h |  1 +
 5 files changed, 75 insertions(+)
 create mode 100644 include/hw/riscv/cove.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 902db77218..dab130a45a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -391,6 +391,12 @@ F: target/riscv/XVentanaCondOps.decode
 F: target/riscv/insn_trans/trans_xventanacondops.c.inc
 F: disas/riscv-xventana*
 
+RISC-V CoVE
+M: Baolong Duan <[email protected]>
+L: [email protected]
+S: Maintained
+F: include/hw/riscv/cove.h
+
 RENESAS RX CPUs
 R: Yoshinori Sato <[email protected]>
 S: Orphan
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 73b4d82b4a..578a5cdde5 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -16,6 +16,7 @@
 #include "system/replay.h"
 #include "hw/core/boards.h"
 #include "hw/core/loader.h"
+#include "hw/riscv/cove.h"
 #include "qemu/error-report.h"
 #include "qapi/error.h"
 #include "qapi/qapi-visit-machine.h"
@@ -1335,6 +1336,23 @@ bool machine_require_guest_memfd(MachineState *machine)
     return machine->cgs && machine->cgs->require_guest_memfd;
 }
 
+/*
+ * Whether the machine runs as a RISC-V CoVE guest. This lives here, and not
+ * in hw/riscv/, because target independent code has to query it and must not
+ * depend on the RISC-V machine being linked in.
+ */
+static bool riscv_cove_vm;
+
+bool riscv_cove_vm_active(void)
+{
+    return riscv_cove_vm;
+}
+
+void riscv_cove_vm_set_active(bool active)
+{
+    riscv_cove_vm = active;
+}
+
 static char *cpu_slot_to_string(const CPUArchId *cpu)
 {
     GString *s = g_string_new(NULL);
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 51bac47a91..a76587d362 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -35,6 +35,7 @@
 #include "hw/riscv/riscv-iommu-bits.h"
 #include "hw/riscv/virt.h"
 #include "hw/riscv/boot.h"
+#include "hw/riscv/cove.h"
 #include "hw/riscv/fdt-common.h"
 #include "hw/riscv/machines-qom.h"
 #include "hw/riscv/numa.h"
@@ -1321,6 +1322,11 @@ static void virt_machine_init(MachineState *machine)
         exit(1);
     }
 
+    if (s->cove_vm && !kvm_enabled()) {
+        error_report("'cove-vm' is only available with KVM acceleration");
+        exit(1);
+    }
+
     /* Initialize sockets */
     mmio_irqchip = virtio_irqchip = pcie_irqchip = NULL;
     for (i = 0; i < socket_count; i++) {
@@ -1652,6 +1658,21 @@ static void virt_set_iommu_sys(Object *obj, Visitor *v, const char *name,
     visit_type_OnOffAuto(v, name, &s->iommu_sys, errp);
 }
 
+static bool virt_get_cove_vm(Object *obj, Error **errp)
+{
+    RISCVVirtState *s = RISCV_VIRT_MACHINE(obj);
+
+    return s->cove_vm;
+}
+
+static void virt_set_cove_vm(Object *obj, bool value, Error **errp)
+{
+    RISCVVirtState *s = RISCV_VIRT_MACHINE(obj);
+
+    s->cove_vm = value;
+    riscv_cove_vm_set_active(value);
+}
+
 bool virt_is_acpi_enabled(RISCVVirtState *s)
 {
     return s->acpi != ON_OFF_AUTO_OFF;
@@ -1780,6 +1801,11 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
                               NULL, NULL);
     object_class_property_set_description(oc, "iommu-sys",
                                           "Enable IOMMU platform device");
+
+    object_class_property_add_bool(oc, "cove-vm", virt_get_cove_vm,
+                                   virt_set_cove_vm);
+    object_class_property_set_description(oc, "cove-vm",
+                                          "Enable CoVE confidential VM");
 }
 
 static const TypeInfo virt_machine_typeinfo = {
diff --git a/include/hw/riscv/cove.h b/include/hw/riscv/cove.h
new file mode 100644
index 0000000000..0b29a00786
--- /dev/null
+++ b/include/hw/riscv/cove.h
@@ -0,0 +1,24 @@
+/*
+ * RISC-V Confidential VM Extension (CoVE)
+ *
+ * Copyright (c) 2026 Alibaba Group
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_RISCV_COVE_H
+#define HW_RISCV_COVE_H
+
+/*
+ * A CoVE guest is a TEE VM (TVM) whose memory and vCPU state are owned by
+ * the TEE Security Manager (TSM) instead of the host. Subsystems outside of
+ * hw/riscv/ have to behave differently for such a guest, so the state is
+ * kept in target independent code.
+ *
+ * riscv_cove_vm_set_active() is called by the machine that implements CoVE
+ * while its properties are parsed, before any device is created.
+ */
+bool riscv_cove_vm_active(void);
+void riscv_cove_vm_set_active(bool active);
+
+#endif /* HW_RISCV_COVE_H */
diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h
index 36a2def410..99e073ef9a 100644
--- a/include/hw/riscv/virt.h
+++ b/include/hw/riscv/virt.h
@@ -60,6 +60,7 @@ struct RISCVVirtState {
     char *oem_id;
     char *oem_table_id;
     OnOffAuto acpi;
+    bool cove_vm;
     const MemMapEntry *memmap;
     struct GPEXHost *gpex_host;
     OnOffAuto iommu_sys;
-- 
2.34.1