180509c55SSean Christopherson /* 280509c55SSean Christopherson * SGX EPC device 380509c55SSean Christopherson * 480509c55SSean Christopherson * Copyright (C) 2019 Intel Corporation 580509c55SSean Christopherson * 680509c55SSean Christopherson * Authors: 780509c55SSean Christopherson * Sean Christopherson <sean.j.christopherson@intel.com> 880509c55SSean Christopherson * 980509c55SSean Christopherson * This work is licensed under the terms of the GNU GPL, version 2 or later. 1080509c55SSean Christopherson * See the COPYING file in the top-level directory. 1180509c55SSean Christopherson */ 1280509c55SSean Christopherson #include "qemu/osdep.h" 1380509c55SSean Christopherson #include "hw/i386/pc.h" 1480509c55SSean Christopherson #include "hw/i386/sgx-epc.h" 1580509c55SSean Christopherson #include "hw/mem/memory-device.h" 1680509c55SSean Christopherson #include "hw/qdev-properties.h" 1780509c55SSean Christopherson #include "qapi/error.h" 1880509c55SSean Christopherson #include "qapi/visitor.h" 1980509c55SSean Christopherson #include "target/i386/cpu.h" 20dfc56946SRichard Henderson #include "system/address-spaces.h" 2180509c55SSean Christopherson 2290d45638SRichard Henderson static const Property sgx_epc_properties[] = { 2380509c55SSean Christopherson DEFINE_PROP_UINT64(SGX_EPC_ADDR_PROP, SGXEPCDevice, addr, 0), 2411058123SYang Zhong DEFINE_PROP_UINT32(SGX_EPC_NUMA_NODE_PROP, SGXEPCDevice, node, 0), 2580509c55SSean Christopherson DEFINE_PROP_LINK(SGX_EPC_MEMDEV_PROP, SGXEPCDevice, hostmem, 2680509c55SSean Christopherson TYPE_MEMORY_BACKEND_EPC, HostMemoryBackendEpc *), 2780509c55SSean Christopherson }; 2880509c55SSean Christopherson 2980509c55SSean Christopherson static void sgx_epc_get_size(Object *obj, Visitor *v, const char *name, 3080509c55SSean Christopherson void *opaque, Error **errp) 3180509c55SSean Christopherson { 3280509c55SSean Christopherson Error *local_err = NULL; 3380509c55SSean Christopherson uint64_t value; 3480509c55SSean Christopherson 3580509c55SSean Christopherson value = memory_device_get_region_size(MEMORY_DEVICE(obj), &local_err); 3680509c55SSean Christopherson if (local_err) { 3780509c55SSean Christopherson error_propagate(errp, local_err); 3880509c55SSean Christopherson return; 3980509c55SSean Christopherson } 4080509c55SSean Christopherson 4180509c55SSean Christopherson visit_type_uint64(v, name, &value, errp); 4280509c55SSean Christopherson } 4380509c55SSean Christopherson 4480509c55SSean Christopherson static void sgx_epc_init(Object *obj) 4580509c55SSean Christopherson { 4680509c55SSean Christopherson object_property_add(obj, SGX_EPC_SIZE_PROP, "uint64", sgx_epc_get_size, 4780509c55SSean Christopherson NULL, NULL, NULL); 4880509c55SSean Christopherson } 4980509c55SSean Christopherson 5080509c55SSean Christopherson static void sgx_epc_realize(DeviceState *dev, Error **errp) 5180509c55SSean Christopherson { 5280509c55SSean Christopherson PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); 5380509c55SSean Christopherson X86MachineState *x86ms = X86_MACHINE(pcms); 54dfce81f1SSean Christopherson MemoryDeviceState *md = MEMORY_DEVICE(dev); 55dfce81f1SSean Christopherson SGXEPCState *sgx_epc = &pcms->sgx_epc; 5680509c55SSean Christopherson SGXEPCDevice *epc = SGX_EPC(dev); 5780509c55SSean Christopherson HostMemoryBackend *hostmem; 5880509c55SSean Christopherson const char *path; 5980509c55SSean Christopherson 6080509c55SSean Christopherson if (x86ms->boot_cpus != 0) { 6180509c55SSean Christopherson error_setg(errp, "'" TYPE_SGX_EPC "' can't be created after vCPUs," 6280509c55SSean Christopherson "e.g. via -device"); 6380509c55SSean Christopherson return; 6480509c55SSean Christopherson } 6580509c55SSean Christopherson 6680509c55SSean Christopherson if (!epc->hostmem) { 6780509c55SSean Christopherson error_setg(errp, "'" SGX_EPC_MEMDEV_PROP "' property is not set"); 6880509c55SSean Christopherson return; 6980509c55SSean Christopherson } 7080509c55SSean Christopherson hostmem = MEMORY_BACKEND(epc->hostmem); 7180509c55SSean Christopherson if (host_memory_backend_is_mapped(hostmem)) { 7280509c55SSean Christopherson path = object_get_canonical_path_component(OBJECT(hostmem)); 7380509c55SSean Christopherson error_setg(errp, "can't use already busy memdev: %s", path); 7480509c55SSean Christopherson return; 7580509c55SSean Christopherson } 7680509c55SSean Christopherson 77dfce81f1SSean Christopherson epc->addr = sgx_epc->base + sgx_epc->size; 78dfce81f1SSean Christopherson 79dfce81f1SSean Christopherson memory_region_add_subregion(&sgx_epc->mr, epc->addr - sgx_epc->base, 80dfce81f1SSean Christopherson host_memory_backend_get_memory(hostmem)); 81dfce81f1SSean Christopherson 82dfce81f1SSean Christopherson host_memory_backend_set_mapped(hostmem, true); 83dfce81f1SSean Christopherson 84dfce81f1SSean Christopherson sgx_epc->sections = g_renew(SGXEPCDevice *, sgx_epc->sections, 85dfce81f1SSean Christopherson sgx_epc->nr_sections + 1); 86dfce81f1SSean Christopherson sgx_epc->sections[sgx_epc->nr_sections++] = epc; 87dfce81f1SSean Christopherson 88dfce81f1SSean Christopherson sgx_epc->size += memory_device_get_region_size(md, errp); 8980509c55SSean Christopherson } 9080509c55SSean Christopherson 9180509c55SSean Christopherson static void sgx_epc_unrealize(DeviceState *dev) 9280509c55SSean Christopherson { 9380509c55SSean Christopherson SGXEPCDevice *epc = SGX_EPC(dev); 9480509c55SSean Christopherson HostMemoryBackend *hostmem = MEMORY_BACKEND(epc->hostmem); 9580509c55SSean Christopherson 9680509c55SSean Christopherson host_memory_backend_set_mapped(hostmem, false); 9780509c55SSean Christopherson } 9880509c55SSean Christopherson 9980509c55SSean Christopherson static uint64_t sgx_epc_md_get_addr(const MemoryDeviceState *md) 10080509c55SSean Christopherson { 10180509c55SSean Christopherson const SGXEPCDevice *epc = SGX_EPC(md); 10280509c55SSean Christopherson 10380509c55SSean Christopherson return epc->addr; 10480509c55SSean Christopherson } 10580509c55SSean Christopherson 10680509c55SSean Christopherson static void sgx_epc_md_set_addr(MemoryDeviceState *md, uint64_t addr, 10780509c55SSean Christopherson Error **errp) 10880509c55SSean Christopherson { 10980509c55SSean Christopherson object_property_set_uint(OBJECT(md), SGX_EPC_ADDR_PROP, addr, errp); 11080509c55SSean Christopherson } 11180509c55SSean Christopherson 11280509c55SSean Christopherson static uint64_t sgx_epc_md_get_plugged_size(const MemoryDeviceState *md, 11380509c55SSean Christopherson Error **errp) 11480509c55SSean Christopherson { 11580509c55SSean Christopherson return 0; 11680509c55SSean Christopherson } 11780509c55SSean Christopherson 11880509c55SSean Christopherson static MemoryRegion *sgx_epc_md_get_memory_region(MemoryDeviceState *md, 11980509c55SSean Christopherson Error **errp) 12080509c55SSean Christopherson { 12180509c55SSean Christopherson SGXEPCDevice *epc = SGX_EPC(md); 12280509c55SSean Christopherson HostMemoryBackend *hostmem; 12380509c55SSean Christopherson 12480509c55SSean Christopherson if (!epc->hostmem) { 12580509c55SSean Christopherson error_setg(errp, "'" SGX_EPC_MEMDEV_PROP "' property must be set"); 12680509c55SSean Christopherson return NULL; 12780509c55SSean Christopherson } 12880509c55SSean Christopherson 12980509c55SSean Christopherson hostmem = MEMORY_BACKEND(epc->hostmem); 13080509c55SSean Christopherson return host_memory_backend_get_memory(hostmem); 13180509c55SSean Christopherson } 13280509c55SSean Christopherson 13380509c55SSean Christopherson static void sgx_epc_md_fill_device_info(const MemoryDeviceState *md, 13480509c55SSean Christopherson MemoryDeviceInfo *info) 13580509c55SSean Christopherson { 136a7c565a9SYang Zhong SgxEPCDeviceInfo *se = g_new0(SgxEPCDeviceInfo, 1); 137a7c565a9SYang Zhong SGXEPCDevice *epc = SGX_EPC(md); 138a7c565a9SYang Zhong 139a7c565a9SYang Zhong se->memaddr = epc->addr; 140a7c565a9SYang Zhong se->size = object_property_get_uint(OBJECT(epc), SGX_EPC_SIZE_PROP, 141a7c565a9SYang Zhong NULL); 14211058123SYang Zhong se->node = object_property_get_uint(OBJECT(epc), SGX_EPC_NUMA_NODE_PROP, 14311058123SYang Zhong NULL); 144a7c565a9SYang Zhong se->memdev = object_get_canonical_path(OBJECT(epc->hostmem)); 145a7c565a9SYang Zhong 146a7c565a9SYang Zhong info->u.sgx_epc.data = se; 147a7c565a9SYang Zhong info->type = MEMORY_DEVICE_INFO_KIND_SGX_EPC; 14880509c55SSean Christopherson } 14980509c55SSean Christopherson 150*12d1a768SPhilippe Mathieu-Daudé static void sgx_epc_class_init(ObjectClass *oc, const void *data) 15180509c55SSean Christopherson { 15280509c55SSean Christopherson DeviceClass *dc = DEVICE_CLASS(oc); 15380509c55SSean Christopherson MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(oc); 15480509c55SSean Christopherson 15580509c55SSean Christopherson dc->hotpluggable = false; 15680509c55SSean Christopherson dc->realize = sgx_epc_realize; 15780509c55SSean Christopherson dc->unrealize = sgx_epc_unrealize; 15880509c55SSean Christopherson dc->desc = "SGX EPC section"; 159a0b9c5f7SPaolo Bonzini dc->user_creatable = false; 16080509c55SSean Christopherson device_class_set_props(dc, sgx_epc_properties); 16180509c55SSean Christopherson 16280509c55SSean Christopherson mdc->get_addr = sgx_epc_md_get_addr; 16380509c55SSean Christopherson mdc->set_addr = sgx_epc_md_set_addr; 16480509c55SSean Christopherson mdc->get_plugged_size = sgx_epc_md_get_plugged_size; 16580509c55SSean Christopherson mdc->get_memory_region = sgx_epc_md_get_memory_region; 16680509c55SSean Christopherson mdc->fill_device_info = sgx_epc_md_fill_device_info; 16780509c55SSean Christopherson } 16880509c55SSean Christopherson 1695e78c98bSBernhard Beschow static const TypeInfo sgx_epc_info = { 17080509c55SSean Christopherson .name = TYPE_SGX_EPC, 17180509c55SSean Christopherson .parent = TYPE_DEVICE, 17280509c55SSean Christopherson .instance_size = sizeof(SGXEPCDevice), 17380509c55SSean Christopherson .instance_init = sgx_epc_init, 17480509c55SSean Christopherson .class_init = sgx_epc_class_init, 17580509c55SSean Christopherson .class_size = sizeof(DeviceClass), 17680509c55SSean Christopherson .interfaces = (InterfaceInfo[]) { 17780509c55SSean Christopherson { TYPE_MEMORY_DEVICE }, 17880509c55SSean Christopherson { } 17980509c55SSean Christopherson }, 18080509c55SSean Christopherson }; 18180509c55SSean Christopherson 18280509c55SSean Christopherson static void sgx_epc_register_types(void) 18380509c55SSean Christopherson { 18480509c55SSean Christopherson type_register_static(&sgx_epc_info); 18580509c55SSean Christopherson } 18680509c55SSean Christopherson 18780509c55SSean Christopherson type_init(sgx_epc_register_types) 188