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 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 62 SGXInfo *qmp_query_sgx_capabilities(Error **errp) 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 } 89 90 SGXInfo *qmp_query_sgx(Error **errp) 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 } 119 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 141 bool sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size) 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) { 147 return true; 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 155 return false; 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 } 194