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 "qapi/error.h" 19 #include "exec/address-spaces.h" 20 #include "hw/i386/sgx.h" 21 #include "sysemu/hw_accel.h" 22 23 #define SGX_MAX_EPC_SECTIONS 8 24 #define SGX_CPUID_EPC_INVALID 0x0 25 26 /* A valid EPC section. */ 27 #define SGX_CPUID_EPC_SECTION 0x1 28 #define SGX_CPUID_EPC_MASK 0xF 29 30 static uint64_t sgx_calc_section_metric(uint64_t low, uint64_t high) 31 { 32 return (low & MAKE_64BIT_MASK(12, 20)) + 33 ((high & MAKE_64BIT_MASK(0, 20)) << 32); 34 } 35 36 static uint64_t sgx_calc_host_epc_section_size(void) 37 { 38 uint32_t i, type; 39 uint32_t eax, ebx, ecx, edx; 40 uint64_t size = 0; 41 42 for (i = 0; i < SGX_MAX_EPC_SECTIONS; i++) { 43 host_cpuid(0x12, i + 2, &eax, &ebx, &ecx, &edx); 44 45 type = eax & SGX_CPUID_EPC_MASK; 46 if (type == SGX_CPUID_EPC_INVALID) { 47 break; 48 } 49 50 if (type != SGX_CPUID_EPC_SECTION) { 51 break; 52 } 53 54 size += sgx_calc_section_metric(ecx, edx); 55 } 56 57 return size; 58 } 59 60 SGXInfo *sgx_get_capabilities(Error **errp) 61 { 62 SGXInfo *info = NULL; 63 uint32_t eax, ebx, ecx, edx; 64 65 int fd = qemu_open_old("/dev/sgx_vepc", O_RDWR); 66 if (fd < 0) { 67 error_setg(errp, "SGX is not enabled in KVM"); 68 return NULL; 69 } 70 71 info = g_new0(SGXInfo, 1); 72 host_cpuid(0x7, 0, &eax, &ebx, &ecx, &edx); 73 74 info->sgx = ebx & (1U << 2) ? true : false; 75 info->flc = ecx & (1U << 30) ? true : false; 76 77 host_cpuid(0x12, 0, &eax, &ebx, &ecx, &edx); 78 info->sgx1 = eax & (1U << 0) ? true : false; 79 info->sgx2 = eax & (1U << 1) ? true : false; 80 81 info->section_size = sgx_calc_host_epc_section_size(); 82 83 close(fd); 84 85 return info; 86 } 87 88 SGXInfo *sgx_get_info(Error **errp) 89 { 90 SGXInfo *info = NULL; 91 X86MachineState *x86ms; 92 PCMachineState *pcms = 93 (PCMachineState *)object_dynamic_cast(qdev_get_machine(), 94 TYPE_PC_MACHINE); 95 if (!pcms) { 96 error_setg(errp, "SGX is only supported on PC machines"); 97 return NULL; 98 } 99 100 x86ms = X86_MACHINE(pcms); 101 if (!x86ms->sgx_epc_list) { 102 error_setg(errp, "No EPC regions defined, SGX not available"); 103 return NULL; 104 } 105 106 SGXEPCState *sgx_epc = &pcms->sgx_epc; 107 info = g_new0(SGXInfo, 1); 108 109 info->sgx = true; 110 info->sgx1 = true; 111 info->sgx2 = true; 112 info->flc = true; 113 info->section_size = sgx_epc->size; 114 115 return info; 116 } 117 118 int sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size) 119 { 120 PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); 121 SGXEPCDevice *epc; 122 123 if (pcms->sgx_epc.size == 0 || pcms->sgx_epc.nr_sections <= section_nr) { 124 return 1; 125 } 126 127 epc = pcms->sgx_epc.sections[section_nr]; 128 129 *addr = epc->addr; 130 *size = memory_device_get_region_size(MEMORY_DEVICE(epc), &error_fatal); 131 132 return 0; 133 } 134 135 void pc_machine_init_sgx_epc(PCMachineState *pcms) 136 { 137 SGXEPCState *sgx_epc = &pcms->sgx_epc; 138 X86MachineState *x86ms = X86_MACHINE(pcms); 139 SgxEPCList *list = NULL; 140 Object *obj; 141 142 memset(sgx_epc, 0, sizeof(SGXEPCState)); 143 if (!x86ms->sgx_epc_list) { 144 return; 145 } 146 147 sgx_epc->base = 0x100000000ULL + x86ms->above_4g_mem_size; 148 149 memory_region_init(&sgx_epc->mr, OBJECT(pcms), "sgx-epc", UINT64_MAX); 150 memory_region_add_subregion(get_system_memory(), sgx_epc->base, 151 &sgx_epc->mr); 152 153 for (list = x86ms->sgx_epc_list; list; list = list->next) { 154 obj = object_new("sgx-epc"); 155 156 /* set the memdev link with memory backend */ 157 object_property_parse(obj, SGX_EPC_MEMDEV_PROP, list->value->memdev, 158 &error_fatal); 159 object_property_set_bool(obj, "realized", true, &error_fatal); 160 object_unref(obj); 161 } 162 163 if ((sgx_epc->base + sgx_epc->size) < sgx_epc->base) { 164 error_report("Size of all 'sgx-epc' =0x%"PRIu64" causes EPC to wrap", 165 sgx_epc->size); 166 exit(EXIT_FAILURE); 167 } 168 169 memory_region_set_size(&sgx_epc->mr, sgx_epc->size); 170 } 171