]> git.proxmox.com Git - mirror_qemu.git/blame - hw/i386/sgx.c
Merge remote-tracking branch 'remotes/thuth/tags/pull-request-2021-10-15' into staging
[mirror_qemu.git] / hw / i386 / sgx.c
CommitLineData
1dec2e1f
SC
1/*
2 * SGX common code
3 *
4 * Copyright (C) 2021 Intel Corporation
5 *
6 * Authors:
7 * Yang Zhong<yang.zhong@intel.com>
8 * Sean Christopherson <sean.j.christopherson@intel.com>
9 *
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.
12 */
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"
6e81733e
PMD
18#include "monitor/monitor.h"
19#include "monitor/hmp-target.h"
1dec2e1f 20#include "qapi/error.h"
02165856 21#include "qapi/qapi-commands-misc-target.h"
1dec2e1f 22#include "exec/address-spaces.h"
0205c4fa
YZ
23#include "sysemu/hw_accel.h"
24
25#define SGX_MAX_EPC_SECTIONS 8
26#define SGX_CPUID_EPC_INVALID 0x0
27
28/* A valid EPC section. */
29#define SGX_CPUID_EPC_SECTION 0x1
30#define SGX_CPUID_EPC_MASK 0xF
31
32static uint64_t sgx_calc_section_metric(uint64_t low, uint64_t high)
33{
34 return (low & MAKE_64BIT_MASK(12, 20)) +
35 ((high & MAKE_64BIT_MASK(0, 20)) << 32);
36}
37
38static uint64_t sgx_calc_host_epc_section_size(void)
39{
40 uint32_t i, type;
41 uint32_t eax, ebx, ecx, edx;
42 uint64_t size = 0;
43
44 for (i = 0; i < SGX_MAX_EPC_SECTIONS; i++) {
45 host_cpuid(0x12, i + 2, &eax, &ebx, &ecx, &edx);
46
47 type = eax & SGX_CPUID_EPC_MASK;
48 if (type == SGX_CPUID_EPC_INVALID) {
49 break;
50 }
51
52 if (type != SGX_CPUID_EPC_SECTION) {
53 break;
54 }
55
56 size += sgx_calc_section_metric(ecx, edx);
57 }
58
59 return size;
60}
61
02165856 62SGXInfo *qmp_query_sgx_capabilities(Error **errp)
0205c4fa
YZ
63{
64 SGXInfo *info = NULL;
65 uint32_t eax, ebx, ecx, edx;
66
67 int fd = qemu_open_old("/dev/sgx_vepc", O_RDWR);
68 if (fd < 0) {
69 error_setg(errp, "SGX is not enabled in KVM");
70 return NULL;
71 }
72
73 info = g_new0(SGXInfo, 1);
74 host_cpuid(0x7, 0, &eax, &ebx, &ecx, &edx);
75
76 info->sgx = ebx & (1U << 2) ? true : false;
77 info->flc = ecx & (1U << 30) ? true : false;
78
79 host_cpuid(0x12, 0, &eax, &ebx, &ecx, &edx);
80 info->sgx1 = eax & (1U << 0) ? true : false;
81 info->sgx2 = eax & (1U << 1) ? true : false;
82
83 info->section_size = sgx_calc_host_epc_section_size();
84
85 close(fd);
86
87 return info;
88}
57d874c4 89
6e81733e 90SGXInfo *qmp_query_sgx(Error **errp)
57d874c4
YZ
91{
92 SGXInfo *info = NULL;
93 X86MachineState *x86ms;
94 PCMachineState *pcms =
95 (PCMachineState *)object_dynamic_cast(qdev_get_machine(),
96 TYPE_PC_MACHINE);
97 if (!pcms) {
98 error_setg(errp, "SGX is only supported on PC machines");
99 return NULL;
100 }
101
102 x86ms = X86_MACHINE(pcms);
103 if (!x86ms->sgx_epc_list) {
104 error_setg(errp, "No EPC regions defined, SGX not available");
105 return NULL;
106 }
107
108 SGXEPCState *sgx_epc = &pcms->sgx_epc;
109 info = g_new0(SGXInfo, 1);
110
111 info->sgx = true;
112 info->sgx1 = true;
113 info->sgx2 = true;
114 info->flc = true;
115 info->section_size = sgx_epc->size;
116
117 return info;
118}
1dec2e1f 119
6e81733e
PMD
120void hmp_info_sgx(Monitor *mon, const QDict *qdict)
121{
122 Error *err = NULL;
123 g_autoptr(SGXInfo) info = qmp_query_sgx(&err);
124
125 if (err) {
126 error_report_err(err);
127 return;
128 }
129 monitor_printf(mon, "SGX support: %s\n",
130 info->sgx ? "enabled" : "disabled");
131 monitor_printf(mon, "SGX1 support: %s\n",
132 info->sgx1 ? "enabled" : "disabled");
133 monitor_printf(mon, "SGX2 support: %s\n",
134 info->sgx2 ? "enabled" : "disabled");
135 monitor_printf(mon, "FLC support: %s\n",
136 info->flc ? "enabled" : "disabled");
137 monitor_printf(mon, "size: %" PRIu64 "\n",
138 info->section_size);
139}
140
05fc8db7 141bool sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size)
1dec2e1f
SC
142{
143 PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
144 SGXEPCDevice *epc;
145
146 if (pcms->sgx_epc.size == 0 || pcms->sgx_epc.nr_sections <= section_nr) {
05fc8db7 147 return true;
1dec2e1f
SC
148 }
149
150 epc = pcms->sgx_epc.sections[section_nr];
151
152 *addr = epc->addr;
153 *size = memory_device_get_region_size(MEMORY_DEVICE(epc), &error_fatal);
154
05fc8db7 155 return false;
1dec2e1f
SC
156}
157
158void pc_machine_init_sgx_epc(PCMachineState *pcms)
159{
160 SGXEPCState *sgx_epc = &pcms->sgx_epc;
161 X86MachineState *x86ms = X86_MACHINE(pcms);
162 SgxEPCList *list = NULL;
163 Object *obj;
164
165 memset(sgx_epc, 0, sizeof(SGXEPCState));
166 if (!x86ms->sgx_epc_list) {
167 return;
168 }
169
170 sgx_epc->base = 0x100000000ULL + x86ms->above_4g_mem_size;
171
172 memory_region_init(&sgx_epc->mr, OBJECT(pcms), "sgx-epc", UINT64_MAX);
173 memory_region_add_subregion(get_system_memory(), sgx_epc->base,
174 &sgx_epc->mr);
175
176 for (list = x86ms->sgx_epc_list; list; list = list->next) {
177 obj = object_new("sgx-epc");
178
179 /* set the memdev link with memory backend */
180 object_property_parse(obj, SGX_EPC_MEMDEV_PROP, list->value->memdev,
181 &error_fatal);
182 object_property_set_bool(obj, "realized", true, &error_fatal);
183 object_unref(obj);
184 }
185
186 if ((sgx_epc->base + sgx_epc->size) < sgx_epc->base) {
187 error_report("Size of all 'sgx-epc' =0x%"PRIu64" causes EPC to wrap",
188 sgx_epc->size);
189 exit(EXIT_FAILURE);
190 }
191
192 memory_region_set_size(&sgx_epc->mr, sgx_epc->size);
193}