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 "qapi/qapi-commands-misc-target.h"
22 #include "exec/address-spaces.h"
23 #include "sysemu/hw_accel.h"
24 #include "sysemu/reset.h"
25 #include <sys/ioctl.h>
26 #include "hw/acpi/aml-build.h"
28 #define SGX_MAX_EPC_SECTIONS 8
29 #define SGX_CPUID_EPC_INVALID 0x0
31 /* A valid EPC section. */
32 #define SGX_CPUID_EPC_SECTION 0x1
33 #define SGX_CPUID_EPC_MASK 0xF
35 #define SGX_MAGIC 0xA4
36 #define SGX_IOC_VEPC_REMOVE_ALL _IO(SGX_MAGIC, 0x04)
40 static int sgx_epc_device_list(Object
*obj
, void *opaque
)
42 GSList
**list
= opaque
;
44 if (object_dynamic_cast(obj
, TYPE_SGX_EPC
)) {
45 *list
= g_slist_append(*list
, DEVICE(obj
));
48 object_child_foreach(obj
, sgx_epc_device_list
, opaque
);
52 static GSList
*sgx_epc_get_device_list(void)
56 object_child_foreach(qdev_get_machine(), sgx_epc_device_list
, &list
);
60 void sgx_epc_build_srat(GArray
*table_data
)
62 GSList
*device_list
= sgx_epc_get_device_list();
64 for (; device_list
; device_list
= device_list
->next
) {
65 DeviceState
*dev
= device_list
->data
;
66 Object
*obj
= OBJECT(dev
);
70 node
= object_property_get_uint(obj
, SGX_EPC_NUMA_NODE_PROP
,
72 addr
= object_property_get_uint(obj
, SGX_EPC_ADDR_PROP
, &error_abort
);
73 size
= object_property_get_uint(obj
, SGX_EPC_SIZE_PROP
, &error_abort
);
75 build_srat_memory(table_data
, addr
, size
, node
, MEM_AFFINITY_ENABLED
);
77 g_slist_free(device_list
);
80 static uint64_t sgx_calc_section_metric(uint64_t low
, uint64_t high
)
82 return (low
& MAKE_64BIT_MASK(12, 20)) +
83 ((high
& MAKE_64BIT_MASK(0, 20)) << 32);
86 static SGXEPCSectionList
*sgx_calc_host_epc_sections(uint64_t *size
)
88 SGXEPCSectionList
*head
= NULL
, **tail
= &head
;
89 SGXEPCSection
*section
;
91 uint32_t eax
, ebx
, ecx
, edx
;
94 for (i
= 0; i
< SGX_MAX_EPC_SECTIONS
; i
++) {
95 host_cpuid(0x12, i
+ 2, &eax
, &ebx
, &ecx
, &edx
);
97 type
= eax
& SGX_CPUID_EPC_MASK
;
98 if (type
== SGX_CPUID_EPC_INVALID
) {
102 if (type
!= SGX_CPUID_EPC_SECTION
) {
106 section
= g_new0(SGXEPCSection
, 1);
108 section
->size
= sgx_calc_section_metric(ecx
, edx
);
109 *size
+= section
->size
;
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
;
162 int fd
= qemu_open_old("/dev/sgx_vepc", O_RDWR
);
164 error_setg(errp
, "SGX is not enabled in KVM");
168 info
= g_new0(SGXInfo
, 1);
169 host_cpuid(0x7, 0, &eax
, &ebx
, &ecx
, &edx
);
171 info
->sgx
= ebx
& (1U << 2) ? true : false;
172 info
->flc
= ecx
& (1U << 30) ? true : false;
174 host_cpuid(0x12, 0, &eax
, &ebx
, &ecx
, &edx
);
175 info
->sgx1
= eax
& (1U << 0) ? true : false;
176 info
->sgx2
= eax
& (1U << 1) ? true : false;
178 info
->sections
= sgx_calc_host_epc_sections(&size
);
179 info
->section_size
= size
;
186 static SGXEPCSectionList
*sgx_get_epc_sections_list(void)
188 GSList
*device_list
= sgx_epc_get_device_list();
189 SGXEPCSectionList
*head
= NULL
, **tail
= &head
;
190 SGXEPCSection
*section
;
192 for (; device_list
; device_list
= device_list
->next
) {
193 DeviceState
*dev
= device_list
->data
;
194 Object
*obj
= OBJECT(dev
);
196 section
= g_new0(SGXEPCSection
, 1);
197 section
->node
= object_property_get_uint(obj
, SGX_EPC_NUMA_NODE_PROP
,
199 section
->size
= object_property_get_uint(obj
, SGX_EPC_SIZE_PROP
,
201 QAPI_LIST_APPEND(tail
, section
);
203 g_slist_free(device_list
);
208 SGXInfo
*qmp_query_sgx(Error
**errp
)
210 SGXInfo
*info
= NULL
;
211 X86MachineState
*x86ms
;
212 PCMachineState
*pcms
=
213 (PCMachineState
*)object_dynamic_cast(qdev_get_machine(),
216 error_setg(errp
, "SGX is only supported on PC machines");
220 x86ms
= X86_MACHINE(pcms
);
221 if (!x86ms
->sgx_epc_list
) {
222 error_setg(errp
, "No EPC regions defined, SGX not available");
226 SGXEPCState
*sgx_epc
= &pcms
->sgx_epc
;
227 info
= g_new0(SGXInfo
, 1);
233 info
->section_size
= sgx_epc
->size
;
234 info
->sections
= sgx_get_epc_sections_list();
239 void hmp_info_sgx(Monitor
*mon
, const QDict
*qdict
)
242 SGXEPCSectionList
*section_list
, *section
;
243 g_autoptr(SGXInfo
) info
= qmp_query_sgx(&err
);
246 error_report_err(err
);
249 monitor_printf(mon
, "SGX support: %s\n",
250 info
->sgx
? "enabled" : "disabled");
251 monitor_printf(mon
, "SGX1 support: %s\n",
252 info
->sgx1
? "enabled" : "disabled");
253 monitor_printf(mon
, "SGX2 support: %s\n",
254 info
->sgx2
? "enabled" : "disabled");
255 monitor_printf(mon
, "FLC support: %s\n",
256 info
->flc
? "enabled" : "disabled");
257 monitor_printf(mon
, "size: %" PRIu64
"\n",
260 section_list
= info
->sections
;
261 for (section
= section_list
; section
; section
= section
->next
) {
262 monitor_printf(mon
, "NUMA node #%" PRId64
": ",
263 section
->value
->node
);
264 monitor_printf(mon
, "size=%" PRIu64
"\n",
265 section
->value
->size
);
269 bool sgx_epc_get_section(int section_nr
, uint64_t *addr
, uint64_t *size
)
271 PCMachineState
*pcms
= PC_MACHINE(qdev_get_machine());
274 if (pcms
->sgx_epc
.size
== 0 || pcms
->sgx_epc
.nr_sections
<= section_nr
) {
278 epc
= pcms
->sgx_epc
.sections
[section_nr
];
281 *size
= memory_device_get_region_size(MEMORY_DEVICE(epc
), &error_fatal
);
286 void pc_machine_init_sgx_epc(PCMachineState
*pcms
)
288 SGXEPCState
*sgx_epc
= &pcms
->sgx_epc
;
289 X86MachineState
*x86ms
= X86_MACHINE(pcms
);
290 SgxEPCList
*list
= NULL
;
293 memset(sgx_epc
, 0, sizeof(SGXEPCState
));
294 if (!x86ms
->sgx_epc_list
) {
298 sgx_epc
->base
= 0x100000000ULL
+ x86ms
->above_4g_mem_size
;
300 memory_region_init(&sgx_epc
->mr
, OBJECT(pcms
), "sgx-epc", UINT64_MAX
);
301 memory_region_add_subregion(get_system_memory(), sgx_epc
->base
,
304 for (list
= x86ms
->sgx_epc_list
; list
; list
= list
->next
) {
305 obj
= object_new("sgx-epc");
307 /* set the memdev link with memory backend */
308 object_property_parse(obj
, SGX_EPC_MEMDEV_PROP
, list
->value
->memdev
,
310 /* set the numa node property for sgx epc object */
311 object_property_set_uint(obj
, SGX_EPC_NUMA_NODE_PROP
, list
->value
->node
,
313 object_property_set_bool(obj
, "realized", true, &error_fatal
);
317 if ((sgx_epc
->base
+ sgx_epc
->size
) < sgx_epc
->base
) {
318 error_report("Size of all 'sgx-epc' =0x%"PRIu64
" causes EPC to wrap",
323 memory_region_set_size(&sgx_epc
->mr
, sgx_epc
->size
);
325 /* register the reset callback for sgx epc */
326 qemu_register_reset(sgx_epc_reset
, NULL
);