1 /* 2 * SGX EPC device 3 * 4 * Copyright (C) 2019 Intel Corporation 5 * 6 * Authors: 7 * Sean Christopherson <sean.j.christopherson@intel.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2 or later. 10 * See the COPYING file in the top-level directory. 11 */ 12 #include "qemu/osdep.h" 13 #include "hw/i386/pc.h" 14 #include "hw/i386/sgx-epc.h" 15 #include "hw/mem/memory-device.h" 16 #include "hw/qdev-properties.h" 17 #include "qapi/error.h" 18 #include "qapi/visitor.h" 19 #include "target/i386/cpu.h" 20 #include "exec/address-spaces.h" 21 22 static Property sgx_epc_properties[] = { 23 DEFINE_PROP_UINT64(SGX_EPC_ADDR_PROP, SGXEPCDevice, addr, 0), 24 DEFINE_PROP_UINT32(SGX_EPC_NUMA_NODE_PROP, SGXEPCDevice, node, 0), 25 DEFINE_PROP_LINK(SGX_EPC_MEMDEV_PROP, SGXEPCDevice, hostmem, 26 TYPE_MEMORY_BACKEND_EPC, HostMemoryBackendEpc *), 27 DEFINE_PROP_END_OF_LIST(), 28 }; 29 30 static void sgx_epc_get_size(Object *obj, Visitor *v, const char *name, 31 void *opaque, Error **errp) 32 { 33 Error *local_err = NULL; 34 uint64_t value; 35 36 value = memory_device_get_region_size(MEMORY_DEVICE(obj), &local_err); 37 if (local_err) { 38 error_propagate(errp, local_err); 39 return; 40 } 41 42 visit_type_uint64(v, name, &value, errp); 43 } 44 45 static void sgx_epc_init(Object *obj) 46 { 47 object_property_add(obj, SGX_EPC_SIZE_PROP, "uint64", sgx_epc_get_size, 48 NULL, NULL, NULL); 49 } 50 51 static void sgx_epc_realize(DeviceState *dev, Error **errp) 52 { 53 PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); 54 X86MachineState *x86ms = X86_MACHINE(pcms); 55 MemoryDeviceState *md = MEMORY_DEVICE(dev); 56 SGXEPCState *sgx_epc = &pcms->sgx_epc; 57 SGXEPCDevice *epc = SGX_EPC(dev); 58 HostMemoryBackend *hostmem; 59 const char *path; 60 61 if (x86ms->boot_cpus != 0) { 62 error_setg(errp, "'" TYPE_SGX_EPC "' can't be created after vCPUs," 63 "e.g. via -device"); 64 return; 65 } 66 67 if (!epc->hostmem) { 68 error_setg(errp, "'" SGX_EPC_MEMDEV_PROP "' property is not set"); 69 return; 70 } 71 hostmem = MEMORY_BACKEND(epc->hostmem); 72 if (host_memory_backend_is_mapped(hostmem)) { 73 path = object_get_canonical_path_component(OBJECT(hostmem)); 74 error_setg(errp, "can't use already busy memdev: %s", path); 75 return; 76 } 77 78 epc->addr = sgx_epc->base + sgx_epc->size; 79 80 memory_region_add_subregion(&sgx_epc->mr, epc->addr - sgx_epc->base, 81 host_memory_backend_get_memory(hostmem)); 82 83 host_memory_backend_set_mapped(hostmem, true); 84 85 sgx_epc->sections = g_renew(SGXEPCDevice *, sgx_epc->sections, 86 sgx_epc->nr_sections + 1); 87 sgx_epc->sections[sgx_epc->nr_sections++] = epc; 88 89 sgx_epc->size += memory_device_get_region_size(md, errp); 90 } 91 92 static void sgx_epc_unrealize(DeviceState *dev) 93 { 94 SGXEPCDevice *epc = SGX_EPC(dev); 95 HostMemoryBackend *hostmem = MEMORY_BACKEND(epc->hostmem); 96 97 host_memory_backend_set_mapped(hostmem, false); 98 } 99 100 static uint64_t sgx_epc_md_get_addr(const MemoryDeviceState *md) 101 { 102 const SGXEPCDevice *epc = SGX_EPC(md); 103 104 return epc->addr; 105 } 106 107 static void sgx_epc_md_set_addr(MemoryDeviceState *md, uint64_t addr, 108 Error **errp) 109 { 110 object_property_set_uint(OBJECT(md), SGX_EPC_ADDR_PROP, addr, errp); 111 } 112 113 static uint64_t sgx_epc_md_get_plugged_size(const MemoryDeviceState *md, 114 Error **errp) 115 { 116 return 0; 117 } 118 119 static MemoryRegion *sgx_epc_md_get_memory_region(MemoryDeviceState *md, 120 Error **errp) 121 { 122 SGXEPCDevice *epc = SGX_EPC(md); 123 HostMemoryBackend *hostmem; 124 125 if (!epc->hostmem) { 126 error_setg(errp, "'" SGX_EPC_MEMDEV_PROP "' property must be set"); 127 return NULL; 128 } 129 130 hostmem = MEMORY_BACKEND(epc->hostmem); 131 return host_memory_backend_get_memory(hostmem); 132 } 133 134 static void sgx_epc_md_fill_device_info(const MemoryDeviceState *md, 135 MemoryDeviceInfo *info) 136 { 137 SgxEPCDeviceInfo *se = g_new0(SgxEPCDeviceInfo, 1); 138 SGXEPCDevice *epc = SGX_EPC(md); 139 140 se->memaddr = epc->addr; 141 se->size = object_property_get_uint(OBJECT(epc), SGX_EPC_SIZE_PROP, 142 NULL); 143 se->node = object_property_get_uint(OBJECT(epc), SGX_EPC_NUMA_NODE_PROP, 144 NULL); 145 se->memdev = object_get_canonical_path(OBJECT(epc->hostmem)); 146 147 info->u.sgx_epc.data = se; 148 info->type = MEMORY_DEVICE_INFO_KIND_SGX_EPC; 149 } 150 151 static void sgx_epc_class_init(ObjectClass *oc, void *data) 152 { 153 DeviceClass *dc = DEVICE_CLASS(oc); 154 MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(oc); 155 156 dc->hotpluggable = false; 157 dc->realize = sgx_epc_realize; 158 dc->unrealize = sgx_epc_unrealize; 159 dc->desc = "SGX EPC section"; 160 dc->user_creatable = false; 161 device_class_set_props(dc, sgx_epc_properties); 162 163 mdc->get_addr = sgx_epc_md_get_addr; 164 mdc->set_addr = sgx_epc_md_set_addr; 165 mdc->get_plugged_size = sgx_epc_md_get_plugged_size; 166 mdc->get_memory_region = sgx_epc_md_get_memory_region; 167 mdc->fill_device_info = sgx_epc_md_fill_device_info; 168 } 169 170 static TypeInfo sgx_epc_info = { 171 .name = TYPE_SGX_EPC, 172 .parent = TYPE_DEVICE, 173 .instance_size = sizeof(SGXEPCDevice), 174 .instance_init = sgx_epc_init, 175 .class_init = sgx_epc_class_init, 176 .class_size = sizeof(DeviceClass), 177 .interfaces = (InterfaceInfo[]) { 178 { TYPE_MEMORY_DEVICE }, 179 { } 180 }, 181 }; 182 183 static void sgx_epc_register_types(void) 184 { 185 type_register_static(&sgx_epc_info); 186 } 187 188 type_init(sgx_epc_register_types) 189