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