Commit c88c4e4c authored by Hank Janssen's avatar Hank Janssen Committed by Greg Kroah-Hartman
Browse files

Staging: hv: Added new hv_utils driver with shutdown as first functionality



Addition of new driver for Hyper-V called hv_utils.
This driver is intended to support things like KVP, Timesync, Heartbeat etc.

This first release has support for Gracefull shutdown.
e.g. Select shutdown from the Hyper-V main admin screen and the Linux VM
will do a gracefull shutdown.

Signed-off-by: default avatarHank Janssen <hjanssen@microsoft.com>
Signed-off-by: default avatarHaiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 92d0127c
Loading
Loading
Loading
Loading
+29 −5
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/module.h>
#include "osd.h"
#include "logging.h"
#include "VmbusPrivate.h"
@@ -666,8 +667,19 @@ void VmbusChannelClose(struct vmbus_channel *Channel)
	DPRINT_EXIT(VMBUS);
}

/*
 * VmbusChannelSendPacket - Send the specified buffer on the given channel
/**
 * VmbusChannelSendPacket() - Send the specified buffer on the given channel
 * @Channel: Pointer to vmbus_channel structure.
 * @Buffer: Pointer to the buffer you want to receive the data into.
 * @BufferLen: Maximum size of what the the buffer will hold
 * @RequestId: Identifier of the request
 * @vmbus_packet_type: Type of packet that is being send e.g. negotiate, time
 * packet etc.
 *
 * Sends data in @Buffer directly to hyper-v via the vmbus
 * This will send the data unparsed to hyper-v.
 *
 * Mainly used by Hyper-V drivers.
 */
int VmbusChannelSendPacket(struct vmbus_channel *Channel, const void *Buffer,
			   u32 BufferLen, u64 RequestId,
@@ -711,6 +723,7 @@ int VmbusChannelSendPacket(struct vmbus_channel *Channel, const void *Buffer,

	return ret;
}
EXPORT_SYMBOL(VmbusChannelSendPacket);

/*
 * VmbusChannelSendPacketPageBuffer - Send a range of single-page buffer
@@ -848,10 +861,20 @@ int VmbusChannelSendPacketMultiPageBuffer(struct vmbus_channel *Channel,
	return ret;
}

/*
 * VmbusChannelRecvPacket - Retrieve the user packet on the specified channel

/**
 * VmbusChannelRecvPacket() - Retrieve the user packet on the specified channel
 * @Channel: Pointer to vmbus_channel structure.
 * @Buffer: Pointer to the buffer you want to receive the data into.
 * @BufferLen: Maximum size of what the the buffer will hold
 * @BufferActualLen: The actual size of the data after it was received
 * @RequestId: Identifier of the request
 *
 * Receives directly from the hyper-v vmbus and puts the data it received
 * into Buffer. This will receive the data unparsed from hyper-v.
 *
 * Mainly used by Hyper-V drivers.
 */
/* TODO: Do we ever receive a gpa direct packet other than the ones we send ? */
int VmbusChannelRecvPacket(struct vmbus_channel *Channel, void *Buffer,
			   u32 BufferLen, u32 *BufferActualLen, u64 *RequestId)
{
@@ -913,6 +936,7 @@ int VmbusChannelRecvPacket(struct vmbus_channel *Channel, void *Buffer,

	return 0;
}
EXPORT_SYMBOL(VmbusChannelRecvPacket);

/*
 * VmbusChannelRecvPacketRaw - Retrieve the raw packet on the specified channel
+145 −3
Original line number Diff line number Diff line
@@ -22,16 +22,20 @@
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/module.h>
#include "osd.h"
#include "logging.h"
#include "VmbusPrivate.h"
#include "utils.h"

struct vmbus_channel_message_table_entry {
	enum vmbus_channel_message_type messageType;
	void (*messageHandler)(struct vmbus_channel_message_header *msg);
};

#define MAX_NUM_DEVICE_CLASSES_SUPPORTED 4
#define MAX_MSG_TYPES                    1
#define MAX_NUM_DEVICE_CLASSES_SUPPORTED 5

static const struct hv_guid
	gSupportedDeviceClasses[MAX_NUM_DEVICE_CLASSES_SUPPORTED] = {
	/* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
@@ -69,7 +73,126 @@ static const struct hv_guid
			0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5
		}
	},
	/* 0E0B6031-5213-4934-818B-38D90CED39DB */
	/* Shutdown */
	{
		.data = {
			0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
			0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB
		}
	},
};


/**
 * prep_negotiate_resp() - Create default response for Hyper-V Negotiate message
 * @icmsghdrp: Pointer to msg header structure
 * @icmsg_negotiate: Pointer to negotiate message structure
 * @buf: Raw buffer channel data
 *
 * @icmsghdrp is of type &struct icmsg_hdr.
 * @negop is of type &struct icmsg_negotiate.
 * Set up and fill in default negotiate response message. This response can
 * come from both the vmbus driver and the hv_utils driver. The current api
 * will respond properly to both Windows 2008 and Windows 2008-R2 operating
 * systems.
 *
 * Mainly used by Hyper-V drivers.
 */
void prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
			     struct icmsg_negotiate *negop,
			     u8 *buf)
{
	if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
		icmsghdrp->icmsgsize = 0x10;

		negop = (struct icmsg_negotiate *)&buf[
			sizeof(struct vmbuspipe_hdr) +
			sizeof(struct icmsg_hdr)];

		if (negop->icframe_vercnt == 2 &&
		   negop->icversion_data[1].major == 3) {
			negop->icversion_data[0].major = 3;
			negop->icversion_data[0].minor = 0;
			negop->icversion_data[1].major = 3;
			negop->icversion_data[1].minor = 0;
		} else {
			negop->icversion_data[0].major = 1;
			negop->icversion_data[0].minor = 0;
			negop->icversion_data[1].major = 1;
			negop->icversion_data[1].minor = 0;
		}

		negop->icframe_vercnt = 1;
		negop->icmsg_vercnt = 1;
	}
}
EXPORT_SYMBOL(prep_negotiate_resp);

/**
 * chn_cb_negotiate() - Default handler for non IDE/SCSI/NETWORK
 * Hyper-V requests
 * @context: Pointer to argument structure.
 *
 * Set up the default handler for non device driver specific requests
 * from Hyper-V. This stub responds to the default negotiate messages
 * that come in for every non IDE/SCSI/Network request.
 * This behavior is normally overwritten in the hv_utils driver. That
 * driver handles requests like gracefull shutdown, heartbeats etc.
 *
 * Mainly used by Hyper-V drivers.
 */
void chn_cb_negotiate(void *context)
{
	struct vmbus_channel *channel = context;
	u8 *buf;
	u32 buflen, recvlen;
	u64 requestid;

	struct icmsg_hdr *icmsghdrp;
	struct icmsg_negotiate *negop = NULL;

	buflen = PAGE_SIZE;
	buf = kmalloc(buflen, GFP_ATOMIC);

	VmbusChannelRecvPacket(channel, buf, buflen, &recvlen, &requestid);

	if (recvlen > 0) {
		icmsghdrp = (struct icmsg_hdr *)&buf[
			sizeof(struct vmbuspipe_hdr)];

		prep_negotiate_resp(icmsghdrp, negop, buf);

		icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
			| ICMSGHDRFLAG_RESPONSE;

		VmbusChannelSendPacket(channel, buf,
				       recvlen, requestid,
				       VmbusPacketTypeDataInBand, 0);
	}

	kfree(buf);
}
EXPORT_SYMBOL(chn_cb_negotiate);

/*
 * Function table used for message responses for non IDE/SCSI/Network type
 * messages. (Such as KVP/Shutdown etc)
 */
struct hyperv_service_callback hv_cb_utils[MAX_MSG_TYPES] = {
	/* 0E0B6031-5213-4934-818B-38D90CED39DB */
	/* Shutdown */
	{
		.msg_type = HV_SHUTDOWN_MSG,
		.data = {
			0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
			0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB
		},
		.callback = chn_cb_negotiate,
		.log_msg = "Shutdown channel functionality initialized"
	},
};
EXPORT_SYMBOL(hv_cb_utils);

/*
 * AllocVmbusChannel - Allocate and initialize a vmbus channel object
@@ -132,7 +255,8 @@ void FreeVmbusChannel(struct vmbus_channel *Channel)
}

/*
 * VmbusChannelProcessOffer - Process the offer by creating a channel/device associated with this offer
 * VmbusChannelProcessOffer - Process the offer by creating a channel/device
 * associated with this offer
 */
static void VmbusChannelProcessOffer(void *context)
{
@@ -140,6 +264,7 @@ static void VmbusChannelProcessOffer(void *context)
	struct vmbus_channel *channel;
	bool fNew = true;
	int ret;
	int cnt;
	unsigned long flags;

	DPRINT_ENTER(VMBUS);
@@ -209,6 +334,23 @@ static void VmbusChannelProcessOffer(void *context)
		 * can cleanup properly
		 */
		newChannel->State = CHANNEL_OPEN_STATE;
		cnt = 0;

		while (cnt != MAX_MSG_TYPES) {
			if (memcmp(&newChannel->OfferMsg.Offer.InterfaceType,
				   &hv_cb_utils[cnt].data,
				   sizeof(struct hv_guid)) == 0) {
				DPRINT_INFO(VMBUS, "%s",
					    hv_cb_utils[cnt].log_msg);

				if (VmbusChannelOpen(newChannel, 2 * PAGE_SIZE,
						    2 * PAGE_SIZE, NULL, 0,
						    hv_cb_utils[cnt].callback,
						    newChannel) == 0)
					hv_cb_utils[cnt].channel = newChannel;
			}
			cnt++;
		}
	}
	DPRINT_EXIT(VMBUS);
}
+6 −0
Original line number Diff line number Diff line
@@ -29,4 +29,10 @@ config HYPERV_NET
	help
	  Select this option to enable the Hyper-V virtual network driver.

config HYPERV_UTILS
	tristate "Microsoft Hyper-V Utilities driver"
	default HYPERV
	help
	  Select this option to enable the Hyper-V Utilities.

endif
+2 −0
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@ obj-$(CONFIG_HYPERV) += hv_vmbus.o
obj-$(CONFIG_HYPERV_STORAGE)	+= hv_storvsc.o
obj-$(CONFIG_HYPERV_BLOCK)	+= hv_blkvsc.o
obj-$(CONFIG_HYPERV_NET)	+= hv_netvsc.o
obj-$(CONFIG_HYPERV_UTILS)	+= hv_utils.o

hv_vmbus-objs := vmbus_drv.o osd.o \
		 Vmbus.o Hv.o Connection.o Channel.o \
@@ -9,3 +10,4 @@ hv_vmbus-objs := vmbus_drv.o osd.o \
hv_storvsc-objs := storvsc_drv.o StorVsc.o
hv_blkvsc-objs := blkvsc_drv.o BlkVsc.o
hv_netvsc-objs := netvsc_drv.o NetVsc.o RndisFilter.o
hv_utils-objs := hyperv_utils.o ext_utils.o
+1 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
 */

#ifndef _VMBUSPACKETFORMAT_H_
#define _VMBUSPACKETFORMAT_H_

struct vmpacket_descriptor {
	u16 Type;
Loading