@@ -5414,6 +5414,15 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
ret = kvm_xen_handle_exit(cpu, &run->xen);
break;
#endif
+ case KVM_EXIT_TDX:
+ if (!is_tdx_vm()) {
+ error_report("KVM: get KVM_EXIT_TDX for a non-TDX VM.");
+ ret = -1;
+ break;
+ }
+ tdx_handle_exit(cpu, &run->tdx);
+ ret = 0;
+ break;
default:
fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason);
ret = -1;
@@ -16,3 +16,8 @@ int tdx_parse_tdvf(void *flash_ptr, int size)
{
return -EINVAL;
}
+
+void tdx_handle_exit(X86CPU *cpu, struct kvm_tdx_exit *tdx_exit)
+{
+ abort();
+}
@@ -956,6 +956,9 @@ static void tdx_guest_init(Object *obj)
object_property_add_str(obj, "mrownerconfig",
tdx_guest_get_mrownerconfig,
tdx_guest_set_mrownerconfig);
+
+ tdx->event_notify_interrupt = -1;
+ tdx->event_notify_apic_id = -1;
}
static void tdx_guest_finalize(Object *obj)
@@ -965,3 +968,61 @@ static void tdx_guest_finalize(Object *obj)
static void tdx_guest_class_init(ObjectClass *oc, void *data)
{
}
+
+#define TDG_VP_VMCALL_SETUP_EVENT_NOTIFY_INTERRUPT 0x10004ULL
+
+#define TDG_VP_VMCALL_SUCCESS 0x0000000000000000ULL
+#define TDG_VP_VMCALL_RETRY 0x0000000000000001ULL
+#define TDG_VP_VMCALL_INVALID_OPERAND 0x8000000000000000ULL
+#define TDG_VP_VMCALL_GPA_INUSE 0x8000000000000001ULL
+#define TDG_VP_VMCALL_ALIGN_ERROR 0x8000000000000002ULL
+
+static void tdx_handle_setup_event_notify_interrupt(X86CPU *cpu,
+ struct kvm_tdx_vmcall *vmcall)
+{
+ MachineState *ms = MACHINE(qdev_get_machine());
+ TdxGuest *tdx = TDX_GUEST(ms->cgs);
+ int event_notify_interrupt = vmcall->in_r12;
+
+ if (32 <= event_notify_interrupt && event_notify_interrupt <= 255) {
+ qemu_mutex_lock(&tdx->lock);
+ tdx->event_notify_interrupt = event_notify_interrupt;
+ tdx->event_notify_apic_id = cpu->apic_id;
+ qemu_mutex_unlock(&tdx->lock);
+ vmcall->status_code = TDG_VP_VMCALL_SUCCESS;
+ }
+}
+
+static void tdx_handle_vmcall(X86CPU *cpu, struct kvm_tdx_vmcall *vmcall)
+{
+ vmcall->status_code = TDG_VP_VMCALL_INVALID_OPERAND;
+
+ /* For now handle only TDG.VP.VMCALL. */
+ if (vmcall->type != 0) {
+ warn_report("unknown tdg.vp.vmcall type 0x%llx subfunction 0x%llx",
+ vmcall->type, vmcall->subfunction);
+ return;
+ }
+
+ switch (vmcall->subfunction) {
+ case TDG_VP_VMCALL_SETUP_EVENT_NOTIFY_INTERRUPT:
+ tdx_handle_setup_event_notify_interrupt(cpu, vmcall);
+ break;
+ default:
+ warn_report("unknown tdg.vp.vmcall type 0x%llx subfunction 0x%llx",
+ vmcall->type, vmcall->subfunction);
+ break;
+ }
+}
+
+void tdx_handle_exit(X86CPU *cpu, struct kvm_tdx_exit *tdx_exit)
+{
+ switch (tdx_exit->type) {
+ case KVM_EXIT_TDX_VMCALL:
+ tdx_handle_vmcall(cpu, &tdx_exit->u.vmcall);
+ break;
+ default:
+ warn_report("unknown tdx exit type 0x%x", tdx_exit->type);
+ break;
+ }
+}
@@ -7,6 +7,7 @@
#include "exec/confidential-guest-support.h"
#include "hw/i386/tdvf.h"
+#include "sysemu/kvm.h"
#define TYPE_TDX_GUEST "tdx-guest"
#define TDX_GUEST(obj) OBJECT_CHECK(TdxGuest, (obj), TYPE_TDX_GUEST)
@@ -42,6 +43,10 @@ typedef struct TdxGuest {
uint32_t nr_ram_entries;
TdxRamEntry *ram_entries;
+
+ /* runtime state */
+ int event_notify_interrupt;
+ uint32_t event_notify_apic_id;
} TdxGuest;
#ifdef CONFIG_TDX
@@ -56,5 +61,6 @@ void tdx_get_supported_cpuid(uint32_t function, uint32_t index, int reg,
int tdx_pre_create_vcpu(CPUState *cpu, Error **errp);
void tdx_set_tdvf_region(MemoryRegion *tdvf_region);
int tdx_parse_tdvf(void *flash_ptr, int size);
+void tdx_handle_exit(X86CPU *cpu, struct kvm_tdx_exit *tdx_exit);
#endif /* QEMU_I386_TDX_H */