Beispiel #1
0
/**
 * @brief Synchronize time with host after reboot, restore, etc.
 *
 * ICTIMESYNCFLAG_SYNC flag bit indicates reboot, restore events of the VM.
 * After reboot the flag ICTIMESYNCFLAG_SYNC is included in the first time
 * message after the timesync channel is opened. Since the hv_utils module is
 * loaded after hv_vmbus, the first message is usually missed. The other
 * thing is, systime is automatically set to emulated hardware clock which may
 * not be UTC time or in the same time zone. So, to override these effects, we
 * use the first 50 time samples for initial system time setting.
 */
static inline
void hv_adj_guesttime(uint64_t hosttime, uint8_t flags)
{
	time_sync_data* time_msg;

	time_msg = malloc(sizeof(time_sync_data), M_DEVBUF, M_NOWAIT);

	if (time_msg == NULL)
		return;
	
	time_msg->data = hosttime;

	if ((flags & HV_ICTIMESYNCFLAG_SYNC) != 0) {
		hv_queue_work_item(service_table[HV_TIME_SYNCH].work_queue,
		    hv_set_host_time, time_msg);
	} else if ((flags & HV_ICTIMESYNCFLAG_SAMPLE) != 0) {
		hv_queue_work_item(service_table[HV_TIME_SYNCH].work_queue,
		    hv_set_host_time, time_msg);
	} else {
		free(time_msg, M_DEVBUF);
	}
}
/**
 * @brief Software interrupt thread routine to handle channel messages from
 * the hypervisor.
 */
static void
vmbus_msg_swintr(void *arg)
{
	int 			cpu;
	void*			page_addr;
	hv_vmbus_message*	msg;
	hv_vmbus_message*	copied;

	cpu = (int)(long)arg;
	KASSERT(cpu <= mp_maxid, ("VMBUS: vmbus_msg_swintr: "
	    "cpu out of range!"));

	page_addr = hv_vmbus_g_context.syn_ic_msg_page[cpu];
	msg = (hv_vmbus_message*) page_addr + HV_VMBUS_MESSAGE_SINT;

	for (;;) {
		if (msg->header.message_type == HV_MESSAGE_TYPE_NONE) {
			break; /* no message */
		} else {
			copied = malloc(sizeof(hv_vmbus_message),
					M_DEVBUF, M_NOWAIT);
			KASSERT(copied != NULL,
				("Error VMBUS: malloc failed to allocate"
					" hv_vmbus_message!"));
			if (copied == NULL)
				continue;
			memcpy(copied, msg, sizeof(hv_vmbus_message));
			hv_queue_work_item(hv_vmbus_g_connection.work_queue,
			hv_vmbus_on_channel_message, copied);
	    }

	    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);
	    }
	}
}
/* Timer to establish connection with the user daemon */
static void
kvp_user_rcv_timer(void *arg)
{
	int error=KVP_SUCCESS;
        printf("kvp_user_rcv_timer: timer triggered\n");
	//printf("kvp:guid:%s\n",kvp_hv_dev->class_id);
	
	/* If daemon is already ready, just connect to the host and return */
	if (hv_kvp_ready()) {
		kvp_msg_state.kvp_rcv_timer.callout = NULL;
		error = hv_vmbus_channel_open(kvp_hv_dev->channel, 
					4 * PAGE_SIZE, 4 * PAGE_SIZE, 
				NULL, 0, hv_kvp_callback, kvp_hv_dev->channel);
		if (error) 
			printf("kvp_user_rcv_timer: vmbus_chan_open failed\n");
	}
	else {
		hv_queue_work_item(kvp_work_queue, hv_kvp_conn_register, NULL);
		kvp_msg_state.kvp_rcv_timer = 
			timeout(kvp_user_rcv_timer, NULL, 10);
	}
}
Beispiel #4
0
/*
 * Callback routine that gets called whenever there is a message from host
 */
void
hv_kvp_callback(void *context)
{
	uint64_t pending_cnt = 0;

	if (kvp_globals.register_done == false) {
		
		kvp_globals.channelp = context;
	} else {
		
		mtx_lock(&kvp_globals.pending_mutex);
		kvp_globals.pending_reqs = kvp_globals.pending_reqs + 1;
		pending_cnt = kvp_globals.pending_reqs;
		mtx_unlock(&kvp_globals.pending_mutex);
		if (pending_cnt == 1) {
			hv_kvp_log_info("%s: Queuing work item\n", __func__);
			hv_queue_work_item(
					service_table[HV_KVP].work_queue,
					hv_kvp_process_request,
					context
					);
		}
	}	
}
Beispiel #5
0
/**
 * @brief Software interrupt thread routine to handle channel messages from
 * the hypervisor.
 */
static void
vmbus_msg_swintr(void *arg)
{
	int 			cpu;
	void*			page_addr;
	hv_vmbus_channel_msg_header	 *hdr;
	hv_vmbus_channel_msg_table_entry *entry;
	hv_vmbus_channel_msg_type msg_type;
	hv_vmbus_message*	msg;
	hv_vmbus_message*	copied;
	static bool warned	= false;

	cpu = (int)(long)arg;
	KASSERT(cpu <= mp_maxid, ("VMBUS: vmbus_msg_swintr: "
	    "cpu out of range!"));

	page_addr = hv_vmbus_g_context.syn_ic_msg_page[cpu];
	msg = (hv_vmbus_message*) page_addr + HV_VMBUS_MESSAGE_SINT;

	for (;;) {
		if (msg->header.message_type == HV_MESSAGE_TYPE_NONE)
			break; /* no message */

		hdr = (hv_vmbus_channel_msg_header *)msg->u.payload;
		msg_type = hdr->message_type;

		if (msg_type >= HV_CHANNEL_MESSAGE_COUNT && !warned) {
			warned = true;
			printf("VMBUS: unknown message type = %d\n", msg_type);
			goto handled;
		}

		entry = &g_channel_message_table[msg_type];

		if (entry->handler_no_sleep)
			entry->messageHandler(hdr);
		else {

			copied = malloc(sizeof(hv_vmbus_message),
					M_DEVBUF, M_NOWAIT);
			KASSERT(copied != NULL,
				("Error VMBUS: malloc failed to allocate"
					" hv_vmbus_message!"));
			if (copied == NULL)
				continue;

			memcpy(copied, msg, sizeof(hv_vmbus_message));
			hv_queue_work_item(hv_vmbus_g_connection.work_queue,
					   hv_vmbus_on_channel_message,
					   copied);
		}
handled:
	    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);
	    }
	}
}
/* 
 * Callback routine that gets called whenever there is a message from host
 */
static 
void hv_kvp_callback(void *context)
{
	uint8_t*		buf;
	hv_vmbus_channel*	channel = context;
	uint32_t		recvlen;
	uint64_t		requestid;
	int			ret;

	struct hv_vmbus_icmsg_hdr*		icmsghdrp;
	buf = receive_buffer[0];

#if 0
	/* If driver unloaded abruptly, return */
	if (vmbus_kvp_channel == NULL) 
	{
#ifdef DEBUG
		printf("hv_kvp_cb: kvp unloaded abruptly\n");
#endif
		return;
	}
#endif

	/* Check if kvp is ready to process */
	if (!hv_kvp_ready()) {
#ifdef DEBUG
		printf("hv_kvp_cb: kvp is not ready..initing\n");
#endif
		hv_queue_work_item(kvp_work_queue, hv_kvp_conn_register, NULL);
	}

	/* Check if already one transaction is under process */
	if (hv_kvp_transaction_active()) {
#ifdef DEBUG
		printf("hv_kvp_cb: Already one transaction is active\n");
#endif
		return;
	}
	ret = hv_vmbus_channel_recv_packet(channel, buf, PAGE_SIZE * 2, 
		&recvlen, &requestid);

#ifdef DEBUG
	printf("hv_kvp_cb: vmbus_recv ret:%d rLen:%d rId:%d\n", 
		ret, recvlen, (int)requestid);
#endif
	if ((ret == 0) && (recvlen > 0)) {

		icmsghdrp = (struct hv_vmbus_icmsg_hdr *)
			&buf[sizeof(struct hv_vmbus_pipe_hdr)];

		if (icmsghdrp->icmsgtype == HV_ICMSGTYPE_NEGOTIATE) {
#ifdef DEBUG
			printf("hv_kvp_cb: Negotiate message received\n");
#endif
			hv_negotiate_version(icmsghdrp, NULL, buf);
		} else {
#ifdef DEBUG
			printf("hv_kvp_cb: New host message received\n");
#endif
			hv_kvp_transaction_init(recvlen,channel,requestid, buf);
			hv_queue_work_item(kvp_work_queue,
						hv_kvp_process_msg, NULL);
			return; /* deferred response by KVP process */
		}

		icmsghdrp->icflags = HV_ICMSGHDRFLAG_TRANSACTION |
			HV_ICMSGHDRFLAG_RESPONSE;

		hv_vmbus_channel_send_packet(channel, buf, recvlen, requestid,
			HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0);
	}
}