aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorSean Christopherson <sean.j.christopherson@intel.com>2021-07-19 19:21:07 +0800
committerPaolo Bonzini <pbonzini@redhat.com>2021-09-30 14:50:20 +0200
commit80509c5557a152f876aec524e8136f309583b2cd (patch)
treed5d8d0dba36210690f52e7f3609cd6470bce60e4 /hw
parent46a1d21dbaafab2df25ac354095d90492cd3a98b (diff)
downloadqemu-80509c5557a152f876aec524e8136f309583b2cd.zip
qemu-80509c5557a152f876aec524e8136f309583b2cd.tar.gz
qemu-80509c5557a152f876aec524e8136f309583b2cd.tar.bz2
i386: Add 'sgx-epc' device to expose EPC sections to guest
SGX EPC is enumerated through CPUID, i.e. EPC "devices" need to be realized prior to realizing the vCPUs themselves, which occurs long before generic devices are parsed and realized. Because of this, do not allow 'sgx-epc' devices to be instantiated after vCPUS have been created. The 'sgx-epc' device is essentially a placholder at this time, it will be fully implemented in a future patch along with a dedicated command to create 'sgx-epc' devices. Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com> Signed-off-by: Yang Zhong <yang.zhong@intel.com> Message-Id: <20210719112136.57018-5-yang.zhong@intel.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'hw')
-rw-r--r--hw/i386/meson.build1
-rw-r--r--hw/i386/sgx-epc.c167
2 files changed, 168 insertions, 0 deletions
diff --git a/hw/i386/meson.build b/hw/i386/meson.build
index 80dad29..b1862c8 100644
--- a/hw/i386/meson.build
+++ b/hw/i386/meson.build
@@ -16,6 +16,7 @@ i386_ss.add(when: 'CONFIG_Q35', if_true: files('pc_q35.c'))
i386_ss.add(when: 'CONFIG_VMMOUSE', if_true: files('vmmouse.c'))
i386_ss.add(when: 'CONFIG_VMPORT', if_true: files('vmport.c'))
i386_ss.add(when: 'CONFIG_VTD', if_true: files('intel_iommu.c'))
+i386_ss.add(when: 'CONFIG_SGX', if_true: files('sgx-epc.c'))
i386_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-common.c'))
i386_ss.add(when: 'CONFIG_ACPI_HW_REDUCED', if_true: files('generic_event_device_x86.c'))
diff --git a/hw/i386/sgx-epc.c b/hw/i386/sgx-epc.c
new file mode 100644
index 0000000..c584acc
--- /dev/null
+++ b/hw/i386/sgx-epc.c
@@ -0,0 +1,167 @@
+/*
+ * SGX EPC device
+ *
+ * Copyright (C) 2019 Intel Corporation
+ *
+ * Authors:
+ * Sean Christopherson <sean.j.christopherson@intel.com>
+ *
+ * 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 "monitor/qdev.h"
+#include "qapi/error.h"
+#include "qapi/visitor.h"
+#include "qemu/config-file.h"
+#include "qemu/error-report.h"
+#include "qemu/option.h"
+#include "qemu/units.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);
+ 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;
+ }
+
+ error_setg(errp, "'" TYPE_SGX_EPC "' not supported");
+}
+
+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)
+{
+ /* TODO */
+}
+
+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)