This brings in support for Xen hypercalls via an MI interface
and implements functions to fetch extended version and features.

OK?

---
 sys/dev/pv/xen.c    | 227 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 sys/dev/pv/xenreg.h | 184 ++++++++++++++++++++++++++++++++++++++++++
 sys/dev/pv/xenvar.h |  23 ++++++
 3 files changed, 434 insertions(+)
 create mode 100644 sys/dev/pv/xenreg.h

diff --git sys/dev/pv/xen.c sys/dev/pv/xen.c
index ee16d99..f1198d1 100644
--- sys/dev/pv/xen.c
+++ sys/dev/pv/xen.c
@@ -26,15 +26,19 @@
 #include <machine/cpufunc.h>
 
 #include <uvm/uvm_extern.h>
 
 #include <dev/pv/pvvar.h>
+#include <dev/pv/xenreg.h>
 #include <dev/pv/xenvar.h>
 
 struct xen_softc *xen_sc;
 
 void   xen_find_base(struct xen_softc *);
+int    xen_init_hypercall(struct xen_softc *);
+int    xen_getversion(struct xen_softc *);
+int    xen_getfeatures(struct xen_softc *);
 
 int    xen_match(struct device *, void *, void *);
 void   xen_attach(struct device *, struct device *, void *);
 void   xen_resume(struct device *);
 int    xen_activate(struct device *, int);
@@ -70,12 +74,20 @@ xen_attach(struct device *parent, struct device *self, void 
*aux)
 
        xen_find_base(sc);
 
        printf("\n");
 
+       if (xen_init_hypercall(sc))
+               return;
+
        /* Wire it up to the global */
        xen_sc = sc;
+
+       if (xen_getversion(sc))
+               return;
+       if (xen_getfeatures(sc))
+               return;
 }
 
 void
 xen_resume(struct device *self)
 {
@@ -109,5 +121,220 @@ xen_find_base(struct xen_softc *sc)
                        }
                        break;
                }
        }
 }
+
+int
+xen_init_hypercall(struct xen_softc *sc)
+{
+       extern void *xen_hypercall_page;
+       uint32_t regs[4];
+       paddr_t pa;
+
+       /* Get hypercall page configuration MSR */
+       CPUID(sc->sc_base + CPUID_OFFSET_XEN_HYPERCALL,
+           regs[0], regs[1], regs[2], regs[3]);
+
+       /* We don't support more than one hypercall page */
+       if (regs[0] != 1) {
+               printf("%s: requested %d hypercall pages\n",
+                   sc->sc_dev.dv_xname, regs[0]);
+               return (-1);
+       }
+
+       sc->sc_hc = &xen_hypercall_page;
+
+       if (!pmap_extract(pmap_kernel(), (vaddr_t)sc->sc_hc, &pa)) {
+               printf("%s: hypercall page PA extraction failed\n",
+                   sc->sc_dev.dv_xname);
+               return (-1);
+       }
+       wrmsr(regs[1], pa);
+
+       DPRINTF("%s: hypercall page at va %p pa %#lx\n", sc->sc_dev.dv_xname,
+           sc->sc_hc, pa);
+
+       return (0);
+}
+
+int
+xen_hypercall(struct xen_softc *sc, int op, int argc, ...)
+{
+       va_list ap;
+       ulong argv[5];
+       int i;
+
+       if (argc < 0 || argc > 5)
+               return (-1);
+       va_start(ap, argc);
+       for (i = 0; i < argc; i++)
+               argv[i] = (ulong)va_arg(ap, ulong);
+       return (xen_hypercallv(sc, op, argc, argv));
+}
+
+int
+xen_hypercallv(struct xen_softc *sc, int op, int argc, ulong *argv)
+{
+       ulong hcall;
+       int rv = 0;
+
+       hcall = (ulong)sc->sc_hc + op * 32;
+
+#if defined(XEN_DEBUG) && disabled
+       {
+               int i;
+
+               printf("hypercall %d", op);
+               if (argc > 0) {
+                       printf(", args {");
+                       for (i = 0; i < argc; i++)
+                               printf(" %#lx", argv[i]);
+                       printf(" }\n");
+               } else
+                       printf("\n");
+       }
+#endif
+
+       switch (argc) {
+       case 0: {
+               HYPERCALL_RES1;
+               __asm__ volatile (                      \
+                         HYPERCALL_LABEL               \
+                       : HYPERCALL_OUT1                \
+                       : HYPERCALL_PTR(hcall)          \
+                       : HYPERCALL_CLOBBER             \
+               );
+               HYPERCALL_RET(rv);
+               break;
+       }
+       case 1: {
+               HYPERCALL_RES1; HYPERCALL_RES2;
+               HYPERCALL_ARG1(argv[0]);
+               __asm__ volatile (                      \
+                         HYPERCALL_LABEL               \
+                       : HYPERCALL_OUT1 HYPERCALL_OUT2 \
+                       : HYPERCALL_IN1                 \
+                       , HYPERCALL_PTR(hcall)          \
+                       : HYPERCALL_CLOBBER             \
+               );
+               HYPERCALL_RET(rv);
+               break;
+       }
+       case 2: {
+               HYPERCALL_RES1; HYPERCALL_RES2; HYPERCALL_RES3;
+               HYPERCALL_ARG1(argv[0]); HYPERCALL_ARG2(argv[1]);
+               __asm__ volatile (                      \
+                         HYPERCALL_LABEL               \
+                       : HYPERCALL_OUT1 HYPERCALL_OUT2 \
+                         HYPERCALL_OUT3                \
+                       : HYPERCALL_IN1 HYPERCALL_IN2   \
+                       , HYPERCALL_PTR(hcall)          \
+                       : HYPERCALL_CLOBBER             \
+               );
+               HYPERCALL_RET(rv);
+               break;
+       }
+       case 3: {
+               HYPERCALL_RES1; HYPERCALL_RES2; HYPERCALL_RES3;
+               HYPERCALL_RES4;
+               HYPERCALL_ARG1(argv[0]); HYPERCALL_ARG2(argv[1]);
+               HYPERCALL_ARG3(argv[2]);
+               __asm__ volatile (                      \
+                         HYPERCALL_LABEL               \
+                       : HYPERCALL_OUT1 HYPERCALL_OUT2 \
+                         HYPERCALL_OUT3 HYPERCALL_OUT4 \
+                       : HYPERCALL_IN1 HYPERCALL_IN2   \
+                         HYPERCALL_IN3                 \
+                       , HYPERCALL_PTR(hcall)          \
+                       : HYPERCALL_CLOBBER             \
+               );
+               HYPERCALL_RET(rv);
+               break;
+       }
+       case 4: {
+               HYPERCALL_RES1; HYPERCALL_RES2; HYPERCALL_RES3;
+               HYPERCALL_RES4; HYPERCALL_RES5;
+               HYPERCALL_ARG1(argv[0]); HYPERCALL_ARG2(argv[1]);
+               HYPERCALL_ARG3(argv[2]); HYPERCALL_ARG4(argv[3]);
+               __asm__ volatile (                      \
+                         HYPERCALL_LABEL               \
+                       : HYPERCALL_OUT1 HYPERCALL_OUT2 \
+                         HYPERCALL_OUT3 HYPERCALL_OUT4 \
+                         HYPERCALL_OUT5                \
+                       : HYPERCALL_IN1 HYPERCALL_IN2   \
+                         HYPERCALL_IN3 HYPERCALL_IN4   \
+                       , HYPERCALL_PTR(hcall)          \
+                       : HYPERCALL_CLOBBER             \
+               );
+               HYPERCALL_RET(rv);
+               break;
+       }
+       case 5: {
+               HYPERCALL_RES1; HYPERCALL_RES2; HYPERCALL_RES3;
+               HYPERCALL_RES4; HYPERCALL_RES5; HYPERCALL_RES6;
+               HYPERCALL_ARG1(argv[0]); HYPERCALL_ARG2(argv[1]);
+               HYPERCALL_ARG3(argv[2]); HYPERCALL_ARG4(argv[3]);
+               HYPERCALL_ARG5(argv[4]);
+               __asm__ volatile (                      \
+                         HYPERCALL_LABEL               \
+                       : HYPERCALL_OUT1 HYPERCALL_OUT2 \
+                         HYPERCALL_OUT3 HYPERCALL_OUT4 \
+                         HYPERCALL_OUT5 HYPERCALL_OUT6 \
+                       : HYPERCALL_IN1 HYPERCALL_IN2   \
+                         HYPERCALL_IN3 HYPERCALL_IN4   \
+                         HYPERCALL_IN5                 \
+                       , HYPERCALL_PTR(hcall)          \
+                       : HYPERCALL_CLOBBER             \
+               );
+               HYPERCALL_RET(rv);
+               break;
+       }
+       default:
+               DPRINTF("%s: wrong number of arguments: %d\n", __func__, argc);
+               rv = -1;
+               break;
+       }
+       return (rv);
+}
+
+int
+xen_getversion(struct xen_softc *sc)
+{
+       char buf[16];
+       int version;
+       ulong argv[2] = { XENVER_extraversion, (ulong)&buf[0] };
+       int argc = 2;
+
+       memset(buf, 0, sizeof(buf));
+       if ((version = xen_hypercall(sc, xen_version, 1, XENVER_version)) < 0) {
+               printf("%s: failed to fetch version\n", sc->sc_dev.dv_xname);
+               return (-1);
+       }
+       if (xen_hypercallv(sc, xen_version, argc, argv) < 0) {
+               printf("%s: failed to fetch extended version\n",
+                   sc->sc_dev.dv_xname);
+               return (-1);
+       }
+       printf("%s: version %d.%d%s\n", sc->sc_dev.dv_xname,
+           version >> 16, version & 0xffff, buf);
+       return (0);
+}
+
+int
+xen_getfeatures(struct xen_softc *sc)
+{
+       struct xen_feature_info xfi;
+       ulong argv[2] = { XENVER_get_features, (ulong)&xfi };
+       int argc = 2;
+
+       memset(&xfi, 0, sizeof(xfi));
+       if (xen_hypercallv(sc, xen_version, argc, argv) < 0) {
+               printf("%s: failed to fetch features\n", sc->sc_dev.dv_xname);
+               return (-1);
+       }
+       sc->sc_features = xfi.submap;
+       printf("%s: features %b\n", sc->sc_dev.dv_xname, sc->sc_features,
+           "\20\014DOM0\013PIRQ\012PVCLOCK\011CBVEC\010GNTFLAGS\007HMA"
+           "\006PTUPD\005PAE4G\004SUPERVISOR\003AUTOPMAP\002WDT\001WPT");
+       return (0);
+}
diff --git sys/dev/pv/xenreg.h sys/dev/pv/xenreg.h
new file mode 100644
index 0000000..3f646d3
--- /dev/null
+++ sys/dev/pv/xenreg.h
@@ -0,0 +1,184 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Copyright (c) 2004,2005,2006,2007, Keir Fraser <k...@xensource.com>
+ */
+
+#ifndef _XENREG_H_
+#define _XENREG_H_
+
+/*
+ * Hypercall interface defines
+ */
+
+#if defined(__amd64__)
+# define HYPERCALL_ARG1(_i1)   ulong _a1 = (ulong)(_i1)
+# define HYPERCALL_ARG2(_i2)   ulong _a2 = (ulong)(_i2)
+# define HYPERCALL_ARG3(_i3)   ulong _a3 = (ulong)(_i3)
+# define HYPERCALL_ARG4(_i4)   register ulong _a4 __asm__("r10") = (ulong)(_i4)
+# define HYPERCALL_ARG5(_i5)   register ulong _a5 __asm__("r8") = (ulong)(_i5)
+# define HYPERCALL_RES1                ulong _r1
+# define HYPERCALL_RES2                ulong _r2
+# define HYPERCALL_RES3                ulong _r3
+# define HYPERCALL_RES4                ulong _r4
+# define HYPERCALL_RES5                /* empty */
+# define HYPERCALL_RES6                /* empty */
+# define HYPERCALL_RET(_rv)    (_rv) = _r1
+# define HYPERCALL_LABEL       "call *%[hcall]"
+# define HYPERCALL_PTR(_ptr)   [hcall] "a" (_ptr)
+# define HYPERCALL_OUT1                "=a" (_r1)
+# define HYPERCALL_OUT2                , "=D" (_r2)
+# define HYPERCALL_OUT3                , "=S" (_r3)
+# define HYPERCALL_OUT4                , "=d" (_r4)
+# define HYPERCALL_OUT5                , "+r" (_a4)
+# define HYPERCALL_OUT6                , "+r" (_a5)
+# define HYPERCALL_IN1         "1" (_a1)
+# define HYPERCALL_IN2         , "2" (_a2)
+# define HYPERCALL_IN3         , "3" (_a3)
+# define HYPERCALL_IN4         /* empty */
+# define HYPERCALL_IN5         /* empty */
+# define HYPERCALL_CLOBBER     "memory"
+#elif defined(__i386__)
+# define HYPERCALL_ARG1(_i1)   ulong _a1 = (ulong)(_i1)
+# define HYPERCALL_ARG2(_i2)   ulong _a2 = (ulong)(_i2)
+# define HYPERCALL_ARG3(_i3)   ulong _a3 = (ulong)(_i3)
+# define HYPERCALL_ARG4(_i4)   ulong _a4 = (ulong)(_i4)
+# define HYPERCALL_ARG5(_i5)   ulong _a5 = (ulong)(_i5)
+# define HYPERCALL_RES1                ulong _r1
+# define HYPERCALL_RES2                ulong _r2
+# define HYPERCALL_RES3                ulong _r3
+# define HYPERCALL_RES4                ulong _r4
+# define HYPERCALL_RES5                ulong _r5
+# define HYPERCALL_RES6                ulong _r6
+# define HYPERCALL_RET(_rv)    (_rv) = _r1
+# define HYPERCALL_LABEL       "call *%[hcall]"
+# define HYPERCALL_PTR(_ptr)   [hcall] "a" (_ptr)
+# define HYPERCALL_OUT1                "=a" (_r1)
+# define HYPERCALL_OUT2                , "=b" (_r2)
+# define HYPERCALL_OUT3                , "=c" (_r3)
+# define HYPERCALL_OUT4                , "=d" (_r4)
+# define HYPERCALL_OUT5                , "=S" (_r5)
+# define HYPERCALL_OUT6                , "=D" (_r6)
+# define HYPERCALL_IN1         "1" (_a1)
+# define HYPERCALL_IN2         , "2" (_a2)
+# define HYPERCALL_IN3         , "3" (_a3)
+# define HYPERCALL_IN4         , "4" (_a4)
+# define HYPERCALL_IN5         , "5" (_a5)
+# define HYPERCALL_CLOBBER     "memory"
+#else
+# error "Not implemented"
+#endif
+
+#define CPUID_OFFSET_XEN_HYPERCALL             0x2
+
+/*
+ * interface/xen.h
+ */
+
+typedef uint16_t domid_t;
+
+/* DOMID_SELF is used in certain contexts to refer to oneself. */
+#define DOMID_SELF             (0x7FF0U)
+
+/*
+ * interface/features.h
+ *
+ * Feature flags, reported by XENVER_get_features.
+ */
+
+/*
+ * If set, the guest does not need to write-protect its pagetables, and can
+ * update them via direct writes.
+ */
+#define XENFEAT_writable_page_tables           0
+/*
+ * If set, the guest does not need to write-protect its segment descriptor
+ * tables, and can update them via direct writes.
+ */
+#define XENFEAT_writable_descriptor_tables     1
+/*
+ * If set, translation between the guest's 'pseudo-physical' address space
+ * and the host's machine address space are handled by the hypervisor. In this
+ * mode the guest does not need to perform phys-to/from-machine translations
+ * when performing page table operations.
+ */
+#define XENFEAT_auto_translated_physmap                2
+/* If set, the guest is running in supervisor mode (e.g., x86 ring 0). */
+#define XENFEAT_supervisor_mode_kernel         3
+/*
+ * If set, the guest does not need to allocate x86 PAE page directories
+ * below 4GB. This flag is usually implied by auto_translated_physmap.
+ */
+#define XENFEAT_pae_pgdir_above_4gb            4
+/* x86: Does this Xen host support the MMU_PT_UPDATE_PRESERVE_AD hypercall? */
+#define XENFEAT_mmu_pt_update_preserve_ad      5
+/* x86: Does this Xen host support the MMU_{CLEAR,COPY}_PAGE hypercall? */
+#define XENFEAT_highmem_assist                 6
+/*
+ * If set, GNTTABOP_map_grant_ref honors flags to be placed into guest kernel
+ * available pte bits.
+ */
+#define XENFEAT_gnttab_map_avail_bits          7
+/* x86: Does this Xen host support the HVM callback vector type? */
+#define XENFEAT_hvm_callback_vector            8
+/* x86: pvclock algorithm is safe to use on HVM */
+#define XENFEAT_hvm_safe_pvclock               9
+/* x86: pirq can be used by HVM guests */
+#define XENFEAT_hvm_pirqs                      10
+/* operation as Dom0 is supported */
+#define XENFEAT_dom0                           11
+
+
+/*
+ * interface/version.h
+ *
+ * Xen version, type, and compile information.
+ */
+
+/* arg == NULL; returns major:minor (16:16). */
+#define XENVER_version         0
+
+/* arg == 16 bytes buffer. */
+#define XENVER_extraversion    1
+
+/* arg == xen_compile_info. */
+#define XENVER_compile_info    2
+struct xen_compile_info {
+       char compiler[64];
+       char compile_by[16];
+       char compile_domain[32];
+       char compile_date[32];
+};
+
+#define XENVER_get_features    6
+struct xen_feature_info {
+       unsigned int submap_idx;        /* IN: which 32-bit submap to return */
+       uint32_t submap;                /* OUT: 32-bit submap */
+};
+
+/* arg == NULL; returns host memory page size. */
+#define XENVER_pagesize                7
+
+/* arg == xen_domain_handle_t. */
+#define XENVER_guest_handle    8
+
+#define XENVER_commandline     9
+typedef char xen_commandline_t[1024];
+
+#endif /* _XENREG_H_ */
diff --git sys/dev/pv/xenvar.h sys/dev/pv/xenvar.h
index 76061ee..3fcfc96 100644
--- sys/dev/pv/xenvar.h
+++ sys/dev/pv/xenvar.h
@@ -15,11 +15,34 @@
  */
 
 #ifndef _XENVAR_H_
 #define _XENVAR_H_
 
+#define XEN_DEBUG
+
+#ifdef XEN_DEBUG
+#define DPRINTF(x...)          printf(x)
+#else
+#define DPRINTF(x...)
+#endif
+
 struct xen_softc {
        struct device            sc_dev;
        uint32_t                 sc_base;
+       void                    *sc_hc;
+       uint32_t                 sc_features;
+#define  XENFEAT_CBVEC         (1<<8)
 };
 
+extern struct xen_softc *xen_sc;
+
+/*
+ *  Hypercalls
+ */
+#define memory_op              12
+#define xen_version            17
+#define hvm_op                 34
+
+int    xen_hypercall(struct xen_softc *, int, int, ...);
+int    xen_hypercallv(struct xen_softc *, int, int, ulong *);
+
 #endif /* _XENVAR_H_ */
-- 
2.6.3

Reply via email to