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.