@@ -5413,6 +5413,14 @@ 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;
+ }
+ ret = tdx_handle_exit(cpu, &run->tdx);
+ break;
default:
fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason);
ret = -1;
@@ -11,3 +11,8 @@ int tdx_parse_tdvf(void *flash_ptr, int size)
{
return -EINVAL;
}
+
+int tdx_handle_exit(X86CPU *cpu, struct kvm_tdx_exit *tdx_exit)
+{
+ return -EINVAL;
+}
@@ -866,6 +866,56 @@ int tdx_parse_tdvf(void *flash_ptr, int size)
return tdvf_parse_metadata(&tdx_guest->tdvf, flash_ptr, size);
}
+static int tdx_handle_setup_event_notify_interrupt(X86CPU *cpu,
+ struct kvm_tdx_vmcall *vmcall)
+{
+ int vector = vmcall->in_r12;
+
+ if (32 <= vector && vector <= 255) {
+ qemu_mutex_lock(&tdx_guest->lock);
+ tdx_guest->event_notify_vector = vector;
+ tdx_guest->event_notify_apicid = cpu->apic_id;
+ qemu_mutex_unlock(&tdx_guest->lock);
+ vmcall->status_code = TDG_VP_VMCALL_SUCCESS;
+ } else {
+ vmcall->status_code = TDG_VP_VMCALL_INVALID_OPERAND;
+ }
+
+ return 0;
+}
+
+static int 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 leaf defined in TDX GHCI */
+ if (vmcall->type != 0) {
+ error_report("Unknown TDG.VP.VMCALL type 0x%llx subfunction 0x%llx",
+ vmcall->type, vmcall->subfunction);
+ return -1;
+ }
+
+ switch (vmcall->subfunction) {
+ case TDG_VP_VMCALL_SETUP_EVENT_NOTIFY_INTERRUPT:
+ return tdx_handle_setup_event_notify_interrupt(cpu, vmcall);
+ default:
+ error_report("Unknown TDG.VP.VMCALL type 0x%llx subfunction 0x%llx",
+ vmcall->type, vmcall->subfunction);
+ return -1;
+ }
+}
+
+int tdx_handle_exit(X86CPU *cpu, struct kvm_tdx_exit *tdx_exit)
+{
+ switch (tdx_exit->type) {
+ case KVM_EXIT_TDX_VMCALL:
+ return tdx_handle_vmcall(cpu, &tdx_exit->u.vmcall);
+ default:
+ error_report("unknown tdx exit type 0x%x", tdx_exit->type);
+ return -1;
+ }
+}
+
static bool tdx_guest_get_sept_ve_disable(Object *obj, Error **errp)
{
TdxGuest *tdx = TDX_GUEST(obj);
@@ -956,6 +1006,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_vector = -1;
+ tdx->event_notify_apicid = -1;
}
static void tdx_guest_finalize(Object *obj)
@@ -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)
@@ -15,6 +16,14 @@ typedef struct TdxGuestClass {
ConfidentialGuestSupportClass parent_class;
} TdxGuestClass;
+#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
+
enum TdxRamType{
TDX_RAM_UNACCEPTED,
TDX_RAM_ADDED,
@@ -42,6 +51,10 @@ typedef struct TdxGuest {
uint32_t nr_ram_entries;
TdxRamEntry *ram_entries;
+
+ /* runtime state */
+ uint32_t event_notify_vector;
+ uint32_t event_notify_apicid;
} TdxGuest;
#ifdef CONFIG_TDX
@@ -55,5 +68,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_mr);
int tdx_parse_tdvf(void *flash_ptr, int size);
+int tdx_handle_exit(X86CPU *cpu, struct kvm_tdx_exit *tdx_exit);
#endif /* QEMU_I386_TDX_H */