sgx-epc.c (5497B)
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 22static 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 29static 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 44static 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 50static 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 91static 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 99static 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 106static 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 112static uint64_t sgx_epc_md_get_plugged_size(const MemoryDeviceState *md, 113 Error **errp) 114{ 115 return 0; 116} 117 118static 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 133static 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 148static 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 166static 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 179static void sgx_epc_register_types(void) 180{ 181 type_register_static(&sgx_epc_info); 182} 183 184type_init(sgx_epc_register_types)