[RFC PATCH v1 03/17] target/riscv/kvm: create and measure a CoVE TEE VM

Baolong Duan <[email protected]> Fri, 31 Jul 2026 11:49:57 +0800
Newsgroups org.nongnu.qemu-riscv,org.nongnu.qemu-devel
Message-ID <[email protected]>
Ask KVM for a TEE VM (TVM) instead of a regular guest when the machine
runs in CoVE mode, and add kvm_riscv_cove_measure_region() to add a
memory region to the initial measurement of that TVM.

The measurement is what allows a CoVE guest to be attested later on, so
failing to add a region to it is fatal.

The KVM ABI this relies on is not part of an upstream Linux release yet, so
KVM_VM_TYPE_RISCV_COVE and KVM_RISCV_COVE_MEASURE_REGION are defined here
rather than imported into linux-headers/.  They have to be replaced by a
regular scripts/update-linux-headers.sh run once the kernel side has been
merged.

Signed-off-by: Baolong Duan <[email protected]>
---
 target/riscv/kvm/kvm-cpu.c   | 46 ++++++++++++++++++++++++++++++++++++
 target/riscv/kvm/kvm_riscv.h | 10 ++++++++
 2 files changed, 56 insertions(+)

diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index 495cb42dc8..67c99d68ce 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -48,10 +48,27 @@
 #include "migration/misc.h"
 #include "system/runstate.h"
 #include "hw/riscv/numa.h"
+#include "hw/riscv/cove.h"
 
 #define PR_RISCV_V_SET_CONTROL            69
 #define PR_RISCV_V_VSTATE_CTRL_ON          2
 
+/*
+ * CoVE KVM ABI.  These definitions are not part of an upstream Linux release
+ * yet, so they cannot be imported into linux-headers/ and are kept here until
+ * the kernel side has been merged.
+ */
+#define KVM_VM_TYPE_RISCV_COVE          (1UL << 9)
+
+struct kvm_riscv_cove_measure_region {
+    uint64_t user_addr;
+    uint64_t gpa;
+    uint64_t size;
+};
+
+#define KVM_RISCV_COVE_MEASURE_REGION \
+    _IOR(KVMIO, 0xb5, struct kvm_riscv_cove_measure_region)
+
 void riscv_kvm_aplic_request(void *opaque, int irq, int level)
 {
     kvm_set_irq(kvm_state, irq, !!level);
@@ -1549,6 +1566,9 @@ int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route,
 
 int kvm_arch_get_default_type(MachineState *ms)
 {
+    if (riscv_cove_vm_active()) {
+        return KVM_VM_TYPE_RISCV_COVE;
+    }
     return 0;
 }
 
@@ -1829,6 +1849,32 @@ void kvm_arch_accel_class_init(ObjectClass *oc)
                                     "auto");
 }
 
+/*
+ * Add the contents of a memory region to the initial measurement of the TVM.
+ * Nothing is measured for a guest that is not confidential.
+ */
+void kvm_riscv_cove_measure_region(uint64_t user_addr, uint64_t gpa,
+                                   uint64_t size)
+{
+    struct kvm_riscv_cove_measure_region mr;
+    int ret;
+
+    if (!riscv_cove_vm_active()) {
+        return;
+    }
+
+    mr.user_addr = user_addr;
+    mr.gpa = gpa;
+    mr.size = size;
+
+    ret = kvm_vm_ioctl(kvm_state, KVM_RISCV_COVE_MEASURE_REGION, &mr);
+    if (ret < 0) {
+        error_report("Unable to measure CoVE region at 0x%" PRIx64 ": %s",
+                     gpa, strerror(-ret));
+        exit(EXIT_FAILURE);
+    }
+}
+
 void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift,
                           uint64_t aia_irq_num, uint64_t aia_msi_num,
                           uint64_t aplic_base, uint64_t imsic_base,
diff --git a/target/riscv/kvm/kvm_riscv.h b/target/riscv/kvm/kvm_riscv.h
index b2bcd1041f..cd45f1266b 100644
--- a/target/riscv/kvm/kvm_riscv.h
+++ b/target/riscv/kvm/kvm_riscv.h
@@ -23,6 +23,16 @@
 
 void kvm_riscv_reset_vcpu(RISCVCPU *cpu);
 void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level);
+#ifdef CONFIG_KVM
+void kvm_riscv_cove_measure_region(uint64_t user_addr, uint64_t gpa,
+                                   uint64_t size);
+#else
+static inline void kvm_riscv_cove_measure_region(uint64_t user_addr,
+                                                 uint64_t gpa, uint64_t size)
+{
+    /* A CoVE guest cannot be created without KVM, nothing to measure. */
+}
+#endif
 void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift,
                           uint64_t aia_irq_num, uint64_t aia_msi_num,
                           uint64_t aplic_base, uint64_t imsic_base,
-- 
2.34.1