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 "qemu/error-report.h" 22 #include "qapi/qapi-commands-misc-target.h" 23 #include "exec/address-spaces.h" 24 #include "sysemu/hw_accel.h" 25 #include "sysemu/reset.h" 26 #include <sys/ioctl.h> 27 #include "hw/acpi/aml-build.h" 28 29 #define SGX_MAX_EPC_SECTIONS 8 30 #define SGX_CPUID_EPC_INVALID 0x0 31 32 /* A valid EPC section. */ 33 #define SGX_CPUID_EPC_SECTION 0x1 34 #define SGX_CPUID_EPC_MASK 0xF 35 36 #define SGX_MAGIC 0xA4 37 #define SGX_IOC_VEPC_REMOVE_ALL _IO(SGX_MAGIC, 0x04) 38 39 #define RETRY_NUM 2 40 41 static int sgx_epc_device_list(Object *obj, void *opaque) 42 { 43 GSList **list = opaque; 44 45 if (object_dynamic_cast(obj, TYPE_SGX_EPC)) { 46 *list = g_slist_append(*list, DEVICE(obj)); 47 } 48 49 object_child_foreach(obj, sgx_epc_device_list, opaque); 50 return 0; 51 } 52 53 static GSList *sgx_epc_get_device_list(void) 54 { 55 GSList *list = NULL; 56 57 object_child_foreach(qdev_get_machine(), sgx_epc_device_list, &list); 58 return list; 59 } 60 61 void sgx_epc_build_srat(GArray *table_data) 62 { 63 GSList *device_list = sgx_epc_get_device_list(); 64 65 for (; device_list; device_list = device_list->next) { 66 DeviceState *dev = device_list->data; 67 Object *obj = OBJECT(dev); 68 uint64_t addr, size; 69 int node; 70 71 node = object_property_get_uint(obj, SGX_EPC_NUMA_NODE_PROP, 72 &error_abort); 73 addr = object_property_get_uint(obj, SGX_EPC_ADDR_PROP, &error_abort); 74 size = object_property_get_uint(obj, SGX_EPC_SIZE_PROP, &error_abort); 75 76 build_srat_memory(table_data, addr, size, node, MEM_AFFINITY_ENABLED); 77 } 78 g_slist_free(device_list); 79 } 80 81 static uint64_t sgx_calc_section_metric(uint64_t low, uint64_t high) 82 { 83 return (low & MAKE_64BIT_MASK(12, 20)) + 84 ((high & MAKE_64BIT_MASK(0, 20)) << 32); 85 } 86 87 static SGXEPCSectionList *sgx_calc_host_epc_sections(void) 88 { 89 SGXEPCSectionList *head = NULL, **tail = &head; 90 SGXEPCSection *section; 91 uint32_t i, type; 92 uint32_t eax, ebx, ecx, edx; 93 uint32_t j = 0; 94 95 for (i = 0; i < SGX_MAX_EPC_SECTIONS; i++) { 96 host_cpuid(0x12, i + 2, &eax, &ebx, &ecx, &edx); 97 98 type = eax & SGX_CPUID_EPC_MASK; 99 if (type == SGX_CPUID_EPC_INVALID) { 100 break; 101 } 102 103 if (type != SGX_CPUID_EPC_SECTION) { 104 break; 105 } 106 107 section = g_new0(SGXEPCSection, 1); 108 section->node = j++; 109 section->size = sgx_calc_section_metric(ecx, edx); 110 QAPI_LIST_APPEND(tail, section); 111 } 112 113 return head; 114 } 115 116 static void sgx_epc_reset(void *opaque) 117 { 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; 124 125 /* 126 * The second pass is needed to remove SECS pages that could not 127 * be removed during the first. 128 */ 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)); 135 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); 147 } 148 } 149 } 150 if (!failures) { 151 break; 152 } 153 } 154 } 155 156 SGXInfo *qmp_query_sgx_capabilities(Error **errp) 157 { 158 SGXInfo *info = NULL; 159 uint32_t eax, ebx, ecx, edx; 160 Error *local_err = NULL; 161 162 int fd = qemu_open("/dev/sgx_vepc", O_RDWR, &local_err); 163 if (fd < 0) { 164 error_append_hint(&local_err, "SGX is not enabled in KVM"); 165 error_propagate(errp, local_err); 166 return NULL; 167 } 168 169 info = g_new0(SGXInfo, 1); 170 host_cpuid(0x7, 0, &eax, &ebx, &ecx, &edx); 171 172 info->sgx = ebx & (1U << 2) ? true : false; 173 info->flc = ecx & (1U << 30) ? true : false; 174 175 host_cpuid(0x12, 0, &eax, &ebx, &ecx, &edx); 176 info->sgx1 = eax & (1U << 0) ? true : false; 177 info->sgx2 = eax & (1U << 1) ? true : false; 178 179 info->sections = sgx_calc_host_epc_sections(); 180 181 close(fd); 182 183 return info; 184 } 185 186 static SGXEPCSectionList *sgx_get_epc_sections_list(void) 187 { 188 GSList *device_list = sgx_epc_get_device_list(); 189 SGXEPCSectionList *head = NULL, **tail = &head; 190 SGXEPCSection *section; 191 192 for (; device_list; device_list = device_list->next) { 193 DeviceState *dev = device_list->data; 194 Object *obj = OBJECT(dev); 195 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); 202 } 203 g_slist_free(device_list); 204 205 return head; 206 } 207 208 SGXInfo *qmp_query_sgx(Error **errp) 209 { 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; 218 } 219 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; 224 } 225 226 info = g_new0(SGXInfo, 1); 227 228 info->sgx = true; 229 info->sgx1 = true; 230 info->sgx2 = true; 231 info->flc = true; 232 info->sections = sgx_get_epc_sections_list(); 233 234 return info; 235 } 236 237 void hmp_info_sgx(Monitor *mon, const QDict *qdict) 238 { 239 Error *err = NULL; 240 SGXEPCSectionList *section_list, *section; 241 g_autoptr(SGXInfo) info = qmp_query_sgx(&err); 242 uint64_t size = 0; 243 244 if (err) { 245 error_report_err(err); 246 return; 247 } 248 monitor_printf(mon, "SGX support: %s\n", 249 info->sgx ? "enabled" : "disabled"); 250 monitor_printf(mon, "SGX1 support: %s\n", 251 info->sgx1 ? "enabled" : "disabled"); 252 monitor_printf(mon, "SGX2 support: %s\n", 253 info->sgx2 ? "enabled" : "disabled"); 254 monitor_printf(mon, "FLC support: %s\n", 255 info->flc ? "enabled" : "disabled"); 256 257 section_list = info->sections; 258 for (section = section_list; section; section = section->next) { 259 monitor_printf(mon, "NUMA node #%" PRId64 ": ", 260 section->value->node); 261 monitor_printf(mon, "size=%" PRIu64 "\n", 262 section->value->size); 263 size += section->value->size; 264 } 265 monitor_printf(mon, "total size=%" PRIu64 "\n", 266 size); 267 } 268 269 bool sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size) 270 { 271 PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); 272 SGXEPCDevice *epc; 273 274 if (pcms->sgx_epc.size == 0 || pcms->sgx_epc.nr_sections <= section_nr) { 275 return true; 276 } 277 278 epc = pcms->sgx_epc.sections[section_nr]; 279 280 *addr = epc->addr; 281 *size = memory_device_get_region_size(MEMORY_DEVICE(epc), &error_fatal); 282 283 return false; 284 } 285 286 void pc_machine_init_sgx_epc(PCMachineState *pcms) 287 { 288 SGXEPCState *sgx_epc = &pcms->sgx_epc; 289 X86MachineState *x86ms = X86_MACHINE(pcms); 290 SgxEPCList *list = NULL; 291 292 memset(sgx_epc, 0, sizeof(SGXEPCState)); 293 if (!x86ms->sgx_epc_list) { 294 return; 295 } 296 297 sgx_epc->base = x86ms->above_4g_mem_start + x86ms->above_4g_mem_size; 298 299 memory_region_init(&sgx_epc->mr, OBJECT(pcms), "sgx-epc", UINT64_MAX); 300 memory_region_add_subregion(get_system_memory(), sgx_epc->base, 301 &sgx_epc->mr); 302 303 for (list = x86ms->sgx_epc_list; list; list = list->next) { 304 DeviceState *dev = qdev_new(TYPE_SGX_EPC); 305 306 /* set the memdev link with memory backend */ 307 object_property_parse(OBJECT(dev), SGX_EPC_MEMDEV_PROP, 308 list->value->memdev, &error_fatal); 309 /* set the numa node property for sgx epc object */ 310 object_property_set_uint(OBJECT(dev), SGX_EPC_NUMA_NODE_PROP, 311 list->value->node, &error_fatal); 312 qdev_realize_and_unref(dev, NULL, &error_fatal); 313 } 314 315 if ((sgx_epc->base + sgx_epc->size) < sgx_epc->base) { 316 error_report("Size of all 'sgx-epc' =0x%"PRIx64" causes EPC to wrap", 317 sgx_epc->size); 318 exit(EXIT_FAILURE); 319 } 320 321 memory_region_set_size(&sgx_epc->mr, sgx_epc->size); 322 323 /* register the reset callback for sgx epc */ 324 qemu_register_reset(sgx_epc_reset, NULL); 325 } 326