コード例 #1
0
/**
 * @brief Interrupt filter routine for VMBUS.
 *
 * The purpose of this routine is to determine the type of VMBUS protocol
 * message to process - an event or a channel message.
 */
static inline int
hv_vmbus_isr(void *unused) 
{
	int				cpu;
	hv_vmbus_message*		msg;
	hv_vmbus_synic_event_flags*	event;
	void*				page_addr;

	cpu = PCPU_GET(cpuid);

	/*
	 * The Windows team has advised that we check for events
	 * before checking for messages. This is the way they do it
	 * in Windows when running as a guest in Hyper-V
	 */

	page_addr = hv_vmbus_g_context.syn_ic_event_page[cpu];
	event = (hv_vmbus_synic_event_flags*)
		    page_addr + HV_VMBUS_MESSAGE_SINT;

	if ((hv_vmbus_protocal_version == HV_VMBUS_VERSION_WS2008) ||
	    (hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7)) {
		/* Since we are a child, we only need to check bit 0 */
		if (synch_test_and_clear_bit(0, &event->flags32[0])) {
			swi_sched(hv_vmbus_g_context.event_swintr[cpu], 0);
		}
	} else {
		/*
		 * On host with Win8 or above, we can directly look at
		 * the event page. If bit n is set, we have an interrupt 
		 * on the channel with id n.
		 * Directly schedule the event software interrupt on
		 * current cpu.
		 */
		swi_sched(hv_vmbus_g_context.event_swintr[cpu], 0);
	}

	/* 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_MESSAGE_SINT;

	if (msg->header.message_type != HV_MESSAGE_TYPE_NONE) {
		swi_sched(hv_vmbus_g_context.msg_swintr[cpu], 0);
	}

	return FILTER_HANDLED;
}
/**
 * @brief Interrupt filter routine for VMBUS.
 *
 * The purpose of this routine is to determine the type of VMBUS protocol
 * message to process - an event or a channel message.
 * As this is an interrupt filter routine, the function runs in a very
 * restricted envinronment.  From the manpage for bus_setup_intr(9)
 *
 *   In this restricted environment, care must be taken to account for all
 *   races.  A careful analysis of races should be done as well.  It is gener-
 *   ally cheaper to take an extra interrupt, for example, than to protect
 *   variables with spinlocks.	Read, modify, write cycles of hardware regis-
 *   ters need to be carefully analyzed if other threads are accessing the
 *   same registers.
 */
static int
hv_vmbus_isr(void *unused)
{
    int				cpu;
    hv_vmbus_message*		msg;
    hv_vmbus_synic_event_flags*	event;
    void*				page_addr;

    cpu = PCPU_GET(cpuid);
    /* (Temporary limit) */
    KASSERT(cpu == 0, ("hv_vmbus_isr: Interrupt on CPU other than zero"));

    /*
     * The Windows team has advised that we check for events
     * before checking for messages. This is the way they do it
     * in Windows when running as a guest in Hyper-V
     */

    page_addr = hv_vmbus_g_context.syn_ic_event_page[cpu];
    event = (hv_vmbus_synic_event_flags*)
            page_addr + HV_VMBUS_MESSAGE_SINT;

    /* Since we are a child, we only need to check bit 0 */
    if (synch_test_and_clear_bit(0, &event->flags32[0])) {
        swi_sched(event_swintr, 0);
    }

    /* 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_MESSAGE_SINT;

    if (msg->header.message_type != HV_MESSAGE_TYPE_NONE) {
        swi_sched(msg_swintr, 0);
    }

    return FILTER_HANDLED;
}
コード例 #3
0
ファイル: hv_vmbus_drv_freebsd.c プロジェクト: jp629/freebsd
/**
 * @brief Interrupt filter routine for VMBUS.
 *
 * The purpose of this routine is to determine the type of VMBUS protocol
 * message to process - an event or a channel message.
 */
static inline int
hv_vmbus_isr(struct trapframe *frame)
{
	int				cpu;
	hv_vmbus_message*		msg;
	hv_vmbus_synic_event_flags*	event;
	void*				page_addr;

	cpu = PCPU_GET(cpuid);

	/*
	 * The Windows team has advised that we check for events
	 * before checking for messages. This is the way they do it
	 * in Windows when running as a guest in Hyper-V
	 */

	page_addr = hv_vmbus_g_context.syn_ic_event_page[cpu];
	event = (hv_vmbus_synic_event_flags*)
		    page_addr + HV_VMBUS_MESSAGE_SINT;

	if ((hv_vmbus_protocal_version == HV_VMBUS_VERSION_WS2008) ||
	    (hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7)) {
		/* Since we are a child, we only need to check bit 0 */
		if (synch_test_and_clear_bit(0, &event->flags32[0])) {
			swi_sched(hv_vmbus_g_context.event_swintr[cpu], 0);
		}
	} else {
		/*
		 * On host with Win8 or above, we can directly look at
		 * the event page. If bit n is set, we have an interrupt 
		 * on the channel with id n.
		 * Directly schedule the event software interrupt on
		 * current cpu.
		 */
		swi_sched(hv_vmbus_g_context.event_swintr[cpu], 0);
	}

	/* 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_MESSAGE_SINT;

	/* we call eventtimer process the message */
	if (msg->header.message_type == HV_MESSAGE_TIMER_EXPIRED) {
		msg->header.message_type = HV_MESSAGE_TYPE_NONE;

		/*
		 * Make sure the write to message_type (ie set to
		 * HV_MESSAGE_TYPE_NONE) happens before we read the
		 * message_pending and EOMing. Otherwise, the EOMing will
		 * not deliver any more messages
		 * since there is no empty slot
		 */
		wmb();

		if (msg->header.message_flags.u.message_pending) {
			/*
			 * This will cause message queue rescan to possibly
			 * deliver another msg from the hypervisor
			 */
			wrmsr(HV_X64_MSR_EOM, 0);
		}
		hv_et_intr(frame);
		return (FILTER_HANDLED);
	}

	if (msg->header.message_type != HV_MESSAGE_TYPE_NONE) {
		swi_sched(hv_vmbus_g_context.msg_swintr[cpu], 0);
	}

	return (FILTER_HANDLED);
}