git: 9729f076e4d9 - main - arm64: Hyper-V: enablement for ARM64 in Hyper-V (Part 3, final)

From: Wei Hu <whu_at_FreeBSD.org>
Date: Thu, 27 Oct 2022 13:54:30 UTC
The branch main has been updated by whu:

URL: https://cgit.FreeBSD.org/src/commit/?id=9729f076e4d93c5a37e78d427bfe0f1ab99bbcc6

commit 9729f076e4d93c5a37e78d427bfe0f1ab99bbcc6
Author:     Souradeep Chakrabarti <schakrabarti@microsoft.com>
AuthorDate: 2022-10-27 13:46:08 +0000
Commit:     Wei Hu <whu@FreeBSD.org>
CommitDate: 2022-10-27 13:53:22 +0000

    arm64: Hyper-V: enablement for ARM64 in Hyper-V (Part 3, final)
    
    This is the last part for ARM64 Hyper-V enablement. This includes
    commone files and make file changes to enable the ARM64 FreeBSD
    guest on Hyper-V. With this patch, it should be able to build
    the ARM64 image and install it on Hyper-V.
    
    Reviewed by:    emaste, andrew, whu
    Tested by:      Souradeep Chakrabarti <schakrabarti@microsoft.com>
    Sponsored by:   Microsoft
    Differential Revision:  https://reviews.freebsd.org/D36744
---
 share/mk/src.opts.mk                        |   3 +-
 sys/arm64/conf/GENERIC                      |   1 +
 sys/arm64/conf/std.dev                      |   3 +
 sys/arm64/conf/std.hyperv                   |   6 +
 sys/conf/files.arm64                        |  22 ++++
 sys/conf/files.x86                          |   2 +
 sys/dev/hyperv/include/hyperv.h             |   5 +
 sys/dev/hyperv/vmbus/amd64/hyperv_machdep.c |   5 +-
 sys/dev/hyperv/vmbus/hyperv.c               | 194 +++------------------------
 sys/dev/hyperv/vmbus/hyperv_machdep.h       |  37 ------
 sys/dev/hyperv/vmbus/hyperv_reg.h           | 193 ---------------------------
 sys/dev/hyperv/vmbus/hyperv_var.h           |   4 +
 sys/dev/hyperv/vmbus/i386/hyperv_machdep.c  |   2 +-
 sys/dev/hyperv/vmbus/vmbus.c                | 197 +++++++++-------------------
 sys/dev/hyperv/vmbus/vmbus_et.c             |   7 +-
 sys/dev/hyperv/vmbus/vmbus_reg.h            |   7 +-
 sys/dev/hyperv/vmbus/vmbus_var.h            |  15 +++
 sys/modules/Makefile                        |   1 +
 sys/modules/hyperv/utilities/Makefile       |   1 -
 sys/modules/hyperv/vmbus/Makefile           |  11 +-
 20 files changed, 164 insertions(+), 552 deletions(-)

diff --git a/share/mk/src.opts.mk b/share/mk/src.opts.mk
index a03b8147ecbb..4c0913474ef7 100644
--- a/share/mk/src.opts.mk
+++ b/share/mk/src.opts.mk
@@ -332,8 +332,7 @@ BROKEN_OPTIONS+=CXGBETOOL
 BROKEN_OPTIONS+=MLX5TOOL
 .endif
 
-# HyperV is currently x86-only
-.if ${__T} != "amd64" && ${__T} != "i386"
+.if ${__T} != "amd64" && ${__T} != "i386" && ${__T} != "aarch64"
 BROKEN_OPTIONS+=HYPERV
 .endif
 
diff --git a/sys/arm64/conf/GENERIC b/sys/arm64/conf/GENERIC
index c716183aae61..60772893cdbb 100644
--- a/sys/arm64/conf/GENERIC
+++ b/sys/arm64/conf/GENERIC
@@ -31,6 +31,7 @@ include		"std.amd"
 include		"std.arm"
 include		"std.broadcom"
 include		"std.cavium"
+include		"std.hyperv"
 include		"std.hisilicon"
 include		"std.imx"
 include		"std.marvell"
diff --git a/sys/arm64/conf/std.dev b/sys/arm64/conf/std.dev
index 6ef7358e5e85..8cdd35e2fd21 100644
--- a/sys/arm64/conf/std.dev
+++ b/sys/arm64/conf/std.dev
@@ -107,3 +107,6 @@ device		mmcsd			# mmc/sd flash cards
 # HID support
 options 	HID_DEBUG		# enable debug msgs
 device		hid			# Generic HID support
+
+#hyper-v support
+device		hyperv
diff --git a/sys/arm64/conf/std.hyperv b/sys/arm64/conf/std.hyperv
new file mode 100644
index 000000000000..f87082f15c96
--- /dev/null
+++ b/sys/arm64/conf/std.hyperv
@@ -0,0 +1,6 @@
+#
+# Hyper-V support (Hyper-v Gen 2)
+#
+
+#hyper-v support
+device      hyperv
diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64
index 5178048cb0af..8b6ba43d2a3d 100644
--- a/sys/conf/files.arm64
+++ b/sys/conf/files.arm64
@@ -624,3 +624,25 @@ arm64/rockchip/clk/rk3399_pmucru.c		optional fdt soc_rockchip_rk3399
 
 # Xilinx
 arm/xilinx/uart_dev_cdnc.c			optional uart soc_xilinx_zynq
+
+# Microsoft Hyper-V
+dev/hyperv/vmbus/hyperv.c		optional	hyperv
+dev/hyperv/vmbus/aarch64/hyperv_aarch64.c		optional    hyperv
+dev/hyperv/vmbus/vmbus.c				optional	hyperv pci
+dev/hyperv/vmbus/aarch64/vmbus_aarch64.c		optional    hyperv
+dev/hyperv/vmbus/vmbus_if.m				optional	hyperv
+dev/hyperv/vmbus/vmbus_res.c				optional	hyperv
+dev/hyperv/vmbus/vmbus_xact.c				optional	hyperv
+dev/hyperv/vmbus/aarch64/hyperv_machdep.c				optional    hyperv
+dev/hyperv/vmbus/vmbus_chan.c				optional 		hyperv
+dev/hyperv/vmbus/hyperv_busdma.c				optional hyperv
+dev/hyperv/vmbus/vmbus_br.c				optional 	hyperv
+dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c				optional hyperv
+dev/hyperv/utilities/vmbus_timesync.c				optional        hyperv
+dev/hyperv/utilities/vmbus_heartbeat.c				optional    hyperv
+dev/hyperv/utilities/vmbus_ic.c				optional    hyperv
+dev/hyperv/utilities/vmbus_shutdown.c				optional    hyperv
+dev/hyperv/utilities/hv_kvp.c			optional   hyperv
+dev/hyperv/netvsc/hn_nvs.c				optional	hyperv
+dev/hyperv/netvsc/hn_rndis.c			optional	hyperv
+dev/hyperv/netvsc/if_hn.c				optional	hyperv
diff --git a/sys/conf/files.x86 b/sys/conf/files.x86
index e8f65628c5c1..4547adcda8bb 100644
--- a/sys/conf/files.x86
+++ b/sys/conf/files.x86
@@ -132,6 +132,8 @@ dev/hyperv/utilities/vmbus_ic.c				optional	hyperv
 dev/hyperv/utilities/vmbus_shutdown.c			optional	hyperv
 dev/hyperv/utilities/vmbus_timesync.c			optional	hyperv
 dev/hyperv/vmbus/hyperv.c				optional	hyperv
+dev/hyperv/vmbus/x86/hyperv_x86.c		optional    hyperv
+dev/hyperv/vmbus/x86/vmbus_x86.c		optional    hyperv
 dev/hyperv/vmbus/hyperv_busdma.c			optional	hyperv
 dev/hyperv/vmbus/vmbus.c				optional	hyperv pci
 dev/hyperv/vmbus/vmbus_br.c				optional	hyperv
diff --git a/sys/dev/hyperv/include/hyperv.h b/sys/dev/hyperv/include/hyperv.h
index 8b985b2f31a7..2e46a092a16e 100644
--- a/sys/dev/hyperv/include/hyperv.h
+++ b/sys/dev/hyperv/include/hyperv.h
@@ -86,6 +86,11 @@ typedef uint64_t			(*hyperv_tc64_t)(void);
 int			hyperv_guid2str(const struct hyperv_guid *, char *,
 			    size_t);
 
+void	hyperv_init_tc(void);
+int		hypercall_page_setup(vm_paddr_t);
+void	hypercall_disable(void);
+bool	hyperv_identify_features(void);
+
 /*
  * hyperv_tc64 could be NULL, if there were no suitable Hyper-V
  * specific timecounter.
diff --git a/sys/dev/hyperv/vmbus/amd64/hyperv_machdep.c b/sys/dev/hyperv/vmbus/amd64/hyperv_machdep.c
index f3f5308fa6dc..c158f72eb9e7 100644
--- a/sys/dev/hyperv/vmbus/amd64/hyperv_machdep.c
+++ b/sys/dev/hyperv/vmbus/amd64/hyperv_machdep.c
@@ -44,9 +44,10 @@ __FBSDID("$FreeBSD$");
 
 #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/x86/hyperv_machdep.h>
+#include <dev/hyperv/vmbus/x86/hyperv_reg.h>
 #include <dev/hyperv/vmbus/hyperv_var.h>
+#include <dev/hyperv/vmbus/hyperv_common_reg.h>
 
 struct hyperv_reftsc_ctx {
 	struct hyperv_reftsc	*tsc_ref;
diff --git a/sys/dev/hyperv/vmbus/hyperv.c b/sys/dev/hyperv/vmbus/hyperv.c
index b2a74036f6c3..38217d1f0b67 100644
--- a/sys/dev/hyperv/vmbus/hyperv.c
+++ b/sys/dev/hyperv/vmbus/hyperv.c
@@ -45,8 +45,14 @@ __FBSDID("$FreeBSD$");
 
 #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>
+#if defined(__aarch64__)
+#include <dev/hyperv/vmbus/aarch64/hyperv_machdep.h>
+#include <dev/hyperv/vmbus/aarch64/hyperv_reg.h>
+#else
+#include <dev/hyperv/vmbus/x86/hyperv_machdep.h>
+#include <dev/hyperv/vmbus/x86/hyperv_reg.h>
+#endif
+#include <dev/hyperv/vmbus/hyperv_common_reg.h>
 #include <dev/hyperv/vmbus/hyperv_var.h>
 
 #define HYPERV_FREEBSD_BUILD		0ULL
@@ -68,51 +74,10 @@ __FBSDID("$FreeBSD$");
 	 MSR_HV_GUESTID_OSID_FREEBSD |	\
 	 MSR_HV_GUESTID_OSTYPE_FREEBSD)
 
-struct hypercall_ctx {
-	void			*hc_addr;
-	vm_paddr_t		hc_paddr;
-};
-
-static u_int			hyperv_get_timecount(struct timecounter *);
 static bool			hyperv_identify(void);
 static void			hypercall_memfree(void);
 
-u_int				hyperv_ver_major;
-
-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)
 {
@@ -143,97 +108,8 @@ hyperv_guid2str(const struct hyperv_guid *guid, char *buf, size_t sz)
 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);
-	hyperv_ver_major = regs[1] >> 16;
-	printf("Hyper-V Version: %d.%d.%d [SP%d]\n",
-	    hyperv_ver_major, 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);
+	return(hyperv_identify_features());
 }
-
 static void
 hyperv_init(void *dummy __unused)
 {
@@ -245,22 +121,8 @@ hyperv_init(void *dummy __unused)
 	}
 
 	/* 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.  This should be done as early
-		 * as possible to let DELAY() work, since the 8254 PIT is not
-		 * reliably emulated or even available.
-		 */
-		tc_init(&hyperv_timecounter);
-
-		/*
-		 * Install 64 bits timecounter method for other modules
-		 * to use.
-		 */
-		hyperv_tc64 = hyperv_tc64_rdmsr;
-	}
+	WRMSR(MSR_HV_GUEST_OS_ID, MSR_HV_GUESTID_FREEBSD);
+	hyperv_init_tc();	
 }
 SYSINIT(hyperv_initialize, SI_SUB_HYPERVISOR, SI_ORDER_FIRST, hyperv_init,
     NULL);
@@ -275,8 +137,8 @@ hypercall_memfree(void)
 static void
 hypercall_create(void *arg __unused)
 {
-	uint64_t hc, hc_orig;
 
+	int ret;
 	if (vm_guest != VM_GUEST_HV)
 		return;
 
@@ -288,30 +150,9 @@ hypercall_create(void *arg __unused)
 	 */
 	hypercall_context.hc_addr = kmem_malloc(PAGE_SIZE, M_EXEC | M_WAITOK);
 	hypercall_context.hc_paddr = vtophys(hypercall_context.hc_addr);
-
-	/* 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_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");
+	ret = hypercall_page_setup(hypercall_context.hc_paddr);
+	if (ret) {
 		hypercall_memfree();
-		/* Can't perform any Hyper-V specific actions */
-		vm_guest = VM_GUEST_VM;
 		return;
 	}
 	if (bootverbose)
@@ -322,16 +163,11 @@ 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_disable();
 	hypercall_memfree();
-
 	if (bootverbose)
 		printf("hyperv: Hypercall destroyed\n");
 }
diff --git a/sys/dev/hyperv/vmbus/hyperv_machdep.h b/sys/dev/hyperv/vmbus/hyperv_machdep.h
deleted file mode 100644
index 48cf5b78dc3b..000000000000
--- a/sys/dev/hyperv/vmbus/hyperv_machdep.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*-
- * 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_MACHDEP_H_
-#define _HYPERV_MACHDEP_H_
-
-#include <sys/param.h>
-
-uint64_t	hypercall_md(volatile void *hc_addr, uint64_t in_val,
-		    uint64_t in_paddr, uint64_t out_paddr);
-
-#endif	/* !_HYPERV_MACHDEP_H_ */
diff --git a/sys/dev/hyperv/vmbus/hyperv_reg.h b/sys/dev/hyperv/vmbus/hyperv_reg.h
deleted file mode 100644
index b3b133c84881..000000000000
--- a/sys/dev/hyperv/vmbus/hyperv_reg.h
+++ /dev/null
@@ -1,193 +0,0 @@
-/*-
- * 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_REG_H_
-#define _HYPERV_REG_H_
-
-#include <sys/param.h>
-#include <sys/systm.h>
-
-/*
- * Hyper-V Synthetic MSRs
- */
-
-#define MSR_HV_GUEST_OS_ID		0x40000000
-#define MSR_HV_GUESTID_BUILD_MASK	0xffffULL
-#define MSR_HV_GUESTID_VERSION_MASK	0x0000ffffffff0000ULL
-#define MSR_HV_GUESTID_VERSION_SHIFT	16
-#define MSR_HV_GUESTID_OSID_MASK	0x00ff000000000000ULL
-#define MSR_HV_GUESTID_OSID_SHIFT	48
-#define MSR_HV_GUESTID_OSTYPE_MASK	0x7f00000000000000ULL
-#define MSR_HV_GUESTID_OSTYPE_SHIFT	56
-#define MSR_HV_GUESTID_OPENSRC		0x8000000000000000ULL
-#define MSR_HV_GUESTID_OSTYPE_LINUX	\
-	((0x01ULL << MSR_HV_GUESTID_OSTYPE_SHIFT) | MSR_HV_GUESTID_OPENSRC)
-#define MSR_HV_GUESTID_OSTYPE_FREEBSD	\
-	((0x02ULL << MSR_HV_GUESTID_OSTYPE_SHIFT) | MSR_HV_GUESTID_OPENSRC)
-
-#define MSR_HV_HYPERCALL		0x40000001
-#define MSR_HV_HYPERCALL_ENABLE		0x0001ULL
-#define MSR_HV_HYPERCALL_RSVD_MASK	0x0ffeULL
-#define MSR_HV_HYPERCALL_PGSHIFT	12
-
-#define MSR_HV_VP_INDEX			0x40000002
-
-#define MSR_HV_REFERENCE_TSC		0x40000021
-#define MSR_HV_REFTSC_ENABLE		0x0001ULL
-#define MSR_HV_REFTSC_RSVD_MASK		0x0ffeULL
-#define MSR_HV_REFTSC_PGSHIFT		12
-
-#define MSR_HV_SCONTROL			0x40000080
-#define MSR_HV_SCTRL_ENABLE		0x0001ULL
-#define MSR_HV_SCTRL_RSVD_MASK		0xfffffffffffffffeULL
-
-#define MSR_HV_SIEFP			0x40000082
-#define MSR_HV_SIEFP_ENABLE		0x0001ULL
-#define MSR_HV_SIEFP_RSVD_MASK		0x0ffeULL
-#define MSR_HV_SIEFP_PGSHIFT		12
-
-#define MSR_HV_SIMP			0x40000083
-#define MSR_HV_SIMP_ENABLE		0x0001ULL
-#define MSR_HV_SIMP_RSVD_MASK		0x0ffeULL
-#define MSR_HV_SIMP_PGSHIFT		12
-
-#define MSR_HV_EOM			0x40000084
-
-#define MSR_HV_SINT0			0x40000090
-#define MSR_HV_SINT_VECTOR_MASK		0x00ffULL
-#define MSR_HV_SINT_RSVD1_MASK		0xff00ULL
-#define MSR_HV_SINT_MASKED		0x00010000ULL
-#define MSR_HV_SINT_AUTOEOI		0x00020000ULL
-#define MSR_HV_SINT_RSVD2_MASK		0xfffffffffffc0000ULL
-#define MSR_HV_SINT_RSVD_MASK		(MSR_HV_SINT_RSVD1_MASK |	\
-					 MSR_HV_SINT_RSVD2_MASK)
-
-#define MSR_HV_STIMER0_CONFIG		0x400000b0
-#define MSR_HV_STIMER_CFG_ENABLE	0x0001ULL
-#define MSR_HV_STIMER_CFG_PERIODIC	0x0002ULL
-#define MSR_HV_STIMER_CFG_LAZY		0x0004ULL
-#define MSR_HV_STIMER_CFG_AUTOEN	0x0008ULL
-#define MSR_HV_STIMER_CFG_SINT_MASK	0x000f0000ULL
-#define MSR_HV_STIMER_CFG_SINT_SHIFT	16
-
-#define MSR_HV_STIMER0_COUNT		0x400000b1
-
-/*
- * CPUID leaves
- */
-
-#define CPUID_LEAF_HV_MAXLEAF		0x40000000
-
-#define CPUID_LEAF_HV_INTERFACE		0x40000001
-#define CPUID_HV_IFACE_HYPERV		0x31237648	/* HV#1 */
-
-#define CPUID_LEAF_HV_IDENTITY		0x40000002
-
-#define CPUID_LEAF_HV_FEATURES		0x40000003
-/* EAX: features include/hyperv.h CPUID_HV_MSR */
-/* ECX: power management features */
-#define CPUPM_HV_CSTATE_MASK		0x000f	/* deepest C-state */
-#define CPUPM_HV_C3_HPET		0x0010	/* C3 requires HPET */
-#define CPUPM_HV_CSTATE(f)		((f) & CPUPM_HV_CSTATE_MASK)
-/* EDX: features3 */
-#define CPUID3_HV_MWAIT			0x0001	/* MWAIT */
-#define CPUID3_HV_XMM_HYPERCALL		0x0010	/* Hypercall input through
-						 * XMM regs */
-#define CPUID3_HV_GUEST_IDLE		0x0020	/* guest idle */
-#define CPUID3_HV_NUMA			0x0080	/* NUMA distance query */
-#define CPUID3_HV_TIME_FREQ		0x0100	/* timer frequency query
-						 * (TSC, LAPIC) */
-#define CPUID3_HV_MSR_CRASH		0x0400	/* MSRs for guest crash */
-
-#define CPUID_LEAF_HV_RECOMMENDS	0x40000004
-#define CPUID_LEAF_HV_LIMITS		0x40000005
-#define CPUID_LEAF_HV_HWFEATURES	0x40000006
-
-/*
- * Hyper-V Monitor Notification Facility
- */
-struct hyperv_mon_param {
-	uint32_t	mp_connid;
-	uint16_t	mp_evtflag_ofs;
-	uint16_t	mp_rsvd;
-} __packed;
-
-/*
- * Hyper-V message types
- */
-#define HYPERV_MSGTYPE_NONE		0
-#define HYPERV_MSGTYPE_CHANNEL		1
-#define HYPERV_MSGTYPE_TIMER_EXPIRED	0x80000010
-
-/*
- * Hypercall status codes
- */
-#define HYPERCALL_STATUS_SUCCESS	0x0000
-
-/*
- * Hypercall input values
- */
-#define HYPERCALL_POST_MESSAGE		0x005c
-#define HYPERCALL_SIGNAL_EVENT		0x005d
-
-/*
- * Hypercall input parameters
- */
-#define HYPERCALL_PARAM_ALIGN		8
-#if 0
-/*
- * XXX
- * <<Hypervisor Top Level Functional Specification 4.0b>> requires
- * input parameters size to be multiple of 8, however, many post
- * message input parameters do _not_ meet this requirement.
- */
-#define HYPERCALL_PARAM_SIZE_ALIGN	8
-#endif
-
-/*
- * HYPERCALL_POST_MESSAGE
- */
-#define HYPERCALL_POSTMSGIN_DSIZE_MAX	240
-#define HYPERCALL_POSTMSGIN_SIZE	256
-
-struct hypercall_postmsg_in {
-	uint32_t	hc_connid;
-	uint32_t	hc_rsvd;
-	uint32_t	hc_msgtype;	/* HYPERV_MSGTYPE_ */
-	uint32_t	hc_dsize;
-	uint8_t		hc_data[HYPERCALL_POSTMSGIN_DSIZE_MAX];
-} __packed;
-CTASSERT(sizeof(struct hypercall_postmsg_in) == HYPERCALL_POSTMSGIN_SIZE);
-
-/*
- * HYPERCALL_SIGNAL_EVENT
- *
- * struct hyperv_mon_param.
- */
-
-#endif	/* !_HYPERV_REG_H_ */
diff --git a/sys/dev/hyperv/vmbus/hyperv_var.h b/sys/dev/hyperv/vmbus/hyperv_var.h
index f620e4fd64ae..3272569893e9 100644
--- a/sys/dev/hyperv/vmbus/hyperv_var.h
+++ b/sys/dev/hyperv/vmbus/hyperv_var.h
@@ -31,6 +31,10 @@
 
 extern u_int	hyperv_recommends;
 
+struct hypercall_ctx {
+    void            *hc_addr;
+    vm_paddr_t      hc_paddr;
+};
 uint64_t	hypercall_post_message(bus_addr_t msg_paddr);
 uint64_t	hypercall_signal_event(bus_addr_t monprm_paddr);
 
diff --git a/sys/dev/hyperv/vmbus/i386/hyperv_machdep.c b/sys/dev/hyperv/vmbus/i386/hyperv_machdep.c
index b12bff855f63..f0dcf3ba1004 100644
--- a/sys/dev/hyperv/vmbus/i386/hyperv_machdep.c
+++ b/sys/dev/hyperv/vmbus/i386/hyperv_machdep.c
@@ -28,7 +28,7 @@
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
-#include <dev/hyperv/vmbus/hyperv_machdep.h>
+#include <dev/hyperv/vmbus/x86/hyperv_machdep.h>
 
 uint64_t
 hypercall_md(volatile void *hc_addr, uint64_t in_val,
diff --git a/sys/dev/hyperv/vmbus/vmbus.c b/sys/dev/hyperv/vmbus/vmbus.c
index b0cd750b26c8..f370f2a75b99 100644
--- a/sys/dev/hyperv/vmbus/vmbus.c
+++ b/sys/dev/hyperv/vmbus/vmbus.c
@@ -51,23 +51,29 @@ __FBSDID("$FreeBSD$");
 #include <vm/pmap.h>
 
 #include <machine/bus.h>
+#if defined(__aarch64__)
+#include <dev/psci/smccc.h>
+#include <dev/hyperv/vmbus/aarch64/hyperv_machdep.h>
+#include <dev/hyperv/vmbus/aarch64/hyperv_reg.h>
+#else
+#include <dev/hyperv/vmbus/x86/hyperv_machdep.h>
+#include <dev/hyperv/vmbus/x86/hyperv_reg.h>
 #include <machine/intr_machdep.h>
+#include <x86/include/apicvar.h>
+#endif
 #include <machine/metadata.h>
 #include <machine/md_var.h>
 #include <machine/resource.h>
-#include <x86/include/apicvar.h>
-
 #include <contrib/dev/acpica/include/acpi.h>
 #include <dev/acpica/acpivar.h>
 
 #include <dev/hyperv/include/hyperv.h>
 #include <dev/hyperv/include/vmbus_xact.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 <dev/hyperv/vmbus/vmbus_chanvar.h>
-
+#include <dev/hyperv/vmbus/hyperv_common_reg.h>
 #include "acpi_if.h"
 #include "pcib_if.h"
 #include "vmbus_if.h"
@@ -107,7 +113,7 @@ static uint32_t			vmbus_get_vcpu_id_method(device_t bus,
 				    device_t dev, int cpu);
 static struct taskqueue		*vmbus_get_eventtq_method(device_t, device_t,
 				    int);
-#ifdef EARLY_AP_STARTUP
+#if defined(EARLY_AP_STARTUP) || defined(__aarch64__)
 static void			vmbus_intrhook(void *);
 #endif
 
@@ -132,7 +138,6 @@ static void			vmbus_intr_teardown(struct vmbus_softc *);
 static int			vmbus_doattach(struct vmbus_softc *);
 static void			vmbus_event_proc_dummy(struct vmbus_softc *,
 				    int);
-
 static struct vmbus_softc	*vmbus_sc;
 
 SYSCTL_NODE(_hw, OID_AUTO, vmbus, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
@@ -141,10 +146,6 @@ SYSCTL_NODE(_hw, OID_AUTO, vmbus, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
 static int			vmbus_pin_evttask = 1;
 SYSCTL_INT(_hw_vmbus, OID_AUTO, pin_evttask, CTLFLAG_RDTUN,
     &vmbus_pin_evttask, 0, "Pin event tasks to their respective CPU");
-
-extern inthand_t IDTVEC(vmbus_isr), IDTVEC(vmbus_isr_pti);
-#define VMBUS_ISR_ADDR	trunc_page((uintptr_t)IDTVEC(vmbus_isr_pti))
-
 uint32_t			vmbus_current_version;
 
 static const uint32_t		vmbus_version[] = {
@@ -660,11 +661,10 @@ vmbus_msg_task(void *xsc, int pending __unused)
 			 * This will cause message queue rescan to possibly
 			 * deliver another msg from the hypervisor
 			 */
-			wrmsr(MSR_HV_EOM, 0);
+			WRMSR(MSR_HV_EOM, 0);
 		}
 	}
 }
-
 static __inline int
 vmbus_handle_intr1(struct vmbus_softc *sc, struct trapframe *frame, int cpu)
 {
@@ -678,33 +678,7 @@ vmbus_handle_intr1(struct vmbus_softc *sc, struct trapframe *frame, int cpu)
 	 *
 	 * TODO: move this to independent IDT vector.
 	 */
-	msg = msg_base + VMBUS_SINT_TIMER;
-	if (msg->msg_type == HYPERV_MSGTYPE_TIMER_EXPIRED) {
-		msg->msg_type = HYPERV_MSGTYPE_NONE;
-
-		vmbus_et_intr(frame);
-
-		/*
-		 * Make sure the write to msg_type (i.e. set to
-		 * HYPERV_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);
-		}
-	}
-
+	vmbus_handle_timer_intr1(msg_base, frame);
 	/*
 	 * Check events.  Hot path for network and storage I/O data; high rate.
 	 *
@@ -738,10 +712,12 @@ vmbus_handle_intr(struct trapframe *trap_frame)
 	critical_enter();
 
 	/*
-	 * Do a little interrupt counting.
+	 * Do a little interrupt counting. This used x86 specific
+	 * intrcnt_add function
 	 */
+#if !defined(__aarch64__)
 	(*VMBUS_PCPU_GET(sc, intr_cnt, cpu))++;
-
+#endif /* not for aarch64 */
 	vmbus_handle_intr1(sc, trap_frame, cpu);
 
 	/*
@@ -760,7 +736,7 @@ vmbus_synic_setup(void *xsc)
 
 	if (hyperv_features & CPUID_HV_MSR_VP_INDEX) {
 		/* Save virtual processor id. */
-		VMBUS_PCPU_GET(sc, vcpuid, cpu) = rdmsr(MSR_HV_VP_INDEX);
+		VMBUS_PCPU_GET(sc, vcpuid, cpu) = RDMSR(MSR_HV_VP_INDEX);
 	} else {
 		/* Set virtual processor id to 0 for compatibility. */
 		VMBUS_PCPU_GET(sc, vcpuid, cpu) = 0;
@@ -769,46 +745,39 @@ vmbus_synic_setup(void *xsc)
 	/*
 	 * Setup the SynIC message.
 	 */
-	orig = rdmsr(MSR_HV_SIMP);
+	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);
-
+	    ((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);
+	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);
-
+	    ((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);
+	orig = RDMSR(sint);
 	val = sc->vmbus_idtvec | MSR_HV_SINT_AUTOEOI |
 	    (orig & MSR_HV_SINT_RSVD_MASK);
-	wrmsr(sint, val);
+	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);
-
+	vmbus_synic_setup1(sc);
 	/*
 	 * All done; enable SynIC.
 	 */
-	orig = rdmsr(MSR_HV_SCONTROL);
+	orig = RDMSR(MSR_HV_SCONTROL);
 	val = MSR_HV_SCTRL_ENABLE | (orig & MSR_HV_SCTRL_RSVD_MASK);
-	wrmsr(MSR_HV_SCONTROL, val);
+	WRMSR(MSR_HV_SCONTROL, val);
 }
 
 static void
@@ -820,34 +789,31 @@ vmbus_synic_teardown(void *arg)
 	/*
 	 * Disable SynIC.
 	 */
-	orig = rdmsr(MSR_HV_SCONTROL);
-	wrmsr(MSR_HV_SCONTROL, (orig & MSR_HV_SCTRL_RSVD_MASK));
+	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);
+	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);
-
+	vmbus_synic_teardown1();
 	/*
 	 * Teardown SynIC message.
 	 */
-	orig = rdmsr(MSR_HV_SIMP);
-	wrmsr(MSR_HV_SIMP, (orig & MSR_HV_SIMP_RSVD_MASK));
+	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));
+	orig = RDMSR(MSR_HV_SIEFP);
+	WRMSR(MSR_HV_SIEFP, (orig & MSR_HV_SIEFP_RSVD_MASK));
 }
 
 static int
@@ -948,8 +914,9 @@ vmbus_intr_setup(struct vmbus_softc *sc)
 
 		/* Allocate an interrupt counter for Hyper-V interrupt */
 		snprintf(buf, sizeof(buf), "cpu%d:hyperv", cpu);
+#if !defined(__aarch64__)
 		intrcnt_add(buf, VMBUS_PCPU_PTR(sc, intr_cnt, cpu));
-
+#endif /* not for aarch64 */
 		/*
 		 * Setup taskqueue to handle events.  Task will be per-
 		 * channel.
@@ -981,57 +948,12 @@ vmbus_intr_setup(struct vmbus_softc *sc)
 		TASK_INIT(VMBUS_PCPU_PTR(sc, message_task, cpu), 0,
 		    vmbus_msg_task, sc);
 	}
-
-#if defined(__amd64__) && defined(KLD_MODULE)
-	pmap_pti_add_kva(VMBUS_ISR_ADDR, VMBUS_ISR_ADDR + PAGE_SIZE, true);
-#endif
-
-	/*
-	 * 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(pti ? IDTVEC(vmbus_isr_pti) :
-	    IDTVEC(vmbus_isr));
-	if (sc->vmbus_idtvec < 0) {
-#if defined(__amd64__) && defined(KLD_MODULE)
-		pmap_pti_remove_kva(VMBUS_ISR_ADDR, VMBUS_ISR_ADDR + PAGE_SIZE);
-#endif
-		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;
+	return (vmbus_setup_intr1(sc));
 }
-
 static void
 vmbus_intr_teardown(struct vmbus_softc *sc)
 {
-	int cpu;
-
-	if (sc->vmbus_idtvec >= 0) {
-		lapic_ipi_free(sc->vmbus_idtvec);
*** 274 LINES SKIPPED ***