Date: Thu, 23 Jun 2016 04:40:13 +0000 (UTC) From: Sepherosa Ziehau <sephe@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r302114 - stable/10/sys/dev/hyperv/vmbus Message-ID: <201606230440.u5N4eDxA060532@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: sephe Date: Thu Jun 23 04:40:13 2016 New Revision: 302114 URL: https://svnweb.freebsd.org/changeset/base/302114 Log: MFC 300480,300481,300486 300480 hyperv: Move Hypercall setup to an early place. It does not belong to the vmbus. While I'm here rework the Hypercall setup, e.g. use busdma(9) and avoid bit fields. Discussed with: Jun Su <junsu microsoft com> MFC after: 1 week Sponsored by: Microsoft OSTC Differential Revision: https://reviews.freebsd.org/D6445 300481 hyperv/vmbus: Declare Synic message and event w/ proper types Avoid ugly casts. MFC after: 1 week Sponsored by: Microsoft OSTC Differential Revision: https://reviews.freebsd.org/D6446 300486 hyperv/vmbus: Get rid of vmbus_devp While I'm here, nuke useless print in vmbus_attach(). MFC after: 1 week Sponsored by: Microsoft OSTC Differential Revision: https://reviews.freebsd.org/D6447 Added: stable/10/sys/dev/hyperv/vmbus/hyperv_reg.h - copied unchanged from r300480, head/sys/dev/hyperv/vmbus/hyperv_reg.h Modified: stable/10/sys/dev/hyperv/vmbus/hv_connection.c stable/10/sys/dev/hyperv/vmbus/hv_hv.c stable/10/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c stable/10/sys/dev/hyperv/vmbus/hv_vmbus_priv.h stable/10/sys/dev/hyperv/vmbus/vmbus_var.h Directory Properties: stable/10/ (props changed) Modified: stable/10/sys/dev/hyperv/vmbus/hv_connection.c ============================================================================== --- stable/10/sys/dev/hyperv/vmbus/hv_connection.c Thu Jun 23 03:25:18 2016 (r302113) +++ stable/10/sys/dev/hyperv/vmbus/hv_connection.c Thu Jun 23 04:40:13 2016 (r302114) @@ -336,8 +336,8 @@ vmbus_event_proc(struct vmbus_softc *sc, { hv_vmbus_synic_event_flags *event; - event = ((hv_vmbus_synic_event_flags *) - hv_vmbus_g_context.syn_ic_event_page[cpu]) + HV_VMBUS_MESSAGE_SINT; + event = hv_vmbus_g_context.syn_ic_event_page[cpu] + + HV_VMBUS_MESSAGE_SINT; /* * On Host with Win8 or above, the event page can be checked directly @@ -352,8 +352,8 @@ vmbus_event_proc_compat(struct vmbus_sof { hv_vmbus_synic_event_flags *event; - event = ((hv_vmbus_synic_event_flags *) - hv_vmbus_g_context.syn_ic_event_page[cpu]) + HV_VMBUS_MESSAGE_SINT; + event = hv_vmbus_g_context.syn_ic_event_page[cpu] + + HV_VMBUS_MESSAGE_SINT; if (atomic_testandclear_int(&event->flags32[0], 0)) { vmbus_event_flags_proc( Modified: stable/10/sys/dev/hyperv/vmbus/hv_hv.c ============================================================================== --- stable/10/sys/dev/hyperv/vmbus/hv_hv.c Thu Jun 23 03:25:18 2016 (r302113) +++ stable/10/sys/dev/hyperv/vmbus/hv_hv.c Thu Jun 23 04:40:13 2016 (r302114) @@ -43,8 +43,9 @@ __FBSDID("$FreeBSD$"); #include <vm/vm_param.h> #include <vm/pmap.h> - -#include "hv_vmbus_priv.h" +#include <dev/hyperv/include/hyperv_busdma.h> +#include <dev/hyperv/vmbus/hv_vmbus_priv.h> +#include <dev/hyperv/vmbus/hyperv_reg.h> #define HV_NANOSECONDS_PER_SEC 1000000000L @@ -79,6 +80,13 @@ __FBSDID("$FreeBSD$"); (((uint64_t)__FreeBSD_version) << 16) | \ ((uint64_t)((id) & 0x00ffff))) +struct hypercall_ctx { + void *hc_addr; + struct hyperv_dma hc_dma; +}; + +static struct hypercall_ctx hypercall_context; + static u_int hv_get_timecount(struct timecounter *tc); u_int hyperv_features; @@ -92,7 +100,6 @@ static u_int hyperv_features3; */ hv_vmbus_context hv_vmbus_g_context = { .syn_ic_initialized = FALSE, - .hypercall_page = NULL, }; static struct timecounter hv_timecounter = { @@ -116,7 +123,7 @@ hv_vmbus_do_hypercall(uint64_t control, 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 = hv_vmbus_g_context.hypercall_page; + volatile void *hypercall_page = hypercall_context.hc_addr; __asm__ __volatile__ ("mov %0, %%r8" : : "r" (output_address): "r8"); __asm__ __volatile__ ("call *%3" : "=a"(hv_status): @@ -134,7 +141,7 @@ hv_vmbus_do_hypercall(uint64_t control, 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 = hv_vmbus_g_context.hypercall_page; + volatile void *hypercall_page = hypercall_context.hc_addr; __asm__ __volatile__ ("call *%8" : "=d"(hv_status_high), "=a"(hv_status_low) : "d" (control_high), @@ -147,84 +154,6 @@ hv_vmbus_do_hypercall(uint64_t control, } /** - * @brief Main initialization routine. - * - * This routine must be called - * before any other routines in here are called - */ -int -hv_vmbus_init(void) -{ - hv_vmbus_x64_msr_hypercall_contents hypercall_msr; - void* virt_addr = NULL; - - memset( - hv_vmbus_g_context.syn_ic_event_page, - 0, - sizeof(hv_vmbus_handle) * MAXCPU); - - memset( - hv_vmbus_g_context.syn_ic_msg_page, - 0, - sizeof(hv_vmbus_handle) * MAXCPU); - - if (vm_guest != VM_GUEST_HV) - goto cleanup; - - /* - * See if the hypercall page is already set - */ - hypercall_msr.as_uint64_t = rdmsr(HV_X64_MSR_HYPERCALL); - virt_addr = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK | M_ZERO); - - hypercall_msr.u.enable = 1; - hypercall_msr.u.guest_physical_address = - (hv_get_phys_addr(virt_addr) >> PAGE_SHIFT); - wrmsr(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64_t); - - /* - * Confirm that hypercall page did get set up - */ - hypercall_msr.as_uint64_t = 0; - hypercall_msr.as_uint64_t = rdmsr(HV_X64_MSR_HYPERCALL); - - if (!hypercall_msr.u.enable) - goto cleanup; - - hv_vmbus_g_context.hypercall_page = virt_addr; - - return (0); - - cleanup: - if (virt_addr != NULL) { - if (hypercall_msr.u.enable) { - hypercall_msr.as_uint64_t = 0; - wrmsr(HV_X64_MSR_HYPERCALL, - hypercall_msr.as_uint64_t); - } - - free(virt_addr, M_DEVBUF); - } - return (ENOTSUP); -} - -/** - * @brief Cleanup routine, called normally during driver unloading or exiting - */ -void -hv_vmbus_cleanup(void) -{ - if (hv_vmbus_g_context.hypercall_page != NULL) { - hv_vmbus_x64_msr_hypercall_contents hypercall_msr; - - hypercall_msr.as_uint64_t = 0; - wrmsr(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64_t); - free(hv_vmbus_g_context.hypercall_page, M_DEVBUF); - hv_vmbus_g_context.hypercall_page = NULL; - } -} - -/** * @brief Post a message using the hypervisor message IPC. * (This involves a hypercall.) */ @@ -304,9 +233,6 @@ hv_vmbus_synic_init(void *arg) cpu = PCPU_GET(cpuid); - if (hv_vmbus_g_context.hypercall_page == NULL) - return; - /* * TODO: Check the version */ @@ -537,3 +463,74 @@ hyperv_init(void *dummy __unused) } 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) +{ + if (hypercall_context.hc_addr == NULL) + return; + + /* Disable Hypercall */ + wrmsr(MSR_HV_HYPERCALL, 0); + hypercall_memfree(); + + if (bootverbose) + printf("hyperv: Hypercall destroyed\n"); +} +SYSUNINIT(hypercall_dtor, SI_SUB_DRIVERS, SI_ORDER_FIRST, hypercall_destroy, + NULL); Modified: stable/10/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c ============================================================================== --- stable/10/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c Thu Jun 23 03:25:18 2016 (r302113) +++ stable/10/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c Thu Jun 23 04:40:13 2016 (r302114) @@ -68,7 +68,6 @@ __FBSDID("$FreeBSD$"); struct vmbus_softc *vmbus_sc; -static device_t vmbus_devp; static int vmbus_inited; static hv_setup_args setup_args; /* only CPU 0 supported at this time */ @@ -79,8 +78,9 @@ vmbus_msg_task(void *arg __unused, int p { hv_vmbus_message *msg; - msg = ((hv_vmbus_message *)hv_vmbus_g_context.syn_ic_msg_page[curcpu]) + + msg = hv_vmbus_g_context.syn_ic_msg_page[curcpu] + HV_VMBUS_MESSAGE_SINT; + for (;;) { const hv_vmbus_channel_msg_table_entry *entry; hv_vmbus_channel_msg_header *hdr; @@ -134,9 +134,8 @@ static inline int hv_vmbus_isr(struct trapframe *frame) { struct vmbus_softc *sc = vmbus_get_softc(); + hv_vmbus_message *msg, *msg_base; int cpu = curcpu; - hv_vmbus_message *msg; - void *page_addr; /* * The Windows team has advised that we check for events @@ -146,8 +145,8 @@ hv_vmbus_isr(struct trapframe *frame) sc->vmbus_event_proc(sc, cpu); /* Check if there are actual msgs to be process */ - page_addr = hv_vmbus_g_context.syn_ic_msg_page[cpu]; - msg = ((hv_vmbus_message *)page_addr) + HV_VMBUS_TIMER_SINT; + msg_base = hv_vmbus_g_context.syn_ic_msg_page[cpu]; + msg = msg_base + HV_VMBUS_TIMER_SINT; /* we call eventtimer process the message */ if (msg->header.message_type == HV_MESSAGE_TIMER_EXPIRED) { @@ -178,7 +177,7 @@ hv_vmbus_isr(struct trapframe *frame) } } - msg = ((hv_vmbus_message *)page_addr) + HV_VMBUS_MESSAGE_SINT; + msg = msg_base + HV_VMBUS_MESSAGE_SINT; if (msg->header.message_type != HV_MESSAGE_TYPE_NONE) { taskqueue_enqueue(hv_vmbus_g_context.hv_msg_tq[cpu], &hv_vmbus_g_context.hv_msg_task[cpu]); @@ -324,7 +323,7 @@ hv_vmbus_child_device_register(struct hv printf("VMBUS: Class ID: %s\n", name); } - child = device_add_child(vmbus_devp, NULL, -1); + child = device_add_child(vmbus_get_device(), NULL, -1); child_dev->device = child; device_set_ivars(child, child_dev); @@ -340,7 +339,7 @@ hv_vmbus_child_device_unregister(struct * device_add_child() */ mtx_lock(&Giant); - ret = device_delete_child(vmbus_devp, child_dev->device); + ret = device_delete_child(vmbus_get_device(), child_dev->device); mtx_unlock(&Giant); return(ret); } @@ -349,7 +348,7 @@ static int vmbus_probe(device_t dev) { if (ACPI_ID_PROBE(device_get_parent(dev), dev, vmbus_ids) == NULL || - device_get_unit(dev) != 0) + device_get_unit(dev) != 0 || vm_guest != VM_GUEST_HV) return (ENXIO); device_set_desc(dev, "Hyper-V Vmbus"); @@ -455,14 +454,6 @@ vmbus_bus_init(void) vmbus_inited = 1; sc = vmbus_get_softc(); - ret = hv_vmbus_init(); - - if (ret) { - if(bootverbose) - printf("Error VMBUS: Hypervisor Initialization Failed!\n"); - return (ret); - } - /* * Find a free IDT slot for vmbus callback. */ @@ -472,6 +463,7 @@ vmbus_bus_init(void) if(bootverbose) printf("Error VMBUS: Cannot find free IDT slot for " "vmbus callback!\n"); + ret = ENXIO; goto cleanup; } @@ -559,8 +551,8 @@ vmbus_bus_init(void) hv_vmbus_request_channel_offers(); vmbus_scan(); - bus_generic_attach(vmbus_devp); - device_printf(vmbus_devp, "device scan, probe and attach done\n"); + bus_generic_attach(sc->vmbus_dev); + device_printf(sc->vmbus_dev, "device scan, probe and attach done\n"); return (ret); @@ -585,8 +577,6 @@ vmbus_bus_init(void) vmbus_vector_free(hv_vmbus_g_context.hv_cb_vector); cleanup: - hv_vmbus_cleanup(); - return (ret); } @@ -598,11 +588,8 @@ vmbus_event_proc_dummy(struct vmbus_soft static int vmbus_attach(device_t dev) { - if(bootverbose) - device_printf(dev, "VMBUS: attach dev: %p\n", dev); - - vmbus_devp = dev; vmbus_sc = device_get_softc(dev); + vmbus_sc->vmbus_dev = dev; /* * Event processing logic will be configured: @@ -655,8 +642,6 @@ vmbus_detach(device_t dev) free(setup_args.page_buffers[i], M_DEVBUF); } - hv_vmbus_cleanup(); - /* remove swi */ CPU_FOREACH(i) { if (hv_vmbus_g_context.hv_event_queue[i] != NULL) { Modified: stable/10/sys/dev/hyperv/vmbus/hv_vmbus_priv.h ============================================================================== --- stable/10/sys/dev/hyperv/vmbus/hv_vmbus_priv.h Thu Jun 23 03:25:18 2016 (r302113) +++ stable/10/sys/dev/hyperv/vmbus/hv_vmbus_priv.h Thu Jun 23 04:40:13 2016 (r302114) @@ -197,12 +197,14 @@ enum { #define HV_HYPERCALL_PARAM_ALIGN sizeof(uint64_t) +struct vmbus_message; +union vmbus_event_flags; + typedef struct { - void* hypercall_page; hv_bool_uint8_t syn_ic_initialized; - hv_vmbus_handle syn_ic_msg_page[MAXCPU]; - hv_vmbus_handle syn_ic_event_page[MAXCPU]; + struct vmbus_message *syn_ic_msg_page[MAXCPU]; + union vmbus_event_flags *syn_ic_event_page[MAXCPU]; /* * For FreeBSD cpuid to Hyper-V vcpuid mapping. */ @@ -304,7 +306,7 @@ typedef struct { /* * Define synthetic interrupt controller message format */ -typedef struct { +typedef struct vmbus_message { hv_vmbus_msg_header header; union { uint64_t payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT]; @@ -579,7 +581,7 @@ typedef struct { /* * Define the synthetic interrupt controller event flags format */ -typedef union { +typedef union vmbus_event_flags { uint8_t flags8[HV_EVENT_FLAGS_BYTE_COUNT]; uint32_t flags32[HV_EVENT_FLAGS_DWORD_COUNT]; unsigned long flagsul[HV_EVENT_FLAGS_ULONG_COUNT]; @@ -722,8 +724,6 @@ hv_vmbus_channel* hv_vmbus_allocate_chan void hv_vmbus_free_vmbus_channel(hv_vmbus_channel *channel); int hv_vmbus_request_channel_offers(void); void hv_vmbus_release_unattached_channels(void); -int hv_vmbus_init(void); -void hv_vmbus_cleanup(void); uint16_t hv_vmbus_post_msg_via_msg_ipc( hv_vmbus_connection_id connection_id, Copied: stable/10/sys/dev/hyperv/vmbus/hyperv_reg.h (from r300480, head/sys/dev/hyperv/vmbus/hyperv_reg.h) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ stable/10/sys/dev/hyperv/vmbus/hyperv_reg.h Thu Jun 23 04:40:13 2016 (r302114, copy of r300480, head/sys/dev/hyperv/vmbus/hyperv_reg.h) @@ -0,0 +1,37 @@ +/*- + * 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_ + +#define MSR_HV_HYPERCALL 0x40000001 +#define MSR_HV_HYPERCALL_ENABLE 0x0001ULL +#define MSR_HV_HYPERCALL_RSVD_MASK 0x0ffeULL +#define MSR_HV_HYPERCALL_PGSHIFT 12 + +#endif /* !_HYPERV_REG_H_ */ Modified: stable/10/sys/dev/hyperv/vmbus/vmbus_var.h ============================================================================== --- stable/10/sys/dev/hyperv/vmbus/vmbus_var.h Thu Jun 23 03:25:18 2016 (r302113) +++ stable/10/sys/dev/hyperv/vmbus/vmbus_var.h Thu Jun 23 04:40:13 2016 (r302114) @@ -38,6 +38,7 @@ struct vmbus_pcpu_data { struct vmbus_softc { void (*vmbus_event_proc)(struct vmbus_softc *, int); struct vmbus_pcpu_data vmbus_pcpu[MAXCPU]; + device_t vmbus_dev; }; extern struct vmbus_softc *vmbus_sc; @@ -48,6 +49,12 @@ vmbus_get_softc(void) return vmbus_sc; } +static __inline device_t +vmbus_get_device(void) +{ + return vmbus_sc->vmbus_dev; +} + #define VMBUS_SC_PCPU_GET(sc, field, cpu) (sc)->vmbus_pcpu[(cpu)].field #define VMBUS_SC_PCPU_PTR(sc, field, cpu) &(sc)->vmbus_pcpu[(cpu)].field #define VMBUS_PCPU_GET(field, cpu) \
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201606230440.u5N4eDxA060532>