Solaris dom0 support diff --git a/src/xen_internal.c b/src/xen_internal.c --- a/src/xen_internal.c +++ b/src/xen_internal.c @@ -30,7 +30,11 @@ #include #include #include +#ifdef __linux__ #include +#else +#include +#endif /* required for shutdown flags */ #include @@ -38,6 +42,8 @@ #include "xml.h" /* #define DEBUG */ + +#ifdef __linux__ /* * so far there is 2 versions of the structures usable for doing * hypervisor calls. @@ -60,6 +66,14 @@ typedef struct v1_hypercall_struct _IOC(_IOC_NONE, 'P', 0, sizeof(v1_hypercall_t)) typedef v1_hypercall_t hypercall_t; + +#else +typedef struct v0_hypercall_struct { + unsigned long op; + unsigned long arg[5]; +} v0_hypercall_t; +typedef privcmd_hypercall_t hypercall_t; +#endif #ifndef __HYPERVISOR_sysctl #define __HYPERVISOR_sysctl 35 @@ -579,7 +593,15 @@ typedef struct xen_op_v2_dom xen_op_v2_d #include "xen_unified.h" #include "xen_internal.h" -#define XEN_HYPERVISOR_SOCKET "/proc/xen/privcmd" +#ifdef __linux__ +#define XEN_HYPERVISOR_SOCKET "/proc/xen/privcmd" +#define HYPERVISOR_CAPABILITIES "/sys/hypervisor/properties/capabilities" +#define CPUINFO "/proc/cpuinfo" +#else +#define XEN_HYPERVISOR_SOCKET "/dev/xen/privcmd" +#define HYPERVISOR_CAPABILITIES "" +#define CPUINFO "/dev/cpu/self/cpuid" +#endif #ifndef PROXY static const char * xenHypervisorGetType(virConnectPtr conn); @@ -639,6 +661,9 @@ virDriver xenHypervisorDriver = { }; #endif /* !PROXY */ +static int lock_pages(void *addr, size_t len); +static int unlock_pages(void *addr, size_t len); + /** * virXenError: * @error: the error number @@ -741,7 +766,7 @@ xenHypervisorDoV0Op(int handle, xen_op_v hc.op = __HYPERVISOR_dom0_op; hc.arg[0] = (unsigned long) op; - if (mlock(op, sizeof(dom0_op_t)) < 0) { + if (lock_pages(op, sizeof(dom0_op_t)) < 0) { virXenError(VIR_ERR_XEN_CALL, " locking", sizeof(*op)); return (-1); } @@ -751,7 +776,7 @@ xenHypervisorDoV0Op(int handle, xen_op_v virXenError(VIR_ERR_XEN_CALL, " ioctl ", xen_ioctl_hypercall_cmd); } - if (munlock(op, sizeof(dom0_op_t)) < 0) { + if (unlock_pages(op, sizeof(dom0_op_t)) < 0) { virXenError(VIR_ERR_XEN_CALL, " releasing", sizeof(*op)); ret = -1; } @@ -782,7 +807,7 @@ xenHypervisorDoV1Op(int handle, xen_op_v hc.op = __HYPERVISOR_dom0_op; hc.arg[0] = (unsigned long) op; - if (mlock(op, sizeof(dom0_op_t)) < 0) { + if (lock_pages(op, sizeof(dom0_op_t)) < 0) { virXenError(VIR_ERR_XEN_CALL, " locking", sizeof(*op)); return (-1); } @@ -792,7 +817,7 @@ xenHypervisorDoV1Op(int handle, xen_op_v virXenError(VIR_ERR_XEN_CALL, " ioctl ", xen_ioctl_hypercall_cmd); } - if (munlock(op, sizeof(dom0_op_t)) < 0) { + if (unlock_pages(op, sizeof(dom0_op_t)) < 0) { virXenError(VIR_ERR_XEN_CALL, " releasing", sizeof(*op)); ret = -1; } @@ -824,7 +849,7 @@ xenHypervisorDoV2Sys(int handle, xen_op_ hc.op = __HYPERVISOR_sysctl; hc.arg[0] = (unsigned long) op; - if (mlock(op, sizeof(dom0_op_t)) < 0) { + if (lock_pages(op, sizeof(dom0_op_t)) < 0) { virXenError(VIR_ERR_XEN_CALL, " locking", sizeof(*op)); return (-1); } @@ -834,7 +859,7 @@ xenHypervisorDoV2Sys(int handle, xen_op_ virXenError(VIR_ERR_XEN_CALL, " sys ioctl ", xen_ioctl_hypercall_cmd); } - if (munlock(op, sizeof(dom0_op_t)) < 0) { + if (unlock_pages(op, sizeof(dom0_op_t)) < 0) { virXenError(VIR_ERR_XEN_CALL, " releasing", sizeof(*op)); ret = -1; } @@ -866,7 +891,7 @@ xenHypervisorDoV2Dom(int handle, xen_op_ hc.op = __HYPERVISOR_domctl; hc.arg[0] = (unsigned long) op; - if (mlock(op, sizeof(dom0_op_t)) < 0) { + if (lock_pages(op, sizeof(dom0_op_t)) < 0) { virXenError(VIR_ERR_XEN_CALL, " locking", sizeof(*op)); return (-1); } @@ -876,7 +901,7 @@ xenHypervisorDoV2Dom(int handle, xen_op_ virXenError(VIR_ERR_XEN_CALL, " ioctl ", xen_ioctl_hypercall_cmd); } - if (munlock(op, sizeof(dom0_op_t)) < 0) { + if (unlock_pages(op, sizeof(dom0_op_t)) < 0) { virXenError(VIR_ERR_XEN_CALL, " releasing", sizeof(*op)); ret = -1; } @@ -904,7 +929,7 @@ virXen_getdomaininfolist(int handle, int { int ret = -1; - if (mlock(XEN_GETDOMAININFOLIST_DATA(dominfos), + if (lock_pages(XEN_GETDOMAININFOLIST_DATA(dominfos), XEN_GETDOMAININFO_SIZE * maxids) < 0) { virXenError(VIR_ERR_XEN_CALL, " locking", XEN_GETDOMAININFO_SIZE * maxids); @@ -960,7 +985,7 @@ virXen_getdomaininfolist(int handle, int if (ret == 0) ret = op.u.getdomaininfolist.num_domains; } - if (munlock(XEN_GETDOMAININFOLIST_DATA(dominfos), + if (unlock_pages(XEN_GETDOMAININFOLIST_DATA(dominfos), XEN_GETDOMAININFO_SIZE * maxids) < 0) { virXenError(VIR_ERR_XEN_CALL, " release", XEN_GETDOMAININFO_SIZE * maxids); @@ -1485,7 +1510,7 @@ virXen_setvcpumap(int handle, int id, un if (hypervisor_version > 1) { xen_op_v2_dom op; - if (mlock(cpumap, maplen) < 0) { + if (lock_pages(cpumap, maplen) < 0) { virXenError(VIR_ERR_XEN_CALL, " locking", maplen); return (-1); } @@ -1503,7 +1528,7 @@ virXen_setvcpumap(int handle, int id, un } ret = xenHypervisorDoV2Dom(handle, &op); - if (munlock(cpumap, maplen) < 0) { + if (unlock_pages(cpumap, maplen) < 0) { virXenError(VIR_ERR_XEN_CALL, " release", maplen); ret = -1; } @@ -1600,7 +1625,7 @@ virXen_getvcpusinfo(int handle, int id, ipt->cpu = op.u.getvcpuinfod5.online ? (int)op.u.getvcpuinfod5.cpu : -1; } if ((cpumap != NULL) && (maplen > 0)) { - if (mlock(cpumap, maplen) < 0) { + if (lock_pages(cpumap, maplen) < 0) { virXenError(VIR_ERR_XEN_CALL, " locking", maplen); return (-1); } @@ -1618,7 +1643,7 @@ virXen_getvcpusinfo(int handle, int id, op.u.getvcpumapd5.cpumap.nr_cpus = maplen * 8; } ret = xenHypervisorDoV2Dom(handle, &op); - if (munlock(cpumap, maplen) < 0) { + if (unlock_pages(cpumap, maplen) < 0) { virXenError(VIR_ERR_XEN_CALL, " release", maplen); ret = -1; } @@ -1694,7 +1719,9 @@ xenHypervisorInit(void) { int fd, ret, cmd, errcode; hypercall_t hc; +#ifdef __linux__ v0_hypercall_t v0_hc; +#endif xen_getdomaininfo info; virVcpuInfoPtr ipt = NULL; @@ -1769,6 +1796,7 @@ xenHypervisorInit(void) goto detect_v2; } +#ifdef __linux__ /* * check if the old hypercall are actually working */ @@ -1786,6 +1814,7 @@ xenHypervisorInit(void) hypervisor_version = 0; goto done; } +#endif /* * we faild to make any hypercall @@ -1984,6 +2013,92 @@ xenHypervisorGetVersion(virConnectPtr co return(0); } +#ifdef __linux__ +void +loadCapabilities(FILE *cpuinfo, FILE *capabilities, char *hvm_type, + int *host_pae, char *line, int LINE_SIZE) +{ + regmatch_t subs[4]; + + /* /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) + */ + if (cpuinfo) { + while (fgets (line, LINE_SIZE, cpuinfo)) { + if (regexec (&flags_hvm_rec, line, + sizeof(subs)/sizeof(regmatch_t), subs, 0) == 0 + && subs[0].rm_so != -1) { + strncpy (hvm_type, + &line[subs[1].rm_so], subs[1].rm_eo-subs[1].rm_so+1); + hvm_type[subs[1].rm_eo-subs[1].rm_so] = '\0'; + } else if (regexec (&flags_pae_rec, line, 0, NULL, 0) == 0) + *host_pae = 1; + } + } + + /* Expecting one line in this file - ignore any more. */ + (void) fgets(line, LINE_SIZE, capabilities); +} + +#else +void +loadCapabilities(FILE *cpuinfo, FILE *capabilities, char *hvm_type, + int *host_pae, char *line, int LINE_SIZE) +{ + struct { + uint32_t r_eax, r_ebx, r_ecx, r_edx; + } _r, *rp = &_r; + int d, cmd; + char *s; + hypercall_t hc; + + + if ((d = open(CPUINFO, O_RDONLY)) == -1) { + goto cpuinfo_open_fail; + } + + if (pread(d, rp, sizeof (*rp), 0) != sizeof (*rp)) { + goto cpuinfo_pread_fail; + } + + s = (char *)&rp->r_ebx; + if (strncmp(s, "Auth" "cAMD" "enti", 12) == 0) { + if (pread(d, rp, sizeof (*rp), 0x80000001) == sizeof (*rp)) { + /* Read secure virtual machine bit (bit 2 of ECX feature ID) */ + if ((rp->r_ecx >> 2) & 1) { + strcpy(hvm_type, "svm"); + } + if ((rp->r_edx >> 6) & 1) { + *host_pae = 1; + } + } + } else if (strncmp(s, "Genu" "ntel" "ineI", 12) == 0) { + if (pread(d, rp, sizeof (*rp), 0x00000001) == sizeof (*rp)) { + /* Read VMXE feature bit (bit 5 of ECX feature ID) */ + if ((rp->r_ecx >> 5) & 1) { + strcpy(hvm_type, "vmx"); + } + if ((rp->r_edx >> 6) & 1) { + *host_pae = 1; + } + } + } +cpuinfo_pread_fail: + (void) close(d); +cpuinfo_open_fail: + + d = open(XEN_HYPERVISOR_SOCKET, O_RDWR); + hc.op = __HYPERVISOR_xen_version; + hc.arg[0] = (unsigned long) XENVER_capabilities; + hc.arg[1] = (unsigned long) line; + cmd = IOCTL_PRIVCMD_HYPERCALL; + (void) ioctl(d, cmd, (unsigned long) &hc); + close(d); +} + +#endif + /** * xenHypervisorGetCapabilities: * @conn: pointer to the connection block @@ -1997,7 +2112,8 @@ xenHypervisorMakeCapabilitiesXML(virConn const char *hostmachine, FILE *cpuinfo, FILE *capabilities) { - char line[1024], *str, *token; + const int LINE_SIZE = 1024; + char line[LINE_SIZE], *str, *token; regmatch_t subs[4]; char *saveptr = NULL; int i, r; @@ -2019,24 +2135,12 @@ xenHypervisorMakeCapabilitiesXML(virConn memset(guest_archs, 0, sizeof(guest_archs)); - /* /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) - */ - if (cpuinfo) { - while (fgets (line, sizeof line, cpuinfo)) { - if (regexec (&flags_hvm_rec, line, sizeof(subs)/sizeof(regmatch_t), subs, 0) == 0 - && subs[0].rm_so != -1) { - strncpy (hvm_type, - &line[subs[1].rm_so], subs[1].rm_eo-subs[1].rm_so+1); - hvm_type[subs[1].rm_eo-subs[1].rm_so] = '\0'; - } else if (regexec (&flags_pae_rec, line, 0, NULL, 0) == 0) - host_pae = 1; - } - } - - /* 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. + memset(line, 0, sizeof(line)); + loadCapabilities(cpuinfo, capabilities, hvm_type, &host_pae, line, + LINE_SIZE); + + /* The capabilities line is documented in the code in + * xen-unstable.hg/xen/arch/.../setup.c. * * It is a space-separated list of supported guest architectures. * @@ -2059,77 +2163,74 @@ xenHypervisorMakeCapabilitiesXML(virConn * +--------------- "xen" or "hvm" for para or full virt respectively */ - /* Expecting one line in this file - ignore any more. */ - if (fgets (line, sizeof line, capabilities)) { - /* 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; - nr_guest_archs < sizeof guest_archs / sizeof guest_archs[0] - && (token = strtok_r (str, " ", &saveptr)) != NULL; - str = NULL) { - - if (regexec (&xen_cap_rec, token, sizeof subs / sizeof subs[0], - subs, 0) == 0) { - int hvm = strncmp (&token[subs[1].rm_so], "hvm", 3) == 0; - const char *model; - int bits, pae = 0, nonpae = 0, ia64_be = 0; - if (strncmp (&token[subs[2].rm_so], "x86_32", 6) == 0) { - model = "i686"; - bits = 32; - if (strncmp (&token[subs[3].rm_so], "p", 1) == 0) - pae = 1; - else - nonpae = 1; + /* 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; + nr_guest_archs < sizeof guest_archs / sizeof guest_archs[0] + && (token = strtok_r (str, " ", &saveptr)) != NULL; + str = NULL) { + + if (regexec (&xen_cap_rec, token, sizeof subs / sizeof subs[0], + subs, 0) == 0) { + int hvm = strncmp (&token[subs[1].rm_so], "hvm", 3) == 0; + const char *model; + int bits, pae = 0, nonpae = 0, ia64_be = 0; + if (strncmp (&token[subs[2].rm_so], "x86_32", 6) == 0) { + model = "i686"; + bits = 32; + if (strncmp (&token[subs[3].rm_so], "p", 1) == 0) + pae = 1; + else + nonpae = 1; + } + else if (strncmp (&token[subs[2].rm_so], "x86_64", 6) == 0) { + model = "x86_64"; + bits = 64; + } + else if (strncmp (&token[subs[2].rm_so], "ia64", 4) == 0) { + model = "ia64"; + bits = 64; + if (strncmp (&token[subs[3].rm_so], "be", 2) == 0) + ia64_be = 1; + } + else if (strncmp (&token[subs[2].rm_so], "powerpc64", 4) == 0) { + model = "ppc64"; + bits = 64; + } else { + /* XXX surely no other Xen archs exist */ + continue; + } + + /* Search for existing matching (model,hvm) tuple */ + for (i = 0 ; i < nr_guest_archs ; i++) { + if (!strcmp(guest_archs[i].model, model) && + guest_archs[i].hvm == hvm) { + break; } - else if (strncmp (&token[subs[2].rm_so], "x86_64", 6) == 0) { - model = "x86_64"; - bits = 64; - } - else if (strncmp (&token[subs[2].rm_so], "ia64", 4) == 0) { - model = "ia64"; - bits = 64; - if (strncmp (&token[subs[3].rm_so], "be", 2) == 0) - ia64_be = 1; - } - else if (strncmp (&token[subs[2].rm_so], "powerpc64", 4) == 0) { - model = "ppc64"; - bits = 64; - } else { - /* XXX surely no other Xen archs exist */ - continue; - } - - /* Search for existing matching (model,hvm) tuple */ - for (i = 0 ; i < nr_guest_archs ; i++) { - if (!strcmp(guest_archs[i].model, model) && - guest_archs[i].hvm == hvm) { - break; - } - } - - /* Too many arch flavours - highly unlikely ! */ - if (i >= sizeof(guest_archs)/sizeof(guest_archs[0])) - continue; - /* Didn't find a match, so create a new one */ - if (i == nr_guest_archs) - nr_guest_archs++; - - guest_archs[i].model = model; - guest_archs[i].bits = bits; - 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; } + + /* Too many arch flavours - highly unlikely ! */ + if (i >= sizeof(guest_archs)/sizeof(guest_archs[0])) + continue; + /* Didn't find a match, so create a new one */ + if (i == nr_guest_archs) + nr_guest_archs++; + + guest_archs[i].model = model; + guest_archs[i].bits = bits; + 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; } } @@ -2251,29 +2352,33 @@ xenHypervisorGetCapabilities (virConnect /* Really, this never fails - look at the man-page. */ uname (&utsname); - cpuinfo = fopen ("/proc/cpuinfo", "r"); +#ifdef __linux__ + cpuinfo = fopen (CPUINFO, "r"); if (cpuinfo == NULL) { if (errno != ENOENT) { - virXenPerror (conn, "/proc/cpuinfo"); + virXenPerror (conn, CPUINFO); return NULL; } } - capabilities = fopen ("/sys/hypervisor/properties/capabilities", "r"); + capabilities = fopen (HYPERVISOR_CAPABILITIES, "r"); if (capabilities == NULL) { if (errno != ENOENT) { fclose(cpuinfo); - virXenPerror (conn, "/sys/hypervisor/properties/capabilities"); + virXenPerror (conn, HYPERVISOR_CAPABILITIES); return NULL; } } +#endif xml = xenHypervisorMakeCapabilitiesXML(conn, utsname.machine, cpuinfo, capabilities); +#ifdef __linux__ if (cpuinfo) fclose(cpuinfo); if (capabilities) fclose(capabilities); +#endif return xml; } @@ -2876,6 +2981,27 @@ xenHypervisorGetVcpuMax(virDomainPtr dom return maxcpu; } +static int +lock_pages(void *addr, size_t len) +{ +#ifdef __linux__ + return (mlock(addr, len)); +#else + return (0); +#endif +} + +static int +unlock_pages(void *addr, size_t len) +{ +#ifdef __linux__ + return (munlock(addr, len)); +#else + return (0); +#endif +} + + #endif /* WITH_XEN */ /* * vim: set tabstop=4: diff --git a/src/xend_internal.c b/src/xend_internal.c --- a/src/xend_internal.c +++ b/src/xend_internal.c @@ -1289,11 +1289,13 @@ xend_parse_sexp_desc_os(virConnectPtr xe if (hvm) { virBufferVSprintf(buf, " hvm\n"); tmp = sexpr_node(node, "domain/image/hvm/kernel"); +#ifdef __linux__ if (tmp == NULL && !bootloader) { virXendError(xend, VIR_ERR_INTERNAL_ERROR, _("domain information incomplete, missing kernel & bootloader")); return(-1); } +#endif if (tmp) virBufferVSprintf(buf, " %s\n", tmp); tmp = sexpr_node(node, "domain/image/hvm/boot"); @@ -1320,11 +1322,13 @@ xend_parse_sexp_desc_os(virConnectPtr xe } else { virBufferVSprintf(buf, " linux\n"); tmp = sexpr_node(node, "domain/image/linux/kernel"); +#ifdef __linux__ if (tmp == NULL && !bootloader) { virXendError(xend, VIR_ERR_INTERNAL_ERROR, _("domain information incomplete, missing kernel & bootloader")); return(-1); } +#endif if (tmp) virBufferVSprintf(buf, " %s\n", tmp); tmp = sexpr_node(node, "domain/image/linux/ramdisk"); @@ -1660,10 +1664,13 @@ xend_parse_sexp_desc(virConnectPtr conn, } else if (tmp && !strcmp(tmp, "vnc")) { int port = xenStoreDomainGetVNCPort(conn, domid); const char *listenAddr = sexpr_node(node, "device/vfb/vnclisten"); + const char *vncPasswd = sexpr_node(node, "device/vfb/vncpasswd"); const char *keymap = sexpr_node(node, "device/vfb/keymap"); virBufferVSprintf(&buf, " \n", 3); @@ -1709,6 +1716,7 @@ xend_parse_sexp_desc(virConnectPtr conn, if (tmp[0] == '1') { int port = xenStoreDomainGetVNCPort(conn, domid); const char *listenAddr = sexpr_fmt_node(root, "domain/image/%s/vnclisten", hvm ? "hvm" : "linux"); + const char *vncPasswd = sexpr_fmt_node(root, "domain/image/%s/vncpasswd", hvm ? "hvm" : "linux"); const char *keymap = sexpr_fmt_node(root, "domain/image/%s/keymap", hvm ? "hvm" : "linux"); /* For Xen >= 3.0.3, don't generate a fixed port mapping * because it will almost certainly be wrong ! Just leave @@ -1721,6 +1729,8 @@ xend_parse_sexp_desc(virConnectPtr conn, virBufferVSprintf(&buf, " \n", 3); diff --git a/src/xml.c b/src/xml.c --- a/src/xml.c +++ b/src/xml.c @@ -812,12 +812,18 @@ virDomainParseXMLOSDescPV(virConnectPtr return (-1); } virBufferAdd(buf, "(image (linux ", 14); +#ifdef __linux__ if (kernel == NULL) { virXMLError(conn, VIR_ERR_NO_KERNEL, NULL, 0); return (-1); } else { virBufferVSprintf(buf, "(kernel '%s')", (const char *) kernel); } +#else + if (kernel != NULL) { + virBufferVSprintf(buf, "(kernel '%s')", (const char *) kernel); + } +#endif if (initrd != NULL) virBufferVSprintf(buf, "(ramdisk '%s')", (const char *) initrd); if (root != NULL) diff --git a/src/xs_internal.c b/src/xs_internal.c --- a/src/xs_internal.c +++ b/src/xs_internal.c @@ -31,7 +31,11 @@ #include "xs_internal.h" #include "xen_internal.h" /* for xenHypervisorCheckID */ +#ifdef __linux__ #define XEN_HYPERVISOR_SOCKET "/proc/xen/privcmd" +#else +#define XEN_HYPERVISOR_SOCKET "/dev/xen/privcmd" +#endif #ifndef PROXY static char *xenStoreDomainGetOSType(virDomainPtr domain);