Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F81969412
D5216.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
55 KB
Referenced Files
None
Subscribers
None
D5216.diff
View Options
Index: head/sys/conf/files.amd64
===================================================================
--- head/sys/conf/files.amd64
+++ head/sys/conf/files.amd64
@@ -266,7 +266,10 @@
dev/hyperv/netvsc/hv_rndis_filter.c optional hyperv
dev/hyperv/stordisengage/hv_ata_pci_disengage.c optional hyperv
dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c optional hyperv
+dev/hyperv/utilities/hv_heartbeat.c optional hyperv
dev/hyperv/utilities/hv_kvp.c optional hyperv
+dev/hyperv/utilities/hv_shutdown.c optional hyperv
+dev/hyperv/utilities/hv_timesync.c optional hyperv
dev/hyperv/utilities/hv_util.c optional hyperv
dev/hyperv/vmbus/hv_channel.c optional hyperv
dev/hyperv/vmbus/hv_channel_mgmt.c optional hyperv
Index: head/sys/conf/files.i386
===================================================================
--- head/sys/conf/files.i386
+++ head/sys/conf/files.i386
@@ -240,7 +240,10 @@
dev/hyperv/netvsc/hv_rndis_filter.c optional hyperv
dev/hyperv/stordisengage/hv_ata_pci_disengage.c optional hyperv
dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c optional hyperv
+dev/hyperv/utilities/hv_heartbeat.c optional hyperv
dev/hyperv/utilities/hv_kvp.c optional hyperv
+dev/hyperv/utilities/hv_shutdown.c optional hyperv
+dev/hyperv/utilities/hv_timesync.c optional hyperv
dev/hyperv/utilities/hv_util.c optional hyperv
dev/hyperv/vmbus/hv_channel.c optional hyperv
dev/hyperv/vmbus/hv_channel_mgmt.c optional hyperv
Index: head/sys/dev/hyperv/include/hyperv.h
===================================================================
--- head/sys/dev/hyperv/include/hyperv.h
+++ head/sys/dev/hyperv/include/hyperv.h
@@ -919,40 +919,5 @@
return (ret);
}
-
-/**
- * KVP related structures
- *
- */
-typedef struct hv_vmbus_service {
- hv_guid guid; /* Hyper-V GUID */
- char *name; /* name of service */
- boolean_t enabled; /* service enabled */
- void* context;
- struct task task;
- /*
- * function to initialize service
- */
- int (*init)(struct hv_vmbus_service *);
-
- /*
- * function to process Hyper-V messages
- */
- void (*callback)(void *);
-
- /*
- * function to uninitilize service
- */
- int (*uninit)(struct hv_vmbus_service *);
-} hv_vmbus_service;
-
-extern uint8_t* receive_buffer[];
-extern hv_vmbus_service service_table[];
extern uint32_t hv_vmbus_protocal_version;
-
-void hv_kvp_callback(void *context);
-int hv_kvp_init(hv_vmbus_service *serv);
-void hv_kvp_deinit(void);
-
#endif /* __HYPERV_H__ */
-
Index: head/sys/dev/hyperv/utilities/hv_heartbeat.c
===================================================================
--- head/sys/dev/hyperv/utilities/hv_heartbeat.c
+++ head/sys/dev/hyperv/utilities/hv_heartbeat.c
@@ -0,0 +1,129 @@
+/*-
+ * Copyright (c) 2014 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$
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/timetc.h>
+#include <sys/syscallsubr.h>
+
+#include <dev/hyperv/include/hyperv.h>
+#include "hv_util.h"
+
+/* Heartbeat Service */
+static hv_guid service_guid = { .data =
+ {0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e,
+ 0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d} };
+
+/**
+ * Process heartbeat message
+ */
+static void
+hv_heartbeat_cb(void *context)
+{
+ uint8_t* buf;
+ hv_vmbus_channel* channel;
+ uint32_t recvlen;
+ uint64_t requestid;
+ int ret;
+
+ struct hv_vmbus_heartbeat_msg_data* heartbeat_msg;
+ struct hv_vmbus_icmsg_hdr* icmsghdrp;
+ hv_util_sc *softc;
+
+ softc = (hv_util_sc*)context;
+ buf = softc->receive_buffer;;
+ channel = softc->hv_dev->channel;
+
+ ret = hv_vmbus_channel_recv_packet(channel, buf, PAGE_SIZE, &recvlen,
+ &requestid);
+
+ if ((ret == 0) && recvlen > 0) {
+
+ icmsghdrp = (struct hv_vmbus_icmsg_hdr *)
+ &buf[sizeof(struct hv_vmbus_pipe_hdr)];
+
+ if (icmsghdrp->icmsgtype == HV_ICMSGTYPE_NEGOTIATE) {
+ hv_negotiate_version(icmsghdrp, NULL, buf);
+
+ } else {
+ heartbeat_msg =
+ (struct hv_vmbus_heartbeat_msg_data *)
+ &buf[sizeof(struct hv_vmbus_pipe_hdr) +
+ sizeof(struct hv_vmbus_icmsg_hdr)];
+
+ heartbeat_msg->seq_num += 1;
+ }
+
+ 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);
+ }
+}
+
+static int
+hv_heartbeat_probe(device_t dev)
+{
+ const char *p = vmbus_get_type(dev);
+ if (!memcmp(p, &service_guid, sizeof(hv_guid))) {
+ device_set_desc(dev, "Hyper-V Heartbeat Service");
+ return BUS_PROBE_DEFAULT;
+ }
+
+ return ENXIO;
+}
+
+static int
+hv_heartbeat_attach(device_t dev)
+{
+ hv_util_sc *softc = (hv_util_sc*)device_get_softc(dev);
+
+ softc->callback = hv_heartbeat_cb;
+
+ return hv_util_attach(dev);
+}
+
+static device_method_t heartbeat_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, hv_heartbeat_probe),
+ DEVMETHOD(device_attach, hv_heartbeat_attach),
+ DEVMETHOD(device_detach, hv_util_detach),
+ { 0, 0 }
+};
+
+static driver_t heartbeat_driver = { "hvheartbeat", heartbeat_methods, sizeof(hv_util_sc)};
+
+static devclass_t heartbeat_devclass;
+
+DRIVER_MODULE(hv_heartbeat, vmbus, heartbeat_driver, heartbeat_devclass, NULL, NULL);
+MODULE_VERSION(hv_heartbeat, 1);
+MODULE_DEPEND(hv_heartbeat, vmbus, 1, 1, 1);
Index: head/sys/dev/hyperv/utilities/hv_kvp.h
===================================================================
--- head/sys/dev/hyperv/utilities/hv_kvp.h
+++ head/sys/dev/hyperv/utilities/hv_kvp.h
@@ -238,17 +238,4 @@
struct hv_kvp_ipaddr_value kvp_ip_val;
} __attribute__((packed));
-
-#define HV_SHUT_DOWN 0
-#define HV_TIME_SYNCH 1
-#define HV_HEART_BEAT 2
-#define HV_KVP 3
-#define HV_MAX_UTIL_SERVICES 4
-
-#define HV_WLTIMEDELTA 116444736000000000L /* in 100ns unit */
-#define HV_ICTIMESYNCFLAG_PROBE 0
-#define HV_ICTIMESYNCFLAG_SYNC 1
-#define HV_ICTIMESYNCFLAG_SAMPLE 2
-#define HV_NANO_SEC_PER_SEC 1000000000
-
#endif /* _KVP_H */
Index: head/sys/dev/hyperv/utilities/hv_kvp.c
===================================================================
--- head/sys/dev/hyperv/utilities/hv_kvp.c
+++ head/sys/dev/hyperv/utilities/hv_kvp.c
@@ -63,6 +63,7 @@
#include <dev/hyperv/include/hyperv.h>
#include <dev/hyperv/netvsc/hv_net_vsc.h>
+#include "hv_util.h"
#include "unicode.h"
#include "hv_kvp.h"
@@ -74,8 +75,6 @@
/* hv_kvp debug control */
static int hv_kvp_log = 0;
-SYSCTL_INT(_dev, OID_AUTO, hv_kvp_log, CTLFLAG_RW, &hv_kvp_log, 0,
- "hv_kvp log");
#define hv_kvp_log_error(...) do { \
if (hv_kvp_log > 0) \
@@ -87,6 +86,10 @@
log(LOG_INFO, "hv_kvp: " __VA_ARGS__); \
} while (0)
+static hv_guid service_guid = { .data =
+ {0xe7, 0xf4, 0xa0, 0xa9, 0x45, 0x5a, 0x96, 0x4d,
+ 0xb8, 0x27, 0x8a, 0x84, 0x1e, 0x8c, 0x3, 0xe6} };
+
/* character device prototypes */
static d_open_t hv_kvp_dev_open;
static d_close_t hv_kvp_dev_close;
@@ -94,12 +97,6 @@
static d_write_t hv_kvp_dev_daemon_write;
static d_poll_t hv_kvp_dev_daemon_poll;
-/* hv_kvp prototypes */
-static int hv_kvp_req_in_progress(void);
-static void hv_kvp_transaction_init(uint32_t, hv_vmbus_channel *, uint64_t, uint8_t *);
-static void hv_kvp_send_msg_to_daemon(void);
-static void hv_kvp_process_request(void *context, int pending);
-
/* hv_kvp character device structure */
static struct cdevsw hv_kvp_cdevsw =
{
@@ -111,67 +108,67 @@
.d_poll = hv_kvp_dev_daemon_poll,
.d_name = "hv_kvp_dev",
};
-static struct cdev *hv_kvp_dev;
-static struct hv_kvp_msg *hv_kvp_dev_buf;
-struct proc *daemon_task;
-static struct selinfo hv_kvp_selinfo;
/*
* Global state to track and synchronize multiple
* KVP transaction requests from the host.
*/
-static struct {
+typedef struct hv_kvp_sc {
+ struct hv_util_sc util_sc;
- /* Unless specified the pending mutex should be
+ /* Unless specified the pending mutex should be
* used to alter the values of the following paramters:
* 1. req_in_progress
* 2. req_timed_out
- * 3. pending_reqs.
*/
- struct mtx pending_mutex;
-
+ struct mtx pending_mutex;
+
+ struct task task;
+
/* To track if transaction is active or not */
- boolean_t req_in_progress;
+ boolean_t req_in_progress;
/* Tracks if daemon did not reply back in time */
- boolean_t req_timed_out;
+ boolean_t req_timed_out;
/* Tracks if daemon is serving a request currently */
boolean_t daemon_busy;
- /* Count of KVP requests from Hyper-V. */
- uint64_t pending_reqs;
-
-
- /* Length of host message */
- uint32_t host_msg_len;
- /* Pointer to channel */
- hv_vmbus_channel *channelp;
+ /* Length of host message */
+ uint32_t host_msg_len;
/* Host message id */
- uint64_t host_msg_id;
-
+ uint64_t host_msg_id;
+
/* Current kvp message from the host */
- struct hv_kvp_msg *host_kvp_msg;
-
+ struct hv_kvp_msg *host_kvp_msg;
+
/* Current kvp message for daemon */
- struct hv_kvp_msg daemon_kvp_msg;
-
+ struct hv_kvp_msg daemon_kvp_msg;
+
/* Rcv buffer for communicating with the host*/
- uint8_t *rcv_buf;
-
+ uint8_t *rcv_buf;
+
/* Device semaphore to control communication */
- struct sema dev_sema;
-
+ struct sema dev_sema;
+
/* Indicates if daemon registered with driver */
- boolean_t register_done;
-
+ boolean_t register_done;
+
/* Character device status */
- boolean_t dev_accessed;
-} kvp_globals;
+ boolean_t dev_accessed;
+
+ struct cdev *hv_kvp_dev;
+
+ struct proc *daemon_task;
-/* global vars */
-MALLOC_DECLARE(M_HV_KVP_DEV_BUF);
-MALLOC_DEFINE(M_HV_KVP_DEV_BUF, "hv_kvp_dev buffer", "buffer for hv_kvp_dev module");
+ struct selinfo hv_kvp_selinfo;
+} hv_kvp_sc;
+
+/* hv_kvp prototypes */
+static int hv_kvp_req_in_progress(hv_kvp_sc *sc);
+static void hv_kvp_transaction_init(hv_kvp_sc *sc, uint32_t, uint64_t, uint8_t *);
+static void hv_kvp_send_msg_to_daemon(hv_kvp_sc *sc);
+static void hv_kvp_process_request(void *context, int pending);
/*
* hv_kvp low level functions
@@ -181,10 +178,10 @@
* Check if kvp transaction is in progres
*/
static int
-hv_kvp_req_in_progress(void)
+hv_kvp_req_in_progress(hv_kvp_sc *sc)
{
- return (kvp_globals.req_in_progress);
+ return (sc->req_in_progress);
}
@@ -192,18 +189,17 @@
* This routine is called whenever a message is received from the host
*/
static void
-hv_kvp_transaction_init(uint32_t rcv_len, hv_vmbus_channel *rcv_channel,
+hv_kvp_transaction_init(hv_kvp_sc *sc, uint32_t rcv_len,
uint64_t request_id, uint8_t *rcv_buf)
{
-
+
/* Store all the relevant message details in the global structure */
/* Do not need to use mutex for req_in_progress here */
- kvp_globals.req_in_progress = true;
- kvp_globals.host_msg_len = rcv_len;
- kvp_globals.channelp = rcv_channel;
- kvp_globals.host_msg_id = request_id;
- kvp_globals.rcv_buf = rcv_buf;
- kvp_globals.host_kvp_msg = (struct hv_kvp_msg *)&rcv_buf[
+ sc->req_in_progress = true;
+ sc->host_msg_len = rcv_len;
+ sc->host_msg_id = request_id;
+ sc->rcv_buf = rcv_buf;
+ sc->host_kvp_msg = (struct hv_kvp_msg *)&rcv_buf[
sizeof(struct hv_vmbus_pipe_hdr) +
sizeof(struct hv_vmbus_icmsg_hdr)];
}
@@ -255,12 +251,12 @@
* Convert ip related info in umsg from utf8 to utf16 and store in hmsg
*/
static int
-hv_kvp_convert_utf8_ipinfo_to_utf16(struct hv_kvp_msg *umsg,
+hv_kvp_convert_utf8_ipinfo_to_utf16(struct hv_kvp_msg *umsg,
struct hv_kvp_ip_msg *host_ip_msg)
{
int err_ip, err_subnet, err_gway, err_dns, err_adap;
int UNUSED_FLAG = 1;
-
+
utf8_to_utf16((uint16_t *)host_ip_msg->kvp_ip_val.ip_addr,
MAX_IP_ADDR_SIZE,
(char *)umsg->body.kvp_ip_val.ip_addr,
@@ -291,7 +287,7 @@
strlen((char *)umsg->body.kvp_ip_val.adapter_id),
UNUSED_FLAG,
&err_adap);
-
+
host_ip_msg->kvp_ip_val.dhcp_enabled = umsg->body.kvp_ip_val.dhcp_enabled;
host_ip_msg->kvp_ip_val.addr_family = umsg->body.kvp_ip_val.addr_family;
@@ -386,7 +382,7 @@
MAX_IP_ADDR_SIZE,
UNUSED_FLAG,
&err_subnet);
-
+
utf16_to_utf8((char *)umsg->body.kvp_ip_val.gate_way, MAX_GATEWAY_SIZE,
(uint16_t *)host_ip_msg->kvp_ip_val.gate_way,
MAX_GATEWAY_SIZE,
@@ -408,16 +404,13 @@
* Ensure utf16_utf8 takes care of the additional string terminating char!!
*/
static void
-hv_kvp_convert_hostmsg_to_usermsg(void)
+hv_kvp_convert_hostmsg_to_usermsg(struct hv_kvp_msg *hmsg, struct hv_kvp_msg *umsg)
{
int utf_err = 0;
uint32_t value_type;
- struct hv_kvp_ip_msg *host_ip_msg = (struct hv_kvp_ip_msg *)
- kvp_globals.host_kvp_msg;
-
- struct hv_kvp_msg *hmsg = kvp_globals.host_kvp_msg;
- struct hv_kvp_msg *umsg = &kvp_globals.daemon_kvp_msg;
+ struct hv_kvp_ip_msg *host_ip_msg;
+ host_ip_msg = (struct hv_kvp_ip_msg*)hmsg;
memset(umsg, 0, sizeof(struct hv_kvp_msg));
umsg->kvp_hdr.operation = hmsg->kvp_hdr.operation;
@@ -522,14 +515,12 @@
* Prepare a host kvp msg based on user kvp msg (utf8 to utf16)
*/
static int
-hv_kvp_convert_usermsg_to_hostmsg(void)
+hv_kvp_convert_usermsg_to_hostmsg(struct hv_kvp_msg *umsg, struct hv_kvp_msg *hmsg)
{
int hkey_len = 0, hvalue_len = 0, utf_err = 0;
struct hv_kvp_exchg_msg_value *host_exchg_data;
char *key_name, *value;
- struct hv_kvp_msg *umsg = &kvp_globals.daemon_kvp_msg;
- struct hv_kvp_msg *hmsg = kvp_globals.host_kvp_msg;
struct hv_kvp_ip_msg *host_ip_msg = (struct hv_kvp_ip_msg *)hmsg;
switch (hmsg->kvp_hdr.operation) {
@@ -561,7 +552,7 @@
if ((hkey_len < 0) || (hvalue_len < 0))
return (HV_KVP_E_FAIL);
-
+
return (KVP_SUCCESS);
case HV_KVP_OP_GET:
@@ -577,9 +568,9 @@
/* Use values by string */
host_exchg_data->value_type = HV_REG_SZ;
- if ((hkey_len < 0) || (hvalue_len < 0))
+ if ((hkey_len < 0) || (hvalue_len < 0))
return (HV_KVP_E_FAIL);
-
+
return (KVP_SUCCESS);
default:
@@ -592,22 +583,22 @@
* Send the response back to the host.
*/
static void
-hv_kvp_respond_host(int error)
+hv_kvp_respond_host(hv_kvp_sc *sc, int error)
{
struct hv_vmbus_icmsg_hdr *hv_icmsg_hdrp;
hv_icmsg_hdrp = (struct hv_vmbus_icmsg_hdr *)
- &kvp_globals.rcv_buf[sizeof(struct hv_vmbus_pipe_hdr)];
+ &sc->rcv_buf[sizeof(struct hv_vmbus_pipe_hdr)];
if (error)
error = HV_KVP_E_FAIL;
hv_icmsg_hdrp->status = error;
hv_icmsg_hdrp->icflags = HV_ICMSGHDRFLAG_TRANSACTION | HV_ICMSGHDRFLAG_RESPONSE;
-
- error = hv_vmbus_channel_send_packet(kvp_globals.channelp,
- kvp_globals.rcv_buf,
- kvp_globals.host_msg_len, kvp_globals.host_msg_id,
+
+ error = hv_vmbus_channel_send_packet(sc->util_sc.hv_dev->channel,
+ sc->rcv_buf,
+ sc->host_msg_len, sc->host_msg_id,
HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0);
if (error)
@@ -621,16 +612,19 @@
* and the host
*/
static void
-hv_kvp_send_msg_to_daemon(void)
+hv_kvp_send_msg_to_daemon(hv_kvp_sc *sc)
{
+ struct hv_kvp_msg *hmsg = sc->host_kvp_msg;
+ struct hv_kvp_msg *umsg = &sc->daemon_kvp_msg;
+
/* Prepare kvp_msg to be sent to user */
- hv_kvp_convert_hostmsg_to_usermsg();
+ hv_kvp_convert_hostmsg_to_usermsg(hmsg, umsg);
/* Send the msg to user via function deamon_read - setting sema */
- sema_post(&kvp_globals.dev_sema);
+ sema_post(&sc->dev_sema);
/* We should wake up the daemon, in case it's doing poll() */
- selwakeup(&hv_kvp_selinfo);
+ selwakeup(&sc->hv_kvp_selinfo);
}
@@ -642,95 +636,80 @@
hv_kvp_process_request(void *context, int pending)
{
uint8_t *kvp_buf;
- hv_vmbus_channel *channel = context;
+ hv_vmbus_channel *channel;
uint32_t recvlen = 0;
uint64_t requestid;
struct hv_vmbus_icmsg_hdr *icmsghdrp;
int ret = 0;
- uint64_t pending_cnt = 1;
-
+ hv_kvp_sc *sc;
+
hv_kvp_log_info("%s: entering hv_kvp_process_request\n", __func__);
- kvp_buf = receive_buffer[HV_KVP];
+
+ sc = (hv_kvp_sc*)context;
+ kvp_buf = sc->util_sc.receive_buffer;;
+ channel = sc->util_sc.hv_dev->channel;
+
ret = hv_vmbus_channel_recv_packet(channel, kvp_buf, 2 * PAGE_SIZE,
&recvlen, &requestid);
- /*
- * We start counting only after the daemon registers
- * and therefore there could be requests pending in
- * the VMBus that are not reflected in pending_cnt.
- * Therefore we continue reading as long as either of
- * the below conditions is true.
- */
+ while ((ret == 0) && (recvlen > 0)) {
+
+ icmsghdrp = (struct hv_vmbus_icmsg_hdr *)
+ &kvp_buf[sizeof(struct hv_vmbus_pipe_hdr)];
- while ((pending_cnt>0) || ((ret == 0) && (recvlen > 0))) {
+ hv_kvp_transaction_init(sc, recvlen, requestid, kvp_buf);
+ if (icmsghdrp->icmsgtype == HV_ICMSGTYPE_NEGOTIATE) {
+ hv_kvp_negotiate_version(icmsghdrp, NULL, kvp_buf);
+ hv_kvp_respond_host(sc, ret);
+
+ /*
+ * It is ok to not acquire the mutex before setting
+ * req_in_progress here because negotiation is the
+ * first thing that happens and hence there is no
+ * chance of a race condition.
+ */
+
+ sc->req_in_progress = false;
+ hv_kvp_log_info("%s :version negotiated\n", __func__);
+
+ } else {
+ if (!sc->daemon_busy) {
+
+ hv_kvp_log_info("%s: issuing qury to daemon\n", __func__);
+ mtx_lock(&sc->pending_mutex);
+ sc->req_timed_out = false;
+ sc->daemon_busy = true;
+ mtx_unlock(&sc->pending_mutex);
- if ((ret == 0) && (recvlen>0)) {
-
- icmsghdrp = (struct hv_vmbus_icmsg_hdr *)
- &kvp_buf[sizeof(struct hv_vmbus_pipe_hdr)];
-
- hv_kvp_transaction_init(recvlen, channel, requestid, kvp_buf);
- if (icmsghdrp->icmsgtype == HV_ICMSGTYPE_NEGOTIATE) {
- hv_kvp_negotiate_version(icmsghdrp, NULL, kvp_buf);
- hv_kvp_respond_host(ret);
-
- /*
- * It is ok to not acquire the mutex before setting
- * req_in_progress here because negotiation is the
- * first thing that happens and hence there is no
- * chance of a race condition.
- */
-
- kvp_globals.req_in_progress = false;
- hv_kvp_log_info("%s :version negotiated\n", __func__);
-
- } else {
- if (!kvp_globals.daemon_busy) {
-
- hv_kvp_log_info("%s: issuing qury to daemon\n", __func__);
- mtx_lock(&kvp_globals.pending_mutex);
- kvp_globals.req_timed_out = false;
- kvp_globals.daemon_busy = true;
- mtx_unlock(&kvp_globals.pending_mutex);
-
- hv_kvp_send_msg_to_daemon();
- hv_kvp_log_info("%s: waiting for daemon\n", __func__);
- }
-
- /* Wait 5 seconds for daemon to respond back */
- tsleep(&kvp_globals, 0, "kvpworkitem", 5 * hz);
- hv_kvp_log_info("%s: came out of wait\n", __func__);
+ hv_kvp_send_msg_to_daemon(sc);
+ hv_kvp_log_info("%s: waiting for daemon\n", __func__);
}
+
+ /* Wait 5 seconds for daemon to respond back */
+ tsleep(sc, 0, "kvpworkitem", 5 * hz);
+ hv_kvp_log_info("%s: came out of wait\n", __func__);
}
- mtx_lock(&kvp_globals.pending_mutex);
-
+ mtx_lock(&sc->pending_mutex);
+
/* Notice that once req_timed_out is set to true
* it will remain true until the next request is
* sent to the daemon. The response from daemon
- * is forwarded to host only when this flag is
- * false.
+ * is forwarded to host only when this flag is
+ * false.
*/
- kvp_globals.req_timed_out = true;
+ sc->req_timed_out = true;
/*
* Cancel request if so need be.
*/
- if (hv_kvp_req_in_progress()) {
+ if (hv_kvp_req_in_progress(sc)) {
hv_kvp_log_info("%s: request was still active after wait so failing\n", __func__);
- hv_kvp_respond_host(HV_KVP_E_FAIL);
- kvp_globals.req_in_progress = false;
- }
-
- /*
- * Decrement pending request count and
- */
- if (kvp_globals.pending_reqs>0) {
- kvp_globals.pending_reqs = kvp_globals.pending_reqs - 1;
+ hv_kvp_respond_host(sc, HV_KVP_E_FAIL);
+ sc->req_in_progress = false;
}
- pending_cnt = kvp_globals.pending_reqs;
-
- mtx_unlock(&kvp_globals.pending_mutex);
+
+ mtx_unlock(&sc->pending_mutex);
/*
* Try reading next buffer
@@ -738,104 +717,43 @@
recvlen = 0;
ret = hv_vmbus_channel_recv_packet(channel, kvp_buf, 2 * PAGE_SIZE,
&recvlen, &requestid);
- hv_kvp_log_info("%s: read: context %p, pending_cnt %llu ret =%d, recvlen=%d\n",
- __func__, context, (unsigned long long)pending_cnt, ret, recvlen);
- }
+ hv_kvp_log_info("%s: read: context %p, ret =%d, recvlen=%d\n",
+ __func__, context, ret, recvlen);
+ }
}
/*
* Callback routine that gets called whenever there is a message from host
*/
-void
+static void
hv_kvp_callback(void *context)
{
- uint64_t pending_cnt = 0;
-
- if (kvp_globals.register_done == false) {
- kvp_globals.channelp = context;
- TASK_INIT(&service_table[HV_KVP].task, 0, hv_kvp_process_request, 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__);
- taskqueue_enqueue(taskqueue_thread, &service_table[HV_KVP].task);
- }
- }
-}
-
-
-/*
- * This function is called by the hv_kvp_init -
- * creates character device hv_kvp_dev
- * allocates memory to hv_kvp_dev_buf
- *
- */
-static int
-hv_kvp_dev_init(void)
-{
- int error = 0;
-
- /* initialize semaphore */
- sema_init(&kvp_globals.dev_sema, 0, "hv_kvp device semaphore");
- /* create character device */
- error = make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK,
- &hv_kvp_dev,
- &hv_kvp_cdevsw,
- 0,
- UID_ROOT,
- GID_WHEEL,
- 0640,
- "hv_kvp_dev");
-
- if (error != 0)
- return (error);
-
+ hv_kvp_sc *sc = (hv_kvp_sc*)context;
/*
- * Malloc with M_WAITOK flag will never fail.
- */
- hv_kvp_dev_buf = malloc(sizeof(*hv_kvp_dev_buf), M_HV_KVP_DEV_BUF, M_WAITOK |
- M_ZERO);
-
- return (0);
-}
-
-
-/*
- * This function is called by the hv_kvp_deinit -
- * destroy character device
- */
-static void
-hv_kvp_dev_destroy(void)
-{
-
- if (daemon_task != NULL) {
- PROC_LOCK(daemon_task);
- kern_psignal(daemon_task, SIGKILL);
- PROC_UNLOCK(daemon_task);
+ The first request from host will not be handled until daemon is registered.
+ when callback is triggered without a registered daemon, callback just return.
+ When a new daemon gets regsitered, this callbcak is trigged from _write op.
+ */
+ if (sc->register_done) {
+ hv_kvp_log_info("%s: Queuing work item\n", __func__);
+ taskqueue_enqueue(taskqueue_thread, &sc->task);
}
-
- destroy_dev(hv_kvp_dev);
- free(hv_kvp_dev_buf, M_HV_KVP_DEV_BUF);
- return;
}
-
static int
hv_kvp_dev_open(struct cdev *dev, int oflags, int devtype,
struct thread *td)
{
-
+ hv_kvp_sc *sc = (hv_kvp_sc*)dev->si_drv1;
+
hv_kvp_log_info("%s: Opened device \"hv_kvp_device\" successfully.\n", __func__);
- if (kvp_globals.dev_accessed)
+ if (sc->dev_accessed)
return (-EBUSY);
-
- daemon_task = curproc;
- kvp_globals.dev_accessed = true;
- kvp_globals.daemon_busy = false;
+
+ sc->daemon_task = curproc;
+ sc->dev_accessed = true;
+ sc->daemon_busy = false;
return (0);
}
@@ -844,10 +762,11 @@
hv_kvp_dev_close(struct cdev *dev __unused, int fflag __unused, int devtype __unused,
struct thread *td __unused)
{
+ hv_kvp_sc *sc = (hv_kvp_sc*)dev->si_drv1;
hv_kvp_log_info("%s: Closing device \"hv_kvp_device\".\n", __func__);
- kvp_globals.dev_accessed = false;
- kvp_globals.register_done = false;
+ sc->dev_accessed = false;
+ sc->register_done = false;
return (0);
}
@@ -857,18 +776,21 @@
* acts as a send to daemon
*/
static int
-hv_kvp_dev_daemon_read(struct cdev *dev __unused, struct uio *uio, int ioflag __unused)
+hv_kvp_dev_daemon_read(struct cdev *dev, struct uio *uio, int ioflag __unused)
{
size_t amt;
int error = 0;
+ struct hv_kvp_msg *hv_kvp_dev_buf;
+ hv_kvp_sc *sc = (hv_kvp_sc*)dev->si_drv1;
/* Check hv_kvp daemon registration status*/
- if (!kvp_globals.register_done)
+ if (!sc->register_done)
return (KVP_ERROR);
- sema_wait(&kvp_globals.dev_sema);
+ sema_wait(&sc->dev_sema);
- memcpy(hv_kvp_dev_buf, &kvp_globals.daemon_kvp_msg, sizeof(struct hv_kvp_msg));
+ hv_kvp_dev_buf = malloc(sizeof(*hv_kvp_dev_buf), M_TEMP, M_WAITOK);
+ memcpy(hv_kvp_dev_buf, &sc->daemon_kvp_msg, sizeof(struct hv_kvp_msg));
amt = MIN(uio->uio_resid, uio->uio_offset >= BUFFERSIZE + 1 ? 0 :
BUFFERSIZE + 1 - uio->uio_offset);
@@ -876,6 +798,7 @@
if ((error = uiomove(hv_kvp_dev_buf, amt, uio)) != 0)
hv_kvp_log_info("%s: hv_kvp uiomove read failed!\n", __func__);
+ free(hv_kvp_dev_buf, M_TEMP);
return (error);
}
@@ -885,29 +808,30 @@
* acts as a recieve from daemon
*/
static int
-hv_kvp_dev_daemon_write(struct cdev *dev __unused, struct uio *uio, int ioflag __unused)
+hv_kvp_dev_daemon_write(struct cdev *dev, struct uio *uio, int ioflag __unused)
{
size_t amt;
int error = 0;
+ struct hv_kvp_msg *hv_kvp_dev_buf;
+ hv_kvp_sc *sc = (hv_kvp_sc*)dev->si_drv1;
uio->uio_offset = 0;
+ hv_kvp_dev_buf = malloc(sizeof(*hv_kvp_dev_buf), M_TEMP, M_WAITOK);
amt = MIN(uio->uio_resid, BUFFERSIZE);
error = uiomove(hv_kvp_dev_buf, amt, uio);
- if (error != 0)
+ if (error != 0) {
+ free(hv_kvp_dev_buf, M_TEMP);
return (error);
+ }
+ memcpy(&sc->daemon_kvp_msg, hv_kvp_dev_buf, sizeof(struct hv_kvp_msg));
- memcpy(&kvp_globals.daemon_kvp_msg, hv_kvp_dev_buf, sizeof(struct hv_kvp_msg));
-
- if (kvp_globals.register_done == false) {
- if (kvp_globals.daemon_kvp_msg.kvp_hdr.operation == HV_KVP_OP_REGISTER) {
-
- kvp_globals.register_done = true;
- if (kvp_globals.channelp) {
-
- hv_kvp_callback(kvp_globals.channelp);
- }
+ free(hv_kvp_dev_buf, M_TEMP);
+ if (sc->register_done == false) {
+ if (sc->daemon_kvp_msg.kvp_hdr.operation == HV_KVP_OP_REGISTER) {
+ sc->register_done = true;
+ hv_kvp_callback(dev->si_drv1);
}
else {
hv_kvp_log_info("%s, KVP Registration Failed\n", __func__);
@@ -915,18 +839,20 @@
}
} else {
- mtx_lock(&kvp_globals.pending_mutex);
+ mtx_lock(&sc->pending_mutex);
- if(!kvp_globals.req_timed_out) {
-
- hv_kvp_convert_usermsg_to_hostmsg();
- hv_kvp_respond_host(KVP_SUCCESS);
- wakeup(&kvp_globals);
- kvp_globals.req_in_progress = false;
+ if(!sc->req_timed_out) {
+ struct hv_kvp_msg *hmsg = sc->host_kvp_msg;
+ struct hv_kvp_msg *umsg = &sc->daemon_kvp_msg;
+
+ hv_kvp_convert_usermsg_to_hostmsg(umsg, hmsg);
+ hv_kvp_respond_host(sc, KVP_SUCCESS);
+ wakeup(sc);
+ sc->req_in_progress = false;
}
- kvp_globals.daemon_busy = false;
- mtx_unlock(&kvp_globals.pending_mutex);
+ sc->daemon_busy = false;
+ mtx_unlock(&sc->pending_mutex);
}
return (error);
@@ -938,53 +864,106 @@
* for daemon to read.
*/
static int
-hv_kvp_dev_daemon_poll(struct cdev *dev __unused, int events, struct thread *td)
+hv_kvp_dev_daemon_poll(struct cdev *dev, int events, struct thread *td)
{
int revents = 0;
+ hv_kvp_sc *sc = (hv_kvp_sc*)dev->si_drv1;
- mtx_lock(&kvp_globals.pending_mutex);
+ mtx_lock(&sc->pending_mutex);
/*
* We check global flag daemon_busy for the data availiability for
* userland to read. Deamon_busy is set to true before driver has data
* for daemon to read. It is set to false after daemon sends
* then response back to driver.
*/
- if (kvp_globals.daemon_busy == true)
+ if (sc->daemon_busy == true)
revents = POLLIN;
else
- selrecord(td, &hv_kvp_selinfo);
+ selrecord(td, &sc->hv_kvp_selinfo);
- mtx_unlock(&kvp_globals.pending_mutex);
+ mtx_unlock(&sc->pending_mutex);
return (revents);
}
+static int
+hv_kvp_probe(device_t dev)
+{
+ const char *p = vmbus_get_type(dev);
+ if (!memcmp(p, &service_guid, sizeof(hv_guid))) {
+ device_set_desc(dev, "Hyper-V KVP Service");
+ return BUS_PROBE_DEFAULT;
+ }
-/*
- * hv_kvp initialization function
- * called from hv_util service.
- *
- */
-int
-hv_kvp_init(hv_vmbus_service *srv)
+ return ENXIO;
+}
+
+static int
+hv_kvp_attach(device_t dev)
{
- int error = 0;
+ int error;
+ struct sysctl_oid_list *child;
+ struct sysctl_ctx_list *ctx;
- memset(&kvp_globals, 0, sizeof(kvp_globals));
+ hv_kvp_sc *sc = (hv_kvp_sc*)device_get_softc(dev);
- error = hv_kvp_dev_init();
- mtx_init(&kvp_globals.pending_mutex, "hv-kvp pending mutex",
+ sc->util_sc.callback = hv_kvp_callback;
+ sema_init(&sc->dev_sema, 0, "hv_kvp device semaphore");
+ mtx_init(&sc->pending_mutex, "hv-kvp pending mutex",
NULL, MTX_DEF);
- return (error);
-}
+ ctx = device_get_sysctl_ctx(dev);
+ child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
+
+ SYSCTL_ADD_INT(ctx, child, OID_AUTO, "hv_kvp_log",
+ CTLFLAG_RW, &hv_kvp_log, 0, "Hyperv KVP service log level");
+
+ TASK_INIT(&sc->task, 0, hv_kvp_process_request, sc);
+
+ /* create character device */
+ error = make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK,
+ &sc->hv_kvp_dev,
+ &hv_kvp_cdevsw,
+ 0,
+ UID_ROOT,
+ GID_WHEEL,
+ 0640,
+ "hv_kvp_dev");
+
+ if (error != 0)
+ return (error);
+ sc->hv_kvp_dev->si_drv1 = sc;
+ return hv_util_attach(dev);
+}
-void
-hv_kvp_deinit(void)
+static int
+hv_kvp_detach(device_t dev)
{
- hv_kvp_dev_destroy();
- mtx_destroy(&kvp_globals.pending_mutex);
+ hv_kvp_sc *sc = (hv_kvp_sc*)device_get_softc(dev);
- return;
+ if (sc->daemon_task != NULL) {
+ PROC_LOCK(sc->daemon_task);
+ kern_psignal(sc->daemon_task, SIGKILL);
+ PROC_UNLOCK(sc->daemon_task);
+ }
+
+ destroy_dev(sc->hv_kvp_dev);
+ return hv_util_detach(dev);
}
+
+static device_method_t kvp_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, hv_kvp_probe),
+ DEVMETHOD(device_attach, hv_kvp_attach),
+ DEVMETHOD(device_detach, hv_kvp_detach),
+ { 0, 0 }
+};
+
+static driver_t kvp_driver = { "hvkvp", kvp_methods, sizeof(hv_kvp_sc)};
+
+static devclass_t kvp_devclass;
+
+DRIVER_MODULE(hv_kvp, vmbus, kvp_driver, kvp_devclass, NULL, NULL);
+MODULE_VERSION(hv_kvp, 1);
+MODULE_DEPEND(hv_kvp, vmbus, 1, 1, 1);
Index: head/sys/dev/hyperv/utilities/hv_shutdown.c
===================================================================
--- head/sys/dev/hyperv/utilities/hv_shutdown.c
+++ head/sys/dev/hyperv/utilities/hv_shutdown.c
@@ -0,0 +1,151 @@
+/*-
+ * Copyright (c) 2014 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$
+ */
+
+/*
+ * A common driver for all hyper-V util services.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/reboot.h>
+#include <sys/timetc.h>
+#include <sys/syscallsubr.h>
+
+#include <dev/hyperv/include/hyperv.h>
+#include "hv_util.h"
+
+static hv_guid service_guid = { .data =
+ {0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
+ 0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB} };
+
+/**
+ * Shutdown
+ */
+static void
+hv_shutdown_cb(void *context)
+{
+ uint8_t* buf;
+ hv_vmbus_channel* channel;
+ uint8_t execute_shutdown = 0;
+ hv_vmbus_icmsg_hdr* icmsghdrp;
+ uint32_t recv_len;
+ uint64_t request_id;
+ int ret;
+ hv_vmbus_shutdown_msg_data* shutdown_msg;
+ hv_util_sc *softc;
+
+ softc = (hv_util_sc*)context;
+ buf = softc->receive_buffer;;
+ channel = softc->hv_dev->channel;
+ ret = hv_vmbus_channel_recv_packet(channel, buf, PAGE_SIZE,
+ &recv_len, &request_id);
+
+ if ((ret == 0) && recv_len > 0) {
+
+ icmsghdrp = (struct hv_vmbus_icmsg_hdr *)
+ &buf[sizeof(struct hv_vmbus_pipe_hdr)];
+
+ if (icmsghdrp->icmsgtype == HV_ICMSGTYPE_NEGOTIATE) {
+ hv_negotiate_version(icmsghdrp, NULL, buf);
+
+ } else {
+ shutdown_msg =
+ (struct hv_vmbus_shutdown_msg_data *)
+ &buf[sizeof(struct hv_vmbus_pipe_hdr) +
+ sizeof(struct hv_vmbus_icmsg_hdr)];
+
+ switch (shutdown_msg->flags) {
+ case 0:
+ case 1:
+ icmsghdrp->status = HV_S_OK;
+ execute_shutdown = 1;
+ if(bootverbose)
+ printf("Shutdown request received -"
+ " graceful shutdown initiated\n");
+ break;
+ default:
+ icmsghdrp->status = HV_E_FAIL;
+ execute_shutdown = 0;
+ printf("Shutdown request received -"
+ " Invalid request\n");
+ break;
+ }
+ }
+
+ icmsghdrp->icflags = HV_ICMSGHDRFLAG_TRANSACTION |
+ HV_ICMSGHDRFLAG_RESPONSE;
+
+ hv_vmbus_channel_send_packet(channel, buf,
+ recv_len, request_id,
+ HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0);
+ }
+
+ if (execute_shutdown)
+ shutdown_nice(RB_POWEROFF);
+}
+
+static int
+hv_shutdown_probe(device_t dev)
+{
+ const char *p = vmbus_get_type(dev);
+ if (!memcmp(p, &service_guid, sizeof(hv_guid))) {
+ device_set_desc(dev, "Hyper-V Shutdown Service");
+ return BUS_PROBE_DEFAULT;
+ }
+
+ return ENXIO;
+}
+
+static int
+hv_shutdown_attach(device_t dev)
+{
+ hv_util_sc *softc = (hv_util_sc*)device_get_softc(dev);
+
+ softc->callback = hv_shutdown_cb;
+
+ return hv_util_attach(dev);
+}
+
+static device_method_t shutdown_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, hv_shutdown_probe),
+ DEVMETHOD(device_attach, hv_shutdown_attach),
+ DEVMETHOD(device_detach, hv_util_detach),
+ { 0, 0 }
+};
+
+static driver_t shutdown_driver = { "hvshutdown", shutdown_methods, sizeof(hv_util_sc)};
+
+static devclass_t shutdown_devclass;
+
+DRIVER_MODULE(hv_shutdown, vmbus, shutdown_driver, shutdown_devclass, NULL, NULL);
+MODULE_VERSION(hv_shutdown, 1);
+MODULE_DEPEND(hv_shutdown, vmbus, 1, 1, 1);
Index: head/sys/dev/hyperv/utilities/hv_timesync.c
===================================================================
--- head/sys/dev/hyperv/utilities/hv_timesync.c
+++ head/sys/dev/hyperv/utilities/hv_timesync.c
@@ -0,0 +1,216 @@
+/*-
+ * Copyright (c) 2014 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$
+ */
+
+/*
+ * A common driver for all hyper-V util services.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/reboot.h>
+#include <sys/timetc.h>
+#include <sys/syscallsubr.h>
+
+#include <dev/hyperv/include/hyperv.h>
+#include "hv_util.h"
+
+#define HV_WLTIMEDELTA 116444736000000000L /* in 100ns unit */
+#define HV_ICTIMESYNCFLAG_PROBE 0
+#define HV_ICTIMESYNCFLAG_SYNC 1
+#define HV_ICTIMESYNCFLAG_SAMPLE 2
+#define HV_NANO_SEC_PER_SEC 1000000000
+
+/* Time Sync data */
+typedef struct {
+ uint64_t data;
+} time_sync_data;
+
+ /* Time Synch Service */
+static hv_guid service_guid = {.data =
+ {0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
+ 0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf } };
+
+struct hv_ictimesync_data {
+ uint64_t parenttime;
+ uint64_t childtime;
+ uint64_t roundtriptime;
+ uint8_t flags;
+} __packed;
+
+typedef struct hv_timesync_sc {
+ hv_util_sc util_sc;
+ struct task task;
+ time_sync_data time_msg;
+} hv_timesync_sc;
+
+/**
+ * Set host time based on time sync message from host
+ */
+static void
+hv_set_host_time(void *context, int pending)
+{
+ hv_timesync_sc *softc = (hv_timesync_sc*)context;
+ uint64_t hosttime = softc->time_msg.data;
+ struct timespec guest_ts, host_ts;
+ uint64_t host_tns;
+ int64_t diff;
+ int error;
+
+ host_tns = (hosttime - HV_WLTIMEDELTA) * 100;
+ host_ts.tv_sec = (time_t)(host_tns/HV_NANO_SEC_PER_SEC);
+ host_ts.tv_nsec = (long)(host_tns%HV_NANO_SEC_PER_SEC);
+
+ nanotime(&guest_ts);
+
+ diff = (int64_t)host_ts.tv_sec - (int64_t)guest_ts.tv_sec;
+
+ /*
+ * If host differs by 5 seconds then make the guest catch up
+ */
+ if (diff > 5 || diff < -5) {
+ error = kern_clock_settime(curthread, CLOCK_REALTIME,
+ &host_ts);
+ }
+}
+
+/**
+ * @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(hv_timesync_sc *sc, uint64_t hosttime, uint8_t flags)
+{
+ sc->time_msg.data = hosttime;
+
+ if (((flags & HV_ICTIMESYNCFLAG_SYNC) != 0) ||
+ ((flags & HV_ICTIMESYNCFLAG_SAMPLE) != 0)) {
+ taskqueue_enqueue(taskqueue_thread, &sc->task);
+ }
+}
+
+/**
+ * Time Sync Channel message handler
+ */
+static void
+hv_timesync_cb(void *context)
+{
+ hv_vmbus_channel* channel;
+ hv_vmbus_icmsg_hdr* icmsghdrp;
+ uint32_t recvlen;
+ uint64_t requestId;
+ int ret;
+ uint8_t* time_buf;
+ struct hv_ictimesync_data* timedatap;
+ hv_timesync_sc *softc;
+
+ softc = (hv_timesync_sc*)context;
+ channel = softc->util_sc.hv_dev->channel;
+ time_buf = softc->util_sc.receive_buffer;
+
+ ret = hv_vmbus_channel_recv_packet(channel, time_buf,
+ PAGE_SIZE, &recvlen, &requestId);
+
+ if ((ret == 0) && recvlen > 0) {
+ icmsghdrp = (struct hv_vmbus_icmsg_hdr *) &time_buf[
+ sizeof(struct hv_vmbus_pipe_hdr)];
+
+ if (icmsghdrp->icmsgtype == HV_ICMSGTYPE_NEGOTIATE) {
+ hv_negotiate_version(icmsghdrp, NULL, time_buf);
+ } else {
+ timedatap = (struct hv_ictimesync_data *) &time_buf[
+ sizeof(struct hv_vmbus_pipe_hdr) +
+ sizeof(struct hv_vmbus_icmsg_hdr)];
+ hv_adj_guesttime(softc, timedatap->parenttime, timedatap->flags);
+ }
+
+ icmsghdrp->icflags = HV_ICMSGHDRFLAG_TRANSACTION
+ | HV_ICMSGHDRFLAG_RESPONSE;
+
+ hv_vmbus_channel_send_packet(channel, time_buf,
+ recvlen, requestId,
+ HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0);
+ }
+}
+
+static int
+hv_timesync_probe(device_t dev)
+{
+ const char *p = vmbus_get_type(dev);
+ if (!memcmp(p, &service_guid, sizeof(hv_guid))) {
+ device_set_desc(dev, "Hyper-V Time Synch Service");
+ return BUS_PROBE_DEFAULT;
+ }
+
+ return ENXIO;
+}
+
+static int
+hv_timesync_attach(device_t dev)
+{
+ hv_timesync_sc *softc = device_get_softc(dev);
+
+ softc->util_sc.callback = hv_timesync_cb;
+ TASK_INIT(&softc->task, 1, hv_set_host_time, softc);
+
+ return hv_util_attach(dev);
+}
+
+static int
+hv_timesync_detach(device_t dev)
+{
+ hv_timesync_sc *softc = device_get_softc(dev);
+ taskqueue_drain(taskqueue_thread, &softc->task);
+
+ return hv_util_detach(dev);
+}
+
+static device_method_t timesync_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, hv_timesync_probe),
+ DEVMETHOD(device_attach, hv_timesync_attach),
+ DEVMETHOD(device_detach, hv_timesync_detach),
+ { 0, 0 }
+};
+
+static driver_t timesync_driver = { "hvtimesync", timesync_methods, sizeof(hv_timesync_sc)};
+
+static devclass_t timesync_devclass;
+
+DRIVER_MODULE(hv_timesync, vmbus, timesync_driver, timesync_devclass, NULL, NULL);
+MODULE_VERSION(hv_timesync, 1);
+MODULE_DEPEND(hv_timesync, vmbus, 1, 1, 1);
Index: head/sys/dev/hyperv/utilities/hv_util.h
===================================================================
--- head/sys/dev/hyperv/utilities/hv_util.h
+++ head/sys/dev/hyperv/utilities/hv_util.h
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 2009-2012 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _HVUTIL_H_
+#define _HVUTIL_H_
+
+/**
+ * hv_util related structures
+ *
+ */
+typedef struct hv_util_sc {
+ /*
+ * function to process Hyper-V messages
+ */
+ void (*callback)(void *);
+
+ struct hv_device* hv_dev;
+ uint8_t *receive_buffer;
+} hv_util_sc;
+
+void hv_negotiate_version(
+ struct hv_vmbus_icmsg_hdr* icmsghdrp,
+ struct hv_vmbus_icmsg_negotiate* negop,
+ uint8_t* buf);
+
+int hv_util_attach(device_t dev);
+int hv_util_detach(device_t dev);
+#endif
Index: head/sys/dev/hyperv/utilities/hv_util.c
===================================================================
--- head/sys/dev/hyperv/utilities/hv_util.c
+++ head/sys/dev/hyperv/utilities/hv_util.c
@@ -40,94 +40,9 @@
#include <sys/syscallsubr.h>
#include <dev/hyperv/include/hyperv.h>
-#include "hv_kvp.h"
+#include "hv_util.h"
-/* Time Sync data */
-typedef struct {
- uint64_t data;
-} time_sync_data;
-
-static void hv_shutdown_cb(void *context);
-static void hv_heartbeat_cb(void *context);
-static void hv_timesync_cb(void *context);
-
-static int hv_timesync_init(hv_vmbus_service *serv);
-static int hv_timesync_uninit(hv_vmbus_service *serv);
-static void hv_set_host_time(void *context, int pending);
-
-/*
- * Note: GUID codes below are predefined by the host hypervisor
- * (Hyper-V and Azure)interface and required for correct operation.
- */
-hv_vmbus_service service_table[] = {
- /* Shutdown Service */
- { .guid.data = {0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
- 0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB},
- .name = "Hyper-V Shutdown Service\n",
- .enabled = TRUE,
- .callback = hv_shutdown_cb,
- },
-
- /* Time Synch Service */
- { .guid.data = {0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
- 0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf},
- .name = "Hyper-V Time Synch Service\n",
- .enabled = TRUE,
- .init = hv_timesync_init,
- .callback = hv_timesync_cb,
- .uninit = hv_timesync_uninit,
- },
-
- /* Heartbeat Service */
- { .guid.data = {0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e,
- 0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d},
- .name = "Hyper-V Heartbeat Service\n",
- .enabled = TRUE,
- .callback = hv_heartbeat_cb,
- },
-
- /* KVP (Key Value Pair) Service */
- { .guid.data = {0xe7, 0xf4, 0xa0, 0xa9, 0x45, 0x5a, 0x96, 0x4d,
- 0xb8, 0x27, 0x8a, 0x84, 0x1e, 0x8c, 0x3, 0xe6},
- .name = "Hyper-V KVP Service\n",
- .enabled = TRUE,
- .init = hv_kvp_init,
- .callback = hv_kvp_callback,
- },
-};
-
-/*
- * Receive buffer pointers. There is one buffer per utility service. The
- * buffer is allocated during attach().
- */
-uint8_t *receive_buffer[HV_MAX_UTIL_SERVICES];
-
-static boolean_t destroyed_kvp = FALSE;
-
-struct hv_ictimesync_data {
- uint64_t parenttime;
- uint64_t childtime;
- uint64_t roundtriptime;
- uint8_t flags;
-} __packed;
-
-static int
-hv_timesync_init(hv_vmbus_service *serv)
-{
- void *time_msg = malloc(sizeof(time_sync_data), M_DEVBUF, M_WAITOK);
- TASK_INIT(&serv->task, 1, hv_set_host_time, time_msg);
- return (0);
-}
-
-static int
-hv_timesync_uninit(hv_vmbus_service *serv)
-{
- taskqueue_drain(taskqueue_thread, &serv->task);
- free(serv->task.ta_context, M_DEVBUF);
- return (0);
-}
-
-static void
+void
hv_negotiate_version(
struct hv_vmbus_icmsg_hdr* icmsghdrp,
struct hv_vmbus_icmsg_negotiate* negop,
@@ -156,252 +71,19 @@
negop->icmsg_vercnt = 1;
}
-
-/**
- * Set host time based on time sync message from host
- */
-static void
-hv_set_host_time(void *context, int pending)
-{
- time_sync_data* time_msg = (time_sync_data*) context;
- uint64_t hosttime = time_msg->data;
- struct timespec guest_ts, host_ts;
- uint64_t host_tns;
- int64_t diff;
- int error;
-
- host_tns = (hosttime - HV_WLTIMEDELTA) * 100;
- host_ts.tv_sec = (time_t)(host_tns/HV_NANO_SEC_PER_SEC);
- host_ts.tv_nsec = (long)(host_tns%HV_NANO_SEC_PER_SEC);
-
- nanotime(&guest_ts);
-
- diff = (int64_t)host_ts.tv_sec - (int64_t)guest_ts.tv_sec;
-
- /*
- * If host differs by 5 seconds then make the guest catch up
- */
- if (diff > 5 || diff < -5) {
- error = kern_clock_settime(curthread, CLOCK_REALTIME,
- &host_ts);
- }
-}
-
-/**
- * @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 = service_table[HV_TIME_SYNCH].task.ta_context;
-
- time_msg->data = hosttime;
-
- if (((flags & HV_ICTIMESYNCFLAG_SYNC) != 0) ||
- ((flags & HV_ICTIMESYNCFLAG_SAMPLE) != 0)) {
- taskqueue_enqueue(taskqueue_thread, &service_table[HV_TIME_SYNCH].task);
- }
-}
-
-/**
- * Time Sync Channel message handler
- */
-static void
-hv_timesync_cb(void *context)
-{
- hv_vmbus_channel* channel = context;
- hv_vmbus_icmsg_hdr* icmsghdrp;
- uint32_t recvlen;
- uint64_t requestId;
- int ret;
- uint8_t* time_buf;
- struct hv_ictimesync_data* timedatap;
-
- time_buf = receive_buffer[HV_TIME_SYNCH];
-
- ret = hv_vmbus_channel_recv_packet(channel, time_buf,
- PAGE_SIZE, &recvlen, &requestId);
-
- if ((ret == 0) && recvlen > 0) {
- icmsghdrp = (struct hv_vmbus_icmsg_hdr *) &time_buf[
- sizeof(struct hv_vmbus_pipe_hdr)];
-
- if (icmsghdrp->icmsgtype == HV_ICMSGTYPE_NEGOTIATE) {
- hv_negotiate_version(icmsghdrp, NULL, time_buf);
- } else {
- timedatap = (struct hv_ictimesync_data *) &time_buf[
- sizeof(struct hv_vmbus_pipe_hdr) +
- sizeof(struct hv_vmbus_icmsg_hdr)];
- hv_adj_guesttime(timedatap->parenttime, timedatap->flags);
- }
-
- icmsghdrp->icflags = HV_ICMSGHDRFLAG_TRANSACTION
- | HV_ICMSGHDRFLAG_RESPONSE;
-
- hv_vmbus_channel_send_packet(channel, time_buf,
- recvlen, requestId,
- HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0);
- }
-}
-
-/**
- * Shutdown
- */
-static void
-hv_shutdown_cb(void *context)
-{
- uint8_t* buf;
- hv_vmbus_channel* channel = context;
- uint8_t execute_shutdown = 0;
- hv_vmbus_icmsg_hdr* icmsghdrp;
- uint32_t recv_len;
- uint64_t request_id;
- int ret;
- hv_vmbus_shutdown_msg_data* shutdown_msg;
-
- buf = receive_buffer[HV_SHUT_DOWN];
-
- ret = hv_vmbus_channel_recv_packet(channel, buf, PAGE_SIZE,
- &recv_len, &request_id);
-
- if ((ret == 0) && recv_len > 0) {
-
- icmsghdrp = (struct hv_vmbus_icmsg_hdr *)
- &buf[sizeof(struct hv_vmbus_pipe_hdr)];
-
- if (icmsghdrp->icmsgtype == HV_ICMSGTYPE_NEGOTIATE) {
- hv_negotiate_version(icmsghdrp, NULL, buf);
-
- } else {
- shutdown_msg =
- (struct hv_vmbus_shutdown_msg_data *)
- &buf[sizeof(struct hv_vmbus_pipe_hdr) +
- sizeof(struct hv_vmbus_icmsg_hdr)];
-
- switch (shutdown_msg->flags) {
- case 0:
- case 1:
- icmsghdrp->status = HV_S_OK;
- execute_shutdown = 1;
- if(bootverbose)
- printf("Shutdown request received -"
- " graceful shutdown initiated\n");
- break;
- default:
- icmsghdrp->status = HV_E_FAIL;
- execute_shutdown = 0;
- printf("Shutdown request received -"
- " Invalid request\n");
- break;
- }
- }
-
- icmsghdrp->icflags = HV_ICMSGHDRFLAG_TRANSACTION |
- HV_ICMSGHDRFLAG_RESPONSE;
-
- hv_vmbus_channel_send_packet(channel, buf,
- recv_len, request_id,
- HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0);
- }
-
- if (execute_shutdown)
- shutdown_nice(RB_POWEROFF);
-}
-
-/**
- * Process heartbeat message
- */
-static void
-hv_heartbeat_cb(void *context)
-{
- uint8_t* buf;
- hv_vmbus_channel* channel = context;
- uint32_t recvlen;
- uint64_t requestid;
- int ret;
-
- struct hv_vmbus_heartbeat_msg_data* heartbeat_msg;
- struct hv_vmbus_icmsg_hdr* icmsghdrp;
-
- buf = receive_buffer[HV_HEART_BEAT];
-
- ret = hv_vmbus_channel_recv_packet(channel, buf, PAGE_SIZE, &recvlen,
- &requestid);
-
- if ((ret == 0) && recvlen > 0) {
-
- icmsghdrp = (struct hv_vmbus_icmsg_hdr *)
- &buf[sizeof(struct hv_vmbus_pipe_hdr)];
-
- if (icmsghdrp->icmsgtype == HV_ICMSGTYPE_NEGOTIATE) {
- hv_negotiate_version(icmsghdrp, NULL, buf);
-
- } else {
- heartbeat_msg =
- (struct hv_vmbus_heartbeat_msg_data *)
- &buf[sizeof(struct hv_vmbus_pipe_hdr) +
- sizeof(struct hv_vmbus_icmsg_hdr)];
-
- heartbeat_msg->seq_num += 1;
- }
-
- 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);
- }
-}
-
-
-static int
-hv_util_probe(device_t dev)
-{
- int i;
- int rtn_value = ENXIO;
-
- for (i = 0; i < HV_MAX_UTIL_SERVICES; i++) {
- const char *p = vmbus_get_type(dev);
- if (service_table[i].enabled && !memcmp(p, &service_table[i].guid, sizeof(hv_guid))) {
- device_set_softc(dev, (void *) (&service_table[i]));
- rtn_value = BUS_PROBE_DEFAULT;
- }
- }
-
- return rtn_value;
-}
-
-static int
+int
hv_util_attach(device_t dev)
{
- struct hv_device* hv_dev;
- struct hv_vmbus_service* service;
- int ret;
- size_t receive_buffer_offset;
+ struct hv_device* hv_dev;
+ struct hv_util_sc* softc;
+ int ret;
hv_dev = vmbus_get_devctx(dev);
- service = device_get_softc(dev);
- receive_buffer_offset = service - &service_table[0];
- device_printf(dev, "Hyper-V Service attaching: %s\n", service->name);
- receive_buffer[receive_buffer_offset] =
+ softc = device_get_softc(dev);
+ softc->hv_dev = hv_dev;
+ softc->receive_buffer =
malloc(4 * PAGE_SIZE, M_DEVBUF, M_WAITOK | M_ZERO);
- if (service->init != NULL) {
- ret = service->init(service);
- if (ret) {
- ret = ENODEV;
- goto error0;
- }
- }
-
/*
* These services are not performance critical and do not need
* batched reading. Furthermore, some services such as KVP can
@@ -412,75 +94,30 @@
hv_set_channel_read_state(hv_dev->channel, FALSE);
ret = hv_vmbus_channel_open(hv_dev->channel, 4 * PAGE_SIZE,
- 4 * PAGE_SIZE, NULL, 0,
- service->callback, hv_dev->channel);
+ 4 * PAGE_SIZE, NULL, 0,
+ softc->callback, softc);
if (ret)
- goto error0;
+ goto error0;
return (0);
- error0:
-
- free(receive_buffer[receive_buffer_offset], M_DEVBUF);
- receive_buffer[receive_buffer_offset] = NULL;
-
+error0:
+ free(softc->receive_buffer, M_DEVBUF);
return (ret);
}
-static int
+int
hv_util_detach(device_t dev)
{
- struct hv_device* hv_dev;
- struct hv_vmbus_service* service;
- size_t receive_buffer_offset;
-
- if (!destroyed_kvp) {
- hv_kvp_deinit();
- destroyed_kvp = TRUE;
- }
+ struct hv_device* hv_dev;
+ struct hv_util_sc* softc;
hv_dev = vmbus_get_devctx(dev);
hv_vmbus_channel_close(hv_dev->channel);
- service = device_get_softc(dev);
- receive_buffer_offset = service - &service_table[0];
+ softc = device_get_softc(dev);
- if (service->uninit != NULL)
- service->uninit(service);
-
- free(receive_buffer[receive_buffer_offset], M_DEVBUF);
- receive_buffer[receive_buffer_offset] = NULL;
+ free(softc->receive_buffer, M_DEVBUF);
return (0);
}
-
-static int
-hv_util_modevent(module_t mod, int event, void *arg)
-{
- switch (event) {
- case MOD_LOAD:
- break;
- case MOD_UNLOAD:
- break;
- default:
- break;
- }
- return (0);
-}
-
-static device_method_t util_methods[] = {
- /* Device interface */
- DEVMETHOD(device_probe, hv_util_probe),
- DEVMETHOD(device_attach, hv_util_attach),
- DEVMETHOD(device_detach, hv_util_detach),
- DEVMETHOD(device_shutdown, bus_generic_shutdown),
- { 0, 0 } }
-;
-
-static driver_t util_driver = { "hyperv-utils", util_methods, 0 };
-
-static devclass_t util_devclass;
-
-DRIVER_MODULE(hv_utils, vmbus, util_driver, util_devclass, hv_util_modevent, 0);
-MODULE_VERSION(hv_utils, 1);
-MODULE_DEPEND(hv_utils, vmbus, 1, 1, 1);
Index: head/sys/modules/hyperv/utilities/Makefile
===================================================================
--- head/sys/modules/hyperv/utilities/Makefile
+++ head/sys/modules/hyperv/utilities/Makefile
@@ -3,7 +3,7 @@
.PATH: ${.CURDIR}/../../../dev/hyperv/utilities
KMOD= hv_utils
-SRCS= hv_util.c hv_kvp.c
+SRCS= hv_util.c hv_kvp.c hv_timesync.c hv_shutdown.c hv_heartbeat.c
SRCS+= bus_if.h device_if.h
CFLAGS+= -I${.CURDIR}/../../../dev/hyperv/include \
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Dec 15, 6:31 AM (21 h, 42 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
9091492
Default Alt Text
D5216.diff (55 KB)
Attached To
Mode
D5216: vmm/hyperv: code cleanup of utility drivers
Attached
Detach File
Event Timeline
Log In to Comment