]>
Commit | Line | Data |
---|---|---|
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 | ||
32 | static 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 | ||
38 | static 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 | 62 | SGXInfo *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 | 90 | SGXInfo *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 |
120 | void 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 | 141 | bool 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 | ||
158 | void 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 | } |