]>
Commit | Line | Data |
---|---|---|
80509c55 SC |
1 | /* |
2 | * SGX EPC device | |
3 | * | |
4 | * Copyright (C) 2019 Intel Corporation | |
5 | * | |
6 | * Authors: | |
7 | * Sean Christopherson <sean.j.christopherson@intel.com> | |
8 | * | |
9 | * This work is licensed under the terms of the GNU GPL, version 2 or later. | |
10 | * See the COPYING file in the top-level directory. | |
11 | */ | |
12 | #include "qemu/osdep.h" | |
13 | #include "hw/i386/pc.h" | |
14 | #include "hw/i386/sgx-epc.h" | |
15 | #include "hw/mem/memory-device.h" | |
16 | #include "hw/qdev-properties.h" | |
80509c55 SC |
17 | #include "qapi/error.h" |
18 | #include "qapi/visitor.h" | |
80509c55 SC |
19 | #include "target/i386/cpu.h" |
20 | #include "exec/address-spaces.h" | |
21 | ||
22 | static Property sgx_epc_properties[] = { | |
23 | DEFINE_PROP_UINT64(SGX_EPC_ADDR_PROP, SGXEPCDevice, addr, 0), | |
11058123 | 24 | DEFINE_PROP_UINT32(SGX_EPC_NUMA_NODE_PROP, SGXEPCDevice, node, 0), |
80509c55 SC |
25 | DEFINE_PROP_LINK(SGX_EPC_MEMDEV_PROP, SGXEPCDevice, hostmem, |
26 | TYPE_MEMORY_BACKEND_EPC, HostMemoryBackendEpc *), | |
27 | DEFINE_PROP_END_OF_LIST(), | |
28 | }; | |
29 | ||
30 | static void sgx_epc_get_size(Object *obj, Visitor *v, const char *name, | |
31 | void *opaque, Error **errp) | |
32 | { | |
33 | Error *local_err = NULL; | |
34 | uint64_t value; | |
35 | ||
36 | value = memory_device_get_region_size(MEMORY_DEVICE(obj), &local_err); | |
37 | if (local_err) { | |
38 | error_propagate(errp, local_err); | |
39 | return; | |
40 | } | |
41 | ||
42 | visit_type_uint64(v, name, &value, errp); | |
43 | } | |
44 | ||
45 | static void sgx_epc_init(Object *obj) | |
46 | { | |
47 | object_property_add(obj, SGX_EPC_SIZE_PROP, "uint64", sgx_epc_get_size, | |
48 | NULL, NULL, NULL); | |
49 | } | |
50 | ||
51 | static void sgx_epc_realize(DeviceState *dev, Error **errp) | |
52 | { | |
53 | PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); | |
54 | X86MachineState *x86ms = X86_MACHINE(pcms); | |
dfce81f1 SC |
55 | MemoryDeviceState *md = MEMORY_DEVICE(dev); |
56 | SGXEPCState *sgx_epc = &pcms->sgx_epc; | |
80509c55 SC |
57 | SGXEPCDevice *epc = SGX_EPC(dev); |
58 | HostMemoryBackend *hostmem; | |
59 | const char *path; | |
60 | ||
61 | if (x86ms->boot_cpus != 0) { | |
62 | error_setg(errp, "'" TYPE_SGX_EPC "' can't be created after vCPUs," | |
63 | "e.g. via -device"); | |
64 | return; | |
65 | } | |
66 | ||
67 | if (!epc->hostmem) { | |
68 | error_setg(errp, "'" SGX_EPC_MEMDEV_PROP "' property is not set"); | |
69 | return; | |
70 | } | |
71 | hostmem = MEMORY_BACKEND(epc->hostmem); | |
72 | if (host_memory_backend_is_mapped(hostmem)) { | |
73 | path = object_get_canonical_path_component(OBJECT(hostmem)); | |
74 | error_setg(errp, "can't use already busy memdev: %s", path); | |
75 | return; | |
76 | } | |
77 | ||
dfce81f1 SC |
78 | epc->addr = sgx_epc->base + sgx_epc->size; |
79 | ||
80 | memory_region_add_subregion(&sgx_epc->mr, epc->addr - sgx_epc->base, | |
81 | host_memory_backend_get_memory(hostmem)); | |
82 | ||
83 | host_memory_backend_set_mapped(hostmem, true); | |
84 | ||
85 | sgx_epc->sections = g_renew(SGXEPCDevice *, sgx_epc->sections, | |
86 | sgx_epc->nr_sections + 1); | |
87 | sgx_epc->sections[sgx_epc->nr_sections++] = epc; | |
88 | ||
89 | sgx_epc->size += memory_device_get_region_size(md, errp); | |
80509c55 SC |
90 | } |
91 | ||
92 | static void sgx_epc_unrealize(DeviceState *dev) | |
93 | { | |
94 | SGXEPCDevice *epc = SGX_EPC(dev); | |
95 | HostMemoryBackend *hostmem = MEMORY_BACKEND(epc->hostmem); | |
96 | ||
97 | host_memory_backend_set_mapped(hostmem, false); | |
98 | } | |
99 | ||
100 | static uint64_t sgx_epc_md_get_addr(const MemoryDeviceState *md) | |
101 | { | |
102 | const SGXEPCDevice *epc = SGX_EPC(md); | |
103 | ||
104 | return epc->addr; | |
105 | } | |
106 | ||
107 | static void sgx_epc_md_set_addr(MemoryDeviceState *md, uint64_t addr, | |
108 | Error **errp) | |
109 | { | |
110 | object_property_set_uint(OBJECT(md), SGX_EPC_ADDR_PROP, addr, errp); | |
111 | } | |
112 | ||
113 | static uint64_t sgx_epc_md_get_plugged_size(const MemoryDeviceState *md, | |
114 | Error **errp) | |
115 | { | |
116 | return 0; | |
117 | } | |
118 | ||
119 | static MemoryRegion *sgx_epc_md_get_memory_region(MemoryDeviceState *md, | |
120 | Error **errp) | |
121 | { | |
122 | SGXEPCDevice *epc = SGX_EPC(md); | |
123 | HostMemoryBackend *hostmem; | |
124 | ||
125 | if (!epc->hostmem) { | |
126 | error_setg(errp, "'" SGX_EPC_MEMDEV_PROP "' property must be set"); | |
127 | return NULL; | |
128 | } | |
129 | ||
130 | hostmem = MEMORY_BACKEND(epc->hostmem); | |
131 | return host_memory_backend_get_memory(hostmem); | |
132 | } | |
133 | ||
134 | static void sgx_epc_md_fill_device_info(const MemoryDeviceState *md, | |
135 | MemoryDeviceInfo *info) | |
136 | { | |
a7c565a9 YZ |
137 | SgxEPCDeviceInfo *se = g_new0(SgxEPCDeviceInfo, 1); |
138 | SGXEPCDevice *epc = SGX_EPC(md); | |
139 | ||
140 | se->memaddr = epc->addr; | |
141 | se->size = object_property_get_uint(OBJECT(epc), SGX_EPC_SIZE_PROP, | |
142 | NULL); | |
11058123 YZ |
143 | se->node = object_property_get_uint(OBJECT(epc), SGX_EPC_NUMA_NODE_PROP, |
144 | NULL); | |
a7c565a9 YZ |
145 | se->memdev = object_get_canonical_path(OBJECT(epc->hostmem)); |
146 | ||
147 | info->u.sgx_epc.data = se; | |
148 | info->type = MEMORY_DEVICE_INFO_KIND_SGX_EPC; | |
80509c55 SC |
149 | } |
150 | ||
151 | static void sgx_epc_class_init(ObjectClass *oc, void *data) | |
152 | { | |
153 | DeviceClass *dc = DEVICE_CLASS(oc); | |
154 | MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(oc); | |
155 | ||
156 | dc->hotpluggable = false; | |
157 | dc->realize = sgx_epc_realize; | |
158 | dc->unrealize = sgx_epc_unrealize; | |
159 | dc->desc = "SGX EPC section"; | |
a0b9c5f7 | 160 | dc->user_creatable = false; |
80509c55 SC |
161 | device_class_set_props(dc, sgx_epc_properties); |
162 | ||
163 | mdc->get_addr = sgx_epc_md_get_addr; | |
164 | mdc->set_addr = sgx_epc_md_set_addr; | |
165 | mdc->get_plugged_size = sgx_epc_md_get_plugged_size; | |
166 | mdc->get_memory_region = sgx_epc_md_get_memory_region; | |
167 | mdc->fill_device_info = sgx_epc_md_fill_device_info; | |
168 | } | |
169 | ||
5e78c98b | 170 | static const TypeInfo sgx_epc_info = { |
80509c55 SC |
171 | .name = TYPE_SGX_EPC, |
172 | .parent = TYPE_DEVICE, | |
173 | .instance_size = sizeof(SGXEPCDevice), | |
174 | .instance_init = sgx_epc_init, | |
175 | .class_init = sgx_epc_class_init, | |
176 | .class_size = sizeof(DeviceClass), | |
177 | .interfaces = (InterfaceInfo[]) { | |
178 | { TYPE_MEMORY_DEVICE }, | |
179 | { } | |
180 | }, | |
181 | }; | |
182 | ||
183 | static void sgx_epc_register_types(void) | |
184 | { | |
185 | type_register_static(&sgx_epc_info); | |
186 | } | |
187 | ||
188 | type_init(sgx_epc_register_types) |