xref: /qemu/target/i386/kvm/tdx.c (revision 8eddedc3701d2190db976a05155a8263c8ec175b)
1756e12e7SXiaoyao Li /*
2756e12e7SXiaoyao Li  * QEMU TDX support
3756e12e7SXiaoyao Li  *
4756e12e7SXiaoyao Li  * Copyright (c) 2025 Intel Corporation
5756e12e7SXiaoyao Li  *
6756e12e7SXiaoyao Li  * Author:
7756e12e7SXiaoyao Li  *      Xiaoyao Li <xiaoyao.li@intel.com>
8756e12e7SXiaoyao Li  *
9756e12e7SXiaoyao Li  * SPDX-License-Identifier: GPL-2.0-or-later
10756e12e7SXiaoyao Li  */
11756e12e7SXiaoyao Li 
12756e12e7SXiaoyao Li #include "qemu/osdep.h"
13*8eddedc3SXiaoyao Li #include "qemu/error-report.h"
14*8eddedc3SXiaoyao Li #include "qapi/error.h"
15756e12e7SXiaoyao Li #include "qom/object_interfaces.h"
16756e12e7SXiaoyao Li 
17631a2ac5SXiaoyao Li #include "hw/i386/x86.h"
18b455880eSXiaoyao Li #include "kvm_i386.h"
19756e12e7SXiaoyao Li #include "tdx.h"
20756e12e7SXiaoyao Li 
21*8eddedc3SXiaoyao Li static struct kvm_tdx_capabilities *tdx_caps;
22*8eddedc3SXiaoyao Li 
23*8eddedc3SXiaoyao Li enum tdx_ioctl_level {
24*8eddedc3SXiaoyao Li     TDX_VM_IOCTL,
25*8eddedc3SXiaoyao Li     TDX_VCPU_IOCTL,
26*8eddedc3SXiaoyao Li };
27*8eddedc3SXiaoyao Li 
28*8eddedc3SXiaoyao Li static int tdx_ioctl_internal(enum tdx_ioctl_level level, void *state,
29*8eddedc3SXiaoyao Li                               int cmd_id, __u32 flags, void *data,
30*8eddedc3SXiaoyao Li                               Error **errp)
31631a2ac5SXiaoyao Li {
32*8eddedc3SXiaoyao Li     struct kvm_tdx_cmd tdx_cmd = {};
33*8eddedc3SXiaoyao Li     int r;
34*8eddedc3SXiaoyao Li 
35*8eddedc3SXiaoyao Li     const char *tdx_ioctl_name[] = {
36*8eddedc3SXiaoyao Li         [KVM_TDX_CAPABILITIES] = "KVM_TDX_CAPABILITIES",
37*8eddedc3SXiaoyao Li         [KVM_TDX_INIT_VM] = "KVM_TDX_INIT_VM",
38*8eddedc3SXiaoyao Li         [KVM_TDX_INIT_VCPU] = "KVM_TDX_INIT_VCPU",
39*8eddedc3SXiaoyao Li         [KVM_TDX_INIT_MEM_REGION] = "KVM_TDX_INIT_MEM_REGION",
40*8eddedc3SXiaoyao Li         [KVM_TDX_FINALIZE_VM] = "KVM_TDX_FINALIZE_VM",
41*8eddedc3SXiaoyao Li         [KVM_TDX_GET_CPUID] = "KVM_TDX_GET_CPUID",
42*8eddedc3SXiaoyao Li     };
43*8eddedc3SXiaoyao Li 
44*8eddedc3SXiaoyao Li     tdx_cmd.id = cmd_id;
45*8eddedc3SXiaoyao Li     tdx_cmd.flags = flags;
46*8eddedc3SXiaoyao Li     tdx_cmd.data = (__u64)(unsigned long)data;
47*8eddedc3SXiaoyao Li 
48*8eddedc3SXiaoyao Li     switch (level) {
49*8eddedc3SXiaoyao Li     case TDX_VM_IOCTL:
50*8eddedc3SXiaoyao Li         r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_OP, &tdx_cmd);
51*8eddedc3SXiaoyao Li         break;
52*8eddedc3SXiaoyao Li     case TDX_VCPU_IOCTL:
53*8eddedc3SXiaoyao Li         r = kvm_vcpu_ioctl(state, KVM_MEMORY_ENCRYPT_OP, &tdx_cmd);
54*8eddedc3SXiaoyao Li         break;
55*8eddedc3SXiaoyao Li     default:
56*8eddedc3SXiaoyao Li         error_setg(errp, "Invalid tdx_ioctl_level %d", level);
57*8eddedc3SXiaoyao Li         return -EINVAL;
58*8eddedc3SXiaoyao Li     }
59*8eddedc3SXiaoyao Li 
60*8eddedc3SXiaoyao Li     if (r < 0) {
61*8eddedc3SXiaoyao Li         error_setg_errno(errp, -r, "TDX ioctl %s failed, hw_errors: 0x%llx",
62*8eddedc3SXiaoyao Li                          tdx_ioctl_name[cmd_id], tdx_cmd.hw_error);
63*8eddedc3SXiaoyao Li     }
64*8eddedc3SXiaoyao Li     return r;
65*8eddedc3SXiaoyao Li }
66*8eddedc3SXiaoyao Li 
67*8eddedc3SXiaoyao Li static inline int tdx_vm_ioctl(int cmd_id, __u32 flags, void *data,
68*8eddedc3SXiaoyao Li                                Error **errp)
69*8eddedc3SXiaoyao Li {
70*8eddedc3SXiaoyao Li     return tdx_ioctl_internal(TDX_VM_IOCTL, NULL, cmd_id, flags, data, errp);
71*8eddedc3SXiaoyao Li }
72*8eddedc3SXiaoyao Li 
73*8eddedc3SXiaoyao Li static inline int tdx_vcpu_ioctl(CPUState *cpu, int cmd_id, __u32 flags,
74*8eddedc3SXiaoyao Li                                  void *data, Error **errp)
75*8eddedc3SXiaoyao Li {
76*8eddedc3SXiaoyao Li     return  tdx_ioctl_internal(TDX_VCPU_IOCTL, cpu, cmd_id, flags, data, errp);
77*8eddedc3SXiaoyao Li }
78*8eddedc3SXiaoyao Li 
79*8eddedc3SXiaoyao Li static int get_tdx_capabilities(Error **errp)
80*8eddedc3SXiaoyao Li {
81*8eddedc3SXiaoyao Li     struct kvm_tdx_capabilities *caps;
82*8eddedc3SXiaoyao Li     /* 1st generation of TDX reports 6 cpuid configs */
83*8eddedc3SXiaoyao Li     int nr_cpuid_configs = 6;
84*8eddedc3SXiaoyao Li     size_t size;
85*8eddedc3SXiaoyao Li     int r;
86*8eddedc3SXiaoyao Li 
87*8eddedc3SXiaoyao Li     do {
88*8eddedc3SXiaoyao Li         Error *local_err = NULL;
89*8eddedc3SXiaoyao Li         size = sizeof(struct kvm_tdx_capabilities) +
90*8eddedc3SXiaoyao Li                       nr_cpuid_configs * sizeof(struct kvm_cpuid_entry2);
91*8eddedc3SXiaoyao Li         caps = g_malloc0(size);
92*8eddedc3SXiaoyao Li         caps->cpuid.nent = nr_cpuid_configs;
93*8eddedc3SXiaoyao Li 
94*8eddedc3SXiaoyao Li         r = tdx_vm_ioctl(KVM_TDX_CAPABILITIES, 0, caps, &local_err);
95*8eddedc3SXiaoyao Li         if (r == -E2BIG) {
96*8eddedc3SXiaoyao Li             g_free(caps);
97*8eddedc3SXiaoyao Li             nr_cpuid_configs *= 2;
98*8eddedc3SXiaoyao Li             if (nr_cpuid_configs > KVM_MAX_CPUID_ENTRIES) {
99*8eddedc3SXiaoyao Li                 error_report("KVM TDX seems broken that number of CPUID entries"
100*8eddedc3SXiaoyao Li                              " in kvm_tdx_capabilities exceeds limit: %d",
101*8eddedc3SXiaoyao Li                              KVM_MAX_CPUID_ENTRIES);
102*8eddedc3SXiaoyao Li                 error_propagate(errp, local_err);
103*8eddedc3SXiaoyao Li                 return r;
104*8eddedc3SXiaoyao Li             }
105*8eddedc3SXiaoyao Li             error_free(local_err);
106*8eddedc3SXiaoyao Li         } else if (r < 0) {
107*8eddedc3SXiaoyao Li             g_free(caps);
108*8eddedc3SXiaoyao Li             error_propagate(errp, local_err);
109*8eddedc3SXiaoyao Li             return r;
110*8eddedc3SXiaoyao Li         }
111*8eddedc3SXiaoyao Li     } while (r == -E2BIG);
112*8eddedc3SXiaoyao Li 
113*8eddedc3SXiaoyao Li     tdx_caps = caps;
114631a2ac5SXiaoyao Li 
115631a2ac5SXiaoyao Li     return 0;
116631a2ac5SXiaoyao Li }
117631a2ac5SXiaoyao Li 
118*8eddedc3SXiaoyao Li static int tdx_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
119*8eddedc3SXiaoyao Li {
120*8eddedc3SXiaoyao Li     int r = 0;
121*8eddedc3SXiaoyao Li 
122*8eddedc3SXiaoyao Li     kvm_mark_guest_state_protected();
123*8eddedc3SXiaoyao Li 
124*8eddedc3SXiaoyao Li     if (!tdx_caps) {
125*8eddedc3SXiaoyao Li         r = get_tdx_capabilities(errp);
126*8eddedc3SXiaoyao Li     }
127*8eddedc3SXiaoyao Li 
128*8eddedc3SXiaoyao Li     return r;
129*8eddedc3SXiaoyao Li }
130*8eddedc3SXiaoyao Li 
131b455880eSXiaoyao Li static int tdx_kvm_type(X86ConfidentialGuest *cg)
132b455880eSXiaoyao Li {
133b455880eSXiaoyao Li     /* Do the object check */
134b455880eSXiaoyao Li     TDX_GUEST(cg);
135b455880eSXiaoyao Li 
136b455880eSXiaoyao Li     return KVM_X86_TDX_VM;
137b455880eSXiaoyao Li }
138b455880eSXiaoyao Li 
139756e12e7SXiaoyao Li /* tdx guest */
140756e12e7SXiaoyao Li OBJECT_DEFINE_TYPE_WITH_INTERFACES(TdxGuest,
141756e12e7SXiaoyao Li                                    tdx_guest,
142756e12e7SXiaoyao Li                                    TDX_GUEST,
143756e12e7SXiaoyao Li                                    X86_CONFIDENTIAL_GUEST,
144756e12e7SXiaoyao Li                                    { TYPE_USER_CREATABLE },
145756e12e7SXiaoyao Li                                    { NULL })
146756e12e7SXiaoyao Li 
147756e12e7SXiaoyao Li static void tdx_guest_init(Object *obj)
148756e12e7SXiaoyao Li {
149756e12e7SXiaoyao Li     ConfidentialGuestSupport *cgs = CONFIDENTIAL_GUEST_SUPPORT(obj);
150756e12e7SXiaoyao Li     TdxGuest *tdx = TDX_GUEST(obj);
151756e12e7SXiaoyao Li 
152756e12e7SXiaoyao Li     cgs->require_guest_memfd = true;
153756e12e7SXiaoyao Li     tdx->attributes = 0;
154756e12e7SXiaoyao Li 
155756e12e7SXiaoyao Li     object_property_add_uint64_ptr(obj, "attributes", &tdx->attributes,
156756e12e7SXiaoyao Li                                    OBJ_PROP_FLAG_READWRITE);
157756e12e7SXiaoyao Li }
158756e12e7SXiaoyao Li 
159756e12e7SXiaoyao Li static void tdx_guest_finalize(Object *obj)
160756e12e7SXiaoyao Li {
161756e12e7SXiaoyao Li }
162756e12e7SXiaoyao Li 
163756e12e7SXiaoyao Li static void tdx_guest_class_init(ObjectClass *oc, const void *data)
164756e12e7SXiaoyao Li {
165631a2ac5SXiaoyao Li     ConfidentialGuestSupportClass *klass = CONFIDENTIAL_GUEST_SUPPORT_CLASS(oc);
166b455880eSXiaoyao Li     X86ConfidentialGuestClass *x86_klass = X86_CONFIDENTIAL_GUEST_CLASS(oc);
167b455880eSXiaoyao Li 
168631a2ac5SXiaoyao Li     klass->kvm_init = tdx_kvm_init;
169b455880eSXiaoyao Li     x86_klass->kvm_type = tdx_kvm_type;
170756e12e7SXiaoyao Li }
171