4 * Copyright (C) 2021 Intel Corporation
7 * Yang Zhong<yang.zhong@intel.com>
8 * Sean Christopherson <sean.j.christopherson@intel.com>
10 * This work is licensed under the terms of the GNU GPL, version 2 or later.
11 * See the COPYING file in the top-level directory.
13 #include "qemu/osdep.h"
14 #include "hw/i386/pc.h"
15 #include "hw/i386/sgx-epc.h"
16 #include "hw/mem/memory-device.h"
17 #include "monitor/qdev.h"
18 #include "monitor/monitor.h"
19 #include "monitor/hmp-target.h"
20 #include "qapi/error.h"
21 #include "qemu/error-report.h"
22 #include "qapi/qapi-commands-misc-target.h"
23 #include "exec/address-spaces.h"
24 #include "sysemu/hw_accel.h"
25 #include "sysemu/reset.h"
26 #include <sys/ioctl.h>
27 #include "hw/acpi/aml-build.h"
29 #define SGX_MAX_EPC_SECTIONS 8
30 #define SGX_CPUID_EPC_INVALID 0x0
32 /* A valid EPC section. */
33 #define SGX_CPUID_EPC_SECTION 0x1
34 #define SGX_CPUID_EPC_MASK 0xF
36 #define SGX_MAGIC 0xA4
37 #define SGX_IOC_VEPC_REMOVE_ALL _IO(SGX_MAGIC, 0x04)
41 static int sgx_epc_device_list(Object
*obj
, void *opaque
)
43 GSList
**list
= opaque
;
45 if (object_dynamic_cast(obj
, TYPE_SGX_EPC
)) {
46 *list
= g_slist_append(*list
, DEVICE(obj
));
49 object_child_foreach(obj
, sgx_epc_device_list
, opaque
);
53 static GSList
*sgx_epc_get_device_list(void)
57 object_child_foreach(qdev_get_machine(), sgx_epc_device_list
, &list
);
61 void sgx_epc_build_srat(GArray
*table_data
)
63 GSList
*device_list
= sgx_epc_get_device_list();
65 for (; device_list
; device_list
= device_list
->next
) {
66 DeviceState
*dev
= device_list
->data
;
67 Object
*obj
= OBJECT(dev
);
71 node
= object_property_get_uint(obj
, SGX_EPC_NUMA_NODE_PROP
,
73 addr
= object_property_get_uint(obj
, SGX_EPC_ADDR_PROP
, &error_abort
);
74 size
= object_property_get_uint(obj
, SGX_EPC_SIZE_PROP
, &error_abort
);
76 build_srat_memory(table_data
, addr
, size
, node
, MEM_AFFINITY_ENABLED
);
78 g_slist_free(device_list
);
81 static uint64_t sgx_calc_section_metric(uint64_t low
, uint64_t high
)
83 return (low
& MAKE_64BIT_MASK(12, 20)) +
84 ((high
& MAKE_64BIT_MASK(0, 20)) << 32);
87 static SGXEPCSectionList
*sgx_calc_host_epc_sections(void)
89 SGXEPCSectionList
*head
= NULL
, **tail
= &head
;
90 SGXEPCSection
*section
;
92 uint32_t eax
, ebx
, ecx
, edx
;
95 for (i
= 0; i
< SGX_MAX_EPC_SECTIONS
; i
++) {
96 host_cpuid(0x12, i
+ 2, &eax
, &ebx
, &ecx
, &edx
);
98 type
= eax
& SGX_CPUID_EPC_MASK
;
99 if (type
== SGX_CPUID_EPC_INVALID
) {
103 if (type
!= SGX_CPUID_EPC_SECTION
) {
107 section
= g_new0(SGXEPCSection
, 1);
109 section
->size
= sgx_calc_section_metric(ecx
, edx
);
110 QAPI_LIST_APPEND(tail
, section
);
116 static void sgx_epc_reset(void *opaque
)
118 PCMachineState
*pcms
= PC_MACHINE(qdev_get_machine());
119 HostMemoryBackend
*hostmem
;
123 static bool warned
= false;
126 * The second pass is needed to remove SECS pages that could not
127 * be removed during the first.
129 for (i
= 0; i
< RETRY_NUM
; i
++) {
131 for (j
= 0; j
< pcms
->sgx_epc
.nr_sections
; j
++) {
132 epc
= pcms
->sgx_epc
.sections
[j
];
133 hostmem
= MEMORY_BACKEND(epc
->hostmem
);
134 fd
= memory_region_get_fd(host_memory_backend_get_memory(hostmem
));
136 r
= ioctl(fd
, SGX_IOC_VEPC_REMOVE_ALL
);
137 if (r
== -ENOTTY
&& !warned
) {
139 warn_report("kernel does not support SGX_IOC_VEPC_REMOVE_ALL");
140 warn_report("SGX might operate incorrectly in the guest after reset");
143 /* SECS pages remain */
146 error_report("cannot reset vEPC section %d", j
);
156 SGXInfo
*qmp_query_sgx_capabilities(Error
**errp
)
158 SGXInfo
*info
= NULL
;
159 uint32_t eax
, ebx
, ecx
, edx
;
161 int fd
= qemu_open_old("/dev/sgx_vepc", O_RDWR
);
163 error_setg(errp
, "SGX is not enabled in KVM");
167 info
= g_new0(SGXInfo
, 1);
168 host_cpuid(0x7, 0, &eax
, &ebx
, &ecx
, &edx
);
170 info
->sgx
= ebx
& (1U << 2) ? true : false;
171 info
->flc
= ecx
& (1U << 30) ? true : false;
173 host_cpuid(0x12, 0, &eax
, &ebx
, &ecx
, &edx
);
174 info
->sgx1
= eax
& (1U << 0) ? true : false;
175 info
->sgx2
= eax
& (1U << 1) ? true : false;
177 info
->sections
= sgx_calc_host_epc_sections();
184 static SGXEPCSectionList
*sgx_get_epc_sections_list(void)
186 GSList
*device_list
= sgx_epc_get_device_list();
187 SGXEPCSectionList
*head
= NULL
, **tail
= &head
;
188 SGXEPCSection
*section
;
190 for (; device_list
; device_list
= device_list
->next
) {
191 DeviceState
*dev
= device_list
->data
;
192 Object
*obj
= OBJECT(dev
);
194 section
= g_new0(SGXEPCSection
, 1);
195 section
->node
= object_property_get_uint(obj
, SGX_EPC_NUMA_NODE_PROP
,
197 section
->size
= object_property_get_uint(obj
, SGX_EPC_SIZE_PROP
,
199 QAPI_LIST_APPEND(tail
, section
);
201 g_slist_free(device_list
);
206 SGXInfo
*qmp_query_sgx(Error
**errp
)
208 SGXInfo
*info
= NULL
;
209 X86MachineState
*x86ms
;
210 PCMachineState
*pcms
=
211 (PCMachineState
*)object_dynamic_cast(qdev_get_machine(),
214 error_setg(errp
, "SGX is only supported on PC machines");
218 x86ms
= X86_MACHINE(pcms
);
219 if (!x86ms
->sgx_epc_list
) {
220 error_setg(errp
, "No EPC regions defined, SGX not available");
224 info
= g_new0(SGXInfo
, 1);
230 info
->sections
= sgx_get_epc_sections_list();
235 void hmp_info_sgx(Monitor
*mon
, const QDict
*qdict
)
238 SGXEPCSectionList
*section_list
, *section
;
239 g_autoptr(SGXInfo
) info
= qmp_query_sgx(&err
);
243 error_report_err(err
);
246 monitor_printf(mon
, "SGX support: %s\n",
247 info
->sgx
? "enabled" : "disabled");
248 monitor_printf(mon
, "SGX1 support: %s\n",
249 info
->sgx1
? "enabled" : "disabled");
250 monitor_printf(mon
, "SGX2 support: %s\n",
251 info
->sgx2
? "enabled" : "disabled");
252 monitor_printf(mon
, "FLC support: %s\n",
253 info
->flc
? "enabled" : "disabled");
255 section_list
= info
->sections
;
256 for (section
= section_list
; section
; section
= section
->next
) {
257 monitor_printf(mon
, "NUMA node #%" PRId64
": ",
258 section
->value
->node
);
259 monitor_printf(mon
, "size=%" PRIu64
"\n",
260 section
->value
->size
);
261 size
+= section
->value
->size
;
263 monitor_printf(mon
, "total size=%" PRIu64
"\n",
267 bool sgx_epc_get_section(int section_nr
, uint64_t *addr
, uint64_t *size
)
269 PCMachineState
*pcms
= PC_MACHINE(qdev_get_machine());
272 if (pcms
->sgx_epc
.size
== 0 || pcms
->sgx_epc
.nr_sections
<= section_nr
) {
276 epc
= pcms
->sgx_epc
.sections
[section_nr
];
279 *size
= memory_device_get_region_size(MEMORY_DEVICE(epc
), &error_fatal
);
284 void pc_machine_init_sgx_epc(PCMachineState
*pcms
)
286 SGXEPCState
*sgx_epc
= &pcms
->sgx_epc
;
287 X86MachineState
*x86ms
= X86_MACHINE(pcms
);
288 SgxEPCList
*list
= NULL
;
291 memset(sgx_epc
, 0, sizeof(SGXEPCState
));
292 if (!x86ms
->sgx_epc_list
) {
296 sgx_epc
->base
= x86ms
->above_4g_mem_start
+ x86ms
->above_4g_mem_size
;
298 memory_region_init(&sgx_epc
->mr
, OBJECT(pcms
), "sgx-epc", UINT64_MAX
);
299 memory_region_add_subregion(get_system_memory(), sgx_epc
->base
,
302 for (list
= x86ms
->sgx_epc_list
; list
; list
= list
->next
) {
303 obj
= object_new("sgx-epc");
305 /* set the memdev link with memory backend */
306 object_property_parse(obj
, SGX_EPC_MEMDEV_PROP
, list
->value
->memdev
,
308 /* set the numa node property for sgx epc object */
309 object_property_set_uint(obj
, SGX_EPC_NUMA_NODE_PROP
, list
->value
->node
,
311 object_property_set_bool(obj
, "realized", true, &error_fatal
);
315 if ((sgx_epc
->base
+ sgx_epc
->size
) < sgx_epc
->base
) {
316 error_report("Size of all 'sgx-epc' =0x%"PRIx64
" causes EPC to wrap",
321 memory_region_set_size(&sgx_epc
->mr
, sgx_epc
->size
);
323 /* register the reset callback for sgx epc */
324 qemu_register_reset(sgx_epc_reset
, NULL
);