diff --git a/sys/dev/hyperv/vmbus/x86/hyperv_machdep.h b/sys/dev/hyperv/vmbus/x86/hyperv_machdep.h new file mode 100644 --- /dev/null +++ b/sys/dev/hyperv/vmbus/x86/hyperv_machdep.h @@ -0,0 +1,40 @@ +/*- SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * Copyright (c) 2022 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 + +uint64_t hypercall_md(volatile void *hc_addr, uint64_t in_val, + uint64_t in_paddr, uint64_t out_paddr); + +#define WRMSR(msr, val) wrmsr(msr, val) +#define RDMSR(msr) rdmsr(msr) + +#endif /* !_HYPERV_MACHDEP_H_ */ diff --git a/sys/dev/hyperv/vmbus/x86/hyperv_reg.h b/sys/dev/hyperv/vmbus/x86/hyperv_reg.h new file mode 100644 --- /dev/null +++ b/sys/dev/hyperv/vmbus/x86/hyperv_reg.h @@ -0,0 +1,193 @@ +/*- SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * Copyright (c) 2022 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 +#include + +/* + * 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 + * <> 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/x86/hyperv_x86.c b/sys/dev/hyperv/vmbus/x86/hyperv_x86.c new file mode 100644 --- /dev/null +++ b/sys/dev/hyperv/vmbus/x86/hyperv_x86.c @@ -0,0 +1,241 @@ +/*- SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * Copyright (c) 2009-2012,2016-2017, 2022 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 Hyper-V/Azure + */ +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define HYPERV_FREEBSD_BUILD 0ULL +#define HYPERV_FREEBSD_VERSION ((uint64_t)__FreeBSD_version) +#define HYPERV_FREEBSD_OSID 0ULL + +void hyperv_init_tc(void); +int hypercall_page_setup(vm_paddr_t); +void hypercall_disable(void); +bool hyperv_identify_features(void); + +u_int hyperv_ver_major; +u_int hyperv_features; +u_int hyperv_recommends; + +hyperv_tc64_t hyperv_tc64; + +static u_int hyperv_pm_features; +static u_int hyperv_features3; +static u_int hyperv_get_timecount(struct timecounter *); + +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 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)); +} + +void +hyperv_init_tc(void) +{ + 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; + } +} + +int +hypercall_page_setup(vm_paddr_t paddr) +{ + uint64_t hc, hc_orig; + hc_orig = rdmsr(MSR_HV_HYPERCALL); + + /* + * Setup the Hypercall page. + * + * NOTE: 'reserved' bits MUST be preserved. + */ + 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"); + /* Can't perform any Hyper-V specific actions */ + vm_guest = VM_GUEST_VM; + return (-1); + } + return (0); +} + +void +hypercall_disable(void) +{ + uint64_t hc; + /* Disable Hypercall */ + hc = rdmsr(MSR_HV_HYPERCALL); + wrmsr(MSR_HV_HYPERCALL, (hc & MSR_HV_HYPERCALL_RSVD_MASK)); +} + +bool +hyperv_identify_features(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); +} diff --git a/sys/dev/hyperv/vmbus/x86/vmbus_x86.c b/sys/dev/hyperv/vmbus/x86/vmbus_x86.c new file mode 100644 --- /dev/null +++ b/sys/dev/hyperv/vmbus/x86/vmbus_x86.c @@ -0,0 +1,196 @@ +/*- SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * Copyright (c) 2009-2012,2016-2017, 2022 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "acpi_if.h" +#include "pcib_if.h" +#include "vmbus_if.h" + +extern inthand_t IDTVEC(vmbus_isr), IDTVEC(vmbus_isr_pti); +#define VMBUS_ISR_ADDR trunc_page((uintptr_t)IDTVEC(vmbus_isr_pti)) + +void vmbus_handle_timer_intr1(struct vmbus_message *msg_base, + struct trapframe *frame); +void vmbus_synic_setup1(void *xsc); +void vmbus_synic_teardown1(void); +int vmbus_setup_intr1(struct vmbus_softc *sc); +void vmbus_intr_teardown1(struct vmbus_softc *sc); + +void +vmbus_handle_timer_intr1(struct vmbus_message *msg_base, + struct trapframe *frame) +{ + volatile struct vmbus_message *msg; + 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); + } + } + return; +} + +void +vmbus_synic_setup1(void *xsc) +{ + struct vmbus_softc *sc = xsc; + uint32_t sint; + uint64_t val, orig; + + 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); + return; +} + +void +vmbus_synic_teardown1(void) +{ + uint64_t orig; + uint32_t sint; + + sint = MSR_HV_SINT0 + VMBUS_SINT_TIMER; + orig = RDMSR(sint); + WRMSR(sint, orig | MSR_HV_SINT_MASKED); + return; +} + +int +vmbus_setup_intr1(struct vmbus_softc *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; +} + +void +vmbus_intr_teardown1(struct vmbus_softc *sc) +{ + int cpu; + + if (sc->vmbus_idtvec >= 0) { + lapic_ipi_free(sc->vmbus_idtvec); + sc->vmbus_idtvec = -1; + } + +#if defined(__amd64__) && defined(KLD_MODULE) + pmap_pti_remove_kva(VMBUS_ISR_ADDR, VMBUS_ISR_ADDR + PAGE_SIZE); +#endif + + 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; + } + } +}