1 /*
2 * libxl_capabilities.c: libxl capabilities generation
3 *
4 * Copyright (C) 2016 SUSE LINUX Products GmbH, Nuernberg, Germany.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see
18 * <http://www.gnu.org/licenses/>.
19 */
20
21 #include <config.h>
22
23 #include <libxl.h>
24
25 #include "internal.h"
26 #include "virlog.h"
27 #include "virerror.h"
28 #include "virfile.h"
29 #include "viralloc.h"
30 #include "virstring.h"
31 #include "domain_conf.h"
32 #include "capabilities.h"
33 #include "domain_capabilities.h"
34 #include "vircommand.h"
35 #include "libxl_capabilities.h"
36 #include "cpu/cpu_x86.h"
37 #include "cpu/cpu_x86_data.h"
38
39
40 #define VIR_FROM_THIS VIR_FROM_LIBXL
41
42 VIR_LOG_INIT("libxl.libxl_capabilities");
43
44 /* see xen-unstable.hg/xen/include/asm-x86/cpufeature.h */
45 #define LIBXL_X86_FEATURE_PAE_MASK (1 << 6)
46 #define LIBXL_X86_FEATURE_LM_MASK (1 << 29)
47
48 struct guest_arch {
49 virArch arch;
50 int hvm;
51 int pvh;
52 int pae;
53 int nonpae;
54 int ia64_be;
55 };
56
57 #define XEN_CAP_REGEX "(xen|hvm)-[[:digit:]]+\\.[[:digit:]]+-(aarch64|armv7l|x86_32|x86_64|ia64|powerpc64)(p|be)?"
58
59 static int
libxlCapsAddCPUID(virCPUData * data,virCPUx86CPUID * cpuid,ssize_t ncaps)60 libxlCapsAddCPUID(virCPUData *data, virCPUx86CPUID *cpuid, ssize_t ncaps)
61 {
62 virCPUx86DataItem item = { 0 };
63 size_t i;
64
65 item.type = VIR_CPU_X86_DATA_CPUID;
66 for (i = 0; i < ncaps; i++) {
67 item.data.cpuid = cpuid[i];
68
69 if (virCPUx86DataAdd(data, &item) < 0) {
70 VIR_DEBUG("Failed to add CPUID(%x,%x)",
71 cpuid[i].eax_in, cpuid[i].ecx_in);
72 return -1;
73 }
74 }
75
76 return 0;
77 }
78
79 /*
80 * The words represented in physinfo.hw_cap are host CPUID (sub) leafs.
81 * Position of these hasn't changed much up until Xen 4.7 with a rework
82 * on how CPUID is handled internally. As a side-effect it got normalized
83 * and also added more feature words. Although cannot be relied upon as
84 * stable interface, and hence we version changes in position of the features
85 * across all supported versions of the libxl driver until libxl exposes a
86 * stable representation of these capabilities. Fortunately not a lot of
87 * variation happened so it's still trivial to keep track of these leafs
88 * to describe host CPU in libvirt capabilities.
89 *
90 * | Xen >= 4.7 |
91 * ------------------------
92 * word 0 | CPUID.00000001.EDX |
93 * word 1 | CPUID.00000001.ECX |
94 * word 2 | CPUID.80000001.EDX |
95 * word 3 | CPUID.80000001.ECX |
96 * word 4 | CPUID.0000000D:1.EAX |
97 * word 5 | CPUID.00000007:0.EBX |
98 * word 6 | CPUID.00000007:0.ECX |
99 * word 7 | CPUID.80000007.EDX |
100 * word 8 | CPUID.80000008.EBX |
101 *
102 */
103 static virCPUData *
libxlCapsNodeData(virCPUDef * cpu,libxl_hwcap hwcap)104 libxlCapsNodeData(virCPUDef *cpu, libxl_hwcap hwcap)
105 {
106 ssize_t ncaps;
107 g_autoptr(virCPUData) cpudata = NULL;
108 virCPUx86CPUID cpuid[] = {
109 { .eax_in = 0x00000001, .edx = hwcap[0] },
110 { .eax_in = 0x00000001, .ecx = hwcap[1] },
111 { .eax_in = 0x80000001, .edx = hwcap[2] },
112 { .eax_in = 0x80000001, .ecx = hwcap[3] },
113 { .eax_in = 0x00000007, .ebx = hwcap[5] },
114 { .eax_in = 0x0000000D, .ecx_in = 1U, .eax = hwcap[4] },
115 { .eax_in = 0x00000007, .ecx_in = 0U, .ecx = hwcap[6] },
116 { .eax_in = 0x80000007, .ecx_in = 0U, .edx = hwcap[7] },
117 };
118
119 if (!(cpudata = virCPUDataNew(cpu->arch)))
120 return NULL;
121
122 ncaps = G_N_ELEMENTS(cpuid);
123 if (libxlCapsAddCPUID(cpudata, cpuid, ncaps) < 0)
124 return NULL;
125
126 return g_steal_pointer(&cpudata);
127 }
128
129 /* hw_caps is an array of 32-bit words whose meaning is listed in
130 * xen-unstable.hg/xen/include/asm-x86/cpufeature.h. Each feature
131 * is defined in the form X*32+Y, corresponding to the Y'th bit in
132 * the X'th 32-bit word of hw_cap.
133 */
134 static int
libxlCapsInitCPU(virCaps * caps,libxl_physinfo * phy_info)135 libxlCapsInitCPU(virCaps *caps, libxl_physinfo *phy_info)
136 {
137 g_autoptr(virCPUData) data = NULL;
138 g_autoptr(virCPUDef) cpu = NULL;
139 int host_pae;
140 int host_lm;
141
142 /* On ARM hw_cap vector is zeroed out but not on x86 */
143 if (!phy_info->hw_cap[0])
144 return 0;
145
146 cpu = virCPUDefNew();
147
148 host_pae = phy_info->hw_cap[0] & LIBXL_X86_FEATURE_PAE_MASK;
149 if (host_pae &&
150 virCapabilitiesAddHostFeature(caps, "pae") < 0)
151 return -1;
152
153 host_lm = (phy_info->hw_cap[2] & LIBXL_X86_FEATURE_LM_MASK);
154 if (host_lm)
155 cpu->arch = VIR_ARCH_X86_64;
156 else
157 cpu->arch = VIR_ARCH_I686;
158
159 cpu->type = VIR_CPU_TYPE_HOST;
160 cpu->cores = phy_info->cores_per_socket;
161 cpu->threads = phy_info->threads_per_core;
162 cpu->dies = 1;
163 cpu->sockets = phy_info->nr_cpus / (cpu->cores * cpu->threads);
164
165 if (!(data = libxlCapsNodeData(cpu, phy_info->hw_cap)) ||
166 cpuDecode(cpu, data, NULL) < 0) {
167 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
168 _("Failed to initialize host cpu features"));
169 return -1;
170 }
171
172 caps->host.cpu = g_steal_pointer(&cpu);
173 return 0;
174 }
175
176 static int
libxlCapsInitHost(libxl_ctx * ctx,virCaps * caps)177 libxlCapsInitHost(libxl_ctx *ctx, virCaps *caps)
178 {
179 libxl_physinfo phy_info;
180 int ret = -1;
181
182 libxl_physinfo_init(&phy_info);
183 if (libxl_get_physinfo(ctx, &phy_info) != 0) {
184 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
185 _("Failed to get node physical info from libxenlight"));
186 goto cleanup;
187 }
188
189 if (libxlCapsInitCPU(caps, &phy_info) < 0)
190 goto cleanup;
191
192 if (virCapabilitiesSetNetPrefix(caps, LIBXL_GENERATED_PREFIX_XEN) < 0)
193 goto cleanup;
194
195 ret = 0;
196
197 cleanup:
198 libxl_physinfo_dispose(&phy_info);
199 return ret;
200 }
201
202 static int
libxlCapsInitNuma(libxl_ctx * ctx,virCaps * caps)203 libxlCapsInitNuma(libxl_ctx *ctx, virCaps *caps)
204 {
205 libxl_numainfo *numa_info = NULL;
206 libxl_cputopology *cpu_topo = NULL;
207 int nr_nodes = 0, nr_cpus = 0, nr_distances = 0;
208 virCapsHostNUMACellCPU **cpus = NULL;
209 virNumaDistance *distances = NULL;
210 int *nr_cpus_node = NULL;
211 size_t i;
212 int ret = -1;
213
214 /* Let's try to fetch all the topology information */
215 numa_info = libxl_get_numainfo(ctx, &nr_nodes);
216 if (numa_info == NULL || nr_nodes == 0) {
217 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
218 _("libxl_get_numainfo failed"));
219 goto cleanup;
220 }
221
222 cpu_topo = libxl_get_cpu_topology(ctx, &nr_cpus);
223 if (cpu_topo == NULL || nr_cpus == 0) {
224 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
225 _("libxl_get_cpu_topology failed"));
226 goto cleanup;
227 }
228
229 cpus = g_new0(virCapsHostNUMACellCPU *, nr_nodes);
230
231 nr_cpus_node = g_new0(int, nr_nodes);
232
233 /* For each node, prepare a list of CPUs belonging to that node */
234 for (i = 0; i < nr_cpus; i++) {
235 int node = cpu_topo[i].node;
236
237 if (cpu_topo[i].core == LIBXL_CPUTOPOLOGY_INVALID_ENTRY)
238 continue;
239
240 nr_cpus_node[node]++;
241
242 if (nr_cpus_node[node] == 1) {
243 cpus[node] = g_new0(virCapsHostNUMACellCPU, 1);
244 } else {
245 VIR_REALLOC_N(cpus[node], nr_cpus_node[node]);
246 }
247
248 /* Mapping between what libxl tells and what libvirt wants */
249 cpus[node][nr_cpus_node[node]-1].id = i;
250 cpus[node][nr_cpus_node[node]-1].socket_id = cpu_topo[i].socket;
251 cpus[node][nr_cpus_node[node]-1].core_id = cpu_topo[i].core;
252 /* Until Xen reports die_id, 0 is better than random garbage */
253 cpus[node][nr_cpus_node[node]-1].die_id = 0;
254 /* Allocate the siblings maps. We will be filling them later */
255 cpus[node][nr_cpus_node[node]-1].siblings = virBitmapNew(nr_cpus);
256 }
257
258 /* Let's now populate the siblings bitmaps */
259 for (i = 0; i < nr_cpus; i++) {
260 int node = cpu_topo[i].node;
261 size_t j;
262
263 if (cpu_topo[i].core == LIBXL_CPUTOPOLOGY_INVALID_ENTRY)
264 continue;
265
266 for (j = 0; j < nr_cpus_node[node]; j++) {
267 if (cpus[node][j].socket_id == cpu_topo[i].socket &&
268 cpus[node][j].core_id == cpu_topo[i].core)
269 ignore_value(virBitmapSetBit(cpus[node][j].siblings, i));
270 }
271 }
272
273 caps->host.numa = virCapabilitiesHostNUMANew();
274 for (i = 0; i < nr_nodes; i++) {
275 if (numa_info[i].size == LIBXL_NUMAINFO_INVALID_ENTRY)
276 continue;
277
278 nr_distances = numa_info[i].num_dists;
279 if (nr_distances) {
280 size_t j;
281
282 distances = g_new0(virNumaDistance, nr_distances);
283
284 for (j = 0; j < nr_distances; j++) {
285 distances[j].cellid = j;
286 distances[j].value = numa_info[i].dists[j];
287 }
288 }
289
290 virCapabilitiesHostNUMAAddCell(caps->host.numa, i,
291 numa_info[i].size / 1024,
292 nr_cpus_node[i], &cpus[i],
293 nr_distances, &distances,
294 0, NULL,
295 NULL);
296
297 /* This is safe, as the CPU list is now stored in the NUMA cell */
298 cpus[i] = NULL;
299 }
300
301 ret = 0;
302
303 cleanup:
304 if (ret != 0) {
305 for (i = 0; cpus && i < nr_nodes; i++)
306 VIR_FREE(cpus[i]);
307 if (caps->host.numa) {
308 virCapabilitiesHostNUMAUnref(caps->host.numa);
309 caps->host.numa = NULL;
310 }
311 VIR_FREE(distances);
312 }
313
314 VIR_FREE(cpus);
315 VIR_FREE(nr_cpus_node);
316 libxl_cputopology_list_free(cpu_topo, nr_cpus);
317 libxl_numainfo_list_free(numa_info, nr_nodes);
318
319 return ret;
320 }
321
322 static int
libxlCapsInitGuests(libxl_ctx * ctx,virCaps * caps)323 libxlCapsInitGuests(libxl_ctx *ctx, virCaps *caps)
324 {
325 const libxl_version_info *ver_info;
326 g_autoptr(GRegex) regex = NULL;
327 g_autoptr(GError) err = NULL;
328 g_autoptr(GMatchInfo) info = NULL;
329 char *str, *token;
330 char *saveptr = NULL;
331 size_t i;
332
333 struct guest_arch guest_archs[32];
334 int nr_guest_archs = 0;
335
336 memset(guest_archs, 0, sizeof(guest_archs));
337
338 if ((ver_info = libxl_get_version_info(ctx)) == NULL) {
339 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
340 _("Failed to get version info from libxenlight"));
341 return -1;
342 }
343
344 if (!ver_info->capabilities) {
345 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
346 _("Failed to get capabilities from libxenlight"));
347 return -1;
348 }
349
350 regex = g_regex_new(XEN_CAP_REGEX, 0, 0, &err);
351 if (!regex) {
352 virReportError(VIR_ERR_INTERNAL_ERROR,
353 _("Failed to compile regex %s"), err->message);
354 return -1;
355 }
356
357 /* Format of capabilities string is documented in the code in
358 * xen-unstable.hg/xen/arch/.../setup.c.
359 *
360 * It is a space-separated list of supported guest architectures.
361 *
362 * For x86:
363 * TYP-VER-ARCH[p]
364 * ^ ^ ^ ^
365 * | | | +-- PAE supported
366 * | | +------- x86_32 or x86_64
367 * | +----------- the version of Xen, eg. "3.0"
368 * +--------------- "xen" or "hvm" for para or full virt respectively
369 *
370 * For IA64:
371 * TYP-VER-ARCH[be]
372 * ^ ^ ^ ^
373 * | | | +-- Big-endian supported
374 * | | +------- always "ia64"
375 * | +----------- the version of Xen, eg. "3.0"
376 * +--------------- "xen" or "hvm" for para or full virt respectively
377 */
378
379 /* Split capabilities string into tokens. strtok_r is OK here because
380 * we "own" the buffer. Parse out the features from each token.
381 */
382 for (str = ver_info->capabilities, nr_guest_archs = 0;
383 nr_guest_archs < G_N_ELEMENTS(guest_archs)
384 && (token = strtok_r(str, " ", &saveptr)) != NULL;
385 str = NULL) {
386 if (g_regex_match(regex, token, 0, &info)) {
387 g_autofree char *modestr = g_match_info_fetch(info, 1);
388 g_autofree char *archstr = g_match_info_fetch(info, 2);
389 g_autofree char *suffixstr = g_match_info_fetch(info, 3);
390 int hvm = STRPREFIX(modestr, "hvm");
391 virArch arch;
392 int pae = 0, nonpae = 0, ia64_be = 0;
393
394 if (STRPREFIX(archstr, "x86_32")) {
395 arch = VIR_ARCH_I686;
396 if (suffixstr != NULL && STRPREFIX(suffixstr, "p"))
397 pae = 1;
398 else
399 nonpae = 1;
400 } else if (STRPREFIX(archstr, "x86_64")) {
401 arch = VIR_ARCH_X86_64;
402 } else if (STRPREFIX(archstr, "ia64")) {
403 arch = VIR_ARCH_ITANIUM;
404 if (suffixstr != NULL && STRPREFIX(suffixstr, "be"))
405 ia64_be = 1;
406 } else if (STRPREFIX(archstr, "powerpc64")) {
407 arch = VIR_ARCH_PPC64;
408 } else if (STRPREFIX(archstr, "armv7l")) {
409 arch = VIR_ARCH_ARMV7L;
410 } else if (STRPREFIX(archstr, "aarch64")) {
411 arch = VIR_ARCH_AARCH64;
412 } else {
413 continue;
414 }
415
416 /* Search for existing matching (model,hvm) tuple */
417 for (i = 0; i < nr_guest_archs; i++) {
418 if ((guest_archs[i].arch == arch) &&
419 guest_archs[i].hvm == hvm)
420 break;
421 }
422
423 /* Too many arch flavours - highly unlikely ! */
424 if (i >= G_N_ELEMENTS(guest_archs))
425 continue;
426 /* Didn't find a match, so create a new one */
427 if (i == nr_guest_archs)
428 nr_guest_archs++;
429
430 guest_archs[i].arch = arch;
431 guest_archs[i].hvm = hvm;
432
433 /* Careful not to overwrite a previous positive
434 setting with a negative one here - some archs
435 can do both pae & non-pae, but Xen reports
436 separately capabilities so we're merging archs */
437 if (pae)
438 guest_archs[i].pae = pae;
439 if (nonpae)
440 guest_archs[i].nonpae = nonpae;
441 if (ia64_be)
442 guest_archs[i].ia64_be = ia64_be;
443
444 /*
445 * Xen 4.10 introduced support for the PVH guest type, which
446 * requires hardware virtualization support similar to the
447 * HVM guest type. Add a PVH guest type for each new HVM
448 * guest type.
449 */
450 #ifdef WITH_XEN_PVH
451 if (hvm && i == nr_guest_archs-1) {
452 /* Ensure we have not exhausted the guest_archs array */
453 if (nr_guest_archs >= G_N_ELEMENTS(guest_archs))
454 continue;
455 i = nr_guest_archs;
456 nr_guest_archs++;
457
458 guest_archs[i].arch = arch;
459 guest_archs[i].hvm = 0;
460 guest_archs[i].pvh = 1;
461 }
462 #endif
463 }
464 }
465
466 for (i = 0; i < nr_guest_archs; ++i) {
467 virCapsGuest *guest;
468 char const *const xen_machines[] = {
469 guest_archs[i].hvm ? "xenfv" :
470 (guest_archs[i].pvh ? "xenpvh" : "xenpv")};
471 virCapsGuestMachine **machines;
472
473 if ((machines = virCapabilitiesAllocMachines(xen_machines, 1)) == NULL)
474 return -1;
475
476 guest = virCapabilitiesAddGuest(caps,
477 guest_archs[i].hvm ? VIR_DOMAIN_OSTYPE_HVM :
478 (guest_archs[i].pvh ? VIR_DOMAIN_OSTYPE_XENPVH :
479 VIR_DOMAIN_OSTYPE_XEN),
480 guest_archs[i].arch,
481 LIBXL_EXECBIN_DIR "/qemu-system-i386",
482 (guest_archs[i].hvm ?
483 LIBXL_FIRMWARE_DIR "/hvmloader" :
484 NULL),
485 1,
486 machines);
487 machines = NULL;
488
489 virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_XEN,
490 NULL, NULL, 0, NULL);
491
492 if (guest_archs[i].pae)
493 virCapabilitiesAddGuestFeature(guest, VIR_CAPS_GUEST_FEATURE_TYPE_PAE);
494
495 if (guest_archs[i].nonpae)
496 virCapabilitiesAddGuestFeature(guest, VIR_CAPS_GUEST_FEATURE_TYPE_NONPAE);
497
498 if (guest_archs[i].ia64_be)
499 virCapabilitiesAddGuestFeature(guest, VIR_CAPS_GUEST_FEATURE_TYPE_IA64_BE);
500
501 if (guest_archs[i].hvm) {
502 virCapabilitiesAddGuestFeatureWithToggle(guest, VIR_CAPS_GUEST_FEATURE_TYPE_ACPI,
503 true, true);
504
505 virCapabilitiesAddGuestFeatureWithToggle(guest, VIR_CAPS_GUEST_FEATURE_TYPE_APIC,
506 true, false);
507 }
508
509 if (guest_archs[i].hvm || guest_archs[i].pvh) {
510 virCapabilitiesAddGuestFeatureWithToggle(guest, VIR_CAPS_GUEST_FEATURE_TYPE_HAP,
511 true, true);
512 }
513 }
514
515 return 0;
516 }
517
518 static int
libxlMakeDomainOSCaps(const char * machine,virDomainCapsOS * os,virFirmware ** firmwares,size_t nfirmwares)519 libxlMakeDomainOSCaps(const char *machine,
520 virDomainCapsOS *os,
521 virFirmware **firmwares,
522 size_t nfirmwares)
523 {
524 virDomainCapsLoader *capsLoader = &os->loader;
525 size_t i;
526
527 os->supported = VIR_TRISTATE_BOOL_YES;
528 capsLoader->supported = VIR_TRISTATE_BOOL_NO;
529 capsLoader->type.report = true;
530 capsLoader->readonly.report = true;
531
532 if (STREQ(machine, "xenpv") || STREQ(machine, "xenpvh"))
533 return 0;
534
535 capsLoader->supported = VIR_TRISTATE_BOOL_YES;
536 capsLoader->values.values = g_new0(char *, nfirmwares);
537
538 for (i = 0; i < nfirmwares; i++) {
539 capsLoader->values.values[capsLoader->values.nvalues] = g_strdup(firmwares[i]->name);
540 capsLoader->values.nvalues++;
541 }
542
543 VIR_DOMAIN_CAPS_ENUM_SET(capsLoader->type,
544 VIR_DOMAIN_LOADER_TYPE_ROM,
545 VIR_DOMAIN_LOADER_TYPE_PFLASH);
546 VIR_DOMAIN_CAPS_ENUM_SET(capsLoader->readonly,
547 VIR_TRISTATE_BOOL_YES);
548
549 return 0;
550 }
551
552 static int
libxlMakeDomainDeviceDiskCaps(virDomainCapsDeviceDisk * dev)553 libxlMakeDomainDeviceDiskCaps(virDomainCapsDeviceDisk *dev)
554 {
555 dev->supported = VIR_TRISTATE_BOOL_YES;
556 dev->diskDevice.report = true;
557 dev->bus.report = true;
558 dev->model.report = true;
559
560 VIR_DOMAIN_CAPS_ENUM_SET(dev->diskDevice,
561 VIR_DOMAIN_DISK_DEVICE_DISK,
562 VIR_DOMAIN_DISK_DEVICE_CDROM);
563
564 VIR_DOMAIN_CAPS_ENUM_SET(dev->bus,
565 VIR_DOMAIN_DISK_BUS_IDE,
566 VIR_DOMAIN_DISK_BUS_SCSI,
567 VIR_DOMAIN_DISK_BUS_XEN);
568
569 return 0;
570 }
571
572 static int
libxlMakeDomainDeviceGraphicsCaps(virDomainCapsDeviceGraphics * dev)573 libxlMakeDomainDeviceGraphicsCaps(virDomainCapsDeviceGraphics *dev)
574 {
575 dev->supported = VIR_TRISTATE_BOOL_YES;
576 dev->type.report = true;
577
578 VIR_DOMAIN_CAPS_ENUM_SET(dev->type,
579 VIR_DOMAIN_GRAPHICS_TYPE_SDL,
580 VIR_DOMAIN_GRAPHICS_TYPE_VNC,
581 VIR_DOMAIN_GRAPHICS_TYPE_SPICE);
582
583 return 0;
584 }
585
586 static int
libxlMakeDomainDeviceVideoCaps(virDomainCapsDeviceVideo * dev)587 libxlMakeDomainDeviceVideoCaps(virDomainCapsDeviceVideo *dev)
588 {
589 dev->supported = VIR_TRISTATE_BOOL_YES;
590 dev->modelType.report = true;
591
592 VIR_DOMAIN_CAPS_ENUM_SET(dev->modelType,
593 VIR_DOMAIN_VIDEO_TYPE_VGA,
594 VIR_DOMAIN_VIDEO_TYPE_CIRRUS,
595 VIR_DOMAIN_VIDEO_TYPE_XEN);
596
597 return 0;
598 }
599
600 static int
libxlMakeDomainDeviceHostdevCaps(virDomainCapsDeviceHostdev * dev)601 libxlMakeDomainDeviceHostdevCaps(virDomainCapsDeviceHostdev *dev)
602 {
603 dev->supported = VIR_TRISTATE_BOOL_YES;
604 dev->mode.report = true;
605 dev->startupPolicy.report = true;
606 dev->subsysType.report = true;
607 dev->capsType.report = true;
608 dev->pciBackend.report = true;
609
610 /* VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES is for containers only */
611 VIR_DOMAIN_CAPS_ENUM_SET(dev->mode,
612 VIR_DOMAIN_HOSTDEV_MODE_SUBSYS);
613
614 VIR_DOMAIN_CAPS_ENUM_SET(dev->startupPolicy,
615 VIR_DOMAIN_STARTUP_POLICY_DEFAULT,
616 VIR_DOMAIN_STARTUP_POLICY_MANDATORY,
617 VIR_DOMAIN_STARTUP_POLICY_REQUISITE,
618 VIR_DOMAIN_STARTUP_POLICY_OPTIONAL);
619
620 VIR_DOMAIN_CAPS_ENUM_SET(dev->subsysType,
621 VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI);
622
623 VIR_DOMAIN_CAPS_ENUM_SET(dev->subsysType,
624 VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB);
625
626 /* No virDomainHostdevCapsType for libxl */
627 virDomainCapsEnumClear(&dev->capsType);
628
629 virDomainCapsEnumClear(&dev->pciBackend);
630 VIR_DOMAIN_CAPS_ENUM_SET(dev->pciBackend,
631 VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN);
632 return 0;
633 }
634
635 virCaps *
libxlMakeCapabilities(libxl_ctx * ctx)636 libxlMakeCapabilities(libxl_ctx *ctx)
637 {
638 virCaps *caps;
639
640 #ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
641 if ((caps = virCapabilitiesNew(virArchFromHost(), false, false)) == NULL)
642 #else
643 if ((caps = virCapabilitiesNew(virArchFromHost(), true, true)) == NULL)
644 #endif
645 return NULL;
646
647 if (libxlCapsInitHost(ctx, caps) < 0)
648 goto error;
649
650 if (libxlCapsInitNuma(ctx, caps) < 0)
651 goto error;
652
653 if (libxlCapsInitGuests(ctx, caps) < 0)
654 goto error;
655
656 return caps;
657
658 error:
659 virObjectUnref(caps);
660 return NULL;
661 }
662
663 /*
664 * Currently Xen has no interface to report maxvcpus supported
665 * for the various domain types (PV, HVM, PVH). HVM_MAX_VCPUS
666 * is defined in $xensrc/xen/include/public/hvm/hvm_info_table.h
667 * PV has no equivalent and is relunctantly set here until Xen
668 * can report such capabilities.
669 */
670 #define HVM_MAX_VCPUS 128
671 #define PV_MAX_VCPUS 512
672
673 int
libxlMakeDomainCapabilities(virDomainCaps * domCaps,virFirmware ** firmwares,size_t nfirmwares)674 libxlMakeDomainCapabilities(virDomainCaps *domCaps,
675 virFirmware **firmwares,
676 size_t nfirmwares)
677 {
678 virDomainCapsOS *os = &domCaps->os;
679 virDomainCapsDeviceDisk *disk = &domCaps->disk;
680 virDomainCapsDeviceGraphics *graphics = &domCaps->graphics;
681 virDomainCapsDeviceVideo *video = &domCaps->video;
682 virDomainCapsDeviceHostdev *hostdev = &domCaps->hostdev;
683
684 if (STREQ(domCaps->machine, "xenfv"))
685 domCaps->maxvcpus = HVM_MAX_VCPUS;
686 else
687 domCaps->maxvcpus = PV_MAX_VCPUS;
688
689 if (libxlMakeDomainOSCaps(domCaps->machine, os, firmwares, nfirmwares) < 0 ||
690 libxlMakeDomainDeviceDiskCaps(disk) < 0 ||
691 libxlMakeDomainDeviceGraphicsCaps(graphics) < 0 ||
692 libxlMakeDomainDeviceVideoCaps(video) < 0)
693 return -1;
694 if (STRNEQ(domCaps->machine, "xenpvh") &&
695 libxlMakeDomainDeviceHostdevCaps(hostdev) < 0)
696 return -1;
697
698 domCaps->features[VIR_DOMAIN_CAPS_FEATURE_IOTHREADS] = VIR_TRISTATE_BOOL_NO;
699 domCaps->features[VIR_DOMAIN_CAPS_FEATURE_VMCOREINFO] = VIR_TRISTATE_BOOL_NO;
700 domCaps->features[VIR_DOMAIN_CAPS_FEATURE_GENID] = VIR_TRISTATE_BOOL_NO;
701 domCaps->gic.supported = VIR_TRISTATE_BOOL_NO;
702
703 return 0;
704 }
705
706 #define LIBXL_QEMU_DM_STR "Options specific to the Xen version:"
707
708 int
libxlDomainGetEmulatorType(const virDomainDef * def)709 libxlDomainGetEmulatorType(const virDomainDef *def)
710 {
711 int ret = LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN;
712 g_autoptr(virCommand) cmd = NULL;
713 g_autofree char *output = NULL;
714
715 if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
716 if (def->emulator) {
717 if (!virFileExists(def->emulator))
718 return ret;
719
720 cmd = virCommandNew(def->emulator);
721
722 virCommandAddArgList(cmd, "-help", NULL);
723 virCommandSetOutputBuffer(cmd, &output);
724
725 if (virCommandRun(cmd, NULL) < 0)
726 return ret;
727
728 if (strstr(output, LIBXL_QEMU_DM_STR))
729 ret = LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL;
730 }
731 }
732
733 return ret;
734 }
735