target/arm: Postpone interpretation of stage 2 descriptor attribute bits
[qemu/ar7.git] / hw / i386 / sgx.c
bloba44d66ba2afc3c8780b294b0d7e12e95471dbb5d
1 /*
2 * SGX common code
4 * Copyright (C) 2021 Intel Corporation
6 * Authors:
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)
38 #define RETRY_NUM 2
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);
49 return 0;
52 static GSList *sgx_epc_get_device_list(void)
54 GSList *list = NULL;
56 object_child_foreach(qdev_get_machine(), sgx_epc_device_list, &list);
57 return 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);
67 uint64_t addr, size;
68 int node;
70 node = object_property_get_uint(obj, SGX_EPC_NUMA_NODE_PROP,
71 &error_abort);
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;
90 uint32_t i, type;
91 uint32_t eax, ebx, ecx, edx;
92 uint32_t j = 0;
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) {
99 break;
102 if (type != SGX_CPUID_EPC_SECTION) {
103 break;
106 section = g_new0(SGXEPCSection, 1);
107 section->node = j++;
108 section->size = sgx_calc_section_metric(ecx, edx);
109 *size += section->size;
110 QAPI_LIST_APPEND(tail, section);
113 return head;
116 static void sgx_epc_reset(void *opaque)
118 PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
119 HostMemoryBackend *hostmem;
120 SGXEPCDevice *epc;
121 int failures;
122 int fd, i, j, r;
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++) {
130 failures = 0;
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) {
138 warned = true;
139 warn_report("kernel does not support SGX_IOC_VEPC_REMOVE_ALL");
140 warn_report("SGX might operate incorrectly in the guest after reset");
141 break;
142 } else if (r > 0) {
143 /* SECS pages remain */
144 failures++;
145 if (i == 1) {
146 error_report("cannot reset vEPC section %d", j);
150 if (!failures) {
151 break;
156 SGXInfo *qmp_query_sgx_capabilities(Error **errp)
158 SGXInfo *info = NULL;
159 uint32_t eax, ebx, ecx, edx;
160 uint64_t size = 0;
162 int fd = qemu_open_old("/dev/sgx_vepc", O_RDWR);
163 if (fd < 0) {
164 error_setg(errp, "SGX is not enabled in KVM");
165 return NULL;
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;
181 close(fd);
183 return info;
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,
198 &error_abort);
199 section->size = object_property_get_uint(obj, SGX_EPC_SIZE_PROP,
200 &error_abort);
201 QAPI_LIST_APPEND(tail, section);
203 g_slist_free(device_list);
205 return head;
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(),
214 TYPE_PC_MACHINE);
215 if (!pcms) {
216 error_setg(errp, "SGX is only supported on PC machines");
217 return NULL;
220 x86ms = X86_MACHINE(pcms);
221 if (!x86ms->sgx_epc_list) {
222 error_setg(errp, "No EPC regions defined, SGX not available");
223 return NULL;
226 SGXEPCState *sgx_epc = &pcms->sgx_epc;
227 info = g_new0(SGXInfo, 1);
229 info->sgx = true;
230 info->sgx1 = true;
231 info->sgx2 = true;
232 info->flc = true;
233 info->section_size = sgx_epc->size;
234 info->sections = sgx_get_epc_sections_list();
236 return info;
239 void hmp_info_sgx(Monitor *mon, const QDict *qdict)
241 Error *err = NULL;
242 SGXEPCSectionList *section_list, *section;
243 g_autoptr(SGXInfo) info = qmp_query_sgx(&err);
245 if (err) {
246 error_report_err(err);
247 return;
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",
258 info->section_size);
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());
272 SGXEPCDevice *epc;
274 if (pcms->sgx_epc.size == 0 || pcms->sgx_epc.nr_sections <= section_nr) {
275 return true;
278 epc = pcms->sgx_epc.sections[section_nr];
280 *addr = epc->addr;
281 *size = memory_device_get_region_size(MEMORY_DEVICE(epc), &error_fatal);
283 return false;
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;
291 Object *obj;
293 memset(sgx_epc, 0, sizeof(SGXEPCState));
294 if (!x86ms->sgx_epc_list) {
295 return;
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,
302 &sgx_epc->mr);
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,
309 &error_fatal);
310 /* set the numa node property for sgx epc object */
311 object_property_set_uint(obj, SGX_EPC_NUMA_NODE_PROP, list->value->node,
312 &error_fatal);
313 object_property_set_bool(obj, "realized", true, &error_fatal);
314 object_unref(obj);
317 if ((sgx_epc->base + sgx_epc->size) < sgx_epc->base) {
318 error_report("Size of all 'sgx-epc' =0x%"PRIx64" causes EPC to wrap",
319 sgx_epc->size);
320 exit(EXIT_FAILURE);
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);