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" 2080509c55SSean Christopherson #include "exec/address-spaces.h" 2180509c55SSean Christopherson 2280509c55SSean Christopherson static 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 DEFINE_PROP_END_OF_LIST(), 2880509c55SSean Christopherson }; 2980509c55SSean Christopherson 3080509c55SSean Christopherson static void sgx_epc_get_size(Object *obj, Visitor *v, const char *name, 3180509c55SSean Christopherson void *opaque, Error **errp) 3280509c55SSean Christopherson { 3380509c55SSean Christopherson Error *local_err = NULL; 3480509c55SSean Christopherson uint64_t value; 3580509c55SSean Christopherson 3680509c55SSean Christopherson value = memory_device_get_region_size(MEMORY_DEVICE(obj), &local_err); 3780509c55SSean Christopherson if (local_err) { 3880509c55SSean Christopherson error_propagate(errp, local_err); 3980509c55SSean Christopherson return; 4080509c55SSean Christopherson } 4180509c55SSean Christopherson 4280509c55SSean Christopherson visit_type_uint64(v, name, &value, errp); 4380509c55SSean Christopherson } 4480509c55SSean Christopherson 4580509c55SSean Christopherson static void sgx_epc_init(Object *obj) 4680509c55SSean Christopherson { 4780509c55SSean Christopherson object_property_add(obj, SGX_EPC_SIZE_PROP, "uint64", sgx_epc_get_size, 4880509c55SSean Christopherson NULL, NULL, NULL); 4980509c55SSean Christopherson } 5080509c55SSean Christopherson 5180509c55SSean Christopherson static void sgx_epc_realize(DeviceState *dev, Error **errp) 5280509c55SSean Christopherson { 5380509c55SSean Christopherson PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); 5480509c55SSean Christopherson X86MachineState *x86ms = X86_MACHINE(pcms); 55dfce81f1SSean Christopherson MemoryDeviceState *md = MEMORY_DEVICE(dev); 56dfce81f1SSean Christopherson SGXEPCState *sgx_epc = &pcms->sgx_epc; 5780509c55SSean Christopherson SGXEPCDevice *epc = SGX_EPC(dev); 5880509c55SSean Christopherson HostMemoryBackend *hostmem; 5980509c55SSean Christopherson const char *path; 6080509c55SSean Christopherson 6180509c55SSean Christopherson if (x86ms->boot_cpus != 0) { 6280509c55SSean Christopherson error_setg(errp, "'" TYPE_SGX_EPC "' can't be created after vCPUs," 6380509c55SSean Christopherson "e.g. via -device"); 6480509c55SSean Christopherson return; 6580509c55SSean Christopherson } 6680509c55SSean Christopherson 6780509c55SSean Christopherson if (!epc->hostmem) { 6880509c55SSean Christopherson error_setg(errp, "'" SGX_EPC_MEMDEV_PROP "' property is not set"); 6980509c55SSean Christopherson return; 7080509c55SSean Christopherson } 7180509c55SSean Christopherson hostmem = MEMORY_BACKEND(epc->hostmem); 7280509c55SSean Christopherson if (host_memory_backend_is_mapped(hostmem)) { 7380509c55SSean Christopherson path = object_get_canonical_path_component(OBJECT(hostmem)); 7480509c55SSean Christopherson error_setg(errp, "can't use already busy memdev: %s", path); 7580509c55SSean Christopherson return; 7680509c55SSean Christopherson } 7780509c55SSean Christopherson 78dfce81f1SSean Christopherson epc->addr = sgx_epc->base + sgx_epc->size; 79dfce81f1SSean Christopherson 80dfce81f1SSean Christopherson memory_region_add_subregion(&sgx_epc->mr, epc->addr - sgx_epc->base, 81dfce81f1SSean Christopherson host_memory_backend_get_memory(hostmem)); 82dfce81f1SSean Christopherson 83dfce81f1SSean Christopherson host_memory_backend_set_mapped(hostmem, true); 84dfce81f1SSean Christopherson 85dfce81f1SSean Christopherson sgx_epc->sections = g_renew(SGXEPCDevice *, sgx_epc->sections, 86dfce81f1SSean Christopherson sgx_epc->nr_sections + 1); 87dfce81f1SSean Christopherson sgx_epc->sections[sgx_epc->nr_sections++] = epc; 88dfce81f1SSean Christopherson 89dfce81f1SSean Christopherson sgx_epc->size += memory_device_get_region_size(md, errp); 9080509c55SSean Christopherson } 9180509c55SSean Christopherson 9280509c55SSean Christopherson static void sgx_epc_unrealize(DeviceState *dev) 9380509c55SSean Christopherson { 9480509c55SSean Christopherson SGXEPCDevice *epc = SGX_EPC(dev); 9580509c55SSean Christopherson HostMemoryBackend *hostmem = MEMORY_BACKEND(epc->hostmem); 9680509c55SSean Christopherson 9780509c55SSean Christopherson host_memory_backend_set_mapped(hostmem, false); 9880509c55SSean Christopherson } 9980509c55SSean Christopherson 10080509c55SSean Christopherson static uint64_t sgx_epc_md_get_addr(const MemoryDeviceState *md) 10180509c55SSean Christopherson { 10280509c55SSean Christopherson const SGXEPCDevice *epc = SGX_EPC(md); 10380509c55SSean Christopherson 10480509c55SSean Christopherson return epc->addr; 10580509c55SSean Christopherson } 10680509c55SSean Christopherson 10780509c55SSean Christopherson static void sgx_epc_md_set_addr(MemoryDeviceState *md, uint64_t addr, 10880509c55SSean Christopherson Error **errp) 10980509c55SSean Christopherson { 11080509c55SSean Christopherson object_property_set_uint(OBJECT(md), SGX_EPC_ADDR_PROP, addr, errp); 11180509c55SSean Christopherson } 11280509c55SSean Christopherson 11380509c55SSean Christopherson static uint64_t sgx_epc_md_get_plugged_size(const MemoryDeviceState *md, 11480509c55SSean Christopherson Error **errp) 11580509c55SSean Christopherson { 11680509c55SSean Christopherson return 0; 11780509c55SSean Christopherson } 11880509c55SSean Christopherson 11980509c55SSean Christopherson static MemoryRegion *sgx_epc_md_get_memory_region(MemoryDeviceState *md, 12080509c55SSean Christopherson Error **errp) 12180509c55SSean Christopherson { 12280509c55SSean Christopherson SGXEPCDevice *epc = SGX_EPC(md); 12380509c55SSean Christopherson HostMemoryBackend *hostmem; 12480509c55SSean Christopherson 12580509c55SSean Christopherson if (!epc->hostmem) { 12680509c55SSean Christopherson error_setg(errp, "'" SGX_EPC_MEMDEV_PROP "' property must be set"); 12780509c55SSean Christopherson return NULL; 12880509c55SSean Christopherson } 12980509c55SSean Christopherson 13080509c55SSean Christopherson hostmem = MEMORY_BACKEND(epc->hostmem); 13180509c55SSean Christopherson return host_memory_backend_get_memory(hostmem); 13280509c55SSean Christopherson } 13380509c55SSean Christopherson 13480509c55SSean Christopherson static void sgx_epc_md_fill_device_info(const MemoryDeviceState *md, 13580509c55SSean Christopherson MemoryDeviceInfo *info) 13680509c55SSean Christopherson { 137a7c565a9SYang Zhong SgxEPCDeviceInfo *se = g_new0(SgxEPCDeviceInfo, 1); 138a7c565a9SYang Zhong SGXEPCDevice *epc = SGX_EPC(md); 139a7c565a9SYang Zhong 140a7c565a9SYang Zhong se->memaddr = epc->addr; 141a7c565a9SYang Zhong se->size = object_property_get_uint(OBJECT(epc), SGX_EPC_SIZE_PROP, 142a7c565a9SYang Zhong NULL); 14311058123SYang Zhong se->node = object_property_get_uint(OBJECT(epc), SGX_EPC_NUMA_NODE_PROP, 14411058123SYang Zhong NULL); 145a7c565a9SYang Zhong se->memdev = object_get_canonical_path(OBJECT(epc->hostmem)); 146a7c565a9SYang Zhong 147a7c565a9SYang Zhong info->u.sgx_epc.data = se; 148a7c565a9SYang Zhong info->type = MEMORY_DEVICE_INFO_KIND_SGX_EPC; 14980509c55SSean Christopherson } 15080509c55SSean Christopherson 15180509c55SSean Christopherson static void sgx_epc_class_init(ObjectClass *oc, void *data) 15280509c55SSean Christopherson { 15380509c55SSean Christopherson DeviceClass *dc = DEVICE_CLASS(oc); 15480509c55SSean Christopherson MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(oc); 15580509c55SSean Christopherson 15680509c55SSean Christopherson dc->hotpluggable = false; 15780509c55SSean Christopherson dc->realize = sgx_epc_realize; 15880509c55SSean Christopherson dc->unrealize = sgx_epc_unrealize; 15980509c55SSean Christopherson dc->desc = "SGX EPC section"; 160a0b9c5f7SPaolo Bonzini dc->user_creatable = false; 16180509c55SSean Christopherson device_class_set_props(dc, sgx_epc_properties); 16280509c55SSean Christopherson 16380509c55SSean Christopherson mdc->get_addr = sgx_epc_md_get_addr; 16480509c55SSean Christopherson mdc->set_addr = sgx_epc_md_set_addr; 16580509c55SSean Christopherson mdc->get_plugged_size = sgx_epc_md_get_plugged_size; 16680509c55SSean Christopherson mdc->get_memory_region = sgx_epc_md_get_memory_region; 16780509c55SSean Christopherson mdc->fill_device_info = sgx_epc_md_fill_device_info; 16880509c55SSean Christopherson } 16980509c55SSean Christopherson 170*5e78c98bSBernhard Beschow static const TypeInfo sgx_epc_info = { 17180509c55SSean Christopherson .name = TYPE_SGX_EPC, 17280509c55SSean Christopherson .parent = TYPE_DEVICE, 17380509c55SSean Christopherson .instance_size = sizeof(SGXEPCDevice), 17480509c55SSean Christopherson .instance_init = sgx_epc_init, 17580509c55SSean Christopherson .class_init = sgx_epc_class_init, 17680509c55SSean Christopherson .class_size = sizeof(DeviceClass), 17780509c55SSean Christopherson .interfaces = (InterfaceInfo[]) { 17880509c55SSean Christopherson { TYPE_MEMORY_DEVICE }, 17980509c55SSean Christopherson { } 18080509c55SSean Christopherson }, 18180509c55SSean Christopherson }; 18280509c55SSean Christopherson 18380509c55SSean Christopherson static void sgx_epc_register_types(void) 18480509c55SSean Christopherson { 18580509c55SSean Christopherson type_register_static(&sgx_epc_info); 18680509c55SSean Christopherson } 18780509c55SSean Christopherson 18880509c55SSean Christopherson type_init(sgx_epc_register_types) 189