1 | /* |
2 | * Memory Device Interface |
3 | * |
4 | * Copyright ProfitBricks GmbH 2012 |
5 | * Copyright (C) 2014 Red Hat Inc |
6 | * Copyright (c) 2018 Red Hat Inc |
7 | * |
8 | * This work is licensed under the terms of the GNU GPL, version 2 or later. |
9 | * See the COPYING file in the top-level directory. |
10 | */ |
11 | |
12 | #include "qemu/osdep.h" |
13 | #include "hw/mem/memory-device.h" |
14 | #include "qapi/error.h" |
15 | #include "hw/boards.h" |
16 | #include "qemu/range.h" |
17 | #include "hw/virtio/vhost.h" |
18 | #include "sysemu/kvm.h" |
19 | #include "trace.h" |
20 | |
21 | static gint memory_device_addr_sort(gconstpointer a, gconstpointer b) |
22 | { |
23 | const MemoryDeviceState *md_a = MEMORY_DEVICE(a); |
24 | const MemoryDeviceState *md_b = MEMORY_DEVICE(b); |
25 | const MemoryDeviceClass *mdc_a = MEMORY_DEVICE_GET_CLASS(a); |
26 | const MemoryDeviceClass *mdc_b = MEMORY_DEVICE_GET_CLASS(b); |
27 | const uint64_t addr_a = mdc_a->get_addr(md_a); |
28 | const uint64_t addr_b = mdc_b->get_addr(md_b); |
29 | |
30 | if (addr_a > addr_b) { |
31 | return 1; |
32 | } else if (addr_a < addr_b) { |
33 | return -1; |
34 | } |
35 | return 0; |
36 | } |
37 | |
38 | static int memory_device_build_list(Object *obj, void *opaque) |
39 | { |
40 | GSList **list = opaque; |
41 | |
42 | if (object_dynamic_cast(obj, TYPE_MEMORY_DEVICE)) { |
43 | DeviceState *dev = DEVICE(obj); |
44 | if (dev->realized) { /* only realized memory devices matter */ |
45 | *list = g_slist_insert_sorted(*list, dev, memory_device_addr_sort); |
46 | } |
47 | } |
48 | |
49 | object_child_foreach(obj, memory_device_build_list, opaque); |
50 | return 0; |
51 | } |
52 | |
53 | static int memory_device_used_region_size(Object *obj, void *opaque) |
54 | { |
55 | uint64_t *size = opaque; |
56 | |
57 | if (object_dynamic_cast(obj, TYPE_MEMORY_DEVICE)) { |
58 | const DeviceState *dev = DEVICE(obj); |
59 | const MemoryDeviceState *md = MEMORY_DEVICE(obj); |
60 | |
61 | if (dev->realized) { |
62 | *size += memory_device_get_region_size(md, &error_abort); |
63 | } |
64 | } |
65 | |
66 | object_child_foreach(obj, memory_device_used_region_size, opaque); |
67 | return 0; |
68 | } |
69 | |
70 | static void memory_device_check_addable(MachineState *ms, uint64_t size, |
71 | Error **errp) |
72 | { |
73 | uint64_t used_region_size = 0; |
74 | |
75 | /* we will need a new memory slot for kvm and vhost */ |
76 | if (kvm_enabled() && !kvm_has_free_slot(ms)) { |
77 | error_setg(errp, "hypervisor has no free memory slots left" ); |
78 | return; |
79 | } |
80 | if (!vhost_has_free_slot()) { |
81 | error_setg(errp, "a used vhost backend has no free memory slots left" ); |
82 | return; |
83 | } |
84 | |
85 | /* will we exceed the total amount of memory specified */ |
86 | memory_device_used_region_size(OBJECT(ms), &used_region_size); |
87 | if (used_region_size + size < used_region_size || |
88 | used_region_size + size > ms->maxram_size - ms->ram_size) { |
89 | error_setg(errp, "not enough space, currently 0x%" PRIx64 |
90 | " in use of total space for memory devices 0x" RAM_ADDR_FMT, |
91 | used_region_size, ms->maxram_size - ms->ram_size); |
92 | return; |
93 | } |
94 | |
95 | } |
96 | |
97 | static uint64_t memory_device_get_free_addr(MachineState *ms, |
98 | const uint64_t *hint, |
99 | uint64_t align, uint64_t size, |
100 | Error **errp) |
101 | { |
102 | GSList *list = NULL, *item; |
103 | Range as, new = range_empty; |
104 | |
105 | if (!ms->device_memory) { |
106 | error_setg(errp, "memory devices (e.g. for memory hotplug) are not " |
107 | "supported by the machine" ); |
108 | return 0; |
109 | } |
110 | |
111 | if (!memory_region_size(&ms->device_memory->mr)) { |
112 | error_setg(errp, "memory devices (e.g. for memory hotplug) are not " |
113 | "enabled, please specify the maxmem option" ); |
114 | return 0; |
115 | } |
116 | range_init_nofail(&as, ms->device_memory->base, |
117 | memory_region_size(&ms->device_memory->mr)); |
118 | |
119 | /* start of address space indicates the maximum alignment we expect */ |
120 | if (!QEMU_IS_ALIGNED(range_lob(&as), align)) { |
121 | error_setg(errp, "the alignment (0x%" PRIx64 ") is not supported" , |
122 | align); |
123 | return 0; |
124 | } |
125 | |
126 | memory_device_check_addable(ms, size, errp); |
127 | if (*errp) { |
128 | return 0; |
129 | } |
130 | |
131 | if (hint && !QEMU_IS_ALIGNED(*hint, align)) { |
132 | error_setg(errp, "address must be aligned to 0x%" PRIx64 " bytes" , |
133 | align); |
134 | return 0; |
135 | } |
136 | |
137 | if (!QEMU_IS_ALIGNED(size, align)) { |
138 | error_setg(errp, "backend memory size must be multiple of 0x%" |
139 | PRIx64, align); |
140 | return 0; |
141 | } |
142 | |
143 | if (hint) { |
144 | if (range_init(&new, *hint, size) || !range_contains_range(&as, &new)) { |
145 | error_setg(errp, "can't add memory device [0x%" PRIx64 ":0x%" PRIx64 |
146 | "], usable range for memory devices [0x%" PRIx64 ":0x%" |
147 | PRIx64 "]" , *hint, size, range_lob(&as), |
148 | range_size(&as)); |
149 | return 0; |
150 | } |
151 | } else { |
152 | if (range_init(&new, range_lob(&as), size)) { |
153 | error_setg(errp, "can't add memory device, device too big" ); |
154 | return 0; |
155 | } |
156 | } |
157 | |
158 | /* find address range that will fit new memory device */ |
159 | object_child_foreach(OBJECT(ms), memory_device_build_list, &list); |
160 | for (item = list; item; item = g_slist_next(item)) { |
161 | const MemoryDeviceState *md = item->data; |
162 | const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(OBJECT(md)); |
163 | uint64_t next_addr; |
164 | Range tmp; |
165 | |
166 | range_init_nofail(&tmp, mdc->get_addr(md), |
167 | memory_device_get_region_size(md, &error_abort)); |
168 | |
169 | if (range_overlaps_range(&tmp, &new)) { |
170 | if (hint) { |
171 | const DeviceState *d = DEVICE(md); |
172 | error_setg(errp, "address range conflicts with memory device" |
173 | " id='%s'" , d->id ? d->id : "(unnamed)" ); |
174 | goto out; |
175 | } |
176 | |
177 | next_addr = QEMU_ALIGN_UP(range_upb(&tmp) + 1, align); |
178 | if (!next_addr || range_init(&new, next_addr, range_size(&new))) { |
179 | range_make_empty(&new); |
180 | break; |
181 | } |
182 | } |
183 | } |
184 | |
185 | if (!range_contains_range(&as, &new)) { |
186 | error_setg(errp, "could not find position in guest address space for " |
187 | "memory device - memory fragmented due to alignments" ); |
188 | goto out; |
189 | } |
190 | out: |
191 | g_slist_free(list); |
192 | return range_lob(&new); |
193 | } |
194 | |
195 | MemoryDeviceInfoList *qmp_memory_device_list(void) |
196 | { |
197 | GSList *devices = NULL, *item; |
198 | MemoryDeviceInfoList *list = NULL, *prev = NULL; |
199 | |
200 | object_child_foreach(qdev_get_machine(), memory_device_build_list, |
201 | &devices); |
202 | |
203 | for (item = devices; item; item = g_slist_next(item)) { |
204 | const MemoryDeviceState *md = MEMORY_DEVICE(item->data); |
205 | const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(item->data); |
206 | MemoryDeviceInfoList *elem = g_new0(MemoryDeviceInfoList, 1); |
207 | MemoryDeviceInfo *info = g_new0(MemoryDeviceInfo, 1); |
208 | |
209 | mdc->fill_device_info(md, info); |
210 | |
211 | elem->value = info; |
212 | elem->next = NULL; |
213 | if (prev) { |
214 | prev->next = elem; |
215 | } else { |
216 | list = elem; |
217 | } |
218 | prev = elem; |
219 | } |
220 | |
221 | g_slist_free(devices); |
222 | |
223 | return list; |
224 | } |
225 | |
226 | static int memory_device_plugged_size(Object *obj, void *opaque) |
227 | { |
228 | uint64_t *size = opaque; |
229 | |
230 | if (object_dynamic_cast(obj, TYPE_MEMORY_DEVICE)) { |
231 | const DeviceState *dev = DEVICE(obj); |
232 | const MemoryDeviceState *md = MEMORY_DEVICE(obj); |
233 | const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(obj); |
234 | |
235 | if (dev->realized) { |
236 | *size += mdc->get_plugged_size(md, &error_abort); |
237 | } |
238 | } |
239 | |
240 | object_child_foreach(obj, memory_device_plugged_size, opaque); |
241 | return 0; |
242 | } |
243 | |
244 | uint64_t get_plugged_memory_size(void) |
245 | { |
246 | uint64_t size = 0; |
247 | |
248 | memory_device_plugged_size(qdev_get_machine(), &size); |
249 | |
250 | return size; |
251 | } |
252 | |
253 | void memory_device_pre_plug(MemoryDeviceState *md, MachineState *ms, |
254 | const uint64_t *legacy_align, Error **errp) |
255 | { |
256 | const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(md); |
257 | Error *local_err = NULL; |
258 | uint64_t addr, align; |
259 | MemoryRegion *mr; |
260 | |
261 | mr = mdc->get_memory_region(md, &local_err); |
262 | if (local_err) { |
263 | goto out; |
264 | } |
265 | |
266 | align = legacy_align ? *legacy_align : memory_region_get_alignment(mr); |
267 | addr = mdc->get_addr(md); |
268 | addr = memory_device_get_free_addr(ms, !addr ? NULL : &addr, align, |
269 | memory_region_size(mr), &local_err); |
270 | if (local_err) { |
271 | goto out; |
272 | } |
273 | mdc->set_addr(md, addr, &local_err); |
274 | if (!local_err) { |
275 | trace_memory_device_pre_plug(DEVICE(md)->id ? DEVICE(md)->id : "" , |
276 | addr); |
277 | } |
278 | out: |
279 | error_propagate(errp, local_err); |
280 | } |
281 | |
282 | void memory_device_plug(MemoryDeviceState *md, MachineState *ms) |
283 | { |
284 | const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(md); |
285 | const uint64_t addr = mdc->get_addr(md); |
286 | MemoryRegion *mr; |
287 | |
288 | /* |
289 | * We expect that a previous call to memory_device_pre_plug() succeeded, so |
290 | * it can't fail at this point. |
291 | */ |
292 | mr = mdc->get_memory_region(md, &error_abort); |
293 | g_assert(ms->device_memory); |
294 | |
295 | memory_region_add_subregion(&ms->device_memory->mr, |
296 | addr - ms->device_memory->base, mr); |
297 | trace_memory_device_plug(DEVICE(md)->id ? DEVICE(md)->id : "" , addr); |
298 | } |
299 | |
300 | void memory_device_unplug(MemoryDeviceState *md, MachineState *ms) |
301 | { |
302 | const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(md); |
303 | MemoryRegion *mr; |
304 | |
305 | /* |
306 | * We expect that a previous call to memory_device_pre_plug() succeeded, so |
307 | * it can't fail at this point. |
308 | */ |
309 | mr = mdc->get_memory_region(md, &error_abort); |
310 | g_assert(ms->device_memory); |
311 | |
312 | memory_region_del_subregion(&ms->device_memory->mr, mr); |
313 | trace_memory_device_unplug(DEVICE(md)->id ? DEVICE(md)->id : "" , |
314 | mdc->get_addr(md)); |
315 | } |
316 | |
317 | uint64_t memory_device_get_region_size(const MemoryDeviceState *md, |
318 | Error **errp) |
319 | { |
320 | const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(md); |
321 | MemoryRegion *mr; |
322 | |
323 | /* dropping const here is fine as we don't touch the memory region */ |
324 | mr = mdc->get_memory_region((MemoryDeviceState *)md, errp); |
325 | if (!mr) { |
326 | return 0; |
327 | } |
328 | |
329 | return memory_region_size(mr); |
330 | } |
331 | |
332 | static const TypeInfo memory_device_info = { |
333 | .name = TYPE_MEMORY_DEVICE, |
334 | .parent = TYPE_INTERFACE, |
335 | .class_size = sizeof(MemoryDeviceClass), |
336 | }; |
337 | |
338 | static void memory_device_register_types(void) |
339 | { |
340 | type_register_static(&memory_device_info); |
341 | } |
342 | |
343 | type_init(memory_device_register_types) |
344 | |