diff options
author | Mike Belopuhov <mikeb@cvs.openbsd.org> | 2016-10-11 11:46:50 +0000 |
---|---|---|
committer | Mike Belopuhov <mikeb@cvs.openbsd.org> | 2016-10-11 11:46:50 +0000 |
commit | 9d5cacf3308b5c7205c8633103a8ce7a8b7f25e6 (patch) | |
tree | e06fc596af20f308418aea6047dff0bd17b72b2c /sys/dev/pv | |
parent | 14b61fa386500850d6df6ed4603d4abd2c4f2641 (diff) |
Move Hyper-V integration components into a separate source file
Input & OK reyk.
Diffstat (limited to 'sys/dev/pv')
-rw-r--r-- | sys/dev/pv/files.pv | 3 | ||||
-rw-r--r-- | sys/dev/pv/hyperv.c | 282 | ||||
-rw-r--r-- | sys/dev/pv/hypervic.c | 403 | ||||
-rw-r--r-- | sys/dev/pv/hypervicreg.h | 112 | ||||
-rw-r--r-- | sys/dev/pv/hypervreg.h | 73 |
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_ */ |