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_LINK(SGX_EPC_MEMDEV_PROP, SGXEPCDevice, hostmem, 25 TYPE_MEMORY_BACKEND_EPC, HostMemoryBackendEpc *), 26 DEFINE_PROP_END_OF_LIST(), 27 }; 28 29 static void sgx_epc_get_size(Object *obj, Visitor *v, const char *name, 30 void *opaque, Error **errp) 31 { 32 Error *local_err = NULL; 33 uint64_t value; 34 35 value = memory_device_get_region_size(MEMORY_DEVICE(obj), &local_err); 36 if (local_err) { 37 error_propagate(errp, local_err); 38 return; 39 } 40 41 visit_type_uint64(v, name, &value, errp); 42 } 43 44 static void sgx_epc_init(Object *obj) 45 { 46 object_property_add(obj, SGX_EPC_SIZE_PROP, "uint64", sgx_epc_get_size, 47 NULL, NULL, NULL); 48 } 49 50 static void sgx_epc_realize(DeviceState *dev, Error **errp) 51 { 52 PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); 53 X86MachineState *x86ms = X86_MACHINE(pcms); 54 MemoryDeviceState *md = MEMORY_DEVICE(dev); 55 SGXEPCState *sgx_epc = &pcms->sgx_epc; 56 SGXEPCDevice *epc = SGX_EPC(dev); 57 HostMemoryBackend *hostmem; 58 const char *path; 59 60 if (x86ms->boot_cpus != 0) { 61 error_setg(errp, "'" TYPE_SGX_EPC "' can't be created after vCPUs," 62 "e.g. via -device"); 63 return; 64 } 65 66 if (!epc->hostmem) { 67 error_setg(errp, "'" SGX_EPC_MEMDEV_PROP "' property is not set"); 68 return; 69 } 70 hostmem = MEMORY_BACKEND(epc->hostmem); 71 if (host_memory_backend_is_mapped(hostmem)) { 72 path = object_get_canonical_path_component(OBJECT(hostmem)); 73 error_setg(errp, "can't use already busy memdev: %s", path); 74 return; 75 } 76 77 epc->addr = sgx_epc->base + sgx_epc->size; 78 79 memory_region_add_subregion(&sgx_epc->mr, epc->addr - sgx_epc->base, 80 host_memory_backend_get_memory(hostmem)); 81 82 host_memory_backend_set_mapped(hostmem, true); 83 84 sgx_epc->sections = g_renew(SGXEPCDevice *, sgx_epc->sections, 85 sgx_epc->nr_sections + 1); 86 sgx_epc->sections[sgx_epc->nr_sections++] = epc; 87 88 sgx_epc->size += memory_device_get_region_size(md, errp); 89 } 90 91 static void sgx_epc_unrealize(DeviceState *dev) 92 { 93 SGXEPCDevice *epc = SGX_EPC(dev); 94 HostMemoryBackend *hostmem = MEMORY_BACKEND(epc->hostmem); 95 96 host_memory_backend_set_mapped(hostmem, false); 97 } 98 99 static uint64_t sgx_epc_md_get_addr(const MemoryDeviceState *md) 100 { 101 const SGXEPCDevice *epc = SGX_EPC(md); 102 103 return epc->addr; 104 } 105 106 static void sgx_epc_md_set_addr(MemoryDeviceState *md, uint64_t addr, 107 Error **errp) 108 { 109 object_property_set_uint(OBJECT(md), SGX_EPC_ADDR_PROP, addr, errp); 110 } 111 112 static uint64_t sgx_epc_md_get_plugged_size(const MemoryDeviceState *md, 113 Error **errp) 114 { 115 return 0; 116 } 117 118 static MemoryRegion *sgx_epc_md_get_memory_region(MemoryDeviceState *md, 119 Error **errp) 120 { 121 SGXEPCDevice *epc = SGX_EPC(md); 122 HostMemoryBackend *hostmem; 123 124 if (!epc->hostmem) { 125 error_setg(errp, "'" SGX_EPC_MEMDEV_PROP "' property must be set"); 126 return NULL; 127 } 128 129 hostmem = MEMORY_BACKEND(epc->hostmem); 130 return host_memory_backend_get_memory(hostmem); 131 } 132 133 static void sgx_epc_md_fill_device_info(const MemoryDeviceState *md, 134 MemoryDeviceInfo *info) 135 { 136 SgxEPCDeviceInfo *se = g_new0(SgxEPCDeviceInfo, 1); 137 SGXEPCDevice *epc = SGX_EPC(md); 138 139 se->memaddr = epc->addr; 140 se->size = object_property_get_uint(OBJECT(epc), SGX_EPC_SIZE_PROP, 141 NULL); 142 se->memdev = object_get_canonical_path(OBJECT(epc->hostmem)); 143 144 info->u.sgx_epc.data = se; 145 info->type = MEMORY_DEVICE_INFO_KIND_SGX_EPC; 146 } 147 148 static void sgx_epc_class_init(ObjectClass *oc, void *data) 149 { 150 DeviceClass *dc = DEVICE_CLASS(oc); 151 MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(oc); 152 153 dc->hotpluggable = false; 154 dc->realize = sgx_epc_realize; 155 dc->unrealize = sgx_epc_unrealize; 156 dc->desc = "SGX EPC section"; 157 device_class_set_props(dc, sgx_epc_properties); 158 159 mdc->get_addr = sgx_epc_md_get_addr; 160 mdc->set_addr = sgx_epc_md_set_addr; 161 mdc->get_plugged_size = sgx_epc_md_get_plugged_size; 162 mdc->get_memory_region = sgx_epc_md_get_memory_region; 163 mdc->fill_device_info = sgx_epc_md_fill_device_info; 164 } 165 166 static TypeInfo sgx_epc_info = { 167 .name = TYPE_SGX_EPC, 168 .parent = TYPE_DEVICE, 169 .instance_size = sizeof(SGXEPCDevice), 170 .instance_init = sgx_epc_init, 171 .class_init = sgx_epc_class_init, 172 .class_size = sizeof(DeviceClass), 173 .interfaces = (InterfaceInfo[]) { 174 { TYPE_MEMORY_DEVICE }, 175 { } 176 }, 177 }; 178 179 static void sgx_epc_register_types(void) 180 { 181 type_register_static(&sgx_epc_info); 182 } 183 184 type_init(sgx_epc_register_types) 185