From: Waldemar Kozaczuk <jwkozac...@gmail.com>
Committer: Nadav Har'El <n...@scylladb.com>
Branch: master

Added subset of original FreeBSD driver code for Hyper/V.

- added subset of original FreeBSD driver code for Hyper/V
(https://github.com/freebsd/freebsd/tree/4f55a572a1ac518b3e4f5a856ec0b403fe23ed5e) for now limited to VMBus driver basic functionality and common header files.
- renamed all *.c files to *.cc.
- replaced tabs with spaces.

Most of this code is not necessary to make OSv boot on Hyper/V however it is included in anticipation of the network/disk support later.

Signed-off-by: Waldemar Kozaczuk <jwkozac...@gmail.com>
Message-Id: <1499985397-3562-1-git-send-email-jwkozac...@gmail.com>

---
diff --git a/bsd/sys/dev/hyperv/include/hyperv.h b/bsd/sys/dev/hyperv/include/hyperv.h
--- a/bsd/sys/dev/hyperv/include/hyperv.h
+++ b/bsd/sys/dev/hyperv/include/hyperv.h
@@ -0,0 +1,96 @@
+/*-
+ * Copyright (c) 2009-2012,2016 Microsoft Corp.
+ * Copyright (c) 2012 NetApp Inc.
+ * Copyright (c) 2012 Citrix Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _HYPERV_H_
+#define _HYPERV_H_
+
+#ifdef _KERNEL
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#define MSR_HV_TIME_REF_COUNT           0x40000020
+
+#define CPUID_HV_MSR_TIME_REFCNT        0x0002  /* MSR_HV_TIME_REF_COUNT */
+#define CPUID_HV_MSR_SYNIC              0x0004  /* MSRs for SynIC */
+#define CPUID_HV_MSR_SYNTIMER           0x0008  /* MSRs for SynTimer */
+#define CPUID_HV_MSR_APIC               0x0010  /* MSR_HV_{EOI,ICR,TPR} */
+#define CPUID_HV_MSR_HYPERCALL          0x0020  /* MSR_HV_GUEST_OS_ID
+                         * MSR_HV_HYPERCALL */
+#define CPUID_HV_MSR_VP_INDEX           0x0040  /* MSR_HV_VP_INDEX */
+#define CPUID_HV_MSR_REFERENCE_TSC      0x0200  /* MSR_HV_REFERENCE_TSC */
+#define CPUID_HV_MSR_GUEST_IDLE         0x0400  /* MSR_HV_GUEST_IDLE */
+
+#ifndef NANOSEC
+#define NANOSEC                         1000000000ULL
+#endif
+#define HYPERV_TIMER_NS_FACTOR          100ULL
+#define HYPERV_TIMER_FREQ               (NANOSEC / HYPERV_TIMER_NS_FACTOR)
+
+#endif  /* _KERNEL */
+
+#define HYPERV_REFTSC_DEVNAME           "hv_tsc"
+
+/*
+ * Hyper-V Reference TSC
+ */
+struct hyperv_reftsc {
+    volatile uint32_t           tsc_seq;
+    volatile uint32_t           tsc_rsvd1;
+    volatile uint64_t           tsc_scale;
+    volatile int64_t            tsc_ofs;
+} __packed __aligned(PAGE_SIZE);
+#ifdef CTASSERT
+CTASSERT(sizeof(struct hyperv_reftsc) == PAGE_SIZE);
+#endif
+
+#ifdef _KERNEL
+
+struct hyperv_guid {
+    uint8_t                             hv_guid[16];
+} __packed;
+
+#define HYPERV_GUID_STRLEN              40
+
+typedef uint64_t                        (*hyperv_tc64_t)(void);
+
+int                     hyperv_guid2str(const struct hyperv_guid *, char *,
+                size_t);
+
+/*
+ * hyperv_tc64 could be NULL, if there were no suitable Hyper-V
+ * specific timecounter.
+ */
+extern hyperv_tc64_t    hyperv_tc64;
+extern u_int            hyperv_features;        /* CPUID_HV_MSR_ */
+
+#endif  /* _KERNEL */
+
+#endif  /* _HYPERV_H_ */
diff --git a/bsd/sys/dev/hyperv/include/hyperv_busdma.h b/bsd/sys/dev/hyperv/include/hyperv_busdma.h
--- a/bsd/sys/dev/hyperv/include/hyperv_busdma.h
+++ b/bsd/sys/dev/hyperv/include/hyperv_busdma.h
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2016 Microsoft Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _HYPERV_BUSDMA_H_
+#define _HYPERV_BUSDMA_H_
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <machine/bus.h>
+
+struct hyperv_dma {
+    bus_addr_t  hv_paddr;
+    bus_dma_tag_t       hv_dtag;
+    bus_dmamap_t        hv_dmap;
+};
+
+void            hyperv_dma_map_paddr(void *arg, bus_dma_segment_t *segs,
+                    int nseg, int error);
+void            *hyperv_dmamem_alloc(bus_dma_tag_t parent_dtag,
+ bus_size_t alignment, bus_addr_t boundary, bus_size_t size,
+                    struct hyperv_dma *dma, int flags);
+void            hyperv_dmamem_free(struct hyperv_dma *dma, void *ptr);
+
+#endif  /* !_HYPERV_BUSDMA_H_ */
diff --git a/bsd/sys/dev/hyperv/include/vmbus.h b/bsd/sys/dev/hyperv/include/vmbus.h
--- a/bsd/sys/dev/hyperv/include/vmbus.h
+++ b/bsd/sys/dev/hyperv/include/vmbus.h
@@ -0,0 +1,230 @@
+/*-
+ * Copyright (c) 2016 Microsoft Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _VMBUS_H_
+#define _VMBUS_H_
+
+#include <sys/param.h>
+#include <sys/bus.h>
+
+/*
+ * VMBUS version is 32 bit, upper 16 bit for major_number and lower
+ * 16 bit for minor_number.
+ *
+ * 0.13  --  Windows Server 2008
+ * 1.1   --  Windows 7
+ * 2.4   --  Windows 8
+ * 3.0   --  Windows 8.1
+ */
+#define VMBUS_VERSION_WS2008            ((0 << 16) | (13))
+#define VMBUS_VERSION_WIN7              ((1 << 16) | (1))
+#define VMBUS_VERSION_WIN8              ((2 << 16) | (4))
+#define VMBUS_VERSION_WIN8_1            ((3 << 16) | (0))
+
+#define VMBUS_VERSION_MAJOR(ver)        (((uint32_t)(ver)) >> 16)
+#define VMBUS_VERSION_MINOR(ver)        (((uint32_t)(ver)) & 0xffff)
+
+#define VMBUS_CHAN_POLLHZ_MIN           100     /* 10ms interval */
+#define VMBUS_CHAN_POLLHZ_MAX           1000000 /* 1us interval */
+
+/*
+ * GPA stuffs.
+ */
+struct vmbus_gpa_range {
+    uint32_t    gpa_len;
+    uint32_t    gpa_ofs;
+    uint64_t    gpa_page[0];
+} __packed;
+
+/* This is actually vmbus_gpa_range.gpa_page[1] */
+struct vmbus_gpa {
+    uint32_t    gpa_len;
+    uint32_t    gpa_ofs;
+    uint64_t    gpa_page;
+} __packed;
+
+#define VMBUS_CHANPKT_SIZE_SHIFT        3
+
+#define VMBUS_CHANPKT_GETLEN(pktlen)    \
+    (((int)(pktlen)) << VMBUS_CHANPKT_SIZE_SHIFT)
+
+struct vmbus_chanpkt_hdr {
+    uint16_t    cph_type;       /* VMBUS_CHANPKT_TYPE_ */
+    uint16_t    cph_hlen;       /* header len, in 8 bytes */
+    uint16_t    cph_tlen;       /* total len, in 8 bytes */
+    uint16_t    cph_flags;      /* VMBUS_CHANPKT_FLAG_ */
+    uint64_t    cph_xactid;
+} __packed;
+
+#define VMBUS_CHANPKT_TYPE_INBAND       0x0006
+#define VMBUS_CHANPKT_TYPE_RXBUF        0x0007
+#define VMBUS_CHANPKT_TYPE_GPA          0x0009
+#define VMBUS_CHANPKT_TYPE_COMP         0x000b
+
+#define VMBUS_CHANPKT_FLAG_NONE         0
+#define VMBUS_CHANPKT_FLAG_RC           0x0001  /* report completion */
+
+#define VMBUS_CHANPKT_CONST_DATA(pkt)           \
+    (const void *)((const uint8_t *)(pkt) +     \
+    VMBUS_CHANPKT_GETLEN((pkt)->cph_hlen))
+
+/* Include padding */
+#define VMBUS_CHANPKT_DATALEN(pkt)              \
+    (VMBUS_CHANPKT_GETLEN((pkt)->cph_tlen) -\
+     VMBUS_CHANPKT_GETLEN((pkt)->cph_hlen))
+
+struct vmbus_rxbuf_desc {
+    uint32_t    rb_len;
+    uint32_t    rb_ofs;
+} __packed;
+
+struct vmbus_chanpkt_rxbuf {
+    struct vmbus_chanpkt_hdr cp_hdr;
+    uint16_t    cp_rxbuf_id;
+    uint16_t    cp_rsvd;
+    uint32_t    cp_rxbuf_cnt;
+    struct vmbus_rxbuf_desc cp_rxbuf[];
+} __packed;
+
+struct vmbus_chan_br {
+    void                *cbr;
+    bus_addr_t  cbr_paddr;
+    int         cbr_txsz;
+    int         cbr_rxsz;
+};
+
+struct vmbus_channel;
+struct vmbus_xact;
+struct vmbus_xact_ctx;
+struct hyperv_guid;
+struct task;
+struct taskqueue;
+
+typedef void    (*vmbus_chan_callback_t)(struct vmbus_channel *, void *);
+
+static __inline struct vmbus_channel *
+vmbus_get_channel(device_t dev)
+{
+    return device_get_ivars(dev);
+}
+
+/*
+ * vmbus_chan_open_br()
+ *
+ * Return values:
+ * 0                    Succeeded.
+ * EISCONN              Failed, and the memory passed through 'br' is still
+ *                      connected.  Callers must _not_ free the the memory
+ *                      passed through 'br', if this error happens.
+ * other values Failed. The memory passed through 'br' is no longer + * connected. Callers are free to do anything with the
+ *                      memory passed through 'br'.
+ *
+ *
+ *
+ * vmbus_chan_close_direct()
+ *
+ * NOTE:
+ * Callers of this function _must_ make sure to close all sub-channels before
+ * closing the primary channel.
+ *
+ * Return values:
+ * 0                    Succeeded.
+ * EISCONN              Failed, and the memory associated with the bufring
+ * is still connected. Callers must _not_ free the the
+ *                      memory associated with the bufring, if this error
+ *                      happens.
+ * other values         Failed.  The memory associated with the bufring is
+ * no longer connected. Callers are free to do anything
+ *                      with the memory associated with the bufring.
+ */
+int             vmbus_chan_open(struct vmbus_channel *chan,
+ int txbr_size, int rxbr_size, const void *udata, int udlen,
+                    vmbus_chan_callback_t cb, void *cbarg);
+int             vmbus_chan_open_br(struct vmbus_channel *chan,
+                    const struct vmbus_chan_br *cbr, const void *udata,
+                    int udlen, vmbus_chan_callback_t cb, void *cbarg);
+void            vmbus_chan_close(struct vmbus_channel *chan);
+int             vmbus_chan_close_direct(struct vmbus_channel *chan);
+void            vmbus_chan_intr_drain(struct vmbus_channel *chan);
+void            vmbus_chan_run_task(struct vmbus_channel *chan,
+                    struct task *task);
+void            vmbus_chan_set_orphan(struct vmbus_channel *chan,
+                    struct vmbus_xact_ctx *);
+void            vmbus_chan_unset_orphan(struct vmbus_channel *chan);
+const void      *vmbus_chan_xact_wait(const struct vmbus_channel *chan,
+ struct vmbus_xact *xact, size_t *resp_len, bool can_sleep);
+
+int             vmbus_chan_gpadl_connect(struct vmbus_channel *chan,
+                    bus_addr_t paddr, int size, uint32_t *gpadl);
+int             vmbus_chan_gpadl_disconnect(struct vmbus_channel *chan,
+                    uint32_t gpadl);
+
+void            vmbus_chan_cpu_set(struct vmbus_channel *chan, int cpu);
+void            vmbus_chan_cpu_rr(struct vmbus_channel *chan);
+void vmbus_chan_set_readbatch(struct vmbus_channel *chan, bool on);
+
+struct vmbus_channel **
+                vmbus_subchan_get(struct vmbus_channel *pri_chan,
+                    int subchan_cnt);
+void            vmbus_subchan_rel(struct vmbus_channel **subchan,
+                    int subchan_cnt);
+void            vmbus_subchan_drain(struct vmbus_channel *pri_chan);
+
+int vmbus_chan_recv(struct vmbus_channel *chan, void *data, int *dlen,
+                    uint64_t *xactid);
+int             vmbus_chan_recv_pkt(struct vmbus_channel *chan,
+                    struct vmbus_chanpkt_hdr *pkt, int *pktlen);
+
+int             vmbus_chan_send(struct vmbus_channel *chan, uint16_t type,
+                    uint16_t flags, void *data, int dlen, uint64_t xactid);
+int             vmbus_chan_send_sglist(struct vmbus_channel *chan,
+                    struct vmbus_gpa sg[], int sglen, void *data, int dlen,
+                    uint64_t xactid);
+int             vmbus_chan_send_prplist(struct vmbus_channel *chan,
+                    struct vmbus_gpa_range *prp, int prp_cnt, void *data,
+                    int dlen, uint64_t xactid);
+
+uint32_t        vmbus_chan_id(const struct vmbus_channel *chan);
+uint32_t        vmbus_chan_subidx(const struct vmbus_channel *chan);
+bool            vmbus_chan_is_primary(const struct vmbus_channel *chan);
+bool            vmbus_chan_is_revoked(const struct vmbus_channel *chan);
+const struct hyperv_guid *
+                vmbus_chan_guid_inst(const struct vmbus_channel *chan);
+int             vmbus_chan_prplist_nelem(int br_size, int prpcnt_max,
+                    int dlen_max);
+bool            vmbus_chan_rx_empty(const struct vmbus_channel *chan);
+bool            vmbus_chan_tx_empty(const struct vmbus_channel *chan);
+struct taskqueue *
+                vmbus_chan_mgmt_tq(const struct vmbus_channel *chan);
+
+void            vmbus_chan_poll_enable(struct vmbus_channel *chan,
+                    u_int pollhz);
+void            vmbus_chan_poll_disable(struct vmbus_channel *chan);
+
+#endif  /* !_VMBUS_H_ */
diff --git a/bsd/sys/dev/hyperv/include/vmbus_xact.h b/bsd/sys/dev/hyperv/include/vmbus_xact.h
--- a/bsd/sys/dev/hyperv/include/vmbus_xact.h
+++ b/bsd/sys/dev/hyperv/include/vmbus_xact.h
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 2016 Microsoft Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _VMBUS_XACT_H_
+#define _VMBUS_XACT_H_
+
+#include <sys/param.h>
+#include <sys/bus.h>
+
+struct vmbus_xact;
+struct vmbus_xact_ctx;
+
+struct vmbus_xact_ctx   *vmbus_xact_ctx_create(bus_dma_tag_t dtag,
+                            size_t req_size, size_t resp_size,
+                            size_t priv_size);
+void                    vmbus_xact_ctx_destroy(struct vmbus_xact_ctx *ctx);
+bool                    vmbus_xact_ctx_orphan(struct vmbus_xact_ctx *ctx);
+
+struct vmbus_xact       *vmbus_xact_get(struct vmbus_xact_ctx *ctx,
+                            size_t req_len);
+void                    vmbus_xact_put(struct vmbus_xact *xact);
+
+void *vmbus_xact_req_data(const struct vmbus_xact *xact); +bus_addr_t vmbus_xact_req_paddr(const struct vmbus_xact *xact);
+void                    *vmbus_xact_priv(const struct vmbus_xact *xact,
+                            size_t priv_len);
+void                    vmbus_xact_activate(struct vmbus_xact *xact);
+void                    vmbus_xact_deactivate(struct vmbus_xact *xact);
+const void              *vmbus_xact_wait(struct vmbus_xact *xact,
+                            size_t *resp_len);
+const void              *vmbus_xact_busywait(struct vmbus_xact *xact,
+                            size_t *resp_len);
+const void              *vmbus_xact_poll(struct vmbus_xact *xact,
+                            size_t *resp_len);
+void                    vmbus_xact_wakeup(struct vmbus_xact *xact,
+                            const void *data, size_t dlen);
+void                    vmbus_xact_ctx_wakeup(struct vmbus_xact_ctx *ctx,
+                            const void *data, size_t dlen);
+
+#endif  /* !_VMBUS_XACT_H_ */
diff --git a/bsd/sys/dev/hyperv/vmbus/hyperv.cc b/bsd/sys/dev/hyperv/vmbus/hyperv.cc
--- a/bsd/sys/dev/hyperv/vmbus/hyperv.cc
+++ b/bsd/sys/dev/hyperv/vmbus/hyperv.cc
@@ -0,0 +1,327 @@
+/*-
+ * Copyright (c) 2009-2012,2016 Microsoft Corp.
+ * Copyright (c) 2012 NetApp Inc.
+ * Copyright (c) 2012 Citrix Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Implements low-level interactions with Hypver-V/Azure
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/timetc.h>
+
+#include <dev/hyperv/include/hyperv.h>
+#include <dev/hyperv/include/hyperv_busdma.h>
+#include <dev/hyperv/vmbus/hyperv_machdep.h>
+#include <dev/hyperv/vmbus/hyperv_reg.h>
+#include <dev/hyperv/vmbus/hyperv_var.h>
+
+#define HYPERV_FREEBSD_BUILD            0ULL
+#define HYPERV_FREEBSD_VERSION          ((uint64_t)__FreeBSD_version)
+#define HYPERV_FREEBSD_OSID             0ULL
+
+#define MSR_HV_GUESTID_BUILD_FREEBSD    \
+    (HYPERV_FREEBSD_BUILD & MSR_HV_GUESTID_BUILD_MASK)
+#define MSR_HV_GUESTID_VERSION_FREEBSD  \
+    ((HYPERV_FREEBSD_VERSION << MSR_HV_GUESTID_VERSION_SHIFT) & \
+     MSR_HV_GUESTID_VERSION_MASK)
+#define MSR_HV_GUESTID_OSID_FREEBSD     \
+    ((HYPERV_FREEBSD_OSID << MSR_HV_GUESTID_OSID_SHIFT) & \
+     MSR_HV_GUESTID_OSID_MASK)
+
+#define MSR_HV_GUESTID_FREEBSD          \
+    (MSR_HV_GUESTID_BUILD_FREEBSD |     \
+     MSR_HV_GUESTID_VERSION_FREEBSD | \
+     MSR_HV_GUESTID_OSID_FREEBSD |      \
+     MSR_HV_GUESTID_OSTYPE_FREEBSD)
+
+struct hypercall_ctx {
+    void                        *hc_addr;
+    struct hyperv_dma   hc_dma;
+};
+
+static u_int                    hyperv_get_timecount(struct timecounter *);
+static bool                     hyperv_identify(void);
+static void                     hypercall_memfree(void);
+
+u_int                           hyperv_features;
+u_int                           hyperv_recommends;
+
+static u_int                    hyperv_pm_features;
+static u_int                    hyperv_features3;
+
+hyperv_tc64_t                   hyperv_tc64;
+
+static struct timecounter       hyperv_timecounter = {
+    .tc_get_timecount   = hyperv_get_timecount,
+    .tc_poll_pps        = NULL,
+    .tc_counter_mask    = 0xffffffff,
+    .tc_frequency       = HYPERV_TIMER_FREQ,
+    .tc_name            = "Hyper-V",
+    .tc_quality         = 2000,
+    .tc_flags           = 0,
+    .tc_priv            = NULL
+};
+
+static struct hypercall_ctx     hypercall_context;
+
+static u_int
+hyperv_get_timecount(struct timecounter *tc __unused)
+{
+    return rdmsr(MSR_HV_TIME_REF_COUNT);
+}
+
+static uint64_t
+hyperv_tc64_rdmsr(void)
+{
+
+    return (rdmsr(MSR_HV_TIME_REF_COUNT));
+}
+
+uint64_t
+hypercall_post_message(bus_addr_t msg_paddr)
+{
+    return hypercall_md(hypercall_context.hc_addr,
+        HYPERCALL_POST_MESSAGE, msg_paddr, 0);
+}
+
+uint64_t
+hypercall_signal_event(bus_addr_t monprm_paddr)
+{
+    return hypercall_md(hypercall_context.hc_addr,
+        HYPERCALL_SIGNAL_EVENT, monprm_paddr, 0);
+}
+
+int
+hyperv_guid2str(const struct hyperv_guid *guid, char *buf, size_t sz)
+{
+    const uint8_t *d = guid->hv_guid;
+
+    return snprintf(buf, sz, "%02x%02x%02x%02x-"
+        "%02x%02x-%02x%02x-%02x%02x-"
+        "%02x%02x%02x%02x%02x%02x",
+        d[3], d[2], d[1], d[0],
+        d[5], d[4], d[7], d[6], d[8], d[9],
+        d[10], d[11], d[12], d[13], d[14], d[15]);
+}
+
+static bool
+hyperv_identify(void)
+{
+    u_int regs[4];
+    unsigned int maxleaf;
+
+    if (vm_guest != VM_GUEST_HV)
+        return (false);
+
+    do_cpuid(CPUID_LEAF_HV_MAXLEAF, regs);
+    maxleaf = regs[0];
+    if (maxleaf < CPUID_LEAF_HV_LIMITS)
+        return (false);
+
+    do_cpuid(CPUID_LEAF_HV_INTERFACE, regs);
+    if (regs[0] != CPUID_HV_IFACE_HYPERV)
+        return (false);
+
+    do_cpuid(CPUID_LEAF_HV_FEATURES, regs);
+    if ((regs[0] & CPUID_HV_MSR_HYPERCALL) == 0) {
+        /*
+         * Hyper-V w/o Hypercall is impossible; someone
+         * is faking Hyper-V.
+         */
+        return (false);
+    }
+    hyperv_features = regs[0];
+    hyperv_pm_features = regs[2];
+    hyperv_features3 = regs[3];
+
+    do_cpuid(CPUID_LEAF_HV_IDENTITY, regs);
+    printf("Hyper-V Version: %d.%d.%d [SP%d]\n",
+        regs[1] >> 16, regs[1] & 0xffff, regs[0], regs[2]);
+
+    printf("  Features=0x%b\n", hyperv_features,
+        "\020"
+        "\001VPRUNTIME" /* MSR_HV_VP_RUNTIME */
+        "\002TMREFCNT"  /* MSR_HV_TIME_REF_COUNT */
+        "\003SYNIC"             /* MSRs for SynIC */
+        "\004SYNTM"             /* MSRs for SynTimer */
+        "\005APIC"              /* MSR_HV_{EOI,ICR,TPR} */
+        "\006HYPERCALL" /* MSR_HV_{GUEST_OS_ID,HYPERCALL} */
+        "\007VPINDEX"   /* MSR_HV_VP_INDEX */
+        "\010RESET"             /* MSR_HV_RESET */
+        "\011STATS"             /* MSR_HV_STATS_ */
+        "\012REFTSC"    /* MSR_HV_REFERENCE_TSC */
+        "\013IDLE"              /* MSR_HV_GUEST_IDLE */
+        "\014TMFREQ"    /* MSR_HV_{TSC,APIC}_FREQUENCY */
+        "\015DEBUG");   /* MSR_HV_SYNTH_DEBUG_ */
+    printf("  PM Features=0x%b [C%u]\n",
+        (hyperv_pm_features & ~CPUPM_HV_CSTATE_MASK),
+        "\020"
+        "\005C3HPET",   /* HPET is required for C3 state */
+        CPUPM_HV_CSTATE(hyperv_pm_features));
+    printf("  Features3=0x%b\n", hyperv_features3,
+        "\020"
+        "\001MWAIT"             /* MWAIT */
+        "\002DEBUG"             /* guest debug support */
+        "\003PERFMON"   /* performance monitor */
+        "\004PCPUDPE"   /* physical CPU dynamic partition event */
+        "\005XMMHC"             /* hypercall input through XMM regs */
+        "\006IDLE"              /* guest idle support */
+        "\007SLEEP"             /* hypervisor sleep support */
+        "\010NUMA"              /* NUMA distance query support */
+        "\011TMFREQ"    /* timer frequency query (TSC, LAPIC) */
+        "\012SYNCMC"    /* inject synthetic machine checks */
+        "\013CRASH"             /* MSRs for guest crash */
+        "\014DEBUGMSR"  /* MSRs for guest debug */
+        "\015NPIEP"             /* NPIEP */
+        "\016HVDIS");   /* disabling hypervisor */
+
+    do_cpuid(CPUID_LEAF_HV_RECOMMENDS, regs);
+    hyperv_recommends = regs[0];
+    if (bootverbose)
+        printf("  Recommends: %08x %08x\n", regs[0], regs[1]);
+
+    do_cpuid(CPUID_LEAF_HV_LIMITS, regs);
+    if (bootverbose) {
+        printf("  Limits: Vcpu:%d Lcpu:%d Int:%d\n",
+            regs[0], regs[1], regs[2]);
+    }
+
+    if (maxleaf >= CPUID_LEAF_HV_HWFEATURES) {
+        do_cpuid(CPUID_LEAF_HV_HWFEATURES, regs);
+        if (bootverbose) {
+            printf("  HW Features: %08x, AMD: %08x\n",
+                regs[0], regs[3]);
+        }
+    }
+
+    return (true);
+}
+
+static void
+hyperv_init(void *dummy __unused)
+{
+    if (!hyperv_identify()) {
+        /* Not Hyper-V; reset guest id to the generic one. */
+        if (vm_guest == VM_GUEST_HV)
+            vm_guest = VM_GUEST_VM;
+        return;
+    }
+
+    /* Set guest id */
+    wrmsr(MSR_HV_GUEST_OS_ID, MSR_HV_GUESTID_FREEBSD);
+
+    if (hyperv_features & CPUID_HV_MSR_TIME_REFCNT) {
+        /* Register Hyper-V timecounter */
+        tc_init(&hyperv_timecounter);
+
+        /*
+         * Install 64 bits timecounter method for other modules
+         * to use.
+         */
+        hyperv_tc64 = hyperv_tc64_rdmsr;
+    }
+}
+SYSINIT(hyperv_initialize, SI_SUB_HYPERVISOR, SI_ORDER_FIRST, hyperv_init,
+    NULL);
+
+static void
+hypercall_memfree(void)
+{
+    hyperv_dmamem_free(&hypercall_context.hc_dma,
+        hypercall_context.hc_addr);
+    hypercall_context.hc_addr = NULL;
+}
+
+static void
+hypercall_create(void *arg __unused)
+{
+    uint64_t hc, hc_orig;
+
+    if (vm_guest != VM_GUEST_HV)
+        return;
+
+    hypercall_context.hc_addr = hyperv_dmamem_alloc(NULL, PAGE_SIZE, 0,
+        PAGE_SIZE, &hypercall_context.hc_dma, BUS_DMA_WAITOK);
+    if (hypercall_context.hc_addr == NULL) {
+        printf("hyperv: Hypercall page allocation failed\n");
+        /* Can't perform any Hyper-V specific actions */
+        vm_guest = VM_GUEST_VM;
+        return;
+    }
+
+    /* Get the 'reserved' bits, which requires preservation. */
+    hc_orig = rdmsr(MSR_HV_HYPERCALL);
+
+    /*
+     * Setup the Hypercall page.
+     *
+     * NOTE: 'reserved' bits MUST be preserved.
+     */
+    hc = ((hypercall_context.hc_dma.hv_paddr >> PAGE_SHIFT) <<
+        MSR_HV_HYPERCALL_PGSHIFT) |
+        (hc_orig & MSR_HV_HYPERCALL_RSVD_MASK) |
+        MSR_HV_HYPERCALL_ENABLE;
+    wrmsr(MSR_HV_HYPERCALL, hc);
+
+    /*
+     * Confirm that Hypercall page did get setup.
+     */
+    hc = rdmsr(MSR_HV_HYPERCALL);
+    if ((hc & MSR_HV_HYPERCALL_ENABLE) == 0) {
+        printf("hyperv: Hypercall setup failed\n");
+        hypercall_memfree();
+        /* Can't perform any Hyper-V specific actions */
+        vm_guest = VM_GUEST_VM;
+        return;
+    }
+    if (bootverbose)
+        printf("hyperv: Hypercall created\n");
+}
+SYSINIT(hypercall_ctor, SI_SUB_DRIVERS, SI_ORDER_FIRST, hypercall_create, NULL);
+
+static void
+hypercall_destroy(void *arg __unused)
+{
+    uint64_t hc;
+
+    if (hypercall_context.hc_addr == NULL)
+        return;
+
+    /* Disable Hypercall */
+    hc = rdmsr(MSR_HV_HYPERCALL);
+    wrmsr(MSR_HV_HYPERCALL, (hc & MSR_HV_HYPERCALL_RSVD_MASK));
+    hypercall_memfree();
+
+    if (bootverbose)
+        printf("hyperv: Hypercall destroyed\n");
+}
+SYSUNINIT(hypercall_dtor, SI_SUB_DRIVERS, SI_ORDER_FIRST, hypercall_destroy,
+    NULL);

--
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to osv-dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to