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" 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" 27 28 #define SGX_MAX_EPC_SECTIONS 8 29 #define SGX_CPUID_EPC_INVALID 0x0 30 31 /* A valid EPC section. */ 32 #define SGX_CPUID_EPC_SECTION 0x1 33 #define SGX_CPUID_EPC_MASK 0xF 34 35 #define SGX_MAGIC 0xA4 36 #define SGX_IOC_VEPC_REMOVE_ALL _IO(SGX_MAGIC, 0x04) 37 38 #define RETRY_NUM 2 39 40 static int sgx_epc_device_list(Object *obj, void *opaque) 41 { 42 GSList **list = opaque; 43 44 if (object_dynamic_cast(obj, TYPE_SGX_EPC)) { 45 *list = g_slist_append(*list, DEVICE(obj)); 46 } 47 48 object_child_foreach(obj, sgx_epc_device_list, opaque); 49 return 0; 50 } 51 52 static GSList *sgx_epc_get_device_list(void) 53 { 54 GSList *list = NULL; 55 56 object_child_foreach(qdev_get_machine(), sgx_epc_device_list, &list); 57 return list; 58 } 59 60 void sgx_epc_build_srat(GArray *table_data) 61 { 62 GSList *device_list = sgx_epc_get_device_list(); 63 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; 69 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); 74 75 build_srat_memory(table_data, addr, size, node, MEM_AFFINITY_ENABLED); 76 } 77 g_slist_free(device_list); 78 } 79 80 static uint64_t sgx_calc_section_metric(uint64_t low, uint64_t high) 81 { 82 return (low & MAKE_64BIT_MASK(12, 20)) + 83 ((high & MAKE_64BIT_MASK(0, 20)) << 32); 84 } 85 86 static SGXEPCSectionList *sgx_calc_host_epc_sections(void) 87 { 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; 93 94 for (i = 0; i < SGX_MAX_EPC_SECTIONS; i++) { 95 host_cpuid(0x12, i + 2, &eax, &ebx, &ecx, &edx); 96 97 type = eax & SGX_CPUID_EPC_MASK; 98 if (type == SGX_CPUID_EPC_INVALID) { 99 break; 100 } 101 102 if (type != SGX_CPUID_EPC_SECTION) { 103 break; 104 } 105 106 section = g_new0(SGXEPCSection, 1); 107 section->node = j++; 108 section->size = sgx_calc_section_metric(ecx, edx); 109 QAPI_LIST_APPEND(tail, section); 110 } 111 112 return head; 113 } 114 115 static void sgx_epc_reset(void *opaque) 116 { 117 PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); 118 HostMemoryBackend *hostmem; 119 SGXEPCDevice *epc; 120 int failures; 121 int fd, i, j, r; 122 static bool warned = false; 123 124 /* 125 * The second pass is needed to remove SECS pages that could not 126 * be removed during the first. 127 */ 128 for (i = 0; i < RETRY_NUM; i++) { 129 failures = 0; 130 for (j = 0; j < pcms->sgx_epc.nr_sections; j++) { 131 epc = pcms->sgx_epc.sections[j]; 132 hostmem = MEMORY_BACKEND(epc->hostmem); 133 fd = memory_region_get_fd(host_memory_backend_get_memory(hostmem)); 134 135 r = ioctl(fd, SGX_IOC_VEPC_REMOVE_ALL); 136 if (r == -ENOTTY && !warned) { 137 warned = true; 138 warn_report("kernel does not support SGX_IOC_VEPC_REMOVE_ALL"); 139 warn_report("SGX might operate incorrectly in the guest after reset"); 140 break; 141 } else if (r > 0) { 142 /* SECS pages remain */ 143 failures++; 144 if (i == 1) { 145 error_report("cannot reset vEPC section %d", j); 146 } 147 } 148 } 149 if (!failures) { 150 break; 151 } 152 } 153 } 154 155 SGXInfo *qmp_query_sgx_capabilities(Error **errp) 156 { 157 SGXInfo *info = NULL; 158 uint32_t eax, ebx, ecx, edx; 159 160 int fd = qemu_open_old("/dev/sgx_vepc", O_RDWR); 161 if (fd < 0) { 162 error_setg(errp, "SGX is not enabled in KVM"); 163 return NULL; 164 } 165 166 info = g_new0(SGXInfo, 1); 167 host_cpuid(0x7, 0, &eax, &ebx, &ecx, &edx); 168 169 info->sgx = ebx & (1U << 2) ? true : false; 170 info->flc = ecx & (1U << 30) ? true : false; 171 172 host_cpuid(0x12, 0, &eax, &ebx, &ecx, &edx); 173 info->sgx1 = eax & (1U << 0) ? true : false; 174 info->sgx2 = eax & (1U << 1) ? true : false; 175 176 info->sections = sgx_calc_host_epc_sections(); 177 178 close(fd); 179 180 return info; 181 } 182 183 static SGXEPCSectionList *sgx_get_epc_sections_list(void) 184 { 185 GSList *device_list = sgx_epc_get_device_list(); 186 SGXEPCSectionList *head = NULL, **tail = &head; 187 SGXEPCSection *section; 188 189 for (; device_list; device_list = device_list->next) { 190 DeviceState *dev = device_list->data; 191 Object *obj = OBJECT(dev); 192 193 section = g_new0(SGXEPCSection, 1); 194 section->node = object_property_get_uint(obj, SGX_EPC_NUMA_NODE_PROP, 195 &error_abort); 196 section->size = object_property_get_uint(obj, SGX_EPC_SIZE_PROP, 197 &error_abort); 198 QAPI_LIST_APPEND(tail, section); 199 } 200 g_slist_free(device_list); 201 202 return head; 203 } 204 205 SGXInfo *qmp_query_sgx(Error **errp) 206 { 207 SGXInfo *info = NULL; 208 X86MachineState *x86ms; 209 PCMachineState *pcms = 210 (PCMachineState *)object_dynamic_cast(qdev_get_machine(), 211 TYPE_PC_MACHINE); 212 if (!pcms) { 213 error_setg(errp, "SGX is only supported on PC machines"); 214 return NULL; 215 } 216 217 x86ms = X86_MACHINE(pcms); 218 if (!x86ms->sgx_epc_list) { 219 error_setg(errp, "No EPC regions defined, SGX not available"); 220 return NULL; 221 } 222 223 info = g_new0(SGXInfo, 1); 224 225 info->sgx = true; 226 info->sgx1 = true; 227 info->sgx2 = true; 228 info->flc = true; 229 info->sections = sgx_get_epc_sections_list(); 230 231 return info; 232 } 233 234 void hmp_info_sgx(Monitor *mon, const QDict *qdict) 235 { 236 Error *err = NULL; 237 SGXEPCSectionList *section_list, *section; 238 g_autoptr(SGXInfo) info = qmp_query_sgx(&err); 239 uint64_t size = 0; 240 241 if (err) { 242 error_report_err(err); 243 return; 244 } 245 monitor_printf(mon, "SGX support: %s\n", 246 info->sgx ? "enabled" : "disabled"); 247 monitor_printf(mon, "SGX1 support: %s\n", 248 info->sgx1 ? "enabled" : "disabled"); 249 monitor_printf(mon, "SGX2 support: %s\n", 250 info->sgx2 ? "enabled" : "disabled"); 251 monitor_printf(mon, "FLC support: %s\n", 252 info->flc ? "enabled" : "disabled"); 253 254 section_list = info->sections; 255 for (section = section_list; section; section = section->next) { 256 monitor_printf(mon, "NUMA node #%" PRId64 ": ", 257 section->value->node); 258 monitor_printf(mon, "size=%" PRIu64 "\n", 259 section->value->size); 260 size += section->value->size; 261 } 262 monitor_printf(mon, "total size=%" PRIu64 "\n", 263 size); 264 } 265 266 bool sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size) 267 { 268 PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); 269 SGXEPCDevice *epc; 270 271 if (pcms->sgx_epc.size == 0 || pcms->sgx_epc.nr_sections <= section_nr) { 272 return true; 273 } 274 275 epc = pcms->sgx_epc.sections[section_nr]; 276 277 *addr = epc->addr; 278 *size = memory_device_get_region_size(MEMORY_DEVICE(epc), &error_fatal); 279 280 return false; 281 } 282 283 void pc_machine_init_sgx_epc(PCMachineState *pcms) 284 { 285 SGXEPCState *sgx_epc = &pcms->sgx_epc; 286 X86MachineState *x86ms = X86_MACHINE(pcms); 287 SgxEPCList *list = NULL; 288 Object *obj; 289 290 memset(sgx_epc, 0, sizeof(SGXEPCState)); 291 if (!x86ms->sgx_epc_list) { 292 return; 293 } 294 295 sgx_epc->base = x86ms->above_4g_mem_start + x86ms->above_4g_mem_size; 296 297 memory_region_init(&sgx_epc->mr, OBJECT(pcms), "sgx-epc", UINT64_MAX); 298 memory_region_add_subregion(get_system_memory(), sgx_epc->base, 299 &sgx_epc->mr); 300 301 for (list = x86ms->sgx_epc_list; list; list = list->next) { 302 obj = object_new("sgx-epc"); 303 304 /* set the memdev link with memory backend */ 305 object_property_parse(obj, SGX_EPC_MEMDEV_PROP, list->value->memdev, 306 &error_fatal); 307 /* set the numa node property for sgx epc object */ 308 object_property_set_uint(obj, SGX_EPC_NUMA_NODE_PROP, list->value->node, 309 &error_fatal); 310 object_property_set_bool(obj, "realized", true, &error_fatal); 311 object_unref(obj); 312 } 313 314 if ((sgx_epc->base + sgx_epc->size) < sgx_epc->base) { 315 error_report("Size of all 'sgx-epc' =0x%"PRIx64" causes EPC to wrap", 316 sgx_epc->size); 317 exit(EXIT_FAILURE); 318 } 319 320 memory_region_set_size(&sgx_epc->mr, sgx_epc->size); 321 322 /* register the reset callback for sgx epc */ 323 qemu_register_reset(sgx_epc_reset, NULL); 324 } 325