summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorMike Belopuhov <mikeb@cvs.openbsd.org>2016-10-11 11:46:50 +0000
committerMike Belopuhov <mikeb@cvs.openbsd.org>2016-10-11 11:46:50 +0000
commit9d5cacf3308b5c7205c8633103a8ce7a8b7f25e6 (patch)
treee06fc596af20f308418aea6047dff0bd17b72b2c /sys/dev
parent14b61fa386500850d6df6ed4603d4abd2c4f2641 (diff)
Move Hyper-V integration components into a separate source file
Input & OK reyk.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pv/files.pv3
-rw-r--r--sys/dev/pv/hyperv.c282
-rw-r--r--sys/dev/pv/hypervic.c403
-rw-r--r--sys/dev/pv/hypervicreg.h112
-rw-r--r--sys/dev/pv/hypervreg.h73
5 files changed, 521 insertions, 352 deletions
diff --git a/sys/dev/pv/files.pv b/sys/dev/pv/files.pv
index c49d39dea20..ebb63548c7d 100644
--- a/sys/dev/pv/files.pv
+++ b/sys/dev/pv/files.pv
@@ -1,4 +1,4 @@
-# $OpenBSD: files.pv,v 1.7 2016/07/13 21:59:35 mikeb Exp $
+# $OpenBSD: files.pv,v 1.8 2016/10/11 11:46:49 mikeb Exp $
#
# Config file and device description for paravirtual devices.
# Included by ports that need it.
@@ -27,6 +27,7 @@ file dev/pv/if_xnf.c xnf
device hyperv {}
attach hyperv at pvbus
file dev/pv/hyperv.c hyperv needs-flag
+file dev/pv/hypervic.c hyperv
device hvn: ether, ifnet, ifmedia
attach hvn at hyperv
diff --git a/sys/dev/pv/hyperv.c b/sys/dev/pv/hyperv.c
index 3798440ef90..1c54dd75e17 100644
--- a/sys/dev/pv/hyperv.c
+++ b/sys/dev/pv/hyperv.c
@@ -103,15 +103,7 @@ struct hv_channel *
hv_channel_lookup(struct hv_softc *, uint32_t);
int hv_channel_ring_create(struct hv_channel *, uint32_t, uint32_t);
void hv_channel_ring_destroy(struct hv_channel *);
-void hv_attach_internal(struct hv_softc *);
-void hv_heartbeat(void *);
-void hv_kvp_init(struct hv_channel *);
-void hv_kvp(void *);
-int hv_kvop(void *, int, char *, char *, size_t);
-void hv_shutdown_init(struct hv_channel *);
-void hv_shutdown(void *);
-void hv_timesync_init(struct hv_channel *);
-void hv_timesync(void *);
+extern void hv_attach_icdevs(struct hv_softc *);
int hv_attach_devices(struct hv_softc *);
struct {
@@ -316,8 +308,6 @@ hv_deferred(void *arg)
if (hv_channel_scan(sc))
return;
- hv_attach_internal(sc);
-
if (hv_attach_devices(sc))
return;
}
@@ -1617,273 +1607,6 @@ hv_handle_free(struct hv_channel *ch, uint32_t handle)
sc->sc_dev.dv_xname, rv);
}
-const struct {
- const char *id_name;
- const struct hv_guid *id_type;
- void (*id_init)(struct hv_channel *);
- void (*id_handler)(void *);
-} hv_internal_devs[] = {
- { "heartbeat", &hv_guid_heartbeat, NULL, hv_heartbeat },
- { "kvp", &hv_guid_kvp, hv_kvp_init, hv_kvp },
- { "shutdown", &hv_guid_shutdown, hv_shutdown_init, hv_shutdown },
- { "timesync", &hv_guid_timesync, hv_timesync_init, hv_timesync }
-};
-
-void
-hv_attach_internal(struct hv_softc *sc)
-{
- struct hv_channel *ch;
- int i;
-
- TAILQ_FOREACH(ch, &sc->sc_channels, ch_entry) {
- if (ch->ch_state != HV_CHANSTATE_OFFERED)
- continue;
- if (ch->ch_flags & CHF_MONITOR)
- continue;
- for (i = 0; i < nitems(hv_internal_devs); i++) {
- if (memcmp(hv_internal_devs[i].id_type, &ch->ch_type,
- sizeof(ch->ch_type)) != 0)
- continue;
- /*
- * These services are not performance critical and
- * do not need batched reading. Furthermore, some
- * services such as KVP can only handle one message
- * from the host at a time.
- */
- ch->ch_flags &= ~CHF_BATCHED;
-
- if (hv_internal_devs[i].id_init)
- hv_internal_devs[i].id_init(ch);
-
- ch->ch_buf = km_alloc(PAGE_SIZE, &kv_any, &kp_zero,
- (cold ? &kd_nowait : &kd_waitok));
- if (ch->ch_buf == NULL) {
- hv_channel_ring_destroy(ch);
- printf("%s: failed to allocate channel data "
- "buffer for \"%s\"", sc->sc_dev.dv_xname,
- hv_internal_devs[i].id_name);
- continue;
- }
- ch->ch_buflen = PAGE_SIZE;
-
- if (hv_channel_open(ch, NULL, 0,
- hv_internal_devs[i].id_handler, ch)) {
- km_free(ch->ch_buf, PAGE_SIZE, &kv_any,
- &kp_zero);
- ch->ch_buf = NULL;
- ch->ch_buflen = 0;
- printf("%s: failed to open channel for \"%s\"\n",
- sc->sc_dev.dv_xname,
- hv_internal_devs[i].id_name);
- }
- evcount_attach(&ch->ch_evcnt,
- hv_internal_devs[i].id_name, &sc->sc_idtvec);
- break;
- }
- }
-}
-
-int
-hv_service_common(struct hv_channel *ch, uint32_t *rlen, uint64_t *rid,
- struct hv_icmsg_hdr **hdr)
-{
- struct hv_icmsg_negotiate *msg;
- int rv;
-
- rv = hv_channel_recv(ch, ch->ch_buf, ch->ch_buflen, rlen, rid, 0);
- if (rv || *rlen == 0)
- return (rv);
- *hdr = (struct hv_icmsg_hdr *)&ch->ch_buf[sizeof(struct hv_pipe_hdr)];
- if ((*hdr)->icmsgtype == HV_ICMSGTYPE_NEGOTIATE) {
- msg = (struct hv_icmsg_negotiate *)(*hdr + 1);
- if (msg->icframe_vercnt >= 2 &&
- msg->icversion_data[1].major == 3) {
- msg->icversion_data[0].major = 3;
- msg->icversion_data[0].minor = 0;
- msg->icversion_data[1].major = 3;
- msg->icversion_data[1].minor = 0;
- } else {
- msg->icversion_data[0].major = 1;
- msg->icversion_data[0].minor = 0;
- msg->icversion_data[1].major = 1;
- msg->icversion_data[1].minor = 0;
- }
- msg->icframe_vercnt = 1;
- msg->icmsg_vercnt = 1;
- (*hdr)->icmsgsize = 0x10;
- }
- return (0);
-}
-
-void
-hv_heartbeat(void *arg)
-{
- struct hv_channel *ch = arg;
- struct hv_softc *sc = ch->ch_sc;
- struct hv_icmsg_hdr *hdr;
- struct hv_heartbeat_msg *msg;
- uint64_t rid;
- uint32_t rlen;
- int rv;
-
- rv = hv_service_common(ch, &rlen, &rid, &hdr);
- if (rv || rlen == 0) {
- if (rv != EAGAIN)
- printf("heartbeat: rv=%d rlen=%u\n", rv, rlen);
- return;
- }
- if (hdr->icmsgtype == HV_ICMSGTYPE_HEARTBEAT) {
- msg = (struct hv_heartbeat_msg *)(hdr + 1);
- msg->seq_num += 1;
- } else if (hdr->icmsgtype != HV_ICMSGTYPE_NEGOTIATE) {
- printf("%s: unhandled heartbeat message type %u\n",
- sc->sc_dev.dv_xname, hdr->icmsgtype);
- }
- hdr->icflags = HV_ICMSGHDRFLAG_TRANSACTION | HV_ICMSGHDRFLAG_RESPONSE;
- hv_channel_send(ch, ch->ch_buf, rlen, rid, VMBUS_CHANPKT_TYPE_INBAND, 0);
-}
-
-void
-hv_kvp_init(struct hv_channel *ch)
-{
- struct hv_softc *sc = ch->ch_sc;
-
- sc->sc_pvbus->hv_kvop = hv_kvop;
- sc->sc_pvbus->hv_arg = sc;
-}
-
-void
-hv_kvp(void *arg)
-{
-}
-
-int
-hv_kvop(void *arg, int op, char *key, char *value, size_t valuelen)
-{
- switch (op) {
- case PVBUS_KVWRITE:
- case PVBUS_KVREAD:
- default:
- return (EOPNOTSUPP);
- }
-}
-
-static void
-hv_shutdown_task(void *arg)
-{
- extern int allowpowerdown;
-
- if (allowpowerdown == 0)
- return;
-
- suspend_randomness();
-
- log(LOG_KERN | LOG_NOTICE, "Shutting down in response to "
- "request from Hyper-V host\n");
- prsignal(initprocess, SIGUSR2);
-}
-
-void
-hv_shutdown_init(struct hv_channel *ch)
-{
- struct hv_softc *sc = ch->ch_sc;
-
- task_set(&sc->sc_sdtask, hv_shutdown_task, sc);
-}
-
-void
-hv_shutdown(void *arg)
-{
- struct hv_channel *ch = arg;
- struct hv_softc *sc = ch->ch_sc;
- struct hv_icmsg_hdr *hdr;
- struct hv_shutdown_msg *msg;
- uint64_t rid;
- uint32_t rlen;
- int rv, shutdown = 0;
-
- rv = hv_service_common(ch, &rlen, &rid, &hdr);
- if (rv || rlen == 0) {
- if (rv != EAGAIN)
- printf("shutdown: rv=%d rlen=%u\n", rv, rlen);
- return;
- }
- if (hdr->icmsgtype == HV_ICMSGTYPE_SHUTDOWN) {
- msg = (struct hv_shutdown_msg *)(hdr + 1);
- if (msg->flags == 0 || msg->flags == 1) {
- shutdown = 1;
- hdr->status = HV_ICMSG_STATUS_OK;
- } else
- hdr->status = HV_ICMSG_STATUS_FAIL;
- } else if (hdr->icmsgtype != HV_ICMSGTYPE_NEGOTIATE) {
- printf("%s: unhandled shutdown message type %u\n",
- sc->sc_dev.dv_xname, hdr->icmsgtype);
- }
-
- hdr->icflags = HV_ICMSGHDRFLAG_TRANSACTION | HV_ICMSGHDRFLAG_RESPONSE;
- hv_channel_send(ch, ch->ch_buf, rlen, rid, VMBUS_CHANPKT_TYPE_INBAND, 0);
-
- if (shutdown)
- task_add(systq, &sc->sc_sdtask);
-}
-
-void
-hv_timesync_init(struct hv_channel *ch)
-{
- struct hv_softc *sc = ch->ch_sc;
-
- strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
- sizeof(sc->sc_sensordev.xname));
-
- sc->sc_sensor.type = SENSOR_TIMEDELTA;
- sc->sc_sensor.status = SENSOR_S_UNKNOWN;
-
- sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
- sensordev_install(&sc->sc_sensordev);
-}
-
-void
-hv_timesync(void *arg)
-{
- struct hv_channel *ch = arg;
- struct hv_softc *sc = ch->ch_sc;
- struct hv_icmsg_hdr *hdr;
- struct hv_timesync_msg *msg;
- struct timespec guest, host, diff;
- uint64_t tns;
- uint64_t rid;
- uint32_t rlen;
- int rv;
-
- rv = hv_service_common(ch, &rlen, &rid, &hdr);
- if (rv || rlen == 0) {
- if (rv != EAGAIN)
- printf("timesync: rv=%d rlen=%u\n", rv, rlen);
- return;
- }
- if (hdr->icmsgtype == HV_ICMSGTYPE_TIMESYNC) {
- msg = (struct hv_timesync_msg *)(hdr + 1);
- if (msg->flags == HV_TIMESYNC_SYNC ||
- msg->flags == HV_TIMESYNC_SAMPLE) {
- microtime(&sc->sc_sensor.tv);
- nanotime(&guest);
- tns = (msg->parent_time - 116444736000000000LL) * 100;
- host.tv_sec = tns / 1000000000LL;
- host.tv_nsec = tns % 1000000000LL;
- timespecsub(&guest, &host, &diff);
- sc->sc_sensor.value = (int64_t)diff.tv_sec *
- 1000000000LL + diff.tv_nsec;
- sc->sc_sensor.status = SENSOR_S_OK;
- }
- } else if (hdr->icmsgtype != HV_ICMSGTYPE_NEGOTIATE) {
- printf("%s: unhandled timesync message type %u\n",
- sc->sc_dev.dv_xname, hdr->icmsgtype);
- }
-
- hdr->icflags = HV_ICMSGHDRFLAG_TRANSACTION | HV_ICMSGHDRFLAG_RESPONSE;
- hv_channel_send(ch, ch->ch_buf, rlen, rid, VMBUS_CHANPKT_TYPE_INBAND, 0);
-}
-
static int
hv_attach_print(void *aux, const char *name)
{
@@ -1904,6 +1627,9 @@ hv_attach_devices(struct hv_softc *sc)
SLIST_INIT(&sc->sc_devs);
mtx_init(&sc->sc_devlck, IPL_NET);
+ /* Attach heartbeat, KVP and other "internal" services */
+ hv_attach_icdevs(sc);
+
TAILQ_FOREACH(ch, &sc->sc_channels, ch_entry) {
if (ch->ch_state != HV_CHANSTATE_OFFERED)
continue;
diff --git a/sys/dev/pv/hypervic.c b/sys/dev/pv/hypervic.c
new file mode 100644
index 00000000000..f131496a2f4
--- /dev/null
+++ b/sys/dev/pv/hypervic.c
@@ -0,0 +1,403 @@
+/*-
+ * Copyright (c) 2009-2016 Microsoft Corp.
+ * Copyright (c) 2012 NetApp Inc.
+ * Copyright (c) 2012 Citrix Inc.
+ * Copyright (c) 2016 Mike Belopuhov <mike@esdenera.com>
+ * 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.
+ */
+
+/*
+ * The OpenBSD port was done under funding by Esdenera Networks GmbH.
+ */
+
+#include <sys/param.h>
+
+/* Hyperv requires locked atomic operations */
+#ifndef MULTIPROCESSOR
+#define _HYPERVMPATOMICS
+#define MULTIPROCESSOR
+#endif
+#include <sys/atomic.h>
+#ifdef _HYPERVMPATOMICS
+#undef MULTIPROCESSOR
+#undef _HYPERVMPATOMICS
+#endif
+
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/signal.h>
+#include <sys/signalvar.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/timetc.h>
+#include <sys/task.h>
+#include <sys/syslog.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/i82489var.h>
+
+#include <dev/rndvar.h>
+
+#include <dev/pv/pvvar.h>
+#include <dev/pv/pvreg.h>
+#include <dev/pv/hypervreg.h>
+#include <dev/pv/hypervvar.h>
+#include <dev/pv/hypervicreg.h>
+
+void hv_heartbeat(void *);
+void hv_kvp_attach(struct hv_channel *);
+void hv_kvp(void *);
+int hv_kvop(void *, int, char *, char *, size_t);
+void hv_shutdown_attach(struct hv_channel *);
+void hv_shutdown(void *);
+void hv_timesync_attach(struct hv_channel *);
+void hv_timesync(void *);
+
+const struct {
+ const char *dv_name;
+ const struct hv_guid *dv_type;
+ void (*dv_attach)(struct hv_channel *);
+ void (*dv_handler)(void *);
+} hv_ic_devs[] = {
+ {
+ "Heartbeat",
+ &hv_guid_heartbeat,
+ NULL,
+ hv_heartbeat
+ },
+ {
+ "KVP",
+ &hv_guid_kvp,
+ hv_kvp_attach,
+ hv_kvp
+ },
+ {
+ "Shutdown",
+ &hv_guid_shutdown,
+ hv_shutdown_attach,
+ hv_shutdown
+ },
+ {
+ "Timesync",
+ &hv_guid_timesync,
+ hv_timesync_attach,
+ hv_timesync
+ }
+};
+
+void
+hv_attach_icdevs(struct hv_softc *sc)
+{
+ struct hv_channel *ch;
+ int i, header = 0;
+
+ TAILQ_FOREACH(ch, &sc->sc_channels, ch_entry) {
+ if (ch->ch_state != HV_CHANSTATE_OFFERED)
+ continue;
+ if (ch->ch_flags & CHF_MONITOR)
+ continue;
+ for (i = 0; i < nitems(hv_ic_devs); i++) {
+ if (memcmp(hv_ic_devs[i].dv_type, &ch->ch_type,
+ sizeof(ch->ch_type)) != 0)
+ continue;
+ /*
+ * These services are not performance critical and
+ * do not need batched reading. Furthermore, some
+ * services such as KVP can only handle one message
+ * from the host at a time.
+ */
+ ch->ch_flags &= ~CHF_BATCHED;
+
+ ch->ch_buf = km_alloc(PAGE_SIZE, &kv_any, &kp_zero,
+ (cold ? &kd_nowait : &kd_waitok));
+ if (ch->ch_buf == NULL) {
+ printf("%s: failed to allocate channel data "
+ "buffer for %s", sc->sc_dev.dv_xname,
+ hv_ic_devs[i].dv_name);
+ continue;
+ }
+ ch->ch_buflen = PAGE_SIZE;
+
+ if (hv_channel_open(ch, NULL, 0,
+ hv_ic_devs[i].dv_handler, ch)) {
+ km_free(ch->ch_buf, PAGE_SIZE, &kv_any,
+ &kp_zero);
+ ch->ch_buf = NULL;
+ ch->ch_buflen = 0;
+ printf("%s: failed to open channel for %s\n",
+ sc->sc_dev.dv_xname, hv_ic_devs[i].dv_name);
+ continue;
+ }
+ evcount_attach(&ch->ch_evcnt, hv_ic_devs[i].dv_name,
+ &sc->sc_idtvec);
+
+ if (hv_ic_devs[i].dv_attach)
+ hv_ic_devs[i].dv_attach(ch);
+
+ if (!header) {
+ printf("%s: %s", sc->sc_dev.dv_xname,
+ hv_ic_devs[i].dv_name);
+ header = 1;
+ } else
+ printf(", %s", hv_ic_devs[i].dv_name);
+
+ break;
+ }
+ }
+ if (header)
+ printf("\n");
+}
+
+static inline void
+hv_ic_negotiate(struct vmbus_icmsg_hdr *hdr)
+{
+ struct vmbus_icmsg_negotiate *msg;
+
+ msg = (struct vmbus_icmsg_negotiate *)hdr;
+ if (msg->ic_fwver_cnt >= 2 &&
+ VMBUS_ICVER_MAJOR(msg->ic_ver[1]) == 3) {
+ msg->ic_ver[0] = VMBUS_IC_VERSION(3, 0);
+ msg->ic_ver[1] = VMBUS_IC_VERSION(3, 0);
+ } else {
+ msg->ic_ver[0] = VMBUS_IC_VERSION(1, 0);
+ msg->ic_ver[1] = VMBUS_IC_VERSION(1, 0);
+ }
+ msg->ic_fwver_cnt = 1;
+ msg->ic_msgver_cnt = 1;
+ hdr->ic_dsize = sizeof(*msg) + 2 * sizeof(uint32_t);
+}
+
+void
+hv_heartbeat(void *arg)
+{
+ struct hv_channel *ch = arg;
+ struct hv_softc *sc = ch->ch_sc;
+ struct vmbus_icmsg_hdr *hdr;
+ struct vmbus_icmsg_heartbeat *msg;
+ uint64_t rid;
+ uint32_t rlen;
+ int rv;
+
+ rv = hv_channel_recv(ch, ch->ch_buf, ch->ch_buflen, &rlen, &rid, 0);
+ if (rv || rlen == 0) {
+ if (rv != EAGAIN)
+ DPRINTF("%s: heartbeat rv=%d rlen=%u\n",
+ sc->sc_dev.dv_xname, rv, rlen);
+ return;
+ }
+ if (rlen < sizeof(struct vmbus_icmsg_hdr)) {
+ DPRINTF("%s: heartbeat short read rlen=%u\n",
+ sc->sc_dev.dv_xname, rlen);
+ return;
+ }
+ hdr = (struct vmbus_icmsg_hdr *)ch->ch_buf;
+ switch (hdr->ic_type) {
+ case VMBUS_ICMSG_TYPE_NEGOTIATE:
+ hv_ic_negotiate(hdr);
+ break;
+ case VMBUS_ICMSG_TYPE_HEARTBEAT:
+ msg = (struct vmbus_icmsg_heartbeat *)hdr;
+ msg->ic_seq += 1;
+ break;
+ default:
+ printf("%s: unhandled heartbeat message type %u\n",
+ sc->sc_dev.dv_xname, hdr->ic_type);
+ return;
+ }
+ hdr->ic_flags = VMBUS_ICMSG_FLAG_TRANSACTION | VMBUS_ICMSG_FLAG_RESPONSE;
+ hv_channel_send(ch, ch->ch_buf, rlen, rid, VMBUS_CHANPKT_TYPE_INBAND, 0);
+}
+
+void
+hv_kvp_attach(struct hv_channel *ch)
+{
+ struct hv_softc *sc = ch->ch_sc;
+
+ sc->sc_pvbus->hv_kvop = hv_kvop;
+ sc->sc_pvbus->hv_arg = sc;
+}
+
+void
+hv_kvp(void *arg)
+{
+}
+
+int
+hv_kvop(void *arg, int op, char *key, char *value, size_t valuelen)
+{
+ switch (op) {
+ case PVBUS_KVWRITE:
+ case PVBUS_KVREAD:
+ default:
+ return (EOPNOTSUPP);
+ }
+}
+
+static void
+hv_shutdown_task(void *arg)
+{
+ extern int allowpowerdown;
+
+ if (allowpowerdown == 0)
+ return;
+
+ suspend_randomness();
+
+ log(LOG_KERN | LOG_NOTICE, "Shutting down in response to "
+ "request from Hyper-V host\n");
+ prsignal(initprocess, SIGUSR2);
+}
+
+void
+hv_shutdown_attach(struct hv_channel *ch)
+{
+ struct hv_softc *sc = ch->ch_sc;
+
+ task_set(&sc->sc_sdtask, hv_shutdown_task, sc);
+}
+
+void
+hv_shutdown(void *arg)
+{
+ struct hv_channel *ch = arg;
+ struct hv_softc *sc = ch->ch_sc;
+ struct vmbus_icmsg_hdr *hdr;
+ struct vmbus_icmsg_shutdown *msg;
+ uint64_t rid;
+ uint32_t rlen;
+ int rv, shutdown = 0;
+
+ rv = hv_channel_recv(ch, ch->ch_buf, ch->ch_buflen, &rlen, &rid, 0);
+ if (rv || rlen == 0) {
+ if (rv != EAGAIN)
+ DPRINTF("%s: shutdown rv=%d rlen=%u\n",
+ sc->sc_dev.dv_xname, rv, rlen);
+ return;
+ }
+ if (rlen < sizeof(struct vmbus_icmsg_hdr)) {
+ DPRINTF("%s: shutdown short read rlen=%u\n",
+ sc->sc_dev.dv_xname, rlen);
+ return;
+ }
+ hdr = (struct vmbus_icmsg_hdr *)ch->ch_buf;
+ switch (hdr->ic_type) {
+ case VMBUS_ICMSG_TYPE_NEGOTIATE:
+ hv_ic_negotiate(hdr);
+ break;
+ case VMBUS_ICMSG_TYPE_SHUTDOWN:
+ msg = (struct vmbus_icmsg_shutdown *)hdr;
+ if (msg->ic_haltflags == 0 || msg->ic_haltflags == 1) {
+ shutdown = 1;
+ hdr->ic_status = VMBUS_ICMSG_STATUS_OK;
+ } else
+ hdr->ic_status = VMBUS_ICMSG_STATUS_FAIL;
+ break;
+ default:
+ printf("%s: unhandled shutdown message type %u\n",
+ sc->sc_dev.dv_xname, hdr->ic_type);
+ return;
+ }
+
+ hdr->ic_flags = VMBUS_ICMSG_FLAG_TRANSACTION | VMBUS_ICMSG_FLAG_RESPONSE;
+ hv_channel_send(ch, ch->ch_buf, rlen, rid, VMBUS_CHANPKT_TYPE_INBAND, 0);
+
+ if (shutdown)
+ task_add(systq, &sc->sc_sdtask);
+}
+
+void
+hv_timesync_attach(struct hv_channel *ch)
+{
+ struct hv_softc *sc = ch->ch_sc;
+
+ strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
+ sizeof(sc->sc_sensordev.xname));
+
+ sc->sc_sensor.type = SENSOR_TIMEDELTA;
+ sc->sc_sensor.status = SENSOR_S_UNKNOWN;
+
+ sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
+ sensordev_install(&sc->sc_sensordev);
+}
+
+void
+hv_timesync(void *arg)
+{
+ struct hv_channel *ch = arg;
+ struct hv_softc *sc = ch->ch_sc;
+ struct vmbus_icmsg_hdr *hdr;
+ struct vmbus_icmsg_timesync *msg;
+ struct timespec guest, host, diff;
+ uint64_t tns;
+ uint64_t rid;
+ uint32_t rlen;
+ int rv;
+
+ rv = hv_channel_recv(ch, ch->ch_buf, ch->ch_buflen, &rlen, &rid, 0);
+ if (rv || rlen == 0) {
+ if (rv != EAGAIN)
+ DPRINTF("%s: timesync rv=%d rlen=%u\n",
+ sc->sc_dev.dv_xname, rv, rlen);
+ return;
+ }
+ if (rlen < sizeof(struct vmbus_icmsg_hdr)) {
+ DPRINTF("%s: timesync short read rlen=%u\n",
+ sc->sc_dev.dv_xname, rlen);
+ return;
+ }
+ hdr = (struct vmbus_icmsg_hdr *)ch->ch_buf;
+ switch (hdr->ic_type) {
+ case VMBUS_ICMSG_TYPE_NEGOTIATE:
+ hv_ic_negotiate(hdr);
+ break;
+ case VMBUS_ICMSG_TYPE_TIMESYNC:
+ msg = (struct vmbus_icmsg_timesync *)hdr;
+ if (msg->ic_tsflags == VMBUS_ICMSG_TS_FLAG_SYNC ||
+ msg->ic_tsflags == VMBUS_ICMSG_TS_FLAG_SAMPLE) {
+ microtime(&sc->sc_sensor.tv);
+ nanotime(&guest);
+ tns = (msg->ic_hvtime - 116444736000000000LL) * 100;
+ host.tv_sec = tns / 1000000000LL;
+ host.tv_nsec = tns % 1000000000LL;
+ timespecsub(&guest, &host, &diff);
+ sc->sc_sensor.value = (int64_t)diff.tv_sec *
+ 1000000000LL + diff.tv_nsec;
+ sc->sc_sensor.status = SENSOR_S_OK;
+ }
+ break;
+ default:
+ printf("%s: unhandled timesync message type %u\n",
+ sc->sc_dev.dv_xname, hdr->ic_type);
+ return;
+ }
+
+ hdr->ic_flags = VMBUS_ICMSG_FLAG_TRANSACTION | VMBUS_ICMSG_FLAG_RESPONSE;
+ hv_channel_send(ch, ch->ch_buf, rlen, rid, VMBUS_CHANPKT_TYPE_INBAND, 0);
+}
diff --git a/sys/dev/pv/hypervicreg.h b/sys/dev/pv/hypervicreg.h
new file mode 100644
index 00000000000..66343783315
--- /dev/null
+++ b/sys/dev/pv/hypervicreg.h
@@ -0,0 +1,112 @@
+/*-
+ * 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: head/sys/dev/hyperv/utilities/vmbus_icreg.h 305281 2016-09-02 06:23:28Z sephe $
+ */
+
+#ifndef _DEV_PV_HYPERVIC_H_
+#define _DEV_PV_HYPERVIC_H_
+
+#define VMBUS_ICMSG_TYPE_NEGOTIATE 0
+#define VMBUS_ICMSG_TYPE_HEARTBEAT 1
+#define VMBUS_ICMSG_TYPE_KVP 2
+#define VMBUS_ICMSG_TYPE_SHUTDOWN 3
+#define VMBUS_ICMSG_TYPE_TIMESYNC 4
+#define VMBUS_ICMSG_TYPE_VSS 5
+
+#define VMBUS_ICMSG_STATUS_OK 0x00000000
+#define VMBUS_ICMSG_STATUS_FAIL 0x80004005
+
+#define VMBUS_ICMSG_FLAG_TRANSACTION 1
+#define VMBUS_ICMSG_FLAG_REQUEST 2
+#define VMBUS_ICMSG_FLAG_RESPONSE 4
+
+#define VMBUS_IC_VERSION(major, minor) ((major) | (((uint32_t)(minor)) << 16))
+#define VMBUS_ICVER_MAJOR(ver) ((ver) & 0xffff)
+#define VMBUS_ICVER_MINOR(ver) (((ver) & 0xffff0000) >> 16)
+
+struct vmbus_pipe_hdr {
+ uint32_t ph_flags;
+ uint32_t ph_msgsz;
+} __packed;
+
+struct vmbus_icmsg_hdr {
+ struct vmbus_pipe_hdr ic_pipe;
+ uint32_t ic_fwver; /* framework version */
+ uint16_t ic_type;
+ uint32_t ic_msgver; /* message version */
+ uint16_t ic_dsize; /* data size */
+ uint32_t ic_status; /* VMBUS_ICMSG_STATUS_ */
+ uint8_t ic_tid;
+ uint8_t ic_flags; /* VMBUS_ICMSG_FLAG_ */
+ uint8_t ic_rsvd[2];
+} __packed;
+
+/* VMBUS_ICMSG_TYPE_NEGOTIATE */
+struct vmbus_icmsg_negotiate {
+ struct vmbus_icmsg_hdr ic_hdr;
+ uint16_t ic_fwver_cnt;
+ uint16_t ic_msgver_cnt;
+ uint32_t ic_rsvd;
+ /*
+ * This version array contains two set of supported
+ * versions:
+ * - The first set consists of #ic_fwver_cnt supported framework
+ * versions.
+ * - The second set consists of #ic_msgver_cnt supported message
+ * versions.
+ */
+ uint32_t ic_ver[0];
+} __packed;
+
+/* VMBUS_ICMSG_TYPE_HEARTBEAT */
+struct vmbus_icmsg_heartbeat {
+ struct vmbus_icmsg_hdr ic_hdr;
+ uint64_t ic_seq;
+ uint32_t ic_rsvd[8];
+} __packed;
+
+/* VMBUS_ICMSG_TYPE_SHUTDOWN */
+struct vmbus_icmsg_shutdown {
+ struct vmbus_icmsg_hdr ic_hdr;
+ uint32_t ic_code;
+ uint32_t ic_timeo;
+ uint32_t ic_haltflags;
+ uint8_t ic_msg[2048];
+} __packed;
+
+/* VMBUS_ICMSG_TYPE_TIMESYNC */
+struct vmbus_icmsg_timesync {
+ struct vmbus_icmsg_hdr ic_hdr;
+ uint64_t ic_hvtime;
+ uint64_t ic_vmtime;
+ uint64_t ic_rtt;
+ uint8_t ic_tsflags; /* VMBUS_ICMSG_TS_FLAG_ */
+} __packed;
+
+#define VMBUS_ICMSG_TS_FLAG_SYNC 0x01
+#define VMBUS_ICMSG_TS_FLAG_SAMPLE 0x02
+
+#endif /* _DEV_PV_HYPERVIC_H_ */
diff --git a/sys/dev/pv/hypervreg.h b/sys/dev/pv/hypervreg.h
index 2a2915fb3fc..e3cc0aa2993 100644
--- a/sys/dev/pv/hypervreg.h
+++ b/sys/dev/pv/hypervreg.h
@@ -542,77 +542,4 @@ struct vmbus_chanmsg_choffer {
#define VMBUS_CHOFFER_FLAG1_HASMNF 0x01
-/*
- * ============================================================================
- * Integrated services
- * ============================================================================
- */
-
- /*
- * Common defines for Hyper-V ICs
- */
-#define HV_ICMSGTYPE_NEGOTIATE 0
-#define HV_ICMSGTYPE_HEARTBEAT 1
-#define HV_ICMSGTYPE_KVPEXCHANGE 2
-#define HV_ICMSGTYPE_SHUTDOWN 3
-#define HV_ICMSGTYPE_TIMESYNC 4
-#define HV_ICMSGTYPE_VSS 5
-
-#define HV_ICMSGHDRFLAG_TRANSACTION 1
-#define HV_ICMSGHDRFLAG_REQUEST 2
-#define HV_ICMSGHDRFLAG_RESPONSE 4
-
-struct hv_pipe_hdr {
- uint32_t flags;
- uint32_t msgsize;
-} __packed;
-
-struct hv_ic_version {
- uint16_t major;
- uint16_t minor;
-} __packed;
-
-struct hv_icmsg_hdr {
- struct hv_ic_version icverframe;
- uint16_t icmsgtype;
- struct hv_ic_version icvermsg;
- uint16_t icmsgsize;
- uint32_t status;
- uint8_t ictransaction_id;
- uint8_t icflags;
- uint8_t reserved[2];
-} __packed;
-
-#define HV_ICMSG_STATUS_OK 0x00000000
-#define HV_ICMSG_STATUS_FAIL 0x80004005
-
-struct hv_icmsg_negotiate {
- uint16_t icframe_vercnt;
- uint16_t icmsg_vercnt;
- uint32_t reserved;
- struct hv_ic_version icversion_data[1]; /* any size array */
-} __packed;
-
-struct hv_shutdown_msg {
- uint32_t reason_code;
- uint32_t timeout_seconds;
- uint32_t flags;
- uint8_t display_message[2048];
-} __packed;
-
-struct hv_timesync_msg {
- uint64_t parent_time;
- uint64_t child_time;
- uint64_t round_trip_time;
- uint8_t flags;
-#define HV_TIMESYNC_PROBE 0
-#define HV_TIMESYNC_SYNC 1
-#define HV_TIMESYNC_SAMPLE 2
-} __packed;
-
-struct hv_heartbeat_msg {
- uint64_t seq_num;
- uint32_t reserved[8];
-} __packed;
-
#endif /* _DEV_PV_HYPERVREG_H_ */