You need to sign in or sign up before continuing.
xen_hypervisor.c 99.3 KB
Newer Older
1
/*
2
 * xen_hypervisor.c: direct access to Xen hypervisor level
3
 *
4
 * Copyright (C) 2005-2014 Red Hat, Inc.
5
 *
O
Osier Yang 已提交
6 7 8 9 10 11 12 13 14 15 16
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library.  If not, see
O
Osier Yang 已提交
18
 * <http://www.gnu.org/licenses/>.
19 20 21 22
 *
 * Daniel Veillard <veillard@redhat.com>
 */

23
#include <config.h>
24

25 26
#include <stdio.h>
#include <string.h>
27
/* required for uint8_t, uint32_t, etc ... */
28 29 30 31 32 33 34
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
35
#include <limits.h>
36 37
#include <regex.h>
#include <errno.h>
38

J
John Levon 已提交
39
#ifdef __sun
40
# include <sys/systeminfo.h>
J
John Levon 已提交
41

42
# include <priv.h>
J
John Levon 已提交
43

44 45 46
# ifndef PRIV_XVM_CONTROL
#  define PRIV_XVM_CONTROL ((const char *)"xvm_control")
# endif
J
John Levon 已提交
47 48 49

#endif /* __sun */

50
/* required for dom0_getdomaininfo_t */
51
#include <xen/dom0_ops.h>
52
#include <xen/version.h>
53
#ifdef HAVE_XEN_LINUX_PRIVCMD_H
54
# include <xen/linux/privcmd.h>
55
#else
56 57 58
# ifdef HAVE_XEN_SYS_PRIVCMD_H
#  include <xen/sys/privcmd.h>
# endif
59
#endif
60

61 62 63
/* required for shutdown flags */
#include <xen/sched.h>

64
#include "virerror.h"
65
#include "virlog.h"
66
#include "datatypes.h"
67
#include "driver.h"
68 69
#include "xen_driver.h"
#include "xen_hypervisor.h"
70
#include "xs_internal.h"
71
#include "virnetdevtap.h"
72
#include "block_stats.h"
73
#include "xend_internal.h"
74
#include "virbuffer.h"
75
#include "capabilities.h"
76
#include "viralloc.h"
77
#include "virthread.h"
E
Eric Blake 已提交
78
#include "virfile.h"
79
#include "virnodesuspend.h"
80
#include "virtypedparam.h"
E
Eric Blake 已提交
81
#include "virendian.h"
82
#include "virstring.h"
83

84 85
#define VIR_FROM_THIS VIR_FROM_XEN

86 87
VIR_LOG_INIT("xen.xen_hypervisor");

88
/*
89
 * so far there is 2 versions of the structures usable for doing
90 91 92 93
 * hypervisor calls.
 */
/* the old one */
typedef struct v0_hypercall_struct {
94 95
    unsigned long op;
    unsigned long arg[5];
96
} v0_hypercall_t;
97 98

#ifdef __linux__
99
# define XEN_V0_IOCTL_HYPERCALL_CMD \
100 101 102 103 104 105 106
        _IOC(_IOC_NONE, 'P', 0, sizeof(v0_hypercall_t))
/* the new one */
typedef struct v1_hypercall_struct
{
    uint64_t op;
    uint64_t arg[5];
} v1_hypercall_t;
107
# define XEN_V1_IOCTL_HYPERCALL_CMD                  \
108
    _IOC(_IOC_NONE, 'P', 0, sizeof(v1_hypercall_t))
109
typedef v1_hypercall_t hypercall_t;
110
#elif defined(__sun)
111 112
typedef privcmd_hypercall_t hypercall_t;
#else
113
# error "unsupported platform"
114
#endif
115 116

#ifndef __HYPERVISOR_sysctl
117
# define __HYPERVISOR_sysctl 35
118 119
#endif
#ifndef __HYPERVISOR_domctl
120
# define __HYPERVISOR_domctl 36
121
#endif
122

123
#define SYS_IFACE_MIN_VERS_NUMA 4
124

125
static int xen_ioctl_hypercall_cmd;
P
Philipp Hahn 已提交
126 127 128 129 130 131 132
static struct xenHypervisorVersions hv_versions = {
    .hv = 0,
    .hypervisor = 2,
    .sys_interface = -1,
    .dom_interface = -1,
};

133
static int kb_per_pages;
134

135 136 137 138 139 140 141 142
/* Regular expressions used by xenHypervisorGetCapabilities, and
 * compiled once by xenHypervisorInit.  Note that these are POSIX.2
 * extended regular expressions (regex(7)).
 */
static const char *flags_hvm_re = "^flags[[:blank:]]+:.* (vmx|svm)[[:space:]]";
static regex_t flags_hvm_rec;
static const char *flags_pae_re = "^flags[[:blank:]]+:.* pae[[:space:]]";
static regex_t flags_pae_rec;
143
static const char *xen_cap_re = "(xen|hvm)-[[:digit:]]+\\.[[:digit:]]+-(x86_32|x86_64|ia64|powerpc64)(p|be)?";
144 145
static regex_t xen_cap_rec;

146 147 148 149
/*
 * The content of the structures for a getdomaininfolist system hypercall
 */
#ifndef DOMFLAGS_DYING
150 151 152 153 154 155 156 157 158 159
# define DOMFLAGS_DYING     (1<<0) /* Domain is scheduled to die.             */
# define DOMFLAGS_HVM       (1<<1) /* Domain is HVM                           */
# define DOMFLAGS_SHUTDOWN  (1<<2) /* The guest OS has shut down.             */
# define DOMFLAGS_PAUSED    (1<<3) /* Currently paused by control software.   */
# define DOMFLAGS_BLOCKED   (1<<4) /* Currently blocked pending an event.     */
# define DOMFLAGS_RUNNING   (1<<5) /* Domain is currently running.            */
# define DOMFLAGS_CPUMASK      255 /* CPU to which this domain is bound.      */
# define DOMFLAGS_CPUSHIFT       8
# define DOMFLAGS_SHUTDOWNMASK 255 /* DOMFLAGS_SHUTDOWN guest-supplied code.  */
# define DOMFLAGS_SHUTDOWNSHIFT 16
160 161
#endif

162 163 164 165 166
/*
 * These flags explain why a system is in the state of "shutdown".  Normally,
 * They are defined in xen/sched.h
 */
#ifndef SHUTDOWN_poweroff
167 168 169 170
# define SHUTDOWN_poweroff   0  /* Domain exited normally. Clean up and kill. */
# define SHUTDOWN_reboot     1  /* Clean up, kill, and then restart.          */
# define SHUTDOWN_suspend    2  /* Clean up, save suspend info, kill.         */
# define SHUTDOWN_crash      3  /* Tell controller we've crashed.             */
171 172
#endif

173 174 175 176 177 178
#define XEN_V0_OP_GETDOMAININFOLIST	38
#define XEN_V1_OP_GETDOMAININFOLIST	38
#define XEN_V2_OP_GETDOMAININFOLIST	6

struct xen_v0_getdomaininfo {
    domid_t  domain;	/* the domain number */
R
Richard W.M. Jones 已提交
179
    uint32_t flags;	/* flags, see before */
180 181
    uint64_t tot_pages;	/* total number of pages used */
    uint64_t max_pages;	/* maximum number of pages allowed */
182
    unsigned long shared_info_frame; /* MFN of shared_info struct */
183 184 185 186 187 188 189 190
    uint64_t cpu_time;  /* CPU time used */
    uint32_t nr_online_vcpus;  /* Number of VCPUs currently online. */
    uint32_t max_vcpu_id; /* Maximum VCPUID in use by this domain. */
    uint32_t ssidref;
    xen_domain_handle_t handle;
};
typedef struct xen_v0_getdomaininfo xen_v0_getdomaininfo;

191 192
struct xen_v2_getdomaininfo {
    domid_t  domain;	/* the domain number */
R
Richard W.M. Jones 已提交
193
    uint32_t flags;	/* flags, see before */
194 195 196 197 198 199 200 201 202 203 204
    uint64_t tot_pages;	/* total number of pages used */
    uint64_t max_pages;	/* maximum number of pages allowed */
    uint64_t shared_info_frame; /* MFN of shared_info struct */
    uint64_t cpu_time;  /* CPU time used */
    uint32_t nr_online_vcpus;  /* Number of VCPUs currently online. */
    uint32_t max_vcpu_id; /* Maximum VCPUID in use by this domain. */
    uint32_t ssidref;
    xen_domain_handle_t handle;
};
typedef struct xen_v2_getdomaininfo xen_v2_getdomaininfo;

205 206 207 208 209 210 211

/* As of Hypervisor Call v2,  DomCtl v5 we are now 8-byte aligned
   even on 32-bit archs when dealing with uint64_t */
#define ALIGN_64 __attribute__((aligned(8)))

struct xen_v2d5_getdomaininfo {
    domid_t  domain;	/* the domain number */
R
Richard W.M. Jones 已提交
212
    uint32_t flags;	/* flags, see before */
213 214 215 216 217 218 219 220 221 222 223
    uint64_t tot_pages ALIGN_64;	/* total number of pages used */
    uint64_t max_pages ALIGN_64;	/* maximum number of pages allowed */
    uint64_t shared_info_frame ALIGN_64; /* MFN of shared_info struct */
    uint64_t cpu_time ALIGN_64;  /* CPU time used */
    uint32_t nr_online_vcpus;  /* Number of VCPUs currently online. */
    uint32_t max_vcpu_id; /* Maximum VCPUID in use by this domain. */
    uint32_t ssidref;
    xen_domain_handle_t handle;
};
typedef struct xen_v2d5_getdomaininfo xen_v2d5_getdomaininfo;

224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
struct xen_v2d6_getdomaininfo {
    domid_t  domain;	/* the domain number */
    uint32_t flags;	/* flags, see before */
    uint64_t tot_pages ALIGN_64;	/* total number of pages used */
    uint64_t max_pages ALIGN_64;	/* maximum number of pages allowed */
    uint64_t shr_pages ALIGN_64;    /* number of shared pages */
    uint64_t shared_info_frame ALIGN_64; /* MFN of shared_info struct */
    uint64_t cpu_time ALIGN_64;  /* CPU time used */
    uint32_t nr_online_vcpus;  /* Number of VCPUs currently online. */
    uint32_t max_vcpu_id; /* Maximum VCPUID in use by this domain. */
    uint32_t ssidref;
    xen_domain_handle_t handle;
};
typedef struct xen_v2d6_getdomaininfo xen_v2d6_getdomaininfo;

J
Jim Fehlig 已提交
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
struct xen_v2d7_getdomaininfo {
    domid_t  domain;	/* the domain number */
    uint32_t flags;	/* flags, see before */
    uint64_t tot_pages ALIGN_64;	/* total number of pages used */
    uint64_t max_pages ALIGN_64;	/* maximum number of pages allowed */
    uint64_t shr_pages ALIGN_64;    /* number of shared pages */
    uint64_t shared_info_frame ALIGN_64; /* MFN of shared_info struct */
    uint64_t cpu_time ALIGN_64;  /* CPU time used */
    uint32_t nr_online_vcpus;  /* Number of VCPUs currently online. */
    uint32_t max_vcpu_id; /* Maximum VCPUID in use by this domain. */
    uint32_t ssidref;
    xen_domain_handle_t handle;
    uint32_t cpupool;
};
typedef struct xen_v2d7_getdomaininfo xen_v2d7_getdomaininfo;

J
Jim Fehlig 已提交
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
struct xen_v2d8_getdomaininfo {
    domid_t  domain;	/* the domain number */
    uint32_t flags;	/* flags, see before */
    uint64_t tot_pages ALIGN_64;	/* total number of pages used */
    uint64_t max_pages ALIGN_64;	/* maximum number of pages allowed */
    uint64_t shr_pages ALIGN_64;    /* number of shared pages */
    uint64_t paged_pages ALIGN_64;    /* number of paged pages */
    uint64_t shared_info_frame ALIGN_64; /* MFN of shared_info struct */
    uint64_t cpu_time ALIGN_64;  /* CPU time used */
    uint32_t nr_online_vcpus;  /* Number of VCPUs currently online. */
    uint32_t max_vcpu_id; /* Maximum VCPUID in use by this domain. */
    uint32_t ssidref;
    xen_domain_handle_t handle;
    uint32_t cpupool;
};
typedef struct xen_v2d8_getdomaininfo xen_v2d8_getdomaininfo;

272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
struct xen_v2d9_getdomaininfo {
    domid_t  domain;	/* the domain number */
    uint32_t flags;	/* flags, see before */
    uint64_t tot_pages ALIGN_64;	/* total number of pages used */
    uint64_t max_pages ALIGN_64;	/* maximum number of pages allowed */
    uint64_t outstanding_pages ALIGN_64;
    uint64_t shr_pages ALIGN_64;    /* number of shared pages */
    uint64_t paged_pages ALIGN_64;    /* number of paged pages */
    uint64_t shared_info_frame ALIGN_64; /* MFN of shared_info struct */
    uint64_t cpu_time ALIGN_64;  /* CPU time used */
    uint32_t nr_online_vcpus;  /* Number of VCPUs currently online. */
    uint32_t max_vcpu_id; /* Maximum VCPUID in use by this domain. */
    uint32_t ssidref;
    xen_domain_handle_t handle;
    uint32_t cpupool;
};
typedef struct xen_v2d9_getdomaininfo xen_v2d9_getdomaininfo;

290 291 292
union xen_getdomaininfo {
    struct xen_v0_getdomaininfo v0;
    struct xen_v2_getdomaininfo v2;
293
    struct xen_v2d5_getdomaininfo v2d5;
294
    struct xen_v2d6_getdomaininfo v2d6;
J
Jim Fehlig 已提交
295
    struct xen_v2d7_getdomaininfo v2d7;
J
Jim Fehlig 已提交
296
    struct xen_v2d8_getdomaininfo v2d8;
297
    struct xen_v2d9_getdomaininfo v2d9;
298 299 300 301 302 303
};
typedef union xen_getdomaininfo xen_getdomaininfo;

union xen_getdomaininfolist {
    struct xen_v0_getdomaininfo *v0;
    struct xen_v2_getdomaininfo *v2;
304
    struct xen_v2d5_getdomaininfo *v2d5;
305
    struct xen_v2d6_getdomaininfo *v2d6;
J
Jim Fehlig 已提交
306
    struct xen_v2d7_getdomaininfo *v2d7;
J
Jim Fehlig 已提交
307
    struct xen_v2d8_getdomaininfo *v2d8;
308
    struct xen_v2d9_getdomaininfo *v2d9;
309 310 311
};
typedef union xen_getdomaininfolist xen_getdomaininfolist;

312 313 314 315 316 317 318 319 320 321 322 323

struct xen_v2_getschedulerid {
    uint32_t sched_id; /* Get Scheduler ID from Xen */
};
typedef struct xen_v2_getschedulerid xen_v2_getschedulerid;


union xen_getschedulerid {
    struct xen_v2_getschedulerid *v2;
};
typedef union xen_getschedulerid xen_getschedulerid;

324 325 326 327 328 329 330 331 332
struct xen_v2s4_availheap {
    uint32_t min_bitwidth;  /* Smallest address width (zero if don't care). */
    uint32_t max_bitwidth;  /* Largest address width (zero if don't care). */
    int32_t  node;          /* NUMA node (-1 for sum across all nodes). */
    uint64_t avail_bytes;   /* Bytes available in the specified region. */
};

typedef struct xen_v2s4_availheap  xen_v2s4_availheap;

333 334 335 336 337 338 339 340 341
struct xen_v2s5_availheap {
    uint32_t min_bitwidth;  /* Smallest address width (zero if don't care). */
    uint32_t max_bitwidth;  /* Largest address width (zero if don't care). */
    int32_t  node;          /* NUMA node (-1 for sum across all nodes). */
    uint64_t avail_bytes ALIGN_64;   /* Bytes available in the specified region. */
};

typedef struct xen_v2s5_availheap  xen_v2s5_availheap;

342

343
#define XEN_GETDOMAININFOLIST_ALLOC(domlist, size)                      \
P
Philipp Hahn 已提交
344
    (hv_versions.hypervisor < 2 ?                                       \
345
     (VIR_ALLOC_N(domlist.v0, (size)) == 0) :                           \
346 347 348
     (hv_versions.dom_interface >= 9 ?                                  \
      (VIR_ALLOC_N(domlist.v2d9, (size)) == 0) :                        \
     (hv_versions.dom_interface == 8 ?                                  \
J
Jim Fehlig 已提交
349 350
      (VIR_ALLOC_N(domlist.v2d8, (size)) == 0) :                        \
     (hv_versions.dom_interface == 7 ?                                  \
J
Jim Fehlig 已提交
351
      (VIR_ALLOC_N(domlist.v2d7, (size)) == 0) :                        \
P
Philipp Hahn 已提交
352
     (hv_versions.dom_interface == 6 ?                                  \
353
      (VIR_ALLOC_N(domlist.v2d6, (size)) == 0) :                        \
P
Philipp Hahn 已提交
354
     (hv_versions.dom_interface == 5 ?                                  \
355
      (VIR_ALLOC_N(domlist.v2d5, (size)) == 0) :                        \
356
      (VIR_ALLOC_N(domlist.v2, (size)) == 0)))))))
357

358
#define XEN_GETDOMAININFOLIST_FREE(domlist)            \
P
Philipp Hahn 已提交
359
    (hv_versions.hypervisor < 2 ?                      \
360
     VIR_FREE(domlist.v0) :                            \
361 362 363
     (hv_versions.dom_interface >= 9 ?                 \
      VIR_FREE(domlist.v2d9) :                         \
     (hv_versions.dom_interface == 8 ?                 \
J
Jim Fehlig 已提交
364 365
      VIR_FREE(domlist.v2d8) :                         \
     (hv_versions.dom_interface == 7 ?                 \
J
Jim Fehlig 已提交
366
      VIR_FREE(domlist.v2d7) :                         \
P
Philipp Hahn 已提交
367
     (hv_versions.dom_interface == 6 ?                 \
368
      VIR_FREE(domlist.v2d6) :                         \
P
Philipp Hahn 已提交
369
     (hv_versions.dom_interface == 5 ?                 \
370
      VIR_FREE(domlist.v2d5) :                         \
371
      VIR_FREE(domlist.v2)))))))
372

373
#define XEN_GETDOMAININFOLIST_CLEAR(domlist, size)            \
P
Philipp Hahn 已提交
374
    (hv_versions.hypervisor < 2 ?                             \
375
     memset(domlist.v0, 0, sizeof(*domlist.v0) * size) :      \
376 377 378
     (hv_versions.dom_interface >= 9 ?                        \
      memset(domlist.v2d9, 0, sizeof(*domlist.v2d9) * size) : \
     (hv_versions.dom_interface == 8 ?                        \
J
Jim Fehlig 已提交
379 380
      memset(domlist.v2d8, 0, sizeof(*domlist.v2d8) * size) : \
     (hv_versions.dom_interface == 7 ?                        \
J
Jim Fehlig 已提交
381
      memset(domlist.v2d7, 0, sizeof(*domlist.v2d7) * size) : \
P
Philipp Hahn 已提交
382
     (hv_versions.dom_interface == 6 ?                        \
383
      memset(domlist.v2d6, 0, sizeof(*domlist.v2d6) * size) : \
P
Philipp Hahn 已提交
384
     (hv_versions.dom_interface == 5 ?                        \
385
      memset(domlist.v2d5, 0, sizeof(*domlist.v2d5) * size) : \
386
      memset(domlist.v2, 0, sizeof(*domlist.v2) * size)))))))
387 388

#define XEN_GETDOMAININFOLIST_DOMAIN(domlist, n)    \
P
Philipp Hahn 已提交
389
    (hv_versions.hypervisor < 2 ?                   \
390
     domlist.v0[n].domain :                         \
391 392 393
     (hv_versions.dom_interface >= 9 ?              \
      domlist.v2d9[n].domain :                      \
     (hv_versions.dom_interface == 8 ?              \
J
Jim Fehlig 已提交
394 395
      domlist.v2d8[n].domain :                      \
     (hv_versions.dom_interface == 7 ?              \
J
Jim Fehlig 已提交
396
      domlist.v2d7[n].domain :                      \
P
Philipp Hahn 已提交
397
     (hv_versions.dom_interface == 6 ?              \
398
      domlist.v2d6[n].domain :                      \
P
Philipp Hahn 已提交
399
     (hv_versions.dom_interface == 5 ?              \
400
      domlist.v2d5[n].domain :                      \
401
      domlist.v2[n].domain))))))
402

403
#define XEN_GETDOMAININFOLIST_UUID(domlist, n)      \
P
Philipp Hahn 已提交
404
    (hv_versions.hypervisor < 2 ?                   \
405
     domlist.v0[n].handle :                         \
406 407 408
     (hv_versions.dom_interface >= 9 ?              \
      domlist.v2d9[n].handle :                      \
     (hv_versions.dom_interface == 8 ?              \
J
Jim Fehlig 已提交
409 410
      domlist.v2d8[n].handle :                      \
     (hv_versions.dom_interface == 7 ?              \
J
Jim Fehlig 已提交
411
      domlist.v2d7[n].handle :                      \
P
Philipp Hahn 已提交
412
     (hv_versions.dom_interface == 6 ?              \
413
      domlist.v2d6[n].handle :                      \
P
Philipp Hahn 已提交
414
     (hv_versions.dom_interface == 5 ?              \
415
      domlist.v2d5[n].handle :                      \
416
      domlist.v2[n].handle))))))
417

418
#define XEN_GETDOMAININFOLIST_DATA(domlist)        \
P
Philipp Hahn 已提交
419
    (hv_versions.hypervisor < 2 ?                  \
420
     (void*)(domlist->v0) :                        \
421 422 423
     (hv_versions.dom_interface >= 9 ?             \
      (void*)(domlist->v2d9) :                     \
     (hv_versions.dom_interface == 8 ?             \
J
Jim Fehlig 已提交
424 425
      (void*)(domlist->v2d8) :                     \
     (hv_versions.dom_interface == 7 ?             \
J
Jim Fehlig 已提交
426
      (void*)(domlist->v2d7) :                     \
P
Philipp Hahn 已提交
427
     (hv_versions.dom_interface == 6 ?             \
428
      (void*)(domlist->v2d6) :                     \
P
Philipp Hahn 已提交
429
     (hv_versions.dom_interface == 5 ?             \
430
      (void*)(domlist->v2d5) :                     \
431
      (void*)(domlist->v2)))))))
432 433

#define XEN_GETDOMAININFO_SIZE                     \
P
Philipp Hahn 已提交
434
    (hv_versions.hypervisor < 2 ?                  \
435
     sizeof(xen_v0_getdomaininfo) :                \
436 437 438
     (hv_versions.dom_interface >= 9 ?             \
      sizeof(xen_v2d9_getdomaininfo) :             \
     (hv_versions.dom_interface == 8 ?             \
J
Jim Fehlig 已提交
439 440
      sizeof(xen_v2d8_getdomaininfo) :             \
     (hv_versions.dom_interface == 7 ?             \
J
Jim Fehlig 已提交
441
      sizeof(xen_v2d7_getdomaininfo) :             \
P
Philipp Hahn 已提交
442
     (hv_versions.dom_interface == 6 ?             \
443
      sizeof(xen_v2d6_getdomaininfo) :             \
P
Philipp Hahn 已提交
444
     (hv_versions.dom_interface == 5 ?             \
445
      sizeof(xen_v2d5_getdomaininfo) :             \
446
      sizeof(xen_v2_getdomaininfo)))))))
447 448

#define XEN_GETDOMAININFO_CLEAR(dominfo)                           \
P
Philipp Hahn 已提交
449
    (hv_versions.hypervisor < 2 ?                                  \
450
     memset(&(dominfo.v0), 0, sizeof(xen_v0_getdomaininfo)) :      \
451 452 453
     (hv_versions.dom_interface >= 9 ?                             \
      memset(&(dominfo.v2d9), 0, sizeof(xen_v2d9_getdomaininfo)) : \
     (hv_versions.dom_interface == 8 ?                             \
J
Jim Fehlig 已提交
454 455
      memset(&(dominfo.v2d8), 0, sizeof(xen_v2d8_getdomaininfo)) : \
     (hv_versions.dom_interface == 7 ?                             \
J
Jim Fehlig 已提交
456
      memset(&(dominfo.v2d7), 0, sizeof(xen_v2d7_getdomaininfo)) : \
P
Philipp Hahn 已提交
457
     (hv_versions.dom_interface == 6 ?                             \
458
      memset(&(dominfo.v2d6), 0, sizeof(xen_v2d6_getdomaininfo)) : \
P
Philipp Hahn 已提交
459
     (hv_versions.dom_interface == 5 ?                             \
460
      memset(&(dominfo.v2d5), 0, sizeof(xen_v2d5_getdomaininfo)) : \
461
      memset(&(dominfo.v2), 0, sizeof(xen_v2_getdomaininfo))))))))
462 463

#define XEN_GETDOMAININFO_DOMAIN(dominfo)       \
P
Philipp Hahn 已提交
464
    (hv_versions.hypervisor < 2 ?               \
465
     dominfo.v0.domain :                        \
466 467 468
     (hv_versions.dom_interface >= 9 ?          \
      dominfo.v2d9.domain :                     \
     (hv_versions.dom_interface == 8 ?          \
J
Jim Fehlig 已提交
469 470
      dominfo.v2d8.domain :                     \
     (hv_versions.dom_interface == 7 ?          \
J
Jim Fehlig 已提交
471
      dominfo.v2d7.domain :                     \
P
Philipp Hahn 已提交
472
     (hv_versions.dom_interface == 6 ?          \
473
      dominfo.v2d6.domain :                     \
P
Philipp Hahn 已提交
474
     (hv_versions.dom_interface == 5 ?          \
475
      dominfo.v2d5.domain :                     \
476
      dominfo.v2.domain))))))
477 478

#define XEN_GETDOMAININFO_CPUTIME(dominfo)      \
P
Philipp Hahn 已提交
479
    (hv_versions.hypervisor < 2 ?               \
480
     dominfo.v0.cpu_time :                      \
481 482 483
     (hv_versions.dom_interface >= 9 ?          \
      dominfo.v2d9.cpu_time :                   \
     (hv_versions.dom_interface == 8 ?          \
J
Jim Fehlig 已提交
484 485
      dominfo.v2d8.cpu_time :                   \
     (hv_versions.dom_interface == 7 ?          \
J
Jim Fehlig 已提交
486
      dominfo.v2d7.cpu_time :                   \
P
Philipp Hahn 已提交
487
     (hv_versions.dom_interface == 6 ?          \
488
      dominfo.v2d6.cpu_time :                   \
P
Philipp Hahn 已提交
489
     (hv_versions.dom_interface == 5 ?          \
490
      dominfo.v2d5.cpu_time :                   \
491
      dominfo.v2.cpu_time))))))
492

493 494

#define XEN_GETDOMAININFO_CPUCOUNT(dominfo)     \
P
Philipp Hahn 已提交
495
    (hv_versions.hypervisor < 2 ?               \
496
     dominfo.v0.nr_online_vcpus :               \
497 498 499
     (hv_versions.dom_interface >= 9 ?          \
      dominfo.v2d9.nr_online_vcpus :            \
     (hv_versions.dom_interface == 8 ?          \
J
Jim Fehlig 已提交
500 501
      dominfo.v2d8.nr_online_vcpus :            \
     (hv_versions.dom_interface == 7 ?          \
J
Jim Fehlig 已提交
502
      dominfo.v2d7.nr_online_vcpus :            \
P
Philipp Hahn 已提交
503
     (hv_versions.dom_interface == 6 ?          \
504
      dominfo.v2d6.nr_online_vcpus :            \
P
Philipp Hahn 已提交
505
     (hv_versions.dom_interface == 5 ?          \
506
      dominfo.v2d5.nr_online_vcpus :            \
507
      dominfo.v2.nr_online_vcpus))))))
508

J
Jim Fehlig 已提交
509
#define XEN_GETDOMAININFO_MAXCPUID(dominfo)     \
P
Philipp Hahn 已提交
510
    (hv_versions.hypervisor < 2 ?               \
511
     dominfo.v0.max_vcpu_id :                   \
512 513 514
     (hv_versions.dom_interface >= 9 ?          \
      dominfo.v2d9.max_vcpu_id :                \
     (hv_versions.dom_interface == 8 ?          \
J
Jim Fehlig 已提交
515 516
      dominfo.v2d8.max_vcpu_id :                \
     (hv_versions.dom_interface == 7 ?          \
J
Jim Fehlig 已提交
517
      dominfo.v2d7.max_vcpu_id :                \
P
Philipp Hahn 已提交
518
     (hv_versions.dom_interface == 6 ?          \
519
      dominfo.v2d6.max_vcpu_id :                \
P
Philipp Hahn 已提交
520
     (hv_versions.dom_interface == 5 ?          \
521
      dominfo.v2d5.max_vcpu_id :                \
522
      dominfo.v2.max_vcpu_id))))))
523

524
#define XEN_GETDOMAININFO_FLAGS(dominfo)        \
P
Philipp Hahn 已提交
525
    (hv_versions.hypervisor < 2 ?               \
526
     dominfo.v0.flags :                         \
527 528 529
     (hv_versions.dom_interface >= 9 ?          \
      dominfo.v2d9.flags :                      \
     (hv_versions.dom_interface == 8 ?          \
J
Jim Fehlig 已提交
530 531
      dominfo.v2d8.flags :                      \
     (hv_versions.dom_interface == 7 ?          \
J
Jim Fehlig 已提交
532
      dominfo.v2d7.flags :                      \
P
Philipp Hahn 已提交
533
     (hv_versions.dom_interface == 6 ?          \
534
      dominfo.v2d6.flags :                      \
P
Philipp Hahn 已提交
535
     (hv_versions.dom_interface == 5 ?          \
536
      dominfo.v2d5.flags :                      \
537
      dominfo.v2.flags))))))
538 539

#define XEN_GETDOMAININFO_TOT_PAGES(dominfo)    \
P
Philipp Hahn 已提交
540
    (hv_versions.hypervisor < 2 ?               \
541
     dominfo.v0.tot_pages :                     \
542 543 544
     (hv_versions.dom_interface >= 9 ?          \
      dominfo.v2d9.tot_pages :                  \
     (hv_versions.dom_interface == 8 ?          \
J
Jim Fehlig 已提交
545 546
      dominfo.v2d8.tot_pages :                  \
     (hv_versions.dom_interface == 7 ?          \
J
Jim Fehlig 已提交
547
      dominfo.v2d7.tot_pages :                  \
P
Philipp Hahn 已提交
548
     (hv_versions.dom_interface == 6 ?          \
549
      dominfo.v2d6.tot_pages :                  \
P
Philipp Hahn 已提交
550
     (hv_versions.dom_interface == 5 ?          \
551
      dominfo.v2d5.tot_pages :                  \
552
      dominfo.v2.tot_pages))))))
553 554

#define XEN_GETDOMAININFO_MAX_PAGES(dominfo)    \
P
Philipp Hahn 已提交
555
    (hv_versions.hypervisor < 2 ?               \
556
     dominfo.v0.max_pages :                     \
557 558 559
     (hv_versions.dom_interface >= 9 ?          \
      dominfo.v2d9.max_pages :                  \
     (hv_versions.dom_interface == 8 ?          \
J
Jim Fehlig 已提交
560 561
      dominfo.v2d8.max_pages :                  \
     (hv_versions.dom_interface == 7 ?          \
J
Jim Fehlig 已提交
562
      dominfo.v2d7.max_pages :                  \
P
Philipp Hahn 已提交
563
     (hv_versions.dom_interface == 6 ?          \
564
      dominfo.v2d6.max_pages :                  \
P
Philipp Hahn 已提交
565
     (hv_versions.dom_interface == 5 ?          \
566
      dominfo.v2d5.max_pages :                  \
567
      dominfo.v2.max_pages))))))
568

569
#define XEN_GETDOMAININFO_UUID(dominfo)         \
P
Philipp Hahn 已提交
570
    (hv_versions.hypervisor < 2 ?               \
571
     dominfo.v0.handle :                        \
572 573 574
     (hv_versions.dom_interface >= 9 ?          \
      dominfo.v2d9.handle :                     \
     (hv_versions.dom_interface == 8 ?          \
J
Jim Fehlig 已提交
575 576
      dominfo.v2d8.handle :                     \
     (hv_versions.dom_interface == 7 ?          \
J
Jim Fehlig 已提交
577
      dominfo.v2d7.handle :                     \
P
Philipp Hahn 已提交
578
     (hv_versions.dom_interface == 6 ?          \
579
      dominfo.v2d6.handle :                     \
P
Philipp Hahn 已提交
580
     (hv_versions.dom_interface == 5 ?          \
581
      dominfo.v2d5.handle :                     \
582
      dominfo.v2.handle))))))
583

584

585 586 587 588
static int
lock_pages(void *addr, size_t len)
{
#ifdef __linux__
589 590 591 592 593 594 595
    if (mlock(addr, len) < 0) {
        virReportSystemError(errno,
                             _("Unable to lock %zu bytes of memory"),
                             len);
        return -1;
    }
    return 0;
596
#elif defined(__sun)
597
    return 0;
598 599 600 601 602 603 604
#endif
}

static int
unlock_pages(void *addr, size_t len)
{
#ifdef __linux__
605 606 607 608 609 610 611
    if (munlock(addr, len) < 0) {
        virReportSystemError(errno,
                             _("Unable to unlock %zu bytes of memory"),
                             len);
        return -1;
    }
    return 0;
612
#elif defined(__sun)
613
    return 0;
614 615 616
#endif
}

617 618

struct xen_v0_getdomaininfolistop {
619 620 621 622 623
    domid_t   first_domain;
    uint32_t  max_domains;
    struct xen_v0_getdomaininfo *buffer;
    uint32_t  num_domains;
};
624 625 626 627 628 629 630 631 632 633 634
typedef struct xen_v0_getdomaininfolistop xen_v0_getdomaininfolistop;


struct xen_v2_getdomaininfolistop {
    domid_t   first_domain;
    uint32_t  max_domains;
    struct xen_v2_getdomaininfo *buffer;
    uint32_t  num_domains;
};
typedef struct xen_v2_getdomaininfolistop xen_v2_getdomaininfolistop;

635 636 637 638
/* As of HV version 2, sysctl version 3 the *buffer pointer is 64-bit aligned */
struct xen_v2s3_getdomaininfolistop {
    domid_t   first_domain;
    uint32_t  max_domains;
639 640
#ifdef __BIG_ENDIAN__
    struct {
641
        int __pad[(sizeof(long long) - sizeof(struct xen_v2d5_getdomaininfo *)) / sizeof(int)];
642 643 644
        struct xen_v2d5_getdomaininfo *v;
    } buffer;
#else
645 646 647 648
    union {
        struct xen_v2d5_getdomaininfo *v;
        uint64_t pad ALIGN_64;
    } buffer;
649
#endif
650 651 652 653
    uint32_t  num_domains;
};
typedef struct xen_v2s3_getdomaininfolistop xen_v2s3_getdomaininfolistop;

654

655 656 657 658 659 660 661

struct xen_v0_domainop {
    domid_t   domain;
};
typedef struct xen_v0_domainop xen_v0_domainop;

/*
662
 * The information for a pausedomain system hypercall
663 664 665 666 667 668
 */
#define XEN_V0_OP_PAUSEDOMAIN	10
#define XEN_V1_OP_PAUSEDOMAIN	10
#define XEN_V2_OP_PAUSEDOMAIN	3

/*
669
 * The information for an unpausedomain system hypercall
670 671 672 673 674 675
 */
#define XEN_V0_OP_UNPAUSEDOMAIN	11
#define XEN_V1_OP_UNPAUSEDOMAIN	11
#define XEN_V2_OP_UNPAUSEDOMAIN	4

/*
E
Eric Blake 已提交
676
 * The information for a setmaxmem system hypercall
677 678 679
 */
#define XEN_V0_OP_SETMAXMEM	28
#define XEN_V1_OP_SETMAXMEM	28
680
#define XEN_V2_OP_SETMAXMEM	11
681 682 683 684 685 686 687 688 689 690 691 692 693

struct xen_v0_setmaxmem {
    domid_t	domain;
    uint64_t	maxmem;
};
typedef struct xen_v0_setmaxmem xen_v0_setmaxmem;
typedef struct xen_v0_setmaxmem xen_v1_setmaxmem;

struct xen_v2_setmaxmem {
    uint64_t	maxmem;
};
typedef struct xen_v2_setmaxmem xen_v2_setmaxmem;

694 695 696 697 698
struct xen_v2d5_setmaxmem {
    uint64_t	maxmem ALIGN_64;
};
typedef struct xen_v2d5_setmaxmem xen_v2d5_setmaxmem;

699
/*
E
Eric Blake 已提交
700
 * The information for a setvcpumap system hypercall
701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725
 * Note that between 1 and 2 the limitation to 64 physical CPU was lifted
 * hence the difference in structures
 */
#define XEN_V0_OP_SETVCPUMAP	20
#define XEN_V1_OP_SETVCPUMAP	20
#define XEN_V2_OP_SETVCPUMAP	9

struct xen_v0_setvcpumap {
    domid_t	domain;
    uint32_t	vcpu;
    cpumap_t    cpumap;
};
typedef struct xen_v0_setvcpumap xen_v0_setvcpumap;
typedef struct xen_v0_setvcpumap xen_v1_setvcpumap;

struct xen_v2_cpumap {
    uint8_t    *bitmap;
    uint32_t    nr_cpus;
};
struct xen_v2_setvcpumap {
    uint32_t	vcpu;
    struct xen_v2_cpumap cpumap;
};
typedef struct xen_v2_setvcpumap xen_v2_setvcpumap;

726 727
/* HV version 2, Dom version 5 requires 64-bit alignment */
struct xen_v2d5_cpumap {
728 729
#ifdef __BIG_ENDIAN__
    struct {
730
        int __pad[(sizeof(long long) - sizeof(uint8_t *)) / sizeof(int)];
731 732 733
        uint8_t *v;
    } bitmap;
#else
734 735 736 737
    union {
        uint8_t    *v;
        uint64_t   pad ALIGN_64;
    } bitmap;
738
#endif
739 740 741 742 743 744 745 746
    uint32_t    nr_cpus;
};
struct xen_v2d5_setvcpumap {
    uint32_t	vcpu;
    struct xen_v2d5_cpumap cpumap;
};
typedef struct xen_v2d5_setvcpumap xen_v2d5_setvcpumap;

747
/*
E
Eric Blake 已提交
748
 * The information for a vcpuinfo system hypercall
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776
 */
#define XEN_V0_OP_GETVCPUINFO   43
#define XEN_V1_OP_GETVCPUINFO	43
#define XEN_V2_OP_GETVCPUINFO   14

struct xen_v0_vcpuinfo {
    domid_t	domain;		/* owner's domain */
    uint32_t	vcpu;		/* the vcpu number */
    uint8_t	online;		/* seen as on line */
    uint8_t	blocked;	/* blocked on event */
    uint8_t	running;	/* scheduled on CPU */
    uint64_t    cpu_time;	/* nanosecond of CPU used */
    uint32_t	cpu;		/* current mapping */
    cpumap_t	cpumap;		/* deprecated in V2 */
};
typedef struct xen_v0_vcpuinfo xen_v0_vcpuinfo;
typedef struct xen_v0_vcpuinfo xen_v1_vcpuinfo;

struct xen_v2_vcpuinfo {
    uint32_t	vcpu;		/* the vcpu number */
    uint8_t	online;		/* seen as on line */
    uint8_t	blocked;	/* blocked on event */
    uint8_t	running;	/* scheduled on CPU */
    uint64_t    cpu_time;	/* nanosecond of CPU used */
    uint32_t	cpu;		/* current mapping */
};
typedef struct xen_v2_vcpuinfo xen_v2_vcpuinfo;

777 778 779 780 781 782 783 784 785 786
struct xen_v2d5_vcpuinfo {
    uint32_t	vcpu;		/* the vcpu number */
    uint8_t	online;		/* seen as on line */
    uint8_t	blocked;	/* blocked on event */
    uint8_t	running;	/* scheduled on CPU */
    uint64_t    cpu_time ALIGN_64; /* nanosecond of CPU used */
    uint32_t	cpu;		/* current mapping */
};
typedef struct xen_v2d5_vcpuinfo xen_v2d5_vcpuinfo;

787 788 789 790 791
/*
 * from V2 the pinning of a vcpu is read with a separate call
 */
#define XEN_V2_OP_GETVCPUMAP	25
typedef struct xen_v2_setvcpumap xen_v2_getvcpumap;
792
typedef struct xen_v2d5_setvcpumap xen_v2d5_getvcpumap;
793

794 795 796 797 798
/*
 * from V2 we get the scheduler information
 */
#define XEN_V2_OP_GETSCHEDULERID	4

799 800 801
/*
 * from V2 we get the available heap information
 */
E
Eric Blake 已提交
802
#define XEN_V2_OP_GETAVAILHEAP		9
803

804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835
/*
 * from V2 we get the scheduler parameter
 */
#define XEN_V2_OP_SCHEDULER		16
/* Scheduler types. */
#define XEN_SCHEDULER_SEDF       4
#define XEN_SCHEDULER_CREDIT     5
/* get/set scheduler parameters */
#define XEN_DOMCTL_SCHEDOP_putinfo 0
#define XEN_DOMCTL_SCHEDOP_getinfo 1

struct xen_v2_setschedinfo {
    uint32_t sched_id;
    uint32_t cmd;
    union {
        struct xen_domctl_sched_sedf {
            uint64_t period ALIGN_64;
            uint64_t slice  ALIGN_64;
            uint64_t latency ALIGN_64;
            uint32_t extratime;
            uint32_t weight;
        } sedf;
        struct xen_domctl_sched_credit {
            uint16_t weight;
            uint16_t cap;
        } credit;
    } u;
};
typedef struct xen_v2_setschedinfo xen_v2_setschedinfo;
typedef struct xen_v2_setschedinfo xen_v2_getschedinfo;


836 837 838 839 840 841 842 843 844
/*
 * The hypercall operation structures also have changed on
 * changeset 86d26e6ec89b
 */
/* the old structure */
struct xen_op_v0 {
    uint32_t cmd;
    uint32_t interface_version;
    union {
845 846 847 848 849 850
        xen_v0_getdomaininfolistop getdomaininfolist;
        xen_v0_domainop          domain;
        xen_v0_setmaxmem         setmaxmem;
        xen_v0_setvcpumap        setvcpumap;
        xen_v0_vcpuinfo          getvcpuinfo;
        uint8_t padding[128];
851 852 853 854 855 856 857 858 859 860
    } u;
};
typedef struct xen_op_v0 xen_op_v0;
typedef struct xen_op_v0 xen_op_v1;

/* the new structure for systems operations */
struct xen_op_v2_sys {
    uint32_t cmd;
    uint32_t interface_version;
    union {
861 862
        xen_v2_getdomaininfolistop   getdomaininfolist;
        xen_v2s3_getdomaininfolistop getdomaininfolists3;
863
        xen_v2_getschedulerid        getschedulerid;
864
        xen_v2s4_availheap           availheap;
865
        xen_v2s5_availheap           availheap5;
866
        uint8_t padding[128];
867 868 869 870 871 872 873 874 875 876
    } u;
};
typedef struct xen_op_v2_sys xen_op_v2_sys;

/* the new structure for domains operation */
struct xen_op_v2_dom {
    uint32_t cmd;
    uint32_t interface_version;
    domid_t  domain;
    union {
877
        xen_v2_setmaxmem         setmaxmem;
878
        xen_v2d5_setmaxmem       setmaxmemd5;
879
        xen_v2_setvcpumap        setvcpumap;
880
        xen_v2d5_setvcpumap      setvcpumapd5;
881
        xen_v2_vcpuinfo          getvcpuinfo;
882
        xen_v2d5_vcpuinfo        getvcpuinfod5;
883
        xen_v2_getvcpumap        getvcpumap;
884
        xen_v2d5_getvcpumap      getvcpumapd5;
885 886
        xen_v2_setschedinfo      setschedinfo;
        xen_v2_getschedinfo      getschedinfo;
887
        uint8_t padding[128];
888 889 890
    } u;
};
typedef struct xen_op_v2_dom xen_op_v2_dom;
891 892


893
#ifdef __linux__
894 895
# define XEN_HYPERVISOR_SOCKET	"/proc/xen/privcmd"
# define HYPERVISOR_CAPABILITIES	"/sys/hypervisor/properties/capabilities"
896
#elif defined(__sun)
897
# define XEN_HYPERVISOR_SOCKET	"/dev/xen/privcmd"
898
#else
899
# error "unsupported platform"
900
#endif
901

902 903 904
/**
 * xenHypervisorDoV0Op:
 * @handle: the handle to the Xen hypervisor
R
Richard W.M. Jones 已提交
905
 * @op: pointer to the hypervisor operation structure
906
 *
E
Eric Blake 已提交
907 908
 * Do a hypervisor operation though the old interface,
 * this leads to a hypervisor call through ioctl.
909 910 911 912 913 914 915 916 917 918
 *
 * Returns 0 in case of success and -1 in case of error.
 */
static int
xenHypervisorDoV0Op(int handle, xen_op_v0 * op)
{
    int ret;
    v0_hypercall_t hc;

    memset(&hc, 0, sizeof(hc));
P
Philipp Hahn 已提交
919
    op->interface_version = hv_versions.hv << 8;
920 921 922
    hc.op = __HYPERVISOR_dom0_op;
    hc.arg[0] = (unsigned long) op;

923
    if (lock_pages(op, sizeof(dom0_op_t)) < 0)
924
        return -1;
925 926 927

    ret = ioctl(handle, xen_ioctl_hypercall_cmd, (unsigned long) &hc);
    if (ret < 0) {
928 929 930
        virReportSystemError(errno,
                             _("Unable to issue hypervisor ioctl %d"),
                             xen_ioctl_hypercall_cmd);
931 932
    }

933
    if (unlock_pages(op, sizeof(dom0_op_t)) < 0)
934 935 936
        ret = -1;

    if (ret < 0)
937
        return -1;
938

939
    return 0;
940 941 942 943
}
/**
 * xenHypervisorDoV1Op:
 * @handle: the handle to the Xen hypervisor
R
Richard W.M. Jones 已提交
944
 * @op: pointer to the hypervisor operation structure
945
 *
E
Eric Blake 已提交
946
 * Do a hypervisor v1 operation, this leads to a hypervisor call through
947 948 949 950 951 952 953 954 955 956 957 958 959 960 961
 * ioctl.
 *
 * Returns 0 in case of success and -1 in case of error.
 */
static int
xenHypervisorDoV1Op(int handle, xen_op_v1* op)
{
    int ret;
    hypercall_t hc;

    memset(&hc, 0, sizeof(hc));
    op->interface_version = DOM0_INTERFACE_VERSION;
    hc.op = __HYPERVISOR_dom0_op;
    hc.arg[0] = (unsigned long) op;

962
    if (lock_pages(op, sizeof(dom0_op_t)) < 0)
963
        return -1;
964 965 966

    ret = ioctl(handle, xen_ioctl_hypercall_cmd, (unsigned long) &hc);
    if (ret < 0) {
967 968 969
        virReportSystemError(errno,
                             _("Unable to issue hypervisor ioctl %d"),
                             xen_ioctl_hypercall_cmd);
970 971
    }

972
    if (unlock_pages(op, sizeof(dom0_op_t)) < 0)
973 974 975
        ret = -1;

    if (ret < 0)
976
        return -1;
977

978
    return 0;
979 980 981 982 983 984 985
}

/**
 * xenHypervisorDoV2Sys:
 * @handle: the handle to the Xen hypervisor
 * @op: pointer to the hypervisor operation structure
 *
E
Eric Blake 已提交
986
 * Do a hypervisor v2 system operation, this leads to a hypervisor
987 988 989 990 991 992 993 994 995 996 997
 * call through ioctl.
 *
 * Returns 0 in case of success and -1 in case of error.
 */
static int
xenHypervisorDoV2Sys(int handle, xen_op_v2_sys* op)
{
    int ret;
    hypercall_t hc;

    memset(&hc, 0, sizeof(hc));
P
Philipp Hahn 已提交
998
    op->interface_version = hv_versions.sys_interface;
999 1000 1001
    hc.op = __HYPERVISOR_sysctl;
    hc.arg[0] = (unsigned long) op;

1002
    if (lock_pages(op, sizeof(dom0_op_t)) < 0)
1003
        return -1;
1004 1005 1006

    ret = ioctl(handle, xen_ioctl_hypercall_cmd, (unsigned long) &hc);
    if (ret < 0) {
1007 1008 1009
        virReportSystemError(errno,
                             _("Unable to issue hypervisor ioctl %d"),
                             xen_ioctl_hypercall_cmd);
1010 1011
    }

1012
    if (unlock_pages(op, sizeof(dom0_op_t)) < 0)
1013 1014 1015
        ret = -1;

    if (ret < 0)
1016
        return -1;
1017

1018
    return 0;
1019 1020 1021 1022 1023 1024 1025
}

/**
 * xenHypervisorDoV2Dom:
 * @handle: the handle to the Xen hypervisor
 * @op: pointer to the hypervisor domain operation structure
 *
E
Eric Blake 已提交
1026
 * Do a hypervisor v2 domain operation, this leads to a hypervisor
1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037
 * call through ioctl.
 *
 * Returns 0 in case of success and -1 in case of error.
 */
static int
xenHypervisorDoV2Dom(int handle, xen_op_v2_dom* op)
{
    int ret;
    hypercall_t hc;

    memset(&hc, 0, sizeof(hc));
P
Philipp Hahn 已提交
1038
    op->interface_version = hv_versions.dom_interface;
1039 1040 1041
    hc.op = __HYPERVISOR_domctl;
    hc.arg[0] = (unsigned long) op;

1042
    if (lock_pages(op, sizeof(dom0_op_t)) < 0)
1043
        return -1;
1044 1045 1046

    ret = ioctl(handle, xen_ioctl_hypercall_cmd, (unsigned long) &hc);
    if (ret < 0) {
1047 1048 1049
        virReportSystemError(errno,
                             _("Unable to issue hypervisor ioctl %d"),
                             xen_ioctl_hypercall_cmd);
1050 1051
    }

1052
    if (unlock_pages(op, sizeof(dom0_op_t)) < 0)
1053 1054 1055
        ret = -1;

    if (ret < 0)
1056
        return -1;
1057

1058
    return 0;
1059 1060 1061 1062 1063 1064 1065 1066 1067
}

/**
 * virXen_getdomaininfolist:
 * @handle: the hypervisor handle
 * @first_domain: first domain in the range
 * @maxids: maximum number of domains to list
 * @dominfos: output structures
 *
1068
 * Do a low level hypercall to list existing domains information
1069 1070 1071 1072
 *
 * Returns the number of domains or -1 in case of failure
 */
static int
1073 1074 1075
virXen_getdomaininfolist(int handle,
                         int first_domain,
                         int maxids,
1076
                         xen_getdomaininfolist *dominfos)
1077 1078 1079
{
    int ret = -1;

1080
    if (lock_pages(XEN_GETDOMAININFOLIST_DATA(dominfos),
1081
                   XEN_GETDOMAININFO_SIZE * maxids) < 0)
1082
        return -1;
1083

P
Philipp Hahn 已提交
1084
    if (hv_versions.hypervisor > 1) {
1085 1086 1087
        xen_op_v2_sys op;

        memset(&op, 0, sizeof(op));
1088
        op.cmd = XEN_V2_OP_GETDOMAININFOLIST;
1089

P
Philipp Hahn 已提交
1090
        if (hv_versions.sys_interface < 3) {
1091 1092 1093 1094 1095 1096 1097 1098 1099 1100
            op.u.getdomaininfolist.first_domain = (domid_t) first_domain;
            op.u.getdomaininfolist.max_domains = maxids;
            op.u.getdomaininfolist.buffer = dominfos->v2;
            op.u.getdomaininfolist.num_domains = maxids;
        } else {
            op.u.getdomaininfolists3.first_domain = (domid_t) first_domain;
            op.u.getdomaininfolists3.max_domains = maxids;
            op.u.getdomaininfolists3.buffer.v = dominfos->v2d5;
            op.u.getdomaininfolists3.num_domains = maxids;
        }
1101
        ret = xenHypervisorDoV2Sys(handle, &op);
1102 1103

        if (ret == 0) {
P
Philipp Hahn 已提交
1104
            if (hv_versions.sys_interface < 3)
1105 1106 1107 1108
                ret = op.u.getdomaininfolist.num_domains;
            else
                ret = op.u.getdomaininfolists3.num_domains;
        }
P
Philipp Hahn 已提交
1109
    } else if (hv_versions.hypervisor == 1) {
1110 1111 1112
        xen_op_v1 op;

        memset(&op, 0, sizeof(op));
1113 1114 1115 1116 1117 1118 1119 1120
        op.cmd = XEN_V1_OP_GETDOMAININFOLIST;
        op.u.getdomaininfolist.first_domain = (domid_t) first_domain;
        op.u.getdomaininfolist.max_domains = maxids;
        op.u.getdomaininfolist.buffer = dominfos->v0;
        op.u.getdomaininfolist.num_domains = maxids;
        ret = xenHypervisorDoV1Op(handle, &op);
        if (ret == 0)
            ret = op.u.getdomaininfolist.num_domains;
P
Philipp Hahn 已提交
1121
    } else if (hv_versions.hypervisor == 0) {
1122 1123 1124
        xen_op_v0 op;

        memset(&op, 0, sizeof(op));
1125 1126 1127 1128 1129 1130 1131 1132
        op.cmd = XEN_V0_OP_GETDOMAININFOLIST;
        op.u.getdomaininfolist.first_domain = (domid_t) first_domain;
        op.u.getdomaininfolist.max_domains = maxids;
        op.u.getdomaininfolist.buffer = dominfos->v0;
        op.u.getdomaininfolist.num_domains = maxids;
        ret = xenHypervisorDoV0Op(handle, &op);
        if (ret == 0)
            ret = op.u.getdomaininfolist.num_domains;
1133
    }
1134
    if (unlock_pages(XEN_GETDOMAININFOLIST_DATA(dominfos),
1135
                     XEN_GETDOMAININFO_SIZE * maxids) < 0)
1136
        ret = -1;
1137

1138
    return ret;
1139 1140
}

1141
static int
1142 1143
virXen_getdomaininfo(int handle, int first_domain, xen_getdomaininfo *dominfo)
{
1144 1145
    xen_getdomaininfolist dominfos;

P
Philipp Hahn 已提交
1146
    if (hv_versions.hypervisor < 2) {
1147 1148 1149 1150 1151 1152 1153 1154 1155
        dominfos.v0 = &(dominfo->v0);
    } else {
        dominfos.v2 = &(dominfo->v2);
    }

    return virXen_getdomaininfolist(handle, first_domain, 1, &dominfos);
}


1156 1157
/**
 * xenHypervisorGetSchedulerType:
1158
 * @conn: the hypervisor connection
1159 1160 1161 1162 1163 1164 1165
 * @nparams:give a number of scheduler parameters.
 *
 * Do a low level hypercall to get scheduler type
 *
 * Returns scheduler name or NULL in case of failure
 */
char *
1166 1167
xenHypervisorGetSchedulerType(virConnectPtr conn,
                              int *nparams)
1168 1169
{
    char *schedulertype = NULL;
1170
    xenUnifiedPrivatePtr priv = conn->privateData;
1171 1172

    /*
P
Philipp Hahn 已提交
1173
     * Support only hv_versions.dom_interface >=5
1174
     * (Xen3.1.0 or later)
1175
     * TODO: check on Xen 3.0.3
1176
     */
P
Philipp Hahn 已提交
1177
    if (hv_versions.dom_interface < 5) {
1178 1179
        virReportError(VIR_ERR_NO_XEN, "%s",
                       _("unsupported in dom interface < 5"));
1180 1181 1182
        return NULL;
    }

P
Philipp Hahn 已提交
1183
    if (hv_versions.hypervisor > 1) {
1184 1185 1186 1187 1188 1189 1190
        xen_op_v2_sys op;
        int ret;

        memset(&op, 0, sizeof(op));
        op.cmd = XEN_V2_OP_GETSCHEDULERID;
        ret = xenHypervisorDoV2Sys(priv->handle, &op);
        if (ret < 0)
1191
            return NULL;
1192

1193
        switch (op.u.getschedulerid.sched_id) {
1194
            case XEN_SCHEDULER_SEDF:
1195
                ignore_value(VIR_STRDUP(schedulertype, "sedf"));
1196
                if (nparams)
1197
                    *nparams = XEN_SCHED_SEDF_NPARAM;
1198 1199
                break;
            case XEN_SCHEDULER_CREDIT:
1200
                ignore_value(VIR_STRDUP(schedulertype, "credit"));
1201
                if (nparams)
1202
                    *nparams = XEN_SCHED_CRED_NPARAM;
1203 1204 1205
                break;
            default:
                break;
1206 1207 1208 1209 1210 1211 1212 1213
        }
    }

    return schedulertype;
}

/**
 * xenHypervisorGetSchedulerParameters:
1214 1215
 * @conn: the hypervisor connection
 * @def: domain configuration
1216 1217
 * @params: pointer to scheduler parameters.
 *     This memory area should be allocated before calling.
1218 1219
 * @nparams: this parameter must be at least as large as
 *     the given number of scheduler parameters.
1220 1221 1222 1223 1224 1225 1226
 *     from xenHypervisorGetSchedulerType().
 *
 * Do a low level hypercall to get scheduler parameters
 *
 * Returns 0 or -1 in case of failure
 */
int
1227 1228
xenHypervisorGetSchedulerParameters(virConnectPtr conn,
                                    virDomainDefPtr def,
1229 1230
                                    virTypedParameterPtr params,
                                    int *nparams)
1231
{
1232
    xenUnifiedPrivatePtr priv = conn->privateData;
1233 1234

    /*
P
Philipp Hahn 已提交
1235
     * Support only hv_versions.dom_interface >=5
1236 1237 1238
     * (Xen3.1.0 or later)
     * TODO: check on Xen 3.0.3
     */
P
Philipp Hahn 已提交
1239
    if (hv_versions.dom_interface < 5) {
1240 1241
        virReportError(VIR_ERR_NO_XEN, "%s",
                       _("unsupported in dom interface < 5"));
1242 1243 1244
        return -1;
    }

P
Philipp Hahn 已提交
1245
    if (hv_versions.hypervisor > 1) {
1246 1247 1248 1249 1250 1251 1252 1253
        xen_op_v2_sys op_sys;
        xen_op_v2_dom op_dom;
        int ret;

        memset(&op_sys, 0, sizeof(op_sys));
        op_sys.cmd = XEN_V2_OP_GETSCHEDULERID;
        ret = xenHypervisorDoV2Sys(priv->handle, &op_sys);
        if (ret < 0)
1254
            return -1;
1255

1256
        switch (op_sys.u.getschedulerid.sched_id) {
1257
            case XEN_SCHEDULER_SEDF:
1258
                if (*nparams < XEN_SCHED_SEDF_NPARAM) {
1259 1260
                    virReportError(VIR_ERR_INVALID_ARG,
                                   "%s", _("Invalid parameter count"));
1261 1262 1263
                    return -1;
                }

1264 1265
                /* TODO: Implement for Xen/SEDF */
                TODO
1266
                return -1;
1267 1268 1269
            case XEN_SCHEDULER_CREDIT:
                memset(&op_dom, 0, sizeof(op_dom));
                op_dom.cmd = XEN_V2_OP_SCHEDULER;
1270
                op_dom.domain = (domid_t) def->id;
1271 1272 1273 1274
                op_dom.u.getschedinfo.sched_id = XEN_SCHEDULER_CREDIT;
                op_dom.u.getschedinfo.cmd = XEN_DOMCTL_SCHEDOP_getinfo;
                ret = xenHypervisorDoV2Dom(priv->handle, &op_dom);
                if (ret < 0)
1275
                    return -1;
1276

1277 1278 1279 1280
                if (virTypedParameterAssign(&params[0],
                                            VIR_DOMAIN_SCHEDULER_WEIGHT,
                                            VIR_TYPED_PARAM_UINT,
                                            op_dom.u.getschedinfo.u.credit.weight) < 0)
C
Chris Lalancette 已提交
1281
                    return -1;
1282 1283 1284 1285 1286 1287

                if (*nparams > 1 &&
                    virTypedParameterAssign(&params[1],
                                            VIR_DOMAIN_SCHEDULER_CAP,
                                            VIR_TYPED_PARAM_UINT,
                                            op_dom.u.getschedinfo.u.credit.cap) < 0)
1288
                        return -1;
1289

1290 1291
                if (*nparams > XEN_SCHED_CRED_NPARAM)
                    *nparams = XEN_SCHED_CRED_NPARAM;
1292 1293
                break;
            default:
1294 1295 1296
                virReportError(VIR_ERR_INVALID_ARG,
                               _("Unknown scheduler %d"),
                               op_sys.u.getschedulerid.sched_id);
1297
                return -1;
1298 1299 1300 1301 1302 1303 1304 1305
        }
    }

    return 0;
}

/**
 * xenHypervisorSetSchedulerParameters:
1306 1307
 * @conn: the hypervisor connection
 * @def: domain configuration
1308 1309 1310 1311 1312 1313 1314
 * @nparams:give a number of scheduler setting parameters .
 *
 * Do a low level hypercall to set scheduler parameters
 *
 * Returns 0 or -1 in case of failure
 */
int
1315 1316
xenHypervisorSetSchedulerParameters(virConnectPtr conn,
                                    virDomainDefPtr def,
1317 1318
                                    virTypedParameterPtr params,
                                    int nparams)
1319
{
1320
    size_t i;
1321
    unsigned int val;
1322
    xenUnifiedPrivatePtr priv = conn->privateData;
1323
    char buf[256];
1324

1325 1326 1327
    if (nparams == 0) {
        /* nothing to do, exit early */
        return 0;
1328 1329
    }

1330 1331 1332 1333 1334 1335
    if (virTypedParamsValidate(params, nparams,
                               VIR_DOMAIN_SCHEDULER_WEIGHT,
                               VIR_TYPED_PARAM_UINT,
                               VIR_DOMAIN_SCHEDULER_CAP,
                               VIR_TYPED_PARAM_UINT,
                               NULL) < 0)
1336 1337
        return -1;

1338
    /*
P
Philipp Hahn 已提交
1339
     * Support only hv_versions.dom_interface >=5
1340 1341 1342
     * (Xen3.1.0 or later)
     * TODO: check on Xen 3.0.3
     */
P
Philipp Hahn 已提交
1343
    if (hv_versions.dom_interface < 5) {
1344 1345
        virReportError(VIR_ERR_NO_XEN, "%s",
                       _("unsupported in dom interface < 5"));
1346 1347 1348
        return -1;
    }

P
Philipp Hahn 已提交
1349
    if (hv_versions.hypervisor > 1) {
1350 1351 1352 1353 1354 1355 1356 1357 1358
        xen_op_v2_sys op_sys;
        xen_op_v2_dom op_dom;
        int ret;

        memset(&op_sys, 0, sizeof(op_sys));
        op_sys.cmd = XEN_V2_OP_GETSCHEDULERID;
        ret = xenHypervisorDoV2Sys(priv->handle, &op_sys);
        if (ret == -1) return -1;

1359
        switch (op_sys.u.getschedulerid.sched_id) {
1360 1361 1362
        case XEN_SCHEDULER_SEDF:
            /* TODO: Implement for Xen/SEDF */
            TODO
1363
            return -1;
1364 1365 1366
        case XEN_SCHEDULER_CREDIT: {
            memset(&op_dom, 0, sizeof(op_dom));
            op_dom.cmd = XEN_V2_OP_SCHEDULER;
1367
            op_dom.domain = (domid_t) def->id;
1368 1369 1370 1371
            op_dom.u.getschedinfo.sched_id = XEN_SCHEDULER_CREDIT;
            op_dom.u.getschedinfo.cmd = XEN_DOMCTL_SCHEDOP_putinfo;

            /*
1372 1373
             * credit scheduler parameters
             * following values do not change the parameters
1374 1375 1376 1377 1378
             */
            op_dom.u.getschedinfo.u.credit.weight = 0;
            op_dom.u.getschedinfo.u.credit.cap    = (uint16_t)~0U;

            for (i = 0; i < nparams; i++) {
1379
                memset(&buf, 0, sizeof(buf));
1380
                if (STREQ(params[i].field, VIR_DOMAIN_SCHEDULER_WEIGHT)) {
1381 1382
                    val = params[i].value.ui;
                    if ((val < 1) || (val > USHRT_MAX)) {
1383 1384 1385
                        virReportError(VIR_ERR_INVALID_ARG,
                                       _("Credit scheduler weight parameter (%d) "
                                         "is out of range (1-65535)"), val);
1386
                        return -1;
1387
                    }
1388
                    op_dom.u.getschedinfo.u.credit.weight = val;
1389
                } else if (STREQ(params[i].field, VIR_DOMAIN_SCHEDULER_CAP)) {
1390
                    val = params[i].value.ui;
1391
                    if (val >= USHRT_MAX) {
1392 1393 1394
                        virReportError(VIR_ERR_INVALID_ARG,
                                       _("Credit scheduler cap parameter (%d) is "
                                         "out of range (0-65534)"), val);
1395
                        return -1;
1396
                    }
1397
                    op_dom.u.getschedinfo.u.credit.cap = val;
1398
                }
1399 1400 1401 1402
            }

            ret = xenHypervisorDoV2Dom(priv->handle, &op_dom);
            if (ret < 0)
1403
                return -1;
1404
            break;
1405
        }
1406
        default:
1407 1408 1409
            virReportError(VIR_ERR_INVALID_ARG,
                           _("Unknown scheduler %d"),
                           op_sys.u.getschedulerid.sched_id);
1410 1411 1412
            return -1;
        }
    }
1413

1414 1415 1416
    return 0;
}

1417 1418

int
1419 1420
xenHypervisorDomainBlockStats(virConnectPtr conn,
                              virDomainDefPtr def,
1421
                              const char *path,
1422
                              virDomainBlockStatsPtr stats)
1423
{
1424
#ifdef __linux__
1425
    xenUnifiedPrivatePtr priv = conn->privateData;
D
Daniel P. Berrange 已提交
1426
    int ret;
1427

D
Daniel P. Berrange 已提交
1428 1429
    xenUnifiedLock(priv);
    /* Need to lock because it hits the xenstore handle :-( */
1430
    ret = xenLinuxDomainBlockStats(priv, def, path, stats);
D
Daniel P. Berrange 已提交
1431 1432
    xenUnifiedUnlock(priv);
    return ret;
1433
#else
1434 1435
    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                   _("block statistics not supported on this platform"));
1436
    return -1;
1437
#endif
1438 1439 1440 1441 1442 1443 1444 1445 1446 1447
}

/* Paths have the form vif<domid>.<n> (this interface checks that
 * <domid> is the real domain ID and returns an error if not).
 *
 * In future we may allow you to query bridge stats (virbrX or
 * xenbrX), but that will probably be through a separate
 * virNetwork interface, as yet not decided.
 */
int
1448
xenHypervisorDomainInterfaceStats(virDomainDefPtr def,
1449
                                  const char *path,
1450
                                  virDomainInterfaceStatsPtr stats)
1451
{
1452
#ifdef __linux__
1453 1454
    int rqdomid, device;

1455 1456 1457
    /* Verify that the vif requested is one belonging to the current
     * domain.
     */
1458
    if (sscanf(path, "vif%d.%d", &rqdomid, &device) != 2) {
1459 1460
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("invalid path, should be vif<domid>.<n>."));
1461 1462
        return -1;
    }
1463
    if (rqdomid != def->id) {
1464 1465
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("invalid path, vif<domid> should match this domain ID"));
1466 1467 1468
        return -1;
    }

1469
    return virNetDevTapInterfaceStats(path, stats);
1470
#else
1471 1472
    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                   _("/proc/net/dev: Interface not found"));
1473
    return -1;
1474
#endif
1475 1476
}

1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488

/**
 * virXen_setmaxmem:
 * @handle: the hypervisor handle
 * @id: the domain id
 * @memory: the amount of memory in kilobytes
 *
 * Do a low level hypercall to change the max memory amount
 *
 * Returns 0 or -1 in case of failure
 */
static int
1489
virXen_setmaxmem(int handle, int id, unsigned long memory)
1490 1491 1492
{
    int ret = -1;

P
Philipp Hahn 已提交
1493
    if (hv_versions.hypervisor > 1) {
1494 1495 1496
        xen_op_v2_dom op;

        memset(&op, 0, sizeof(op));
1497 1498
        op.cmd = XEN_V2_OP_SETMAXMEM;
        op.domain = (domid_t) id;
P
Philipp Hahn 已提交
1499
        if (hv_versions.dom_interface < 5)
1500 1501 1502
            op.u.setmaxmem.maxmem = memory;
        else
            op.u.setmaxmemd5.maxmem = memory;
1503
        ret = xenHypervisorDoV2Dom(handle, &op);
P
Philipp Hahn 已提交
1504
    } else if (hv_versions.hypervisor == 1) {
1505 1506 1507
        xen_op_v1 op;

        memset(&op, 0, sizeof(op));
1508 1509 1510 1511
        op.cmd = XEN_V1_OP_SETMAXMEM;
        op.u.setmaxmem.domain = (domid_t) id;
        op.u.setmaxmem.maxmem = memory;
        ret = xenHypervisorDoV1Op(handle, &op);
P
Philipp Hahn 已提交
1512
    } else if (hv_versions.hypervisor == 0) {
1513
        xen_op_v0 op;
1514 1515

        memset(&op, 0, sizeof(op));
1516 1517 1518 1519
        op.cmd = XEN_V0_OP_SETMAXMEM;
        op.u.setmaxmem.domain = (domid_t) id;
        op.u.setmaxmem.maxmem = memory;
        ret = xenHypervisorDoV0Op(handle, &op);
1520
    }
1521
    return ret;
1522 1523 1524 1525 1526 1527 1528 1529 1530
}


/**
 * virXen_setvcpumap:
 * @handle: the hypervisor handle
 * @id: the domain id
 * @vcpu: the vcpu to map
 * @cpumap: the bitmap for this vcpu
1531
 * @maplen: the size of the bitmap in bytes
1532 1533 1534 1535 1536 1537
 *
 * Do a low level hypercall to change the pinning for vcpu
 *
 * Returns 0 or -1 in case of failure
 */
static int
1538 1539 1540 1541 1542
virXen_setvcpumap(int handle,
                  int id,
                  unsigned int vcpu,
                  unsigned char * cpumap,
                  int maplen)
1543 1544
{
    int ret = -1;
1545 1546 1547
    unsigned char *new = NULL;
    unsigned char *bitmap = NULL;
    uint32_t nr_cpus;
1548

P
Philipp Hahn 已提交
1549
    if (hv_versions.hypervisor > 1) {
1550 1551
        xen_op_v2_dom op;

1552
        if (lock_pages(cpumap, maplen) < 0)
1553
            return -1;
1554

1555
        memset(&op, 0, sizeof(op));
1556 1557
        op.cmd = XEN_V2_OP_SETVCPUMAP;
        op.domain = (domid_t) id;
1558 1559 1560 1561

        /* The allocated memory to cpumap must be 'sizeof(uint64_t)' byte *
         * for Xen, and also nr_cpus must be 'sizeof(uint64_t) * 8'       */
        if (maplen < 8) {
1562
            if (VIR_ALLOC_N(new, sizeof(uint64_t)) < 0)
1563
                return -1;
1564 1565 1566 1567 1568 1569 1570 1571
            memcpy(new, cpumap, maplen);
            bitmap = new;
            nr_cpus = sizeof(uint64_t) * 8;
        } else {
            bitmap = cpumap;
            nr_cpus = maplen * 8;
        }

P
Philipp Hahn 已提交
1572
        if (hv_versions.dom_interface < 5) {
1573
            op.u.setvcpumap.vcpu = vcpu;
1574 1575
            op.u.setvcpumap.cpumap.bitmap = bitmap;
            op.u.setvcpumap.cpumap.nr_cpus = nr_cpus;
1576 1577
        } else {
            op.u.setvcpumapd5.vcpu = vcpu;
1578 1579
            op.u.setvcpumapd5.cpumap.bitmap.v = bitmap;
            op.u.setvcpumapd5.cpumap.nr_cpus = nr_cpus;
1580
        }
1581
        ret = xenHypervisorDoV2Dom(handle, &op);
1582
        VIR_FREE(new);
1583

1584
        if (unlock_pages(cpumap, maplen) < 0)
1585
            ret = -1;
1586
    } else {
1587
        cpumap_t xen_cpumap; /* limited to 64 CPUs in old hypervisors */
E
Eric Blake 已提交
1588
        char buf[8] = "";
1589

E
Eric Blake 已提交
1590
        if (maplen > sizeof(cpumap_t) || sizeof(cpumap_t) != sizeof(uint64_t))
1591
            return -1;
E
Eric Blake 已提交
1592 1593 1594
        /* Supply trailing 0s if user's input array was short */
        memcpy(buf, cpumap, maplen);
        xen_cpumap = virReadBufInt64LE(buf);
1595

P
Philipp Hahn 已提交
1596
        if (hv_versions.hypervisor == 1) {
1597 1598 1599 1600 1601 1602 1603 1604
            xen_op_v1 op;

            memset(&op, 0, sizeof(op));
            op.cmd = XEN_V1_OP_SETVCPUMAP;
            op.u.setvcpumap.domain = (domid_t) id;
            op.u.setvcpumap.vcpu = vcpu;
            op.u.setvcpumap.cpumap = xen_cpumap;
            ret = xenHypervisorDoV1Op(handle, &op);
P
Philipp Hahn 已提交
1605
        } else if (hv_versions.hypervisor == 0) {
1606 1607 1608 1609 1610 1611 1612 1613 1614
            xen_op_v0 op;

            memset(&op, 0, sizeof(op));
            op.cmd = XEN_V0_OP_SETVCPUMAP;
            op.u.setvcpumap.domain = (domid_t) id;
            op.u.setvcpumap.vcpu = vcpu;
            op.u.setvcpumap.cpumap = xen_cpumap;
            ret = xenHypervisorDoV0Op(handle, &op);
        }
1615
    }
1616
    return ret;
1617
}
1618

1619

1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632
/**
 * virXen_getvcpusinfo:
 * @handle: the hypervisor handle
 * @id: the domain id
 * @vcpu: the vcpu to map
 * @cpumap: the bitmap for this vcpu
 * @maplen: the size of the bitmap in bytes
 *
 * Do a low level hypercall to change the pinning for vcpu
 *
 * Returns 0 or -1 in case of failure
 */
static int
1633 1634 1635 1636 1637 1638
virXen_getvcpusinfo(int handle,
                    int id,
                    unsigned int vcpu,
                    virVcpuInfoPtr ipt,
                    unsigned char *cpumap,
                    int maplen)
1639 1640 1641
{
    int ret = -1;

P
Philipp Hahn 已提交
1642
    if (hv_versions.hypervisor > 1) {
1643 1644 1645
        xen_op_v2_dom op;

        memset(&op, 0, sizeof(op));
1646 1647
        op.cmd = XEN_V2_OP_GETVCPUINFO;
        op.domain = (domid_t) id;
P
Philipp Hahn 已提交
1648
        if (hv_versions.dom_interface < 5)
1649 1650 1651
            op.u.getvcpuinfo.vcpu = (uint16_t) vcpu;
        else
            op.u.getvcpuinfod5.vcpu = (uint16_t) vcpu;
1652
        ret = xenHypervisorDoV2Dom(handle, &op);
1653

1654
        if (ret < 0)
1655
            return -1;
1656
        ipt->number = vcpu;
P
Philipp Hahn 已提交
1657
        if (hv_versions.dom_interface < 5) {
1658 1659 1660 1661 1662
            if (op.u.getvcpuinfo.online) {
                if (op.u.getvcpuinfo.running)
                    ipt->state = VIR_VCPU_RUNNING;
                if (op.u.getvcpuinfo.blocked)
                    ipt->state = VIR_VCPU_BLOCKED;
1663
            } else {
1664
                ipt->state = VIR_VCPU_OFFLINE;
1665
            }
1666 1667 1668 1669 1670 1671 1672 1673 1674

            ipt->cpuTime = op.u.getvcpuinfo.cpu_time;
            ipt->cpu = op.u.getvcpuinfo.online ? (int)op.u.getvcpuinfo.cpu : -1;
        } else {
            if (op.u.getvcpuinfod5.online) {
                if (op.u.getvcpuinfod5.running)
                    ipt->state = VIR_VCPU_RUNNING;
                if (op.u.getvcpuinfod5.blocked)
                    ipt->state = VIR_VCPU_BLOCKED;
1675
            } else {
1676
                ipt->state = VIR_VCPU_OFFLINE;
1677
            }
1678 1679 1680

            ipt->cpuTime = op.u.getvcpuinfod5.cpu_time;
            ipt->cpu = op.u.getvcpuinfod5.online ? (int)op.u.getvcpuinfod5.cpu : -1;
1681 1682
        }
        if ((cpumap != NULL) && (maplen > 0)) {
1683
            if (lock_pages(cpumap, maplen) < 0)
1684
                return -1;
1685

1686
            memset(cpumap, 0, maplen);
1687 1688 1689
            memset(&op, 0, sizeof(op));
            op.cmd = XEN_V2_OP_GETVCPUMAP;
            op.domain = (domid_t) id;
P
Philipp Hahn 已提交
1690
            if (hv_versions.dom_interface < 5) {
1691 1692 1693 1694 1695 1696 1697 1698
                op.u.getvcpumap.vcpu = vcpu;
                op.u.getvcpumap.cpumap.bitmap = cpumap;
                op.u.getvcpumap.cpumap.nr_cpus = maplen * 8;
            } else {
                op.u.getvcpumapd5.vcpu = vcpu;
                op.u.getvcpumapd5.cpumap.bitmap.v = cpumap;
                op.u.getvcpumapd5.cpumap.nr_cpus = maplen * 8;
            }
1699
            ret = xenHypervisorDoV2Dom(handle, &op);
1700
            if (unlock_pages(cpumap, maplen) < 0)
1701 1702
                ret = -1;
        }
1703
    } else {
1704 1705 1706 1707 1708
        int mapl = maplen;
        int cpu;

        if (maplen > (int)sizeof(cpumap_t))
            mapl = (int)sizeof(cpumap_t);
1709

P
Philipp Hahn 已提交
1710
        if (hv_versions.hypervisor == 1) {
1711 1712 1713 1714 1715 1716 1717 1718
            xen_op_v1 op;

            memset(&op, 0, sizeof(op));
            op.cmd = XEN_V1_OP_GETVCPUINFO;
            op.u.getvcpuinfo.domain = (domid_t) id;
            op.u.getvcpuinfo.vcpu = vcpu;
            ret = xenHypervisorDoV1Op(handle, &op);
            if (ret < 0)
1719
                return -1;
1720
            ipt->number = vcpu;
1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733
            if (op.u.getvcpuinfo.online) {
                if (op.u.getvcpuinfo.running) ipt->state = VIR_VCPU_RUNNING;
                if (op.u.getvcpuinfo.blocked) ipt->state = VIR_VCPU_BLOCKED;
            }
            else ipt->state = VIR_VCPU_OFFLINE;
            ipt->cpuTime = op.u.getvcpuinfo.cpu_time;
            ipt->cpu = op.u.getvcpuinfo.online ? (int)op.u.getvcpuinfo.cpu : -1;
            if ((cpumap != NULL) && (maplen > 0)) {
                for (cpu = 0; cpu < (mapl * 8); cpu++) {
                    if (op.u.getvcpuinfo.cpumap & ((uint64_t)1<<cpu))
                        VIR_USE_CPU(cpumap, cpu);
                }
            }
P
Philipp Hahn 已提交
1734
        } else if (hv_versions.hypervisor == 0) {
1735 1736 1737 1738 1739 1740 1741 1742
            xen_op_v1 op;

            memset(&op, 0, sizeof(op));
            op.cmd = XEN_V0_OP_GETVCPUINFO;
            op.u.getvcpuinfo.domain = (domid_t) id;
            op.u.getvcpuinfo.vcpu = vcpu;
            ret = xenHypervisorDoV0Op(handle, &op);
            if (ret < 0)
1743
                return -1;
1744
            ipt->number = vcpu;
1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758
            if (op.u.getvcpuinfo.online) {
                if (op.u.getvcpuinfo.running) ipt->state = VIR_VCPU_RUNNING;
                if (op.u.getvcpuinfo.blocked) ipt->state = VIR_VCPU_BLOCKED;
            }
            else ipt->state = VIR_VCPU_OFFLINE;
            ipt->cpuTime = op.u.getvcpuinfo.cpu_time;
            ipt->cpu = op.u.getvcpuinfo.online ? (int)op.u.getvcpuinfo.cpu : -1;
            if ((cpumap != NULL) && (maplen > 0)) {
                for (cpu = 0; cpu < (mapl * 8); cpu++) {
                    if (op.u.getvcpuinfo.cpumap & ((uint64_t)1<<cpu))
                        VIR_USE_CPU(cpumap, cpu);
                }
            }
        }
1759
    }
1760
    return ret;
1761
}
1762

1763 1764
/**
 * xenHypervisorInit:
P
Philipp Hahn 已提交
1765 1766
 * @override_versions: pointer to optional struct xenHypervisorVersions with
 *     version information used instead of automatic version detection.
1767 1768 1769
 *
 * Initialize the hypervisor layer. Try to detect the kind of interface
 * used i.e. pre or post changeset 10277
P
Philipp Hahn 已提交
1770 1771
 *
 * Returns 0 or -1 in case of failure
1772
 */
1773
int
P
Philipp Hahn 已提交
1774
xenHypervisorInit(struct xenHypervisorVersions *override_versions)
1775
{
1776
    int fd, ret, cmd, errcode;
1777
    hypercall_t hc;
1778
    v0_hypercall_t v0_hc;
1779
    xen_getdomaininfo info;
D
Daniel Veillard 已提交
1780
    virVcpuInfoPtr ipt = NULL;
1781

1782 1783 1784 1785
    /* Compile regular expressions used by xenHypervisorGetCapabilities.
     * Note that errors here are really internal errors since these
     * regexps should never fail to compile.
     */
1786
    errcode = regcomp(&flags_hvm_rec, flags_hvm_re, REG_EXTENDED);
1787 1788
    if (errcode != 0) {
        char error[100];
1789
        regerror(errcode, &flags_hvm_rec, error, sizeof(error));
1790
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", error);
1791 1792
        return -1;
    }
1793
    errcode = regcomp(&flags_pae_rec, flags_pae_re, REG_EXTENDED);
1794 1795
    if (errcode != 0) {
        char error[100];
1796 1797
        regerror(errcode, &flags_pae_rec, error, sizeof(error));
        regfree(&flags_hvm_rec);
1798
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", error);
1799 1800
        return -1;
    }
1801
    errcode = regcomp(&xen_cap_rec, xen_cap_re, REG_EXTENDED);
1802 1803
    if (errcode != 0) {
        char error[100];
1804 1805 1806
        regerror(errcode, &xen_cap_rec, error, sizeof(error));
        regfree(&flags_pae_rec);
        regfree(&flags_hvm_rec);
1807
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", error);
1808 1809 1810
        return -1;
    }

P
Philipp Hahn 已提交
1811 1812 1813 1814 1815
    if (override_versions) {
      hv_versions = *override_versions;
      return 0;
    }

1816
    /* Xen hypervisor version detection begins. */
1817 1818
    ret = open(XEN_HYPERVISOR_SOCKET, O_RDWR);
    if (ret < 0) {
P
Philipp Hahn 已提交
1819
        hv_versions.hypervisor = -1;
1820
        return -1;
1821 1822 1823
    }
    fd = ret;

1824 1825 1826 1827
    /*
     * The size of the hypervisor call block changed July 2006
     * this detect if we are using the new or old hypercall_t structure
     */
1828 1829 1830 1831 1832 1833 1834 1835
    hc.op = __HYPERVISOR_xen_version;
    hc.arg[0] = (unsigned long) XENVER_version;
    hc.arg[1] = 0;

    cmd = IOCTL_PRIVCMD_HYPERCALL;
    ret = ioctl(fd, cmd, (unsigned long) &hc);

    if ((ret != -1) && (ret != 0)) {
1836
        VIR_DEBUG("Using new hypervisor call: %X", ret);
P
Philipp Hahn 已提交
1837
        hv_versions.hv = ret;
1838 1839
        xen_ioctl_hypercall_cmd = cmd;
        goto detect_v2;
1840
    }
1841

1842
#ifndef __sun
1843 1844 1845 1846 1847 1848 1849 1850
    /*
     * check if the old hypercall are actually working
     */
    v0_hc.op = __HYPERVISOR_xen_version;
    v0_hc.arg[0] = (unsigned long) XENVER_version;
    v0_hc.arg[1] = 0;
    cmd = _IOC(_IOC_NONE, 'P', 0, sizeof(v0_hypercall_t));
    ret = ioctl(fd, cmd, (unsigned long) &v0_hc);
1851
    if ((ret != -1) && (ret != 0)) {
1852
        VIR_DEBUG("Using old hypervisor call: %X", ret);
P
Philipp Hahn 已提交
1853
        hv_versions.hv = ret;
1854
        xen_ioctl_hypercall_cmd = cmd;
P
Philipp Hahn 已提交
1855
        hv_versions.hypervisor = 0;
1856
        goto done;
1857
    }
1858
#endif
1859

1860
    /*
R
Richard W.M. Jones 已提交
1861
     * we failed to make any hypercall
1862 1863
     */

P
Philipp Hahn 已提交
1864
    hv_versions.hypervisor = -1;
1865 1866 1867
    virReportSystemError(errno,
                         _("Unable to issue hypervisor ioctl %lu"),
                         (unsigned long)IOCTL_PRIVCMD_HYPERCALL);
1868
    VIR_FORCE_CLOSE(fd);
1869
    return -1;
1870

1871
 detect_v2:
1872 1873 1874 1875 1876
    /*
     * The hypercalls were refactored into 3 different section in August 2006
     * Try to detect if we are running a version post 3.0.2 with the new ones
     * or the old ones
     */
P
Philipp Hahn 已提交
1877
    hv_versions.hypervisor = 2;
1878

1879
    if (VIR_ALLOC(ipt) < 0)
1880
        return -1;
1881
    /* Currently consider RHEL5.0 Fedora7, xen-3.1, and xen-unstable */
P
Philipp Hahn 已提交
1882
    hv_versions.sys_interface = 2; /* XEN_SYSCTL_INTERFACE_VERSION */
1883
    if (virXen_getdomaininfo(fd, 0, &info) == 1) {
1884
        /* RHEL 5.0 */
P
Philipp Hahn 已提交
1885
        hv_versions.dom_interface = 3; /* XEN_DOMCTL_INTERFACE_VERSION */
1886
        if (virXen_getvcpusinfo(fd, 0, 0, ipt, NULL, 0) == 0) {
1887
            VIR_DEBUG("Using hypervisor call v2, sys ver2 dom ver3");
1888 1889 1890
            goto done;
        }
        /* Fedora 7 */
P
Philipp Hahn 已提交
1891
        hv_versions.dom_interface = 4; /* XEN_DOMCTL_INTERFACE_VERSION */
1892
        if (virXen_getvcpusinfo(fd, 0, 0, ipt, NULL, 0) == 0) {
1893
            VIR_DEBUG("Using hypervisor call v2, sys ver2 dom ver4");
1894 1895 1896 1897
            goto done;
        }
    }

P
Philipp Hahn 已提交
1898
    hv_versions.sys_interface = 3; /* XEN_SYSCTL_INTERFACE_VERSION */
1899
    if (virXen_getdomaininfo(fd, 0, &info) == 1) {
1900
        /* xen-3.1 */
P
Philipp Hahn 已提交
1901
        hv_versions.dom_interface = 5; /* XEN_DOMCTL_INTERFACE_VERSION */
1902
        if (virXen_getvcpusinfo(fd, 0, 0, ipt, NULL, 0) == 0) {
1903
            VIR_DEBUG("Using hypervisor call v2, sys ver3 dom ver5");
1904 1905
            goto done;
        }
1906
    }
1907

P
Philipp Hahn 已提交
1908
    hv_versions.sys_interface = 4; /* XEN_SYSCTL_INTERFACE_VERSION */
1909
    if (virXen_getdomaininfo(fd, 0, &info) == 1) {
1910
        /* Fedora 8 */
P
Philipp Hahn 已提交
1911
        hv_versions.dom_interface = 5; /* XEN_DOMCTL_INTERFACE_VERSION */
1912
        if (virXen_getvcpusinfo(fd, 0, 0, ipt, NULL, 0) == 0) {
1913
            VIR_DEBUG("Using hypervisor call v2, sys ver4 dom ver5");
1914 1915 1916 1917
            goto done;
        }
    }

P
Philipp Hahn 已提交
1918
    hv_versions.sys_interface = 6; /* XEN_SYSCTL_INTERFACE_VERSION */
1919 1920
    if (virXen_getdomaininfo(fd, 0, &info) == 1) {
        /* Xen 3.2, Fedora 9 */
P
Philipp Hahn 已提交
1921
        hv_versions.dom_interface = 5; /* XEN_DOMCTL_INTERFACE_VERSION */
1922
        if (virXen_getvcpusinfo(fd, 0, 0, ipt, NULL, 0) == 0) {
1923
            VIR_DEBUG("Using hypervisor call v2, sys ver6 dom ver5");
1924 1925
            goto done;
        }
J
Jim Fehlig 已提交
1926 1927 1928
    }

    /* Xen 4.0 */
P
Philipp Hahn 已提交
1929
    hv_versions.sys_interface = 7; /* XEN_SYSCTL_INTERFACE_VERSION */
J
Jim Fehlig 已提交
1930
    if (virXen_getdomaininfo(fd, 0, &info) == 1) {
P
Philipp Hahn 已提交
1931
        hv_versions.dom_interface = 6; /* XEN_DOMCTL_INTERFACE_VERSION */
1932
        VIR_DEBUG("Using hypervisor call v2, sys ver7 dom ver6");
J
Jim Fehlig 已提交
1933
        goto done;
1934 1935
    }

J
Jim Fehlig 已提交
1936 1937 1938
    /* Xen 4.1
     * sysctl version 8 -> xen-unstable c/s 21118:28e5409e3fb3
     * domctl version 7 -> xen-unstable c/s 21212:de94884a669c
J
Jim Fehlig 已提交
1939
     * domctl version 8 -> xen-unstable c/s 23874:651aed73b39c
J
Jim Fehlig 已提交
1940
     */
P
Philipp Hahn 已提交
1941
    hv_versions.sys_interface = 8; /* XEN_SYSCTL_INTERFACE_VERSION */
J
Jim Fehlig 已提交
1942
    if (virXen_getdomaininfo(fd, 0, &info) == 1) {
P
Philipp Hahn 已提交
1943
        hv_versions.dom_interface = 7; /* XEN_DOMCTL_INTERFACE_VERSION */
1944
        if (virXen_getvcpusinfo(fd, 0, 0, ipt, NULL, 0) == 0) {
J
Jim Fehlig 已提交
1945 1946 1947 1948
            VIR_DEBUG("Using hypervisor call v2, sys ver8 dom ver7");
            goto done;
        }
        hv_versions.dom_interface = 8; /* XEN_DOMCTL_INTERFACE_VERSION */
1949
        if (virXen_getvcpusinfo(fd, 0, 0, ipt, NULL, 0) == 0) {
J
Jim Fehlig 已提交
1950 1951 1952
            VIR_DEBUG("Using hypervisor call v2, sys ver8 dom ver8");
            goto done;
        }
J
Jim Fehlig 已提交
1953 1954
    }

1955 1956 1957 1958 1959 1960 1961
    /* Xen 4.2
     * sysctl version 9 -> xen-unstable c/s 24102:dc8e55c90604
     * domctl version 8 -> unchanged from Xen 4.1
     */
    hv_versions.sys_interface = 9; /* XEN_SYSCTL_INTERFACE_VERSION */
    if (virXen_getdomaininfo(fd, 0, &info) == 1) {
        hv_versions.dom_interface = 8; /* XEN_DOMCTL_INTERFACE_VERSION */
1962
        if (virXen_getvcpusinfo(fd, 0, 0, ipt, NULL, 0) == 0) {
1963 1964 1965 1966
            VIR_DEBUG("Using hypervisor call v2, sys ver9 dom ver8");
            goto done;
        }
    }
1967

1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980
    /* Xen 4.3
     * sysctl version 10 -> xen-unstable commit bec8f17e
     * domctl version 9 -> xen-unstable commit 65c9792d
     */
    hv_versions.sys_interface = 10; /* XEN_SYSCTL_INTERFACE_VERSION */
    if (virXen_getdomaininfo(fd, 0, &info) == 1) {
        hv_versions.dom_interface = 9; /* XEN_DOMCTL_INTERFACE_VERSION */
        if (virXen_getvcpusinfo(fd, 0, 0, ipt, NULL, 0) == 0) {
            VIR_DEBUG("Using hypervisor call v2, sys ver10 dom ver9");
            goto done;
        }
    }

J
Jim Fehlig 已提交
1981 1982 1983 1984 1985 1986 1987
    hv_versions.hypervisor = 1;
    hv_versions.sys_interface = -1;
    if (virXen_getdomaininfo(fd, 0, &info) == 1) {
        VIR_DEBUG("Using hypervisor call v1");
        goto done;
    }

1988
    /*
R
Richard W.M. Jones 已提交
1989
     * we failed to make the getdomaininfolist hypercall
1990
     */
P
Philipp Hahn 已提交
1991
    hv_versions.hypervisor = -1;
1992 1993 1994 1995
    virReportSystemError(errno,
                         _("Unable to issue hypervisor ioctl %lu"),
                         (unsigned long)IOCTL_PRIVCMD_HYPERCALL);
    VIR_DEBUG("Failed to find any Xen hypervisor method");
1996
    VIR_FORCE_CLOSE(fd);
1997
    VIR_FREE(ipt);
1998
    return -1;
1999

2000
 done:
2001
    VIR_FORCE_CLOSE(fd);
2002
    VIR_FREE(ipt);
2003
    return 0;
2004 2005
}

2006

2007 2008
static int xenHypervisorOnceInit(void)
{
2009 2010 2011 2012 2013
    return xenHypervisorInit(NULL);
}

VIR_ONCE_GLOBAL_INIT(xenHypervisor)

2014 2015
/**
 * xenHypervisorOpen:
2016 2017 2018
 * @conn: pointer to the connection block
 * @name: URL for the target, NULL for local
 * @flags: combination of virDrvOpenFlag(s)
2019 2020 2021
 *
 * Connects to the Xen hypervisor.
 *
2022
 * Returns 0 or -1 in case of error.
2023
 */
2024
int
2025
xenHypervisorOpen(virConnectPtr conn,
2026
                  virConnectAuthPtr auth ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
2027
                  unsigned int flags)
2028
{
2029
    int ret;
2030
    xenUnifiedPrivatePtr priv = conn->privateData;
2031

2032
    virCheckFlags(VIR_CONNECT_RO, -1);
E
Eric Blake 已提交
2033

2034
    if (xenHypervisorInitialize() < 0)
2035
        return -1;
2036

2037
    priv->handle = -1;
2038

2039
    ret = open(XEN_HYPERVISOR_SOCKET, O_RDWR);
2040
    if (ret < 0) {
2041
        virReportError(VIR_ERR_NO_XEN, "%s", XEN_HYPERVISOR_SOCKET);
2042
        return -1;
2043
    }
2044 2045

    priv->handle = ret;
2046

2047
    return 0;
2048 2049 2050 2051
}

/**
 * xenHypervisorClose:
2052
 * @conn: pointer to the connection block
2053 2054 2055 2056 2057
 *
 * Close the connection to the Xen hypervisor.
 *
 * Returns 0 in case of success or -1 in case of error.
 */
2058
int
2059
xenHypervisorClose(virConnectPtr conn)
2060
{
2061
    int ret;
2062
    xenUnifiedPrivatePtr priv = conn->privateData;
2063

2064
    ret = VIR_CLOSE(priv->handle);
2065
    if (ret < 0)
2066
        return -1;
2067

2068
    return 0;
2069 2070 2071
}


2072 2073
/**
 * xenHypervisorGetVersion:
2074 2075
 * @conn: pointer to the connection block
 * @hvVer: where to store the version
2076 2077 2078
 *
 * Call the hypervisor to extracts his own internal API version
 *
2079
 * Returns 0 in case of success, -1 in case of error
2080
 */
2081
int
2082
xenHypervisorGetVersion(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *hvVer)
2083
{
P
Philipp Hahn 已提交
2084
    *hvVer = (hv_versions.hv >> 16) * 1000000 + (hv_versions.hv & 0xFFFF) * 1000;
2085
    return 0;
2086 2087
}

2088
struct guest_arch {
2089
    virArch arch;
2090 2091 2092 2093 2094 2095 2096 2097
    int hvm;
    int pae;
    int nonpae;
    int ia64_be;
};


static virCapsPtr
2098
xenHypervisorBuildCapabilities(virConnectPtr conn, virArch hostarch,
2099
                               int host_pae,
2100
                               const char *hvm_type,
2101
                               struct guest_arch *guest_archs,
2102 2103
                               int nr_guest_archs)
{
2104
    virCapsPtr caps;
2105
    size_t i;
P
Philipp Hahn 已提交
2106 2107
    int hv_major = hv_versions.hv >> 16;
    int hv_minor = hv_versions.hv & 0xFFFF;
2108

2109
    if ((caps = virCapabilitiesNew(hostarch, true, true)) == NULL)
2110
        goto no_memory;
2111

2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124
    if (hvm_type && STRNEQ(hvm_type, "") &&
        virCapabilitiesAddHostFeature(caps, hvm_type) < 0)
        goto no_memory;
    if (host_pae &&
        virCapabilitiesAddHostFeature(caps, "pae") < 0)
        goto no_memory;


    if (virCapabilitiesAddHostMigrateTransport(caps,
                                               "xenmigr") < 0)
        goto no_memory;


P
Philipp Hahn 已提交
2125
    if (hv_versions.sys_interface >= SYS_IFACE_MIN_VERS_NUMA && conn != NULL) {
2126
        if (xenDaemonNodeGetTopology(conn, caps) != 0) {
2127
            virObjectUnref(caps);
2128 2129 2130 2131 2132 2133
            return NULL;
        }
    }

    for (i = 0; i < nr_guest_archs; ++i) {
        virCapsGuestPtr guest;
2134 2135 2136
        char const *const xen_machines[] = {guest_archs[i].hvm ? "xenfv" : "xenpv"};
        virCapsGuestMachinePtr *machines;

2137
        if ((machines = virCapabilitiesAllocMachines(xen_machines, 1)) == NULL)
2138
            goto no_memory;
2139 2140

        if ((guest = virCapabilitiesAddGuest(caps,
2141
                                             guest_archs[i].hvm ? VIR_DOMAIN_OSTYPE_HVM : VIR_DOMAIN_OSTYPE_XEN,
2142 2143
                                             guest_archs[i].arch,
                                             (hostarch == VIR_ARCH_X86_64 ?
2144 2145 2146 2147 2148 2149
                                              "/usr/lib64/xen/bin/qemu-dm" :
                                              "/usr/lib/xen/bin/qemu-dm"),
                                             (guest_archs[i].hvm ?
                                              "/usr/lib/xen/boot/hvmloader" :
                                              NULL),
                                             1,
2150 2151
                                             machines)) == NULL) {
            virCapabilitiesFreeMachines(machines, 1);
2152
            goto no_memory;
2153
        }
2154
        machines = NULL;
2155 2156

        if (virCapabilitiesAddGuestDomain(guest,
2157
                                          VIR_DOMAIN_VIRT_XEN,
2158 2159 2160 2161 2162 2163 2164 2165 2166
                                          NULL,
                                          NULL,
                                          0,
                                          NULL) == NULL)
            goto no_memory;

        if (guest_archs[i].pae &&
            virCapabilitiesAddGuestFeature(guest,
                                           "pae",
2167 2168
                                           true,
                                           false) == NULL)
2169 2170 2171 2172 2173
            goto no_memory;

        if (guest_archs[i].nonpae &&
            virCapabilitiesAddGuestFeature(guest,
                                           "nonpae",
2174 2175
                                           true,
                                           false) == NULL)
2176 2177 2178 2179 2180
            goto no_memory;

        if (guest_archs[i].ia64_be &&
            virCapabilitiesAddGuestFeature(guest,
                                           "ia64_be",
2181 2182
                                           true,
                                           false) == NULL)
2183 2184 2185 2186 2187
            goto no_memory;

        if (guest_archs[i].hvm) {
            if (virCapabilitiesAddGuestFeature(guest,
                                               "acpi",
2188
                                               true, true) == NULL)
2189 2190
                goto no_memory;

2191
            /* In Xen 3.1.0, APIC is always on and can't be toggled */
2192 2193
            if (virCapabilitiesAddGuestFeature(guest,
                                               "apic",
2194 2195 2196
                                               true,
                                               !(hv_major > 3 &&
                                                 hv_minor > 0)) == NULL)
2197
                goto no_memory;
2198 2199 2200 2201 2202 2203 2204

            /* Xen 3.3.x and beyond supports enabling/disabling
             * hardware assisted paging.  Default is off.
             */
            if ((hv_major == 3 && hv_minor >= 3) || (hv_major > 3))
                if (virCapabilitiesAddGuestFeature(guest,
                                                   "hap",
2205
                                                   true,
2206
                                                   true) == NULL)
2207
                    goto no_memory;
2208 2209 2210 2211 2212 2213 2214

            /* Xen 3.4.x and beyond supports the Viridian (Hyper-V)
             * enlightenment interface.  Default is off.
             */
            if ((hv_major == 3 && hv_minor >= 4) || (hv_major > 3))
                if (virCapabilitiesAddGuestFeature(guest,
                                                   "viridian",
2215 2216
                                                   false,
                                                   true) == NULL)
2217
                    goto no_memory;
2218
        }
2219

2220 2221 2222 2223 2224
    }

    return caps;

 no_memory:
2225
    virObjectUnref(caps);
2226 2227 2228
    return NULL;
}

2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246
#ifdef __sun

static int
get_cpu_flags(virConnectPtr conn, const char **hvm, int *pae, int *longmode)
{
    struct {
        uint32_t r_eax, r_ebx, r_ecx, r_edx;
    } regs;

    char tmpbuf[20];
    int ret = 0;
    int fd;

    /* returns -1, errno 22 if in 32-bit mode */
    *longmode = (sysinfo(SI_ARCHITECTURE_64, tmpbuf, sizeof(tmpbuf)) != -1);

    if ((fd = open("/dev/cpu/self/cpuid", O_RDONLY)) == -1 ||
        pread(fd, &regs, sizeof(regs), 0) != sizeof(regs)) {
2247
        virReportSystemError(errno, "%s", _("could not read CPU flags"));
2248 2249 2250 2251 2252 2253
        goto out;
    }

    *pae = 0;
    *hvm = "";

2254
    if (STRPREFIX((const char *)&regs.r_ebx, "AuthcAMDenti")) {
2255
        if (pread(fd, &regs, sizeof(regs), 0x80000001) == sizeof(regs)) {
2256
            /* Read secure virtual machine bit (bit 2 of ECX feature ID) */
2257
            if ((regs.r_ecx >> 2) & 1)
2258 2259 2260 2261
                *hvm = "svm";
            if ((regs.r_edx >> 6) & 1)
                *pae = 1;
        }
2262
    } else if (STRPREFIX((const char *)&regs.r_ebx, "GenuntelineI")) {
2263
        if (pread(fd, &regs, sizeof(regs), 0x00000001) == sizeof(regs)) {
2264 2265 2266 2267 2268 2269 2270 2271 2272 2273
            /* Read VMXE feature bit (bit 5 of ECX feature ID) */
            if ((regs.r_ecx >> 5) & 1)
                *hvm = "vmx";
            if ((regs.r_edx >> 6) & 1)
                *pae = 1;
        }
    }

    ret = 1;

2274
 out:
2275
    VIR_FORCE_CLOSE(fd);
2276 2277 2278 2279 2280 2281 2282
    return ret;
}

static virCapsPtr
xenHypervisorMakeCapabilitiesSunOS(virConnectPtr conn)
{
    struct guest_arch guest_arches[32];
2283
    size_t i = 0;
2284 2285 2286 2287 2288 2289 2290
    virCapsPtr caps = NULL;
    int pae, longmode;
    const char *hvm;

    if (!get_cpu_flags(conn, &hvm, &pae, &longmode))
        return NULL;

2291
    guest_arches[i].arch = VIR_ARCH_I686;
2292 2293 2294 2295 2296 2297 2298
    guest_arches[i].hvm = 0;
    guest_arches[i].pae = pae;
    guest_arches[i].nonpae = !pae;
    guest_arches[i].ia64_be = 0;
    i++;

    if (longmode) {
2299
        guest_arches[i].arch = VIR_ARCH_X86_64;
2300 2301 2302 2303 2304 2305 2306 2307
        guest_arches[i].hvm = 0;
        guest_arches[i].pae = 0;
        guest_arches[i].nonpae = 0;
        guest_arches[i].ia64_be = 0;
        i++;
    }

    if (hvm[0] != '\0') {
2308
        guest_arches[i].arch = VIR_ARCH_I686;
2309 2310 2311 2312 2313 2314 2315
        guest_arches[i].hvm = 1;
        guest_arches[i].pae = pae;
        guest_arches[i].nonpae = 1;
        guest_arches[i].ia64_be = 0;
        i++;

        if (longmode) {
2316
            guest_arches[i].arch = VIR_ARCH_X86_64;
2317 2318 2319 2320 2321 2322 2323 2324
            guest_arches[i].hvm = 1;
            guest_arches[i].pae = 0;
            guest_arches[i].nonpae = 0;
            guest_arches[i].ia64_be = 0;
            i++;
        }
    }

2325 2326 2327 2328
    caps = xenHypervisorBuildCapabilities(conn,
                                          virArchFromHost(),
                                          pae, hvm,
                                          guest_arches, i);
2329 2330 2331 2332 2333 2334

    return caps;
}

#endif /* __sun */

2335
/**
2336
 * xenHypervisorMakeCapabilitiesInternal:
2337
 * @conn: pointer to the connection block
2338 2339
 * @cpuinfo: file handle containing /proc/cpuinfo data, or NULL
 * @capabilities: file handle containing /sys/hypervisor/properties/capabilities data, or NULL
2340 2341 2342
 *
 * Return the capabilities of this hypervisor.
 */
2343
virCapsPtr
2344
xenHypervisorMakeCapabilitiesInternal(virConnectPtr conn,
2345
                                      virArch hostarch,
2346 2347
                                      FILE *cpuinfo,
                                      FILE *capabilities)
2348 2349
{
    char line[1024], *str, *token;
2350
    regmatch_t subs[4];
2351
    char *saveptr = NULL;
2352
    size_t i;
2353 2354 2355

    char hvm_type[4] = ""; /* "vmx" or "svm" (or "" if not in CPU). */
    int host_pae = 0;
2356
    struct guest_arch guest_archs[32];
2357
    int nr_guest_archs = 0;
2358
    virCapsPtr caps = NULL;
2359

2360 2361
    memset(guest_archs, 0, sizeof(guest_archs));

2362 2363 2364 2365
    /* /proc/cpuinfo: flags: Intel calls HVM "vmx", AMD calls it "svm".
     * It's not clear if this will work on IA64, let alone other
     * architectures and non-Linux. (XXX)
     */
2366
    if (cpuinfo) {
2367 2368
        while (fgets(line, sizeof(line), cpuinfo)) {
            if (regexec(&flags_hvm_rec, line, sizeof(subs)/sizeof(regmatch_t), subs, 0) == 0
2369
                && subs[0].rm_so != -1) {
C
Chris Lalancette 已提交
2370 2371 2372 2373
                if (virStrncpy(hvm_type,
                               &line[subs[1].rm_so],
                               subs[1].rm_eo-subs[1].rm_so,
                               sizeof(hvm_type)) == NULL)
2374
                    goto no_memory;
2375
            } else if (regexec(&flags_pae_rec, line, 0, NULL, 0) == 0) {
2376
                host_pae = 1;
2377
            }
2378
        }
2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405
    }

    /* Most of the useful info is in /sys/hypervisor/properties/capabilities
     * which is documented in the code in xen-unstable.hg/xen/arch/.../setup.c.
     *
     * It is a space-separated list of supported guest architectures.
     *
     * For x86:
     *    TYP-VER-ARCH[p]
     *    ^   ^   ^    ^
     *    |   |   |    +-- PAE supported
     *    |   |   +------- x86_32 or x86_64
     *    |   +----------- the version of Xen, eg. "3.0"
     *    +--------------- "xen" or "hvm" for para or full virt respectively
     *
     * For PPC this file appears to be always empty (?)
     *
     * For IA64:
     *    TYP-VER-ARCH[be]
     *    ^   ^   ^    ^
     *    |   |   |    +-- Big-endian supported
     *    |   |   +------- always "ia64"
     *    |   +----------- the version of Xen, eg. "3.0"
     *    +--------------- "xen" or "hvm" for para or full virt respectively
     */

    /* Expecting one line in this file - ignore any more. */
2406
    if ((capabilities) && (fgets(line, sizeof(line), capabilities))) {
2407 2408 2409 2410
        /* Split the line into tokens.  strtok_r is OK here because we "own"
         * this buffer.  Parse out the features from each token.
         */
        for (str = line, nr_guest_archs = 0;
2411
             nr_guest_archs < sizeof(guest_archs) / sizeof(guest_archs[0])
2412
                 && (token = strtok_r(str, " ", &saveptr)) != NULL;
2413 2414
             str = NULL) {

2415 2416
            if (regexec(&xen_cap_rec, token, sizeof(subs) / sizeof(subs[0]),
                        subs, 0) == 0) {
2417
                int hvm = STRPREFIX(&token[subs[1].rm_so], "hvm");
2418 2419
                int pae = 0, nonpae = 0, ia64_be = 0;
                virArch arch;
2420 2421

                if (STRPREFIX(&token[subs[2].rm_so], "x86_32")) {
2422
                    arch = VIR_ARCH_I686;
2423 2424
                    if (subs[3].rm_so != -1 &&
                        STRPREFIX(&token[subs[3].rm_so], "p"))
2425 2426 2427
                        pae = 1;
                    else
                        nonpae = 1;
2428
                } else if (STRPREFIX(&token[subs[2].rm_so], "x86_64")) {
2429
                    arch = VIR_ARCH_X86_64;
2430
                } else if (STRPREFIX(&token[subs[2].rm_so], "ia64")) {
2431
                    arch = VIR_ARCH_ITANIUM;
2432 2433
                    if (subs[3].rm_so != -1 &&
                        STRPREFIX(&token[subs[3].rm_so], "be"))
2434
                        ia64_be = 1;
2435
                } else if (STRPREFIX(&token[subs[2].rm_so], "powerpc64")) {
2436
                    arch = VIR_ARCH_PPC64;
2437
                } else {
2438
                    /* XXX surely no other Xen archs exist. Arrrrrrrrrm  */
2439 2440
                    continue;
                }
2441

2442
                /* Search for existing matching (model,hvm) tuple */
2443
                for (i = 0; i < nr_guest_archs; i++) {
2444
                    if (guest_archs[i].arch == arch &&
2445 2446 2447 2448
                        guest_archs[i].hvm == hvm) {
                        break;
                    }
                }
2449

2450
                /* Too many arch flavours - highly unlikely ! */
J
Jim Meyering 已提交
2451
                if (i >= ARRAY_CARDINALITY(guest_archs))
2452 2453 2454 2455 2456
                    continue;
                /* Didn't find a match, so create a new one */
                if (i == nr_guest_archs)
                    nr_guest_archs++;

2457
                guest_archs[i].arch = arch;
2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469
                guest_archs[i].hvm = hvm;

                /* Careful not to overwrite a previous positive
                   setting with a negative one here - some archs
                   can do both pae & non-pae, but Xen reports
                   separately capabilities so we're merging archs */
                if (pae)
                    guest_archs[i].pae = pae;
                if (nonpae)
                    guest_archs[i].nonpae = nonpae;
                if (ia64_be)
                    guest_archs[i].ia64_be = ia64_be;
2470 2471 2472 2473
            }
        }
    }

2474
    if ((caps = xenHypervisorBuildCapabilities(conn,
2475
                                               hostarch,
2476 2477 2478 2479 2480
                                               host_pae,
                                               hvm_type,
                                               guest_archs,
                                               nr_guest_archs)) == NULL)
        goto no_memory;
2481

2482
    return caps;
2483

2484
 no_memory:
2485
    virObjectUnref(caps);
2486 2487 2488 2489
    return NULL;
}

/**
2490
 * xenHypervisorMakeCapabilities:
2491 2492 2493
 *
 * Return the capabilities of this hypervisor.
 */
2494
virCapsPtr
2495
xenHypervisorMakeCapabilities(virConnectPtr conn)
2496
{
2497 2498 2499
#ifdef __sun
    return xenHypervisorMakeCapabilitiesSunOS(conn);
#else
2500
    virCapsPtr caps = NULL;
2501 2502
    FILE *cpuinfo, *capabilities;

2503
    cpuinfo = fopen("/proc/cpuinfo", "r");
2504 2505
    if (cpuinfo == NULL) {
        if (errno != ENOENT) {
2506
            virReportSystemError(errno,
2507 2508
                                 _("cannot read file %s"),
                                 "/proc/cpuinfo");
2509 2510 2511 2512
            return NULL;
        }
    }

2513
    capabilities = fopen("/sys/hypervisor/properties/capabilities", "r");
2514 2515
    if (capabilities == NULL) {
        if (errno != ENOENT) {
2516
            VIR_FORCE_FCLOSE(cpuinfo);
2517
            virReportSystemError(errno,
2518 2519
                                 _("cannot read file %s"),
                                 "/sys/hypervisor/properties/capabilities");
2520 2521 2522 2523
            return NULL;
        }
    }

2524
    caps = xenHypervisorMakeCapabilitiesInternal(conn,
2525
                                                 virArchFromHost(),
2526 2527
                                                 cpuinfo,
                                                 capabilities);
2528
    if (caps == NULL)
2529
        goto cleanup;
2530

2531 2532 2533
    if (virNodeSuspendGetTargetMask(&caps->host.powerMgmt) < 0)
        VIR_WARN("Failed to get host power management capabilities");

2534
 cleanup:
2535 2536
    VIR_FORCE_FCLOSE(cpuinfo);
    VIR_FORCE_FCLOSE(capabilities);
2537

2538
    return caps;
2539
#endif /* __sun */
2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550
}



/**
 * xenHypervisorGetCapabilities:
 * @conn: pointer to the connection block
 *
 * Return the capabilities of this hypervisor.
 */
char *
2551
xenHypervisorGetCapabilities(virConnectPtr conn)
2552
{
2553
    xenUnifiedPrivatePtr priv = conn->privateData;
2554

2555
    return virCapabilitiesFormatXML(priv->caps);
2556 2557
}

2558

2559
char *
2560 2561
xenHypervisorDomainGetOSType(virConnectPtr conn,
                             virDomainDefPtr def)
2562
{
2563
    xenUnifiedPrivatePtr priv = conn->privateData;
2564
    xen_getdomaininfo dominfo;
2565
    char *ostype = NULL;
2566 2567

    /* HV's earlier than 3.1.0 don't include the HVM flags in guests status*/
P
Philipp Hahn 已提交
2568 2569
    if (hv_versions.hypervisor < 2 ||
        hv_versions.dom_interface < 4) {
2570
        return xenDaemonDomainGetOSType(conn, def);
2571
    }
2572 2573 2574

    XEN_GETDOMAININFO_CLEAR(dominfo);

2575
    if (virXen_getdomaininfo(priv->handle, def->id, &dominfo) < 0) {
2576 2577
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot get domain details"));
2578
        return NULL;
2579
    }
2580

2581
    if (XEN_GETDOMAININFO_DOMAIN(dominfo) != def->id) {
2582 2583
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot get domain details"));
2584
        return NULL;
2585
    }
2586

2587 2588 2589
    ignore_value(VIR_STRDUP(ostype,
                            XEN_GETDOMAININFO_FLAGS(dominfo) & DOMFLAGS_HVM ?
                            "hvm" : "linux"));
2590
    return ostype;
2591 2592
}

2593
int
2594
xenHypervisorHasDomain(virConnectPtr conn, int id)
2595
{
2596
    xenUnifiedPrivatePtr priv = conn->privateData;
2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609
    xen_getdomaininfo dominfo;

    XEN_GETDOMAININFO_CLEAR(dominfo);

    if (virXen_getdomaininfo(priv->handle, id, &dominfo) < 0)
        return 0;

    if (XEN_GETDOMAININFO_DOMAIN(dominfo) != id)
        return 0;

    return 1;
}

2610 2611

virDomainDefPtr
2612
xenHypervisorLookupDomainByID(virConnectPtr conn, int id)
2613
{
2614
    xenUnifiedPrivatePtr priv = conn->privateData;
2615
    xen_getdomaininfo dominfo;
2616
    virDomainDefPtr ret;
2617 2618 2619 2620 2621
    char *name;

    XEN_GETDOMAININFO_CLEAR(dominfo);

    if (virXen_getdomaininfo(priv->handle, id, &dominfo) < 0)
2622
        return NULL;
2623 2624

    if (XEN_GETDOMAININFO_DOMAIN(dominfo) != id)
2625
        return NULL;
2626

D
Daniel P. Berrange 已提交
2627 2628 2629 2630
    xenUnifiedLock(priv);
    name = xenStoreDomainGetName(conn, id);
    xenUnifiedUnlock(priv);
    if (!name)
2631
        return NULL;
2632

2633 2634 2635
    ret = virDomainDefNewFull(name,
                              XEN_GETDOMAININFO_UUID(dominfo),
                              id);
2636
    VIR_FREE(name);
2637 2638 2639 2640
    return ret;
}


2641
virDomainDefPtr
2642
xenHypervisorLookupDomainByUUID(virConnectPtr conn, const unsigned char *uuid)
2643 2644
{
    xen_getdomaininfolist dominfos;
2645
    xenUnifiedPrivatePtr priv = conn->privateData;
2646
    virDomainDefPtr ret;
2647
    char *name;
2648 2649
    int maxids = 100, nids, id;
    size_t i;
2650 2651 2652

 retry:
    if (!(XEN_GETDOMAININFOLIST_ALLOC(dominfos, maxids))) {
2653
        virReportOOMError();
2654
        return NULL;
2655 2656 2657 2658 2659 2660 2661 2662
    }

    XEN_GETDOMAININFOLIST_CLEAR(dominfos, maxids);

    nids = virXen_getdomaininfolist(priv->handle, 0, maxids, &dominfos);

    if (nids < 0) {
        XEN_GETDOMAININFOLIST_FREE(dominfos);
2663
        return NULL;
2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676
    }

    /* Can't possibly have more than 65,000 concurrent guests
     * so limit how many times we try, to avoid increasing
     * without bound & thus allocating all of system memory !
     * XXX I'll regret this comment in a few years time ;-)
     */
    if (nids == maxids) {
        XEN_GETDOMAININFOLIST_FREE(dominfos);
        if (maxids < 65000) {
            maxids *= 2;
            goto retry;
        }
2677
        return NULL;
2678 2679 2680
    }

    id = -1;
2681
    for (i = 0; i < nids; i++) {
2682 2683 2684 2685 2686 2687 2688 2689
        if (memcmp(XEN_GETDOMAININFOLIST_UUID(dominfos, i), uuid, VIR_UUID_BUFLEN) == 0) {
            id = XEN_GETDOMAININFOLIST_DOMAIN(dominfos, i);
            break;
        }
    }
    XEN_GETDOMAININFOLIST_FREE(dominfos);

    if (id == -1)
2690
        return NULL;
2691

D
Daniel P. Berrange 已提交
2692 2693 2694 2695
    xenUnifiedLock(priv);
    name = xenStoreDomainGetName(conn, id);
    xenUnifiedUnlock(priv);
    if (!name)
2696
        return NULL;
2697

2698
    ret = virDomainDefNewFull(name, uuid, id);
2699 2700
    if (ret)
        ret->id = id;
2701
    VIR_FREE(name);
2702 2703 2704
    return ret;
}

2705
/**
2706
 * xenHypervisorGetMaxVcpus:
2707 2708 2709 2710
 *
 * Returns the maximum of CPU defined by Xen.
 */
int
2711 2712
xenHypervisorGetMaxVcpus(virConnectPtr conn ATTRIBUTE_UNUSED,
                         const char *type ATTRIBUTE_UNUSED)
2713 2714 2715 2716
{
    return MAX_VIRT_CPUS;
}

2717
/**
2718 2719
 * xenHypervisorDomMaxMemory:
 * @dom: domain
2720
 *
2721
 * Retrieve the maximum amount of physical memory allocated to a
2722
 * domain.
2723 2724 2725
 *
 * Returns the memory size in kilobytes or 0 in case of error.
 */
2726
unsigned long
2727 2728
xenHypervisorGetMaxMemory(virConnectPtr conn,
                          virDomainDefPtr def)
2729
{
2730
    xenUnifiedPrivatePtr priv = conn->privateData;
2731
    xen_getdomaininfo dominfo;
2732 2733
    int ret;

2734
    if (kb_per_pages == 0) {
2735
        kb_per_pages = virGetSystemPageSizeKB();
2736 2737
        if (kb_per_pages <= 0)
            kb_per_pages = 4;
2738 2739
    }

2740
    XEN_GETDOMAININFO_CLEAR(dominfo);
2741

2742
    ret = virXen_getdomaininfo(priv->handle, def->id, &dominfo);
2743

2744
    if ((ret < 0) || (XEN_GETDOMAININFO_DOMAIN(dominfo) != def->id))
2745
        return 0;
2746

2747
    return (unsigned long) XEN_GETDOMAININFO_MAX_PAGES(dominfo) * kb_per_pages;
2748 2749
}

2750

2751
/**
2752 2753 2754
 * xenHypervisorGetDomInfo:
 * @conn: connection data
 * @id: the domain ID
2755
 * @info: the place where information should be stored
2756
 *
E
Eric Blake 已提交
2757
 * Do a hypervisor call to get the related set of domain information.
2758 2759 2760 2761
 *
 * Returns 0 in case of success, -1 in case of error.
 */
int
2762
xenHypervisorGetDomInfo(virConnectPtr conn, int id, virDomainInfoPtr info)
2763
{
2764
    xenUnifiedPrivatePtr priv = conn->privateData;
2765
    xen_getdomaininfo dominfo;
2766
    int ret;
2767
    uint32_t domain_flags, domain_state, domain_shutdown_cause;
2768 2769

    if (kb_per_pages == 0) {
2770
        kb_per_pages = virGetSystemPageSizeKB();
2771 2772
        if (kb_per_pages <= 0)
            kb_per_pages = 4;
2773
    }
2774

2775
    memset(info, 0, sizeof(virDomainInfo));
2776
    XEN_GETDOMAININFO_CLEAR(dominfo);
2777

2778
    ret = virXen_getdomaininfo(priv->handle, id, &dominfo);
2779

2780
    if ((ret < 0) || (XEN_GETDOMAININFO_DOMAIN(dominfo) != id))
2781
        return -1;
2782

2783
    domain_flags = XEN_GETDOMAININFO_FLAGS(dominfo);
2784 2785
    domain_flags &= ~DOMFLAGS_HVM; /* Mask out HVM flags */
    domain_state = domain_flags & 0xFF; /* Mask out high bits */
2786
    switch (domain_state) {
2787 2788 2789 2790
        case DOMFLAGS_DYING:
            info->state = VIR_DOMAIN_SHUTDOWN;
            break;
        case DOMFLAGS_SHUTDOWN:
2791 2792 2793 2794 2795 2796 2797 2798 2799
            /* The domain is shutdown.  Determine the cause. */
            domain_shutdown_cause = domain_flags >> DOMFLAGS_SHUTDOWNSHIFT;
            switch (domain_shutdown_cause) {
                case SHUTDOWN_crash:
                    info->state = VIR_DOMAIN_CRASHED;
                    break;
                default:
                    info->state = VIR_DOMAIN_SHUTOFF;
            }
2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811
            break;
        case DOMFLAGS_PAUSED:
            info->state = VIR_DOMAIN_PAUSED;
            break;
        case DOMFLAGS_BLOCKED:
            info->state = VIR_DOMAIN_BLOCKED;
            break;
        case DOMFLAGS_RUNNING:
            info->state = VIR_DOMAIN_RUNNING;
            break;
        default:
            info->state = VIR_DOMAIN_NOSTATE;
2812 2813 2814 2815 2816 2817 2818
    }

    /*
     * the API brings back the cpu time in nanoseconds,
     * convert to microseconds, same thing convert to
     * kilobytes from page counts
     */
2819
    info->cpuTime = XEN_GETDOMAININFO_CPUTIME(dominfo);
2820
    info->memory = XEN_GETDOMAININFO_TOT_PAGES(dominfo) * kb_per_pages;
2821
    info->maxMem = XEN_GETDOMAININFO_MAX_PAGES(dominfo);
2822
    if (info->maxMem != UINT_MAX)
2823
        info->maxMem *= kb_per_pages;
2824
    info->nrVirtCpu = XEN_GETDOMAININFO_CPUCOUNT(dominfo);
2825
    return 0;
2826 2827
}

2828 2829 2830
/**
 * xenHypervisorGetDomainInfo:
 * @domain: pointer to the domain block
2831
 * @info: the place where information should be stored
2832
 *
E
Eric Blake 已提交
2833
 * Do a hypervisor call to get the related set of domain information.
2834 2835 2836 2837
 *
 * Returns 0 in case of success, -1 in case of error.
 */
int
2838 2839 2840
xenHypervisorGetDomainInfo(virConnectPtr conn,
                           virDomainDefPtr def,
                           virDomainInfoPtr info)
2841
{
2842
    return xenHypervisorGetDomInfo(conn, def->id, info);
2843 2844
}

2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855
/**
 * xenHypervisorGetDomainState:
 * @domain: pointer to the domain block
 * @state: returned state of the domain
 * @reason: returned reason for the state
 *
 * Do a hypervisor call to get the related set of domain information.
 *
 * Returns 0 in case of success, -1 in case of error.
 */
int
2856 2857
xenHypervisorGetDomainState(virConnectPtr conn,
                            virDomainDefPtr def,
2858
                            int *state,
2859
                            int *reason)
2860 2861 2862
{
    virDomainInfo info;

2863
    if (xenHypervisorGetDomInfo(conn, def->id, &info) < 0)
2864 2865 2866 2867 2868 2869 2870 2871 2872
        return -1;

    *state = info.state;
    if (reason)
        *reason = 0;

    return 0;
}

2873 2874 2875 2876
/**
 * xenHypervisorNodeGetCellsFreeMemory:
 * @conn: pointer to the hypervisor connection
 * @freeMems: pointer to the array of unsigned long long
2877 2878
 * @startCell: index of first cell to return freeMems info on.
 * @maxCells: Maximum number of cells for which freeMems information can
2879 2880 2881 2882
 *            be returned.
 *
 * This call returns the amount of free memory in one or more NUMA cells.
 * The @freeMems array must be allocated by the caller and will be filled
2883 2884 2885
 * with the amount of free memory in kilobytes for each cell requested,
 * starting with startCell (in freeMems[0]), up to either
 * (startCell + maxCells), or the number of additional cells in the node,
2886 2887 2888 2889 2890
 * whichever is smaller.
 *
 * Returns the number of entries filled in freeMems, or -1 in case of error.
 */
int
2891 2892 2893 2894
xenHypervisorNodeGetCellsFreeMemory(virConnectPtr conn,
                                    unsigned long long *freeMems,
                                    int startCell,
                                    int maxCells)
2895 2896
{
    xen_op_v2_sys op_sys;
2897 2898 2899
    size_t i;
    int cell;
    int ret;
2900
    xenUnifiedPrivatePtr priv = conn->privateData;
D
Daniel P. Berrange 已提交
2901 2902

    if (priv->nbNodeCells < 0) {
2903 2904
        virReportError(VIR_ERR_XEN_CALL, "%s",
                       _("cannot determine actual number of cells"));
2905
        return -1;
2906 2907
    }

D
Daniel P. Berrange 已提交
2908
    if ((maxCells < 1) || (startCell >= priv->nbNodeCells)) {
2909 2910
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("invalid argument"));
2911 2912
        return -1;
    }
2913

2914
    /*
P
Philipp Hahn 已提交
2915
     * Support only hv_versions.sys_interface >=4
2916
     */
P
Philipp Hahn 已提交
2917
    if (hv_versions.sys_interface < SYS_IFACE_MIN_VERS_NUMA) {
2918 2919
        virReportError(VIR_ERR_XEN_CALL, "%s",
                       _("unsupported in sys interface < 4"));
2920 2921 2922 2923 2924 2925
        return -1;
    }

    memset(&op_sys, 0, sizeof(op_sys));
    op_sys.cmd = XEN_V2_OP_GETAVAILHEAP;

2926 2927
    for (cell = startCell, i = 0;
         cell < priv->nbNodeCells && i < maxCells; cell++, i++) {
P
Philipp Hahn 已提交
2928
        if (hv_versions.sys_interface >= 5)
2929
            op_sys.u.availheap5.node = cell;
2930
        else
2931
            op_sys.u.availheap.node = cell;
2932
        ret = xenHypervisorDoV2Sys(priv->handle, &op_sys);
2933
        if (ret < 0)
2934
            return -1;
P
Philipp Hahn 已提交
2935
        if (hv_versions.sys_interface >= 5)
2936
            freeMems[i] = op_sys.u.availheap5.avail_bytes;
2937
        else
2938
            freeMems[i] = op_sys.u.availheap.avail_bytes;
2939
    }
2940
    return i;
2941 2942 2943
}


2944 2945
/**
 * xenHypervisorSetMaxMemory:
2946
 * @domain: pointer to the domain block
2947 2948
 * @memory: the max memory size in kilobytes.
 *
E
Eric Blake 已提交
2949
 * Do a hypervisor call to change the maximum amount of memory used
2950 2951 2952 2953
 *
 * Returns 0 in case of success, -1 in case of error.
 */
int
2954 2955 2956
xenHypervisorSetMaxMemory(virConnectPtr conn,
                          virDomainDefPtr def,
                          unsigned long memory)
2957
{
2958
    int ret;
2959
    xenUnifiedPrivatePtr priv = conn->privateData;
2960

2961
    ret = virXen_setmaxmem(priv->handle, def->id, memory);
2962
    if (ret < 0)
2963 2964
        return -1;
    return 0;
2965
}
2966

2967

2968 2969 2970 2971 2972 2973
/**
 * xenHypervisorPinVcpu:
 * @domain: pointer to domain object
 * @vcpu: virtual CPU number
 * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes)
 * @maplen: length of cpumap in bytes
2974
 *
2975 2976 2977 2978 2979 2980
 * Dynamically change the real CPUs which can be allocated to a virtual CPU.
 *
 * Returns 0 in case of success, -1 in case of failure.
 */

int
2981 2982 2983 2984 2985
xenHypervisorPinVcpu(virConnectPtr conn,
                     virDomainDefPtr def,
                     unsigned int vcpu,
                     unsigned char *cpumap,
                     int maplen)
2986
{
2987
    int ret;
2988
    xenUnifiedPrivatePtr priv = conn->privateData;
2989

2990
    ret = virXen_setvcpumap(priv->handle, def->id, vcpu,
2991 2992
                            cpumap, maplen);
    if (ret < 0)
2993 2994
        return -1;
    return 0;
2995 2996 2997 2998 2999 3000 3001
}

/**
 * virDomainGetVcpus:
 * @domain: pointer to domain object, or NULL for Domain0
 * @info: pointer to an array of virVcpuInfo structures (OUT)
 * @maxinfo: number of structures in info array
E
Eric Blake 已提交
3002
 * @cpumaps: pointer to a bit map of real CPUs for all vcpus of this domain (in 8-bit bytes) (OUT)
D
Daniel Veillard 已提交
3003
 *	If cpumaps is NULL, then no cpumap information is returned by the API.
3004 3005 3006 3007 3008 3009
 *	It's assumed there is <maxinfo> cpumap in cpumaps array.
 *	The memory allocated to cpumaps must be (maxinfo * maplen) bytes
 *	(ie: calloc(maxinfo, maplen)).
 *	One cpumap inside cpumaps has the format described in virDomainPinVcpu() API.
 * @maplen: number of bytes in one cpumap, from 1 up to size of CPU map in
 *	underlying virtualization system (Xen...).
3010
 *
3011
 * Extract information about virtual CPUs of domain, store it in info array
R
Richard W.M. Jones 已提交
3012
 * and also in cpumaps if this pointer isn't NULL.
3013 3014 3015 3016
 *
 * Returns the number of info filled in case of success, -1 in case of failure.
 */
int
3017 3018
xenHypervisorGetVcpus(virConnectPtr conn,
                      virDomainDefPtr def,
3019 3020 3021 3022
                      virVcpuInfoPtr info,
                      int maxinfo,
                      unsigned char *cpumaps,
                      int maplen)
3023
{
3024
    xen_getdomaininfo dominfo;
3025
    int ret;
3026
    xenUnifiedPrivatePtr priv = conn->privateData;
3027
    virVcpuInfoPtr ipt;
3028 3029
    int nbinfo;
    size_t i;
3030

3031
    if (sizeof(cpumap_t) & 7) {
3032
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3033
                       _("invalid cpumap_t size"));
3034
        return -1;
3035
    }
3036

3037
    /* first get the number of virtual CPUs in this domain */
3038
    XEN_GETDOMAININFO_CLEAR(dominfo);
3039
    ret = virXen_getdomaininfo(priv->handle, def->id,
3040
                               &dominfo);
3041

3042
    if ((ret < 0) || (XEN_GETDOMAININFO_DOMAIN(dominfo) != def->id)) {
3043 3044
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot get domain details"));
3045
        return -1;
3046
    }
3047
    nbinfo = XEN_GETDOMAININFO_CPUCOUNT(dominfo) + 1;
3048 3049 3050
    if (nbinfo > maxinfo) nbinfo = maxinfo;

    if (cpumaps != NULL)
3051
        memset(cpumaps, 0, maxinfo * maplen);
3052

3053 3054
    for (i = 0, ipt = info; i < nbinfo; i++, ipt++) {
        if ((cpumaps != NULL) && (i < maxinfo)) {
3055
            ret = virXen_getvcpusinfo(priv->handle, def->id, i,
3056 3057 3058
                                      ipt,
                                      (unsigned char *)VIR_GET_CPUMAP(cpumaps, maplen, i),
                                      maplen);
3059
            if (ret < 0) {
3060 3061
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("cannot get VCPUs info"));
3062
                return -1;
3063
            }
3064
        } else {
3065
            ret = virXen_getvcpusinfo(priv->handle, def->id, i,
3066
                                      ipt, NULL, 0);
3067
            if (ret < 0) {
3068 3069
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("cannot get VCPUs info"));
3070
                return -1;
3071
            }
3072
        }
3073 3074 3075
    }
    return nbinfo;
}
3076

3077 3078 3079 3080 3081 3082 3083 3084 3085
/**
 * xenHypervisorGetVcpuMax:
 *
 *  Returns the maximum number of virtual CPUs supported for
 *  the guest VM. If the guest is inactive, this is the maximum
 *  of CPU defined by Xen. If the guest is running this reflect
 *  the maximum number of virtual CPUs the guest was booted with.
 */
int
3086 3087
xenHypervisorGetVcpuMax(virConnectPtr conn,
                        virDomainDefPtr def)
3088 3089 3090 3091
{
    xen_getdomaininfo dominfo;
    int ret;
    int maxcpu;
3092
    xenUnifiedPrivatePtr priv = conn->privateData;
3093 3094

    /* inactive domain */
3095
    if (def->id < 0) {
3096 3097 3098
        maxcpu = MAX_VIRT_CPUS;
    } else {
        XEN_GETDOMAININFO_CLEAR(dominfo);
3099
        ret = virXen_getdomaininfo(priv->handle, def->id,
3100 3101
                                   &dominfo);

3102
        if ((ret < 0) || (XEN_GETDOMAININFO_DOMAIN(dominfo) != def->id))
3103
            return -1;
3104 3105 3106 3107 3108 3109
        maxcpu = XEN_GETDOMAININFO_MAXCPUID(dominfo) + 1;
    }

    return maxcpu;
}

J
John Levon 已提交
3110 3111 3112 3113 3114 3115
/**
 * xenHavePrivilege()
 *
 * Return true if the current process should be able to connect to Xen.
 */
int
3116
xenHavePrivilege(void)
J
John Levon 已提交
3117 3118
{
#ifdef __sun
3119
    return priv_ineffect(PRIV_XVM_CONTROL);
J
John Levon 已提交
3120
#else
3121
    return access(XEN_HYPERVISOR_SOCKET, R_OK) == 0;
J
John Levon 已提交
3122 3123
#endif
}