/* * SGX EPC device * * Copyright (C) 2019 Intel Corporation * * Authors: * Sean Christopherson * * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. */ #include "qemu/osdep.h" #include "hw/i386/pc.h" #include "hw/i386/sgx-epc.h" #include "hw/mem/memory-device.h" #include "hw/qdev-properties.h" #include "qapi/error.h" #include "qapi/visitor.h" #include "target/i386/cpu.h" #include "exec/address-spaces.h" static Property sgx_epc_properties[] = { DEFINE_PROP_UINT64(SGX_EPC_ADDR_PROP, SGXEPCDevice, addr, 0), DEFINE_PROP_LINK(SGX_EPC_MEMDEV_PROP, SGXEPCDevice, hostmem, TYPE_MEMORY_BACKEND_EPC, HostMemoryBackendEpc *), DEFINE_PROP_END_OF_LIST(), }; static void sgx_epc_get_size(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { Error *local_err = NULL; uint64_t value; value = memory_device_get_region_size(MEMORY_DEVICE(obj), &local_err); if (local_err) { error_propagate(errp, local_err); return; } visit_type_uint64(v, name, &value, errp); } static void sgx_epc_init(Object *obj) { object_property_add(obj, SGX_EPC_SIZE_PROP, "uint64", sgx_epc_get_size, NULL, NULL, NULL); } static void sgx_epc_realize(DeviceState *dev, Error **errp) { PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); X86MachineState *x86ms = X86_MACHINE(pcms); MemoryDeviceState *md = MEMORY_DEVICE(dev); SGXEPCState *sgx_epc = &pcms->sgx_epc; SGXEPCDevice *epc = SGX_EPC(dev); HostMemoryBackend *hostmem; const char *path; if (x86ms->boot_cpus != 0) { error_setg(errp, "'" TYPE_SGX_EPC "' can't be created after vCPUs," "e.g. via -device"); return; } if (!epc->hostmem) { error_setg(errp, "'" SGX_EPC_MEMDEV_PROP "' property is not set"); return; } hostmem = MEMORY_BACKEND(epc->hostmem); if (host_memory_backend_is_mapped(hostmem)) { path = object_get_canonical_path_component(OBJECT(hostmem)); error_setg(errp, "can't use already busy memdev: %s", path); return; } epc->addr = sgx_epc->base + sgx_epc->size; memory_region_add_subregion(&sgx_epc->mr, epc->addr - sgx_epc->base, host_memory_backend_get_memory(hostmem)); host_memory_backend_set_mapped(hostmem, true); sgx_epc->sections = g_renew(SGXEPCDevice *, sgx_epc->sections, sgx_epc->nr_sections + 1); sgx_epc->sections[sgx_epc->nr_sections++] = epc; sgx_epc->size += memory_device_get_region_size(md, errp); } static void sgx_epc_unrealize(DeviceState *dev) { SGXEPCDevice *epc = SGX_EPC(dev); HostMemoryBackend *hostmem = MEMORY_BACKEND(epc->hostmem); host_memory_backend_set_mapped(hostmem, false); } static uint64_t sgx_epc_md_get_addr(const MemoryDeviceState *md) { const SGXEPCDevice *epc = SGX_EPC(md); return epc->addr; } static void sgx_epc_md_set_addr(MemoryDeviceState *md, uint64_t addr, Error **errp) { object_property_set_uint(OBJECT(md), SGX_EPC_ADDR_PROP, addr, errp); } static uint64_t sgx_epc_md_get_plugged_size(const MemoryDeviceState *md, Error **errp) { return 0; } static MemoryRegion *sgx_epc_md_get_memory_region(MemoryDeviceState *md, Error **errp) { SGXEPCDevice *epc = SGX_EPC(md); HostMemoryBackend *hostmem; if (!epc->hostmem) { error_setg(errp, "'" SGX_EPC_MEMDEV_PROP "' property must be set"); return NULL; } hostmem = MEMORY_BACKEND(epc->hostmem); return host_memory_backend_get_memory(hostmem); } static void sgx_epc_md_fill_device_info(const MemoryDeviceState *md, MemoryDeviceInfo *info) { SgxEPCDeviceInfo *se = g_new0(SgxEPCDeviceInfo, 1); SGXEPCDevice *epc = SGX_EPC(md); se->memaddr = epc->addr; se->size = object_property_get_uint(OBJECT(epc), SGX_EPC_SIZE_PROP, NULL); se->memdev = object_get_canonical_path(OBJECT(epc->hostmem)); info->u.sgx_epc.data = se; info->type = MEMORY_DEVICE_INFO_KIND_SGX_EPC; } static void sgx_epc_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(oc); dc->hotpluggable = false; dc->realize = sgx_epc_realize; dc->unrealize = sgx_epc_unrealize; dc->desc = "SGX EPC section"; device_class_set_props(dc, sgx_epc_properties); mdc->get_addr = sgx_epc_md_get_addr; mdc->set_addr = sgx_epc_md_set_addr; mdc->get_plugged_size = sgx_epc_md_get_plugged_size; mdc->get_memory_region = sgx_epc_md_get_memory_region; mdc->fill_device_info = sgx_epc_md_fill_device_info; } static TypeInfo sgx_epc_info = { .name = TYPE_SGX_EPC, .parent = TYPE_DEVICE, .instance_size = sizeof(SGXEPCDevice), .instance_init = sgx_epc_init, .class_init = sgx_epc_class_init, .class_size = sizeof(DeviceClass), .interfaces = (InterfaceInfo[]) { { TYPE_MEMORY_DEVICE }, { } }, }; static void sgx_epc_register_types(void) { type_register_static(&sgx_epc_info); } type_init(sgx_epc_register_types)