---
hw/i386/sgx-epc.c | 104 +++++++++++++++++++++++++++++++++++++-
include/hw/i386/pc.h | 6 +++
include/hw/i386/sgx-epc.h | 16 ++++++
qemu-options.hx | 8 +++
softmmu/globals.c | 1 +
softmmu/vl.c | 9 ++++
6 files changed, 143 insertions(+), 1 deletion(-)
diff --git a/hw/i386/sgx-epc.c b/hw/i386/sgx-epc.c
index aa487dea79..0858819a71 100644
--- a/hw/i386/sgx-epc.c
+++ b/hw/i386/sgx-epc.c
@@ -56,6 +56,8 @@ 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);
const char *path;
@@ -74,7 +76,18 @@ static void sgx_epc_realize(DeviceState *dev, Error **errp)
return;
}
- error_setg(errp, "'" TYPE_SGX_EPC "' not supported");
+ 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(epc->hostmem));
+
+ host_memory_backend_set_mapped(epc->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)
@@ -159,3 +172,92 @@ static void sgx_epc_register_types(void)
}
type_init(sgx_epc_register_types)
+
+
+static int sgx_epc_set_property(void *opaque, const char *name,
+ const char *value, Error **errp)
+{
+ Object *obj = opaque;
+ Error *err = NULL;
+
+ object_property_parse(obj, name, value, &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return -1;
+ }
+ return 0;
+}
+
+static int sgx_epc_init_func(void *opaque, QemuOpts *opts, Error **errp)
+{
+ Error *err = NULL;
+ Object *obj;
+
+ obj = object_new("sgx-epc");
+
+ qdev_set_id(DEVICE(obj), qemu_opts_id(opts));
+
+ if (qemu_opt_foreach(opts, sgx_epc_set_property, obj, &err)) {
+ goto out;
+ }
+
+ object_property_set_bool(obj, "realized", true, &err);
+
+out:
+ if (err != NULL) {
+ error_propagate(errp, err);
+ }
+ object_unref(obj);
+ return err != NULL ? -1 : 0;
+}
+
+void pc_machine_init_sgx_epc(PCMachineState *pcms)
+{
+ SGXEPCState *sgx_epc;
+ X86MachineState *x86ms = X86_MACHINE(pcms);
+
+ sgx_epc = g_malloc0(sizeof(*sgx_epc));
+ pcms->sgx_epc = sgx_epc;
+
+ sgx_epc->base = 0x100000000ULL + x86ms->above_4g_mem_size;
+
+ memory_region_init(&sgx_epc->mr, OBJECT(pcms), "sgx-epc", UINT64_MAX);
+ memory_region_add_subregion(get_system_memory(), sgx_epc->base,
+ &sgx_epc->mr);
+
+ qemu_opts_foreach(qemu_find_opts("sgx-epc"), sgx_epc_init_func, NULL,
+ &error_fatal);
+
+ if ((sgx_epc->base + sgx_epc->size) < sgx_epc->base) {
+ error_report("Size of all 'sgx-epc' =0x%"PRIu64" causes EPC to wrap",
+ sgx_epc->size);
+ exit(EXIT_FAILURE);
+ }
+
+ memory_region_set_size(&sgx_epc->mr, sgx_epc->size);
+}
+
+static QemuOptsList sgx_epc_opts = {
+ .name = "sgx-epc",
+ .implied_opt_name = "id",
+ .head = QTAILQ_HEAD_INITIALIZER(sgx_epc_opts.head),
+ .desc = {
+ {
+ .name = "id",
+ .type = QEMU_OPT_STRING,
+ .help = "SGX EPC section ID",
+ },{
+ .name = "memdev",
+ .type = QEMU_OPT_STRING,
+ .help = "memory object backend",
+ },
+ { /* end of list */ }
+ },
+};
+
+static void sgx_epc_register_opts(void)
+{
+ qemu_add_opts(&sgx_epc_opts);
+}
+
+opts_init(sgx_epc_register_opts);
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index dcf060b791..71e2fc6f26 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -12,6 +12,7 @@
#include "hw/acpi/acpi_dev_interface.h"
#include "hw/hotplug.h"
#include "qom/object.h"
+#include "hw/i386/sgx-epc.h"
#define HPET_INTCAP "hpet-intcap"
@@ -53,6 +54,8 @@ typedef struct PCMachineState {
/* ACPI Memory hotplug IO base address */
hwaddr memhp_io_base;
+
+ SGXEPCState *sgx_epc;
} PCMachineState;
#define PC_MACHINE_ACPI_DEVICE_PROP "acpi-device"
@@ -197,6 +200,9 @@ bool pc_system_ovmf_table_find(const char *entry, uint8_t
**data,
void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
const CPUArchIdList *apic_ids, GArray *entry);
+/* sgx-epc.c */
+void pc_machine_init_sgx_epc(PCMachineState *pcms);
+
extern GlobalProperty pc_compat_5_2[];
extern const size_t pc_compat_5_2_len;
diff --git a/include/hw/i386/sgx-epc.h b/include/hw/i386/sgx-epc.h
index 5fd9ae2d0c..1f7dd17c17 100644
--- a/include/hw/i386/sgx-epc.h
+++ b/include/hw/i386/sgx-epc.h
@@ -41,4 +41,20 @@ typedef struct SGXEPCDevice {
HostMemoryBackend *hostmem;
} SGXEPCDevice;
+/*
+ * @base: address in guest physical address space where EPC regions start
+ * @mr: address space container for memory devices
+ */
+typedef struct SGXEPCState {
+ uint64_t base;
+ uint64_t size;
+
+ MemoryRegion mr;
+
+ struct SGXEPCDevice **sections;
+ int nr_sections;
+} SGXEPCState;
+
+extern int sgx_epc_enabled;
+
#endif
diff --git a/qemu-options.hx b/qemu-options.hx
index fd21002bd6..262c3084af 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -532,6 +532,14 @@ SRST
Preallocate memory when using -mem-path.
ERST
+DEF("sgx-epc", HAS_ARG, QEMU_OPTION_sgx_epc,
+ "-sgx-epc memdev=memid[,id=epcid]\n",
+ QEMU_ARCH_I386)
+SRST
+``-sgx-epc memdev=@var{memid}[,id=@var{epcid}]``
+ Define an SGX EPC section.
+ERST
+
DEF("k", HAS_ARG, QEMU_OPTION_k,
"-k language use keyboard layout (for example 'fr' for French)\n",
QEMU_ARCH_ALL)
diff --git a/softmmu/globals.c b/softmmu/globals.c
index 7d0fc81183..d3029953ce 100644
--- a/softmmu/globals.c
+++ b/softmmu/globals.c
@@ -70,3 +70,4 @@ bool qemu_uuid_set;
uint32_t xen_domid;
enum xen_mode xen_mode = XEN_EMULATE;
bool xen_domid_restrict;
+int sgx_epc_enabled;
diff --git a/softmmu/vl.c b/softmmu/vl.c
index aadb526138..0c7e9fab78 100644
--- a/softmmu/vl.c
+++ b/softmmu/vl.c
@@ -74,6 +74,7 @@
#include "hw/block/block.h"
#include "hw/i386/x86.h"
#include "hw/i386/pc.h"
+#include "hw/i386/sgx-epc.h"
#include "migration/misc.h"
#include "migration/snapshot.h"
#include "sysemu/tpm.h"
@@ -2891,6 +2892,14 @@ void qemu_init(int argc, char **argv, char **envp)
case QEMU_OPTION_mem_prealloc:
mem_prealloc = 1;
break;
+ case QEMU_OPTION_sgx_epc:
+ opts = qemu_opts_parse_noisily(qemu_find_opts("sgx-epc"),
+ optarg, false);
+ if (!opts) {
+ exit(1);
+ }
+ sgx_epc_enabled = 1;
+ break;
case QEMU_OPTION_d:
log_mask = optarg;
break;