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