svn commit: r301113 - in head/sys: conf dev/hyperv/vmbus dev/hyperv/vmbus/amd64 dev/hyperv/vmbus/i386 modules/hyperv/vmbus

Sepherosa Ziehau sephe at FreeBSD.org
Wed Jun 1 09:20:53 UTC 2016


Author: sephe
Date: Wed Jun  1 09:20:52 2016
New Revision: 301113
URL: https://svnweb.freebsd.org/changeset/base/301113

Log:
  hyperv: Rename some cleaned up/almost cleaned up files
  
  MFC after:	1 week
  Sponsored by:	Microsoft OSTC

Added:
  head/sys/dev/hyperv/vmbus/amd64/vmbus_vector.S
     - copied unchanged from r301112, head/sys/dev/hyperv/vmbus/amd64/hv_vector.S
  head/sys/dev/hyperv/vmbus/hyperv.c
     - copied unchanged from r301112, head/sys/dev/hyperv/vmbus/hv_hv.c
  head/sys/dev/hyperv/vmbus/i386/vmbus_vector.S
     - copied unchanged from r301112, head/sys/dev/hyperv/vmbus/i386/hv_vector.S
  head/sys/dev/hyperv/vmbus/vmbus.c
     - copied unchanged from r301112, head/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c
  head/sys/dev/hyperv/vmbus/vmbus_et.c
     - copied unchanged from r301112, head/sys/dev/hyperv/vmbus/hv_et.c
Deleted:
  head/sys/dev/hyperv/vmbus/amd64/hv_vector.S
  head/sys/dev/hyperv/vmbus/hv_et.c
  head/sys/dev/hyperv/vmbus/hv_hv.c
  head/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c
  head/sys/dev/hyperv/vmbus/i386/hv_vector.S
Modified:
  head/sys/conf/files.amd64
  head/sys/conf/files.i386
  head/sys/modules/hyperv/vmbus/Makefile

Modified: head/sys/conf/files.amd64
==============================================================================
--- head/sys/conf/files.amd64	Wed Jun  1 08:20:10 2016	(r301112)
+++ head/sys/conf/files.amd64	Wed Jun  1 09:20:52 2016	(r301113)
@@ -273,12 +273,12 @@ dev/hyperv/utilities/hv_util.c				option
 dev/hyperv/vmbus/hv_channel.c				optional	hyperv
 dev/hyperv/vmbus/hv_channel_mgmt.c			optional	hyperv
 dev/hyperv/vmbus/hv_connection.c			optional	hyperv
-dev/hyperv/vmbus/hv_hv.c				optional	hyperv
-dev/hyperv/vmbus/hv_et.c				optional	hyperv
 dev/hyperv/vmbus/hv_ring_buffer.c			optional	hyperv
-dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c			optional	hyperv
+dev/hyperv/vmbus/hyperv.c				optional	hyperv
 dev/hyperv/vmbus/hyperv_busdma.c			optional	hyperv
-dev/hyperv/vmbus/amd64/hv_vector.S			optional	hyperv
+dev/hyperv/vmbus/vmbus.c				optional	hyperv
+dev/hyperv/vmbus/vmbus_et.c				optional	hyperv
+dev/hyperv/vmbus/amd64/vmbus_vector.S			optional	hyperv
 dev/nfe/if_nfe.c		optional	nfe pci
 dev/ntb/if_ntb/if_ntb.c		optional	if_ntb
 dev/ntb/ntb_hw/ntb_hw.c		optional	if_ntb | ntb_hw

Modified: head/sys/conf/files.i386
==============================================================================
--- head/sys/conf/files.i386	Wed Jun  1 08:20:10 2016	(r301112)
+++ head/sys/conf/files.i386	Wed Jun  1 09:20:52 2016	(r301113)
@@ -248,12 +248,12 @@ dev/hyperv/utilities/hv_util.c				option
 dev/hyperv/vmbus/hv_channel.c				optional	hyperv
 dev/hyperv/vmbus/hv_channel_mgmt.c			optional	hyperv
 dev/hyperv/vmbus/hv_connection.c			optional	hyperv
-dev/hyperv/vmbus/hv_hv.c				optional	hyperv
-dev/hyperv/vmbus/hv_et.c				optional	hyperv
 dev/hyperv/vmbus/hv_ring_buffer.c			optional	hyperv
-dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c			optional	hyperv
+dev/hyperv/vmbus/hyperv.c				optional	hyperv
 dev/hyperv/vmbus/hyperv_busdma.c			optional	hyperv
-dev/hyperv/vmbus/i386/hv_vector.S			optional	hyperv
+dev/hyperv/vmbus/vmbus.c				optional	hyperv
+dev/hyperv/vmbus/vmbus_et.c				optional	hyperv
+dev/hyperv/vmbus/i386/vmbus_vector.S			optional	hyperv
 dev/ichwd/ichwd.c		optional ichwd
 dev/if_ndis/if_ndis.c		optional ndis
 dev/if_ndis/if_ndis_pccard.c	optional ndis pccard

Copied: head/sys/dev/hyperv/vmbus/amd64/vmbus_vector.S (from r301112, head/sys/dev/hyperv/vmbus/amd64/hv_vector.S)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/hyperv/vmbus/amd64/vmbus_vector.S	Wed Jun  1 09:20:52 2016	(r301113, copy of r301112, head/sys/dev/hyperv/vmbus/amd64/hv_vector.S)
@@ -0,0 +1,46 @@
+/*-
+ * 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$
+ */
+
+#include <machine/asmacros.h>
+#include <machine/specialreg.h>
+
+#include "assym.s"
+
+/*
+ * This is the Hyper-V vmbus channel direct callback interrupt.
+ * Only used when it is running on Hyper-V.
+ */
+	.text
+	SUPERALIGN_TEXT
+IDTVEC(vmbus_isr)
+	PUSH_FRAME
+	FAKE_MCOUNT(TF_RIP(%rsp))
+	movq	%rsp, %rdi
+	call	vmbus_handle_intr
+	MEXITCOUNT
+	jmp	doreti

Copied: head/sys/dev/hyperv/vmbus/hyperv.c (from r301112, head/sys/dev/hyperv/vmbus/hv_hv.c)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/hyperv/vmbus/hyperv.c	Wed Jun  1 09:20:52 2016	(r301113, copy of r301112, head/sys/dev/hyperv/vmbus/hv_hv.c)
@@ -0,0 +1,404 @@
+/*-
+ * 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/malloc.h>
+#include <sys/pcpu.h>
+#include <sys/timetc.h>
+#include <machine/bus.h>
+#include <machine/md_var.h>
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+
+#include <dev/hyperv/include/hyperv_busdma.h>
+#include <dev/hyperv/vmbus/hv_vmbus_priv.h>
+#include <dev/hyperv/vmbus/hyperv_reg.h>
+#include <dev/hyperv/vmbus/hyperv_var.h>
+#include <dev/hyperv/vmbus/vmbus_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 *tc);
+
+u_int		hyperv_features;
+u_int		hyperv_recommends;
+
+static u_int	hyperv_pm_features;
+static u_int	hyperv_features3;
+
+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);
+}
+
+/**
+ * @brief Invoke the specified hypercall
+ */
+static uint64_t
+hv_vmbus_do_hypercall(uint64_t control, void* input, void* output)
+{
+#ifdef __x86_64__
+	uint64_t hv_status = 0;
+	uint64_t input_address = (input) ? hv_get_phys_addr(input) : 0;
+	uint64_t output_address = (output) ? hv_get_phys_addr(output) : 0;
+	volatile void *hypercall_page = hypercall_context.hc_addr;
+
+	__asm__ __volatile__ ("mov %0, %%r8" : : "r" (output_address): "r8");
+	__asm__ __volatile__ ("call *%3" : "=a"(hv_status):
+				"c" (control), "d" (input_address),
+				"m" (hypercall_page));
+	return (hv_status);
+#else
+	uint32_t control_high = control >> 32;
+	uint32_t control_low = control & 0xFFFFFFFF;
+	uint32_t hv_status_high = 1;
+	uint32_t hv_status_low = 1;
+	uint64_t input_address = (input) ? hv_get_phys_addr(input) : 0;
+	uint32_t input_address_high = input_address >> 32;
+	uint32_t input_address_low = input_address & 0xFFFFFFFF;
+	uint64_t output_address = (output) ? hv_get_phys_addr(output) : 0;
+	uint32_t output_address_high = output_address >> 32;
+	uint32_t output_address_low = output_address & 0xFFFFFFFF;
+	volatile void *hypercall_page = hypercall_context.hc_addr;
+
+	__asm__ __volatile__ ("call *%8" : "=d"(hv_status_high),
+				"=a"(hv_status_low) : "d" (control_high),
+				"a" (control_low), "b" (input_address_high),
+				"c" (input_address_low),
+				"D"(output_address_high),
+				"S"(output_address_low), "m" (hypercall_page));
+	return (hv_status_low | ((uint64_t)hv_status_high << 32));
+#endif /* __x86_64__ */
+}
+
+/**
+ * @brief Post a message using the hypervisor message IPC.
+ * (This involves a hypercall.)
+ */
+hv_vmbus_status
+hv_vmbus_post_msg_via_msg_ipc(
+	hv_vmbus_connection_id	connection_id,
+	hv_vmbus_msg_type	message_type,
+	void*			payload,
+	size_t			payload_size)
+{
+	struct alignedinput {
+	    uint64_t alignment8;
+	    hv_vmbus_input_post_message msg;
+	};
+
+	hv_vmbus_input_post_message*	aligned_msg;
+	hv_vmbus_status 		status;
+	size_t				addr;
+
+	if (payload_size > HV_MESSAGE_PAYLOAD_BYTE_COUNT)
+	    return (EMSGSIZE);
+
+	addr = (size_t) malloc(sizeof(struct alignedinput), M_DEVBUF,
+			    M_ZERO | M_NOWAIT);
+	KASSERT(addr != 0,
+	    ("Error VMBUS: malloc failed to allocate message buffer!"));
+	if (addr == 0)
+	    return (ENOMEM);
+
+	aligned_msg = (hv_vmbus_input_post_message*)
+	    (HV_ALIGN_UP(addr, HV_HYPERCALL_PARAM_ALIGN));
+
+	aligned_msg->connection_id = connection_id;
+	aligned_msg->message_type = message_type;
+	aligned_msg->payload_size = payload_size;
+	memcpy((void*) aligned_msg->payload, payload, payload_size);
+
+	status = hv_vmbus_do_hypercall(
+		    HV_CALL_POST_MESSAGE, aligned_msg, 0) & 0xFFFF;
+
+	free((void *) addr, M_DEVBUF);
+	return (status);
+}
+
+/**
+ * @brief Signal an event on the specified connection using the hypervisor
+ * event IPC. (This involves a hypercall.)
+ */
+hv_vmbus_status
+hv_vmbus_signal_event(void *con_id)
+{
+	hv_vmbus_status status;
+
+	status = hv_vmbus_do_hypercall(
+		    HV_CALL_SIGNAL_EVENT,
+		    con_id,
+		    0) & 0xFFFF;
+
+	return (status);
+}
+
+int
+hyperv_guid2str(const struct hv_guid *guid, char *buf, size_t sz)
+{
+	const uint8_t *d = guid->data;
+
+	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);
+	}
+}
+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);

Copied: head/sys/dev/hyperv/vmbus/i386/vmbus_vector.S (from r301112, head/sys/dev/hyperv/vmbus/i386/hv_vector.S)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/hyperv/vmbus/i386/vmbus_vector.S	Wed Jun  1 09:20:52 2016	(r301113, copy of r301112, head/sys/dev/hyperv/vmbus/i386/hv_vector.S)
@@ -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$
+ */
+
+#include <machine/asmacros.h>
+#include <machine/specialreg.h>
+
+#include "assym.s"
+
+/*
+ * This is the Hyper-V vmbus channel direct callback interrupt.
+ * Only used when it is running on Hyper-V.
+ */
+	.text
+	SUPERALIGN_TEXT
+IDTVEC(vmbus_isr)
+	PUSH_FRAME
+	SET_KERNEL_SREGS
+	cld
+	FAKE_MCOUNT(TF_EIP(%esp))
+	pushl	%esp
+	call	vmbus_handle_intr
+	add	$4, %esp
+	MEXITCOUNT
+	jmp	doreti

Copied: head/sys/dev/hyperv/vmbus/vmbus.c (from r301112, head/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/hyperv/vmbus/vmbus.c	Wed Jun  1 09:20:52 2016	(r301113, copy of r301112, head/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c)
@@ -0,0 +1,759 @@
+/*-
+ * 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.
+ */
+
+/*
+ * VM Bus Driver Implementation
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/proc.h>
+#include <sys/sysctl.h>
+#include <sys/syslog.h>
+#include <sys/systm.h>
+#include <sys/rtprio.h>
+#include <sys/interrupt.h>
+#include <sys/sx.h>
+#include <sys/taskqueue.h>
+#include <sys/mutex.h>
+#include <sys/smp.h>
+
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <machine/stdarg.h>
+#include <machine/intr_machdep.h>
+#include <machine/md_var.h>
+#include <machine/segments.h>
+#include <sys/pcpu.h>
+#include <x86/apicvar.h>
+
+#include <dev/hyperv/include/hyperv.h>
+#include <dev/hyperv/vmbus/hv_vmbus_priv.h>
+#include <dev/hyperv/vmbus/hyperv_reg.h>
+#include <dev/hyperv/vmbus/hyperv_var.h>
+#include <dev/hyperv/vmbus/vmbus_reg.h>
+#include <dev/hyperv/vmbus/vmbus_var.h>
+
+#include <contrib/dev/acpica/include/acpi.h>
+#include "acpi_if.h"
+
+struct vmbus_softc	*vmbus_sc;
+
+extern inthand_t IDTVEC(vmbus_isr);
+
+static void
+vmbus_msg_task(void *xsc, int pending __unused)
+{
+	struct vmbus_softc *sc = xsc;
+	volatile struct vmbus_message *msg;
+
+	msg = VMBUS_PCPU_GET(sc, message, curcpu) + VMBUS_SINT_MESSAGE;
+	for (;;) {
+		const hv_vmbus_channel_msg_table_entry *entry;
+		hv_vmbus_channel_msg_header *hdr;
+		hv_vmbus_channel_msg_type msg_type;
+
+		if (msg->msg_type == VMBUS_MSGTYPE_NONE)
+			break; /* no message */
+
+		/* XXX: update messageHandler interface */
+		hdr = __DEVOLATILE(hv_vmbus_channel_msg_header *,
+		    msg->msg_data);
+		msg_type = hdr->message_type;
+
+		if (msg_type >= HV_CHANNEL_MESSAGE_COUNT) {
+			printf("VMBUS: unknown message type = %d\n", msg_type);
+			goto handled;
+		}
+
+		entry = &g_channel_message_table[msg_type];
+		if (entry->messageHandler)
+			entry->messageHandler(hdr);
+handled:
+		msg->msg_type = VMBUS_MSGTYPE_NONE;
+		/*
+		 * Make sure the write to msg_type (i.e. set to
+		 * VMBUS_MSGTYPE_NONE) happens before we read the
+		 * msg_flags and EOMing. Otherwise, the EOMing will
+		 * not deliver any more messages since there is no
+		 * empty slot
+		 *
+		 * NOTE:
+		 * mb() is used here, since atomic_thread_fence_seq_cst()
+		 * will become compiler fence on UP kernel.
+		 */
+		mb();
+		if (msg->msg_flags & VMBUS_MSGFLAG_PENDING) {
+			/*
+			 * This will cause message queue rescan to possibly
+			 * deliver another msg from the hypervisor
+			 */
+			wrmsr(MSR_HV_EOM, 0);
+		}
+	}
+}
+
+static __inline int
+vmbus_handle_intr1(struct vmbus_softc *sc, struct trapframe *frame, int cpu)
+{
+	volatile struct vmbus_message *msg;
+	struct vmbus_message *msg_base;
+
+	msg_base = VMBUS_PCPU_GET(sc, message, cpu);
+
+	/*
+	 * Check event timer.
+	 *
+	 * TODO: move this to independent IDT vector.
+	 */
+	msg = msg_base + VMBUS_SINT_TIMER;
+	if (msg->msg_type == VMBUS_MSGTYPE_TIMER_EXPIRED) {
+		msg->msg_type = VMBUS_MSGTYPE_NONE;
+
+		vmbus_et_intr(frame);
+
+		/*
+		 * Make sure the write to msg_type (i.e. set to
+		 * VMBUS_MSGTYPE_NONE) happens before we read the
+		 * msg_flags and EOMing. Otherwise, the EOMing will
+		 * not deliver any more messages since there is no
+		 * empty slot
+		 *
+		 * NOTE:
+		 * mb() is used here, since atomic_thread_fence_seq_cst()
+		 * will become compiler fence on UP kernel.
+		 */
+		mb();
+		if (msg->msg_flags & VMBUS_MSGFLAG_PENDING) {
+			/*
+			 * This will cause message queue rescan to possibly
+			 * deliver another msg from the hypervisor
+			 */
+			wrmsr(MSR_HV_EOM, 0);
+		}
+	}
+
+	/*
+	 * Check events.  Hot path for network and storage I/O data; high rate.
+	 *
+	 * NOTE:
+	 * As recommended by the Windows guest fellows, we check events before
+	 * checking messages.
+	 */
+	sc->vmbus_event_proc(sc, cpu);
+
+	/*
+	 * Check messages.  Mainly management stuffs; ultra low rate.
+	 */
+	msg = msg_base + VMBUS_SINT_MESSAGE;
+	if (__predict_false(msg->msg_type != VMBUS_MSGTYPE_NONE)) {
+		taskqueue_enqueue(VMBUS_PCPU_GET(sc, message_tq, cpu),
+		    VMBUS_PCPU_PTR(sc, message_task, cpu));
+	}
+
+	return (FILTER_HANDLED);
+}
+
+void
+vmbus_handle_intr(struct trapframe *trap_frame)
+{
+	struct vmbus_softc *sc = vmbus_get_softc();
+	int cpu = curcpu;
+
+	/*
+	 * Disable preemption.
+	 */
+	critical_enter();
+
+	/*
+	 * Do a little interrupt counting.
+	 */
+	(*VMBUS_PCPU_GET(sc, intr_cnt, cpu))++;
+
+	vmbus_handle_intr1(sc, trap_frame, cpu);
+
+	/*
+	 * Enable preemption.
+	 */
+	critical_exit();
+}
+
+static void
+vmbus_synic_setup(void *xsc)
+{
+	struct vmbus_softc *sc = xsc;
+	int cpu = curcpu;
+	uint64_t val, orig;
+	uint32_t sint;
+
+	if (hyperv_features & CPUID_HV_MSR_VP_INDEX) {
+		/*
+		 * Save virtual processor id.
+		 */
+		VMBUS_PCPU_GET(sc, vcpuid, cpu) = rdmsr(MSR_HV_VP_INDEX);
+	} else {
+		/*
+		 * XXX
+		 * Virtual processoor id is only used by a pretty broken
+		 * channel selection code from storvsc.  It's nothing
+		 * critical even if CPUID_HV_MSR_VP_INDEX is not set; keep
+		 * moving on.
+		 */
+		VMBUS_PCPU_GET(sc, vcpuid, cpu) = cpu;
+	}
+
+	/*
+	 * Setup the SynIC message.
+	 */
+	orig = rdmsr(MSR_HV_SIMP);
+	val = MSR_HV_SIMP_ENABLE | (orig & MSR_HV_SIMP_RSVD_MASK) |
+	    ((VMBUS_PCPU_GET(sc, message_dma.hv_paddr, cpu) >> PAGE_SHIFT) <<
+	     MSR_HV_SIMP_PGSHIFT);
+	wrmsr(MSR_HV_SIMP, val);
+
+	/*
+	 * Setup the SynIC event flags.
+	 */
+	orig = rdmsr(MSR_HV_SIEFP);
+	val = MSR_HV_SIEFP_ENABLE | (orig & MSR_HV_SIEFP_RSVD_MASK) |
+	    ((VMBUS_PCPU_GET(sc, event_flags_dma.hv_paddr, cpu)
+	      >> PAGE_SHIFT) << MSR_HV_SIEFP_PGSHIFT);
+	wrmsr(MSR_HV_SIEFP, val);
+
+
+	/*
+	 * Configure and unmask SINT for message and event flags.
+	 */
+	sint = MSR_HV_SINT0 + VMBUS_SINT_MESSAGE;
+	orig = rdmsr(sint);
+	val = sc->vmbus_idtvec | MSR_HV_SINT_AUTOEOI |
+	    (orig & MSR_HV_SINT_RSVD_MASK);
+	wrmsr(sint, val);
+
+	/*
+	 * Configure and unmask SINT for timer.
+	 */
+	sint = MSR_HV_SINT0 + VMBUS_SINT_TIMER;
+	orig = rdmsr(sint);
+	val = sc->vmbus_idtvec | MSR_HV_SINT_AUTOEOI |
+	    (orig & MSR_HV_SINT_RSVD_MASK);
+	wrmsr(sint, val);
+
+	/*
+	 * All done; enable SynIC.
+	 */
+	orig = rdmsr(MSR_HV_SCONTROL);
+	val = MSR_HV_SCTRL_ENABLE | (orig & MSR_HV_SCTRL_RSVD_MASK);
+	wrmsr(MSR_HV_SCONTROL, val);
+}
+
+static void
+vmbus_synic_teardown(void *arg)
+{
+	uint64_t orig;
+	uint32_t sint;
+
+	/*
+	 * Disable SynIC.
+	 */
+	orig = rdmsr(MSR_HV_SCONTROL);
+	wrmsr(MSR_HV_SCONTROL, (orig & MSR_HV_SCTRL_RSVD_MASK));
+
+	/*
+	 * Mask message and event flags SINT.
+	 */
+	sint = MSR_HV_SINT0 + VMBUS_SINT_MESSAGE;
+	orig = rdmsr(sint);
+	wrmsr(sint, orig | MSR_HV_SINT_MASKED);
+
+	/*
+	 * Mask timer SINT.
+	 */
+	sint = MSR_HV_SINT0 + VMBUS_SINT_TIMER;
+	orig = rdmsr(sint);
+	wrmsr(sint, orig | MSR_HV_SINT_MASKED);
+
+	/*
+	 * Teardown SynIC message.
+	 */
+	orig = rdmsr(MSR_HV_SIMP);
+	wrmsr(MSR_HV_SIMP, (orig & MSR_HV_SIMP_RSVD_MASK));
+
+	/*
+	 * Teardown SynIC event flags.
+	 */
+	orig = rdmsr(MSR_HV_SIEFP);
+	wrmsr(MSR_HV_SIEFP, (orig & MSR_HV_SIEFP_RSVD_MASK));
+}
+
+static int
+vmbus_dma_alloc(struct vmbus_softc *sc)
+{
+	int cpu;
+
+	CPU_FOREACH(cpu) {
+		void *ptr;
+
+		/*
+		 * Per-cpu messages and event flags.
+		 */
+		ptr = hyperv_dmamem_alloc(bus_get_dma_tag(sc->vmbus_dev),
+		    PAGE_SIZE, 0, PAGE_SIZE,
+		    VMBUS_PCPU_PTR(sc, message_dma, cpu),
+		    BUS_DMA_WAITOK | BUS_DMA_ZERO);
+		if (ptr == NULL)
+			return ENOMEM;
+		VMBUS_PCPU_GET(sc, message, cpu) = ptr;
+
+		ptr = hyperv_dmamem_alloc(bus_get_dma_tag(sc->vmbus_dev),
+		    PAGE_SIZE, 0, PAGE_SIZE,
+		    VMBUS_PCPU_PTR(sc, event_flags_dma, cpu),
+		    BUS_DMA_WAITOK | BUS_DMA_ZERO);
+		if (ptr == NULL)
+			return ENOMEM;
+		VMBUS_PCPU_GET(sc, event_flags, cpu) = ptr;
+	}
+	return 0;
+}
+
+static void
+vmbus_dma_free(struct vmbus_softc *sc)
+{
+	int cpu;
+
+	CPU_FOREACH(cpu) {
+		if (VMBUS_PCPU_GET(sc, message, cpu) != NULL) {
+			hyperv_dmamem_free(
+			    VMBUS_PCPU_PTR(sc, message_dma, cpu),
+			    VMBUS_PCPU_GET(sc, message, cpu));
+			VMBUS_PCPU_GET(sc, message, cpu) = NULL;
+		}
+		if (VMBUS_PCPU_GET(sc, event_flags, cpu) != NULL) {
+			hyperv_dmamem_free(
+			    VMBUS_PCPU_PTR(sc, event_flags_dma, cpu),
+			    VMBUS_PCPU_GET(sc, event_flags, cpu));
+			VMBUS_PCPU_GET(sc, event_flags, cpu) = NULL;
+		}
+	}
+}
+
+static int
+vmbus_intr_setup(struct vmbus_softc *sc)
+{
+	int cpu;
+
+	CPU_FOREACH(cpu) {
+		char buf[MAXCOMLEN + 1];
+		cpuset_t cpu_mask;
+
+		/* Allocate an interrupt counter for Hyper-V interrupt */
+		snprintf(buf, sizeof(buf), "cpu%d:hyperv", cpu);
+		intrcnt_add(buf, VMBUS_PCPU_PTR(sc, intr_cnt, cpu));
+
+		/*
+		 * Setup taskqueue to handle events.  Task will be per-
+		 * channel.
+		 */
+		VMBUS_PCPU_GET(sc, event_tq, cpu) = taskqueue_create_fast(
+		    "hyperv event", M_WAITOK, taskqueue_thread_enqueue,
+		    VMBUS_PCPU_PTR(sc, event_tq, cpu));
+		CPU_SETOF(cpu, &cpu_mask);
+		taskqueue_start_threads_cpuset(
+		    VMBUS_PCPU_PTR(sc, event_tq, cpu), 1, PI_NET, &cpu_mask,
+		    "hvevent%d", cpu);
+
+		/*
+		 * Setup tasks and taskqueues to handle messages.
+		 */
+		VMBUS_PCPU_GET(sc, message_tq, cpu) = taskqueue_create_fast(
+		    "hyperv msg", M_WAITOK, taskqueue_thread_enqueue,
+		    VMBUS_PCPU_PTR(sc, message_tq, cpu));
+		CPU_SETOF(cpu, &cpu_mask);
+		taskqueue_start_threads_cpuset(
+		    VMBUS_PCPU_PTR(sc, message_tq, cpu), 1, PI_NET, &cpu_mask,
+		    "hvmsg%d", cpu);
+		TASK_INIT(VMBUS_PCPU_PTR(sc, message_task, cpu), 0,
+		    vmbus_msg_task, sc);
+	}
+
+	/*
+	 * All Hyper-V ISR required resources are setup, now let's find a
+	 * free IDT vector for Hyper-V ISR and set it up.
+	 */
+	sc->vmbus_idtvec = lapic_ipi_alloc(IDTVEC(vmbus_isr));
+	if (sc->vmbus_idtvec < 0) {
+		device_printf(sc->vmbus_dev, "cannot find free IDT vector\n");
+		return ENXIO;
+	}
+	if(bootverbose) {
+		device_printf(sc->vmbus_dev, "vmbus IDT vector %d\n",
+		    sc->vmbus_idtvec);
+	}
+	return 0;
+}
+
+static void
+vmbus_intr_teardown(struct vmbus_softc *sc)
+{
+	int cpu;
+
+	if (sc->vmbus_idtvec >= 0) {
+		lapic_ipi_free(sc->vmbus_idtvec);
+		sc->vmbus_idtvec = -1;
+	}
+
+	CPU_FOREACH(cpu) {
+		if (VMBUS_PCPU_GET(sc, event_tq, cpu) != NULL) {
+			taskqueue_free(VMBUS_PCPU_GET(sc, event_tq, cpu));
+			VMBUS_PCPU_GET(sc, event_tq, cpu) = NULL;
+		}
+		if (VMBUS_PCPU_GET(sc, message_tq, cpu) != NULL) {
+			taskqueue_drain(VMBUS_PCPU_GET(sc, message_tq, cpu),
+			    VMBUS_PCPU_PTR(sc, message_task, cpu));
+			taskqueue_free(VMBUS_PCPU_GET(sc, message_tq, cpu));
+			VMBUS_PCPU_GET(sc, message_tq, cpu) = NULL;
+		}
+	}
+}
+
+static int

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list