[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